@rotki/ui-library 2.24.0 → 2.25.1

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 (337) hide show
  1. package/README.md +3 -2
  2. package/dist/components/accordions/accordion/RuiAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
  3. package/dist/components/accordions/accordions/RuiAccordions.vue_vue_type_script_setup_true_lang.js.map +1 -1
  4. package/dist/components/alerts/RuiAlert.vue_vue_type_script_setup_true_lang.js.map +1 -1
  5. package/dist/components/avatars/RuiAvatar.vue.d.ts +1 -1
  6. package/dist/components/avatars/RuiAvatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  7. package/dist/components/avatars/RuiAvatarGroup.js.map +1 -1
  8. package/dist/components/avatars/RuiAvatarGroup.vue.d.ts +1 -1
  9. package/dist/components/avatars/RuiAvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  10. package/dist/components/avatars/use-avatar-group.d.ts +1 -1
  11. package/dist/components/buttons/button/RuiButton.vue.d.ts +1 -1
  12. package/dist/components/buttons/button/RuiButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  13. package/dist/components/buttons/button/button-styles.d.ts +40 -2
  14. package/dist/components/buttons/button/button-styles.js +38 -0
  15. package/dist/components/buttons/button/button-styles.js.map +1 -1
  16. package/dist/components/buttons/button-group/RuiButtonGroup.js.map +1 -1
  17. package/dist/components/buttons/button-group/RuiButtonGroup.vue.d.ts +1 -1
  18. package/dist/components/buttons/button-group/RuiButtonGroup.vue_vue_type_script_setup_true_lang.js +26 -14
  19. package/dist/components/buttons/button-group/RuiButtonGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  20. package/dist/components/calendar/RuiCalendar.js.map +1 -1
  21. package/dist/components/calendar/RuiCalendar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  22. package/dist/components/calendar/RuiCalendarGrid.js.map +1 -1
  23. package/dist/components/calendar/RuiCalendarGrid.vue_vue_type_script_setup_true_lang.js +7 -0
  24. package/dist/components/calendar/RuiCalendarGrid.vue_vue_type_script_setup_true_lang.js.map +1 -1
  25. package/dist/components/calendar/RuiCalendarHeader.vue.d.ts +1 -1
  26. package/dist/components/calendar/RuiCalendarHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
  27. package/dist/components/calendar/RuiCalendarMenu.js.map +1 -1
  28. package/dist/components/calendar/RuiCalendarMenu.vue.d.ts +1 -1
  29. package/dist/components/calendar/RuiCalendarMenu.vue_vue_type_script_setup_true_lang.js +1 -0
  30. package/dist/components/calendar/RuiCalendarMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  31. package/dist/components/cards/RuiCard.vue_vue_type_script_setup_true_lang.js.map +1 -1
  32. package/dist/components/cards/RuiCardHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
  33. package/dist/components/chips/RuiChip.vue.d.ts +1 -1
  34. package/dist/components/chips/RuiChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
  35. package/dist/components/color-picker/RuiColorBoard.vue_vue_type_script_setup_true_lang.js.map +1 -1
  36. package/dist/components/color-picker/RuiColorDisplay.vue_vue_type_script_setup_true_lang.js.map +1 -1
  37. package/dist/components/color-picker/RuiColorHue.vue_vue_type_script_setup_true_lang.js +2 -1
  38. package/dist/components/color-picker/RuiColorHue.vue_vue_type_script_setup_true_lang.js.map +1 -1
  39. package/dist/components/color-picker/RuiColorInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  40. package/dist/components/color-picker/RuiColorPicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  41. package/dist/components/date-time-picker/RuiDateTimePicker.js.map +1 -1
  42. package/dist/components/date-time-picker/RuiDateTimePicker.vue.d.ts +2 -2
  43. package/dist/components/date-time-picker/RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js +78 -33
  44. package/dist/components/date-time-picker/RuiDateTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  45. package/dist/components/date-time-picker/RuiDateTimePickerMenu.vue.d.ts +2 -2
  46. package/dist/components/date-time-picker/RuiDateTimePickerMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  47. package/dist/components/date-time-picker/RuiTimezoneSelect.vue.d.ts +3 -3
  48. package/dist/components/date-time-picker/RuiTimezoneSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
  49. package/dist/components/date-time-picker/date-time-picker-styles.d.ts +48 -3
  50. package/dist/components/date-time-picker/partial-time.d.ts +1 -1
  51. package/dist/components/date-time-picker/partial-time.js +17 -6
  52. package/dist/components/date-time-picker/partial-time.js.map +1 -1
  53. package/dist/components/date-time-picker/segment-config.d.ts +1 -1
  54. package/dist/components/date-time-picker/segment-utils.d.ts +18 -3
  55. package/dist/components/date-time-picker/segment-utils.js +88 -19
  56. package/dist/components/date-time-picker/segment-utils.js.map +1 -1
  57. package/dist/components/date-time-picker/timezones.js.map +1 -1
  58. package/dist/components/date-time-picker/use-date-bounds.d.ts +2 -1
  59. package/dist/components/date-time-picker/use-date-bounds.js +7 -3
  60. package/dist/components/date-time-picker/use-date-bounds.js.map +1 -1
  61. package/dist/components/date-time-picker/use-date-time-selection.d.ts +13 -13
  62. package/dist/components/date-time-picker/use-date-time-selection.js +96 -86
  63. package/dist/components/date-time-picker/use-date-time-selection.js.map +1 -1
  64. package/dist/components/date-time-picker/use-input-handler.d.ts +1 -1
  65. package/dist/components/date-time-picker/use-keyboard-handler.d.ts +4 -2
  66. package/dist/components/date-time-picker/use-keyboard-handler.js +62 -16
  67. package/dist/components/date-time-picker/use-keyboard-handler.js.map +1 -1
  68. package/dist/components/date-time-picker/utils.d.ts +1 -1
  69. package/dist/components/date-time-picker/utils.js.map +1 -1
  70. package/dist/components/divider/RuiDivider.vue_vue_type_script_setup_true_lang.js.map +1 -1
  71. package/dist/components/forms/auto-complete/RuiAutoComplete.js.map +1 -1
  72. package/dist/components/forms/auto-complete/RuiAutoComplete.vue.d.ts +2 -2
  73. package/dist/components/forms/auto-complete/RuiAutoComplete.vue_vue_type_script_setup_true_lang.js +136 -158
  74. package/dist/components/forms/auto-complete/RuiAutoComplete.vue_vue_type_script_setup_true_lang.js.map +1 -1
  75. package/dist/components/forms/auto-complete/RuiAutoCompleteOption.js +7 -0
  76. package/dist/components/forms/auto-complete/RuiAutoCompleteOption.js.map +1 -0
  77. package/dist/components/forms/auto-complete/RuiAutoCompleteOption.vue.d.ts +45 -0
  78. package/dist/components/forms/auto-complete/RuiAutoCompleteOption.vue_vue_type_script_setup_true_lang.js +58 -0
  79. package/dist/components/forms/auto-complete/RuiAutoCompleteOption.vue_vue_type_script_setup_true_lang.js.map +1 -0
  80. package/dist/components/forms/auto-complete/RuiAutoCompleteOptionList.js +7 -0
  81. package/dist/components/forms/auto-complete/RuiAutoCompleteOptionList.js.map +1 -0
  82. package/dist/components/forms/auto-complete/RuiAutoCompleteOptionList.vue.d.ts +70 -0
  83. package/dist/components/forms/auto-complete/RuiAutoCompleteOptionList.vue_vue_type_script_setup_true_lang.js +140 -0
  84. package/dist/components/forms/auto-complete/RuiAutoCompleteOptionList.vue_vue_type_script_setup_true_lang.js.map +1 -0
  85. package/dist/components/forms/auto-complete/RuiAutoCompleteSelection.js +7 -0
  86. package/dist/components/forms/auto-complete/RuiAutoCompleteSelection.js.map +1 -0
  87. package/dist/components/forms/auto-complete/RuiAutoCompleteSelection.vue.d.ts +39 -0
  88. package/dist/components/forms/auto-complete/RuiAutoCompleteSelection.vue_vue_type_script_setup_true_lang.js +56 -0
  89. package/dist/components/forms/auto-complete/RuiAutoCompleteSelection.vue_vue_type_script_setup_true_lang.js.map +1 -0
  90. package/dist/components/forms/auto-complete/auto-complete-styles.d.ts +48 -3
  91. package/dist/components/forms/category-picker/RuiCategoryPicker.js.map +1 -1
  92. package/dist/components/forms/category-picker/RuiCategoryPicker.vue.d.ts +2 -2
  93. package/dist/components/forms/category-picker/RuiCategoryPicker.vue_vue_type_script_setup_true_lang.js +49 -5
  94. package/dist/components/forms/category-picker/RuiCategoryPicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  95. package/dist/components/forms/category-picker/category-picker-styles.d.ts +69 -5
  96. package/dist/components/forms/category-picker/category-picker-styles.js +19 -0
  97. package/dist/components/forms/category-picker/category-picker-styles.js.map +1 -1
  98. package/dist/components/forms/check-control-styles.d.ts +2 -2
  99. package/dist/components/forms/checkbox/RuiCheckbox.vue_vue_type_script_setup_true_lang.js.map +1 -1
  100. package/dist/components/forms/checkbox/checkbox-group/RuiCheckboxGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  101. package/dist/components/forms/file-upload/RuiFileUpload.js.map +1 -1
  102. package/dist/components/forms/file-upload/RuiFileUpload.vue.d.ts +1 -1
  103. package/dist/components/forms/file-upload/RuiFileUpload.vue_vue_type_script_setup_true_lang.js.map +1 -1
  104. package/dist/components/forms/radio-button/radio/RuiRadio.vue_vue_type_script_setup_true_lang.js.map +1 -1
  105. package/dist/components/forms/radio-button/radio-group/RuiRadioGroup.js.map +1 -1
  106. package/dist/components/forms/radio-button/radio-group/RuiRadioGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  107. package/dist/components/forms/revealable-text-field/RuiRevealableTextField.vue.d.ts +1 -1
  108. package/dist/components/forms/revealable-text-field/RuiRevealableTextField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  109. package/dist/components/forms/select/RuiMenuSelect.js.map +1 -1
  110. package/dist/components/forms/select/RuiMenuSelect.vue.d.ts +2 -2
  111. package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js +10 -8
  112. package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
  113. package/dist/components/forms/select/RuiSimpleSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
  114. package/dist/components/forms/select/menu-select-styles.d.ts +48 -3
  115. package/dist/components/forms/slider/RuiSlider.js.map +1 -1
  116. package/dist/components/forms/slider/RuiSlider.vue_vue_type_script_setup_true_lang.js +22 -12
  117. package/dist/components/forms/slider/RuiSlider.vue_vue_type_script_setup_true_lang.js.map +1 -1
  118. package/dist/components/forms/slider/RuiSliderTicks.js +7 -0
  119. package/dist/components/forms/slider/RuiSliderTicks.js.map +1 -0
  120. package/dist/components/forms/slider/RuiSliderTicks.vue.d.ts +15 -0
  121. package/dist/components/forms/slider/RuiSliderTicks.vue_vue_type_script_setup_true_lang.js +59 -0
  122. package/dist/components/forms/slider/RuiSliderTicks.vue_vue_type_script_setup_true_lang.js.map +1 -0
  123. package/dist/components/forms/slider/slider-styles.d.ts +2 -2
  124. package/dist/components/forms/switch/RuiSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
  125. package/dist/components/forms/text-area/RuiTextArea.vue.d.ts +1 -1
  126. package/dist/components/forms/text-area/RuiTextArea.vue_vue_type_script_setup_true_lang.js.map +1 -1
  127. package/dist/components/forms/text-area/text-area-styles.d.ts +3 -3
  128. package/dist/components/forms/text-area/text-area-styles.js.map +1 -1
  129. package/dist/components/forms/text-field/RuiTextField.vue.d.ts +3 -3
  130. package/dist/components/forms/text-field/RuiTextField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  131. package/dist/components/forms/text-field/text-field-styles.d.ts +37 -4
  132. package/dist/components/forms/text-field/text-field-styles.js +34 -1
  133. package/dist/components/forms/text-field/text-field-styles.js.map +1 -1
  134. package/dist/components/forms/text-input-styles.d.ts +20 -5
  135. package/dist/components/forms/text-input-styles.js +16 -1
  136. package/dist/components/forms/text-input-styles.js.map +1 -1
  137. package/dist/components/helpers/RuiFormTextDetail.vue_vue_type_script_setup_true_lang.js.map +1 -1
  138. package/dist/components/icons/RuiIcon.js.map +1 -1
  139. package/dist/components/icons/RuiIcon.vue_vue_type_script_setup_true_lang.js +26 -0
  140. package/dist/components/icons/RuiIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
  141. package/dist/components/index.d.ts +57 -53
  142. package/dist/components/index.js +5 -1
  143. package/dist/components/loaders/RuiSkeletonBase.vue_vue_type_script_setup_true_lang.js.map +1 -1
  144. package/dist/components/loaders/RuiSkeletonLoader.vue.d.ts +2 -2
  145. package/dist/components/loaders/RuiSkeletonLoader.vue_vue_type_script_setup_true_lang.js.map +1 -1
  146. package/dist/components/logos/RuiLogo.vue_vue_type_script_setup_true_lang.js.map +1 -1
  147. package/dist/components/logos/use-logo-sources.d.ts +1 -1
  148. package/dist/components/logos/use-logo-sources.js +6 -1
  149. package/dist/components/logos/use-logo-sources.js.map +1 -1
  150. package/dist/components/overlays/badge/RuiBadge.vue.d.ts +1 -1
  151. package/dist/components/overlays/badge/RuiBadge.vue_vue_type_script_setup_true_lang.js.map +1 -1
  152. package/dist/components/overlays/bottom-sheet/RuiBottomSheet.js.map +1 -1
  153. package/dist/components/overlays/bottom-sheet/RuiBottomSheet.vue.d.ts +1 -0
  154. package/dist/components/overlays/bottom-sheet/RuiBottomSheet.vue_vue_type_script_setup_true_lang.js.map +1 -1
  155. package/dist/components/overlays/dialog/RuiDialog.js.map +1 -1
  156. package/dist/components/overlays/dialog/RuiDialog.vue.d.ts +2 -0
  157. package/dist/components/overlays/dialog/RuiDialog.vue_vue_type_script_setup_true_lang.js +15 -1
  158. package/dist/components/overlays/dialog/RuiDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
  159. package/dist/components/overlays/menu/RuiMenu.js.map +1 -1
  160. package/dist/components/overlays/menu/RuiMenu.vue_vue_type_script_setup_true_lang.js +20 -0
  161. package/dist/components/overlays/menu/RuiMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  162. package/dist/components/overlays/navigation-drawer/RuiNavigationDrawer.js.map +1 -1
  163. package/dist/components/overlays/navigation-drawer/RuiNavigationDrawer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  164. package/dist/components/overlays/notification/RuiNotification.vue_vue_type_script_setup_true_lang.js.map +1 -1
  165. package/dist/components/overlays/tooltip/RuiTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
  166. package/dist/components/overlays/tooltip/tooltip-styles.d.ts +2 -2
  167. package/dist/components/progress/RuiProgress.js.map +1 -1
  168. package/dist/components/progress/RuiProgress.vue.d.ts +3 -3
  169. package/dist/components/progress/RuiProgress.vue_vue_type_script_setup_true_lang.js.map +1 -1
  170. package/dist/components/steppers/RuiFooterStepper.vue.d.ts +1 -1
  171. package/dist/components/steppers/RuiFooterStepper.vue_vue_type_script_setup_true_lang.js.map +1 -1
  172. package/dist/components/steppers/RuiStepper.js.map +1 -1
  173. package/dist/components/steppers/RuiStepper.vue_vue_type_script_setup_true_lang.js +8 -0
  174. package/dist/components/steppers/RuiStepper.vue_vue_type_script_setup_true_lang.js.map +1 -1
  175. package/dist/components/steppers/RuiStepperCustomIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
  176. package/dist/components/steppers/RuiStepperIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
  177. package/dist/components/tables/RuiDataTable.js.map +1 -1
  178. package/dist/components/tables/RuiDataTable.vue.d.ts +5 -6
  179. package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js +42 -22
  180. package/dist/components/tables/RuiDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
  181. package/dist/components/tables/RuiExpandButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  182. package/dist/components/tables/RuiTable.js +7 -0
  183. package/dist/components/tables/RuiTable.js.map +1 -0
  184. package/dist/components/tables/RuiTable.vue.d.ts +40 -0
  185. package/dist/components/tables/RuiTable.vue_vue_type_script_setup_true_lang.js +95 -0
  186. package/dist/components/tables/RuiTable.vue_vue_type_script_setup_true_lang.js.map +1 -0
  187. package/dist/components/tables/RuiTableEmptyState.js.map +1 -1
  188. package/dist/components/tables/RuiTableEmptyState.vue.d.ts +5 -0
  189. package/dist/components/tables/RuiTableEmptyState.vue_vue_type_script_setup_true_lang.js +25 -10
  190. package/dist/components/tables/RuiTableEmptyState.vue_vue_type_script_setup_true_lang.js.map +1 -1
  191. package/dist/components/tables/RuiTableErrorState.js +7 -0
  192. package/dist/components/tables/RuiTableErrorState.js.map +1 -0
  193. package/dist/components/tables/RuiTableErrorState.vue.d.ts +28 -0
  194. package/dist/components/tables/RuiTableErrorState.vue_vue_type_script_setup_true_lang.js +44 -0
  195. package/dist/components/tables/RuiTableErrorState.vue_vue_type_script_setup_true_lang.js.map +1 -0
  196. package/dist/components/tables/RuiTableHead.js.map +1 -1
  197. package/dist/components/tables/RuiTableHead.vue.d.ts +5 -9
  198. package/dist/components/tables/RuiTableHead.vue_vue_type_script_setup_true_lang.js.map +1 -1
  199. package/dist/components/tables/RuiTableLoadingState.js +7 -0
  200. package/dist/components/tables/RuiTableLoadingState.js.map +1 -0
  201. package/dist/components/tables/RuiTableLoadingState.vue.d.ts +13 -0
  202. package/dist/components/tables/RuiTableLoadingState.vue_vue_type_script_setup_true_lang.js +40 -0
  203. package/dist/components/tables/RuiTableLoadingState.vue_vue_type_script_setup_true_lang.js.map +1 -0
  204. package/dist/components/tables/RuiTablePagination.vue.d.ts +1 -1
  205. package/dist/components/tables/RuiTablePagination.vue_vue_type_script_setup_true_lang.js +2 -1
  206. package/dist/components/tables/RuiTablePagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
  207. package/dist/components/tables/data-table/RuiDataTableBody.vue.d.ts +1 -1
  208. package/dist/components/tables/data-table/RuiDataTableBody.vue_vue_type_script_setup_true_lang.js.map +1 -1
  209. package/dist/components/tables/data-table/RuiDataTableCell.js.map +1 -1
  210. package/dist/components/tables/data-table/RuiDataTableCell.vue.d.ts +1 -1
  211. package/dist/components/tables/data-table/RuiDataTableCell.vue_vue_type_script_setup_true_lang.js +6 -0
  212. package/dist/components/tables/data-table/RuiDataTableCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
  213. package/dist/components/tables/data-table/RuiDataTableEmptyRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
  214. package/dist/components/tables/data-table/RuiDataTableExpandedRow.js.map +1 -1
  215. package/dist/components/tables/data-table/RuiDataTableExpandedRow.vue_vue_type_script_setup_true_lang.js +6 -0
  216. package/dist/components/tables/data-table/RuiDataTableExpandedRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
  217. package/dist/components/tables/data-table/RuiDataTableGroupRow.js.map +1 -1
  218. package/dist/components/tables/data-table/RuiDataTableGroupRow.vue_vue_type_script_setup_true_lang.js +5 -0
  219. package/dist/components/tables/data-table/RuiDataTableGroupRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
  220. package/dist/components/tables/data-table/RuiDataTableLoadingRow.js.map +1 -1
  221. package/dist/components/tables/data-table/RuiDataTableLoadingRow.vue_vue_type_script_setup_true_lang.js +2 -6
  222. package/dist/components/tables/data-table/RuiDataTableLoadingRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
  223. package/dist/components/tables/data-table/RuiDataTableMobileSort.js.map +1 -1
  224. package/dist/components/tables/data-table/RuiDataTableMobileSort.vue.d.ts +2 -2
  225. package/dist/components/tables/data-table/RuiDataTableMobileSort.vue_vue_type_script_setup_true_lang.js +4 -0
  226. package/dist/components/tables/data-table/RuiDataTableMobileSort.vue_vue_type_script_setup_true_lang.js.map +1 -1
  227. package/dist/components/tables/data-table/RuiDataTableRow.js.map +1 -1
  228. package/dist/components/tables/data-table/RuiDataTableRow.vue.d.ts +1 -1
  229. package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js +25 -0
  230. package/dist/components/tables/data-table/RuiDataTableRow.vue_vue_type_script_setup_true_lang.js.map +1 -1
  231. package/dist/components/tables/data-table/context.d.ts +2 -3
  232. package/dist/components/tables/data-table/context.js.map +1 -1
  233. package/dist/components/tables/data-table-styles.d.ts +2 -5
  234. package/dist/components/tables/data-table-styles.js +1 -2
  235. package/dist/components/tables/data-table-styles.js.map +1 -1
  236. package/dist/components/tabs/tab/RuiTab.js.map +1 -1
  237. package/dist/components/tabs/tab/RuiTab.vue.d.ts +1 -1
  238. package/dist/components/tabs/tab/RuiTab.vue_vue_type_script_setup_true_lang.js.map +1 -1
  239. package/dist/components/tabs/tab-item/RuiTabItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  240. package/dist/components/tabs/tab-items/RuiTabItems.js.map +1 -1
  241. package/dist/components/tabs/tab-items/RuiTabItems.vue.d.ts +9 -0
  242. package/dist/components/tabs/tab-items/RuiTabItems.vue_vue_type_script_setup_true_lang.js +16 -0
  243. package/dist/components/tabs/tab-items/RuiTabItems.vue_vue_type_script_setup_true_lang.js.map +1 -1
  244. package/dist/components/tabs/tabs/RuiTabs.js.map +1 -1
  245. package/dist/components/tabs/tabs/RuiTabs.vue.d.ts +6 -1
  246. package/dist/components/tabs/tabs/RuiTabs.vue_vue_type_script_setup_true_lang.js +12 -0
  247. package/dist/components/tabs/tabs/RuiTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
  248. package/dist/components/tabs/tabs/use-tab-routing.d.ts +1 -1
  249. package/dist/components/time-picker/RuiTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  250. package/dist/components/time-picker/time-picker-styles.d.ts +2 -2
  251. package/dist/composables/colors/index.d.ts +3 -3
  252. package/dist/composables/dropdown-menu.d.ts +2 -2
  253. package/dist/composables/dropdown-menu.js +26 -23
  254. package/dist/composables/dropdown-menu.js.map +1 -1
  255. package/dist/composables/floating.d.ts +7 -8
  256. package/dist/composables/floating.js +19 -14
  257. package/dist/composables/floating.js.map +1 -1
  258. package/dist/composables/forms/auto-complete/focus.js +5 -0
  259. package/dist/composables/forms/auto-complete/focus.js.map +1 -1
  260. package/dist/composables/forms/auto-complete/keyboard-navigation.js +12 -5
  261. package/dist/composables/forms/auto-complete/keyboard-navigation.js.map +1 -1
  262. package/dist/composables/forms/auto-complete/search.d.ts +1 -1
  263. package/dist/composables/forms/auto-complete/search.js +5 -0
  264. package/dist/composables/forms/auto-complete/search.js.map +1 -1
  265. package/dist/composables/forms/auto-complete/value.js.map +1 -1
  266. package/dist/composables/forms/category-picker/use-category-picker.d.ts +1 -1
  267. package/dist/composables/forms/category-picker/use-category-picker.js +1 -0
  268. package/dist/composables/forms/category-picker/use-category-picker.js.map +1 -1
  269. package/dist/composables/forms/use-prepend-append-width.d.ts +18 -3
  270. package/dist/composables/forms/use-prepend-append-width.js +18 -3
  271. package/dist/composables/forms/use-prepend-append-width.js.map +1 -1
  272. package/dist/composables/index.d.ts +4 -3
  273. package/dist/composables/index.js +2 -1
  274. package/dist/composables/overlay-stack.d.ts +52 -0
  275. package/dist/composables/overlay-stack.js +93 -0
  276. package/dist/composables/overlay-stack.js.map +1 -0
  277. package/dist/composables/sticky-header.js.map +1 -1
  278. package/dist/composables/tables/data-table/expansion.js +7 -0
  279. package/dist/composables/tables/data-table/expansion.js.map +1 -1
  280. package/dist/composables/tables/data-table/grouping.d.ts +1 -1
  281. package/dist/composables/tables/data-table/pagination.d.ts +2 -2
  282. package/dist/composables/tables/data-table/selection.d.ts +1 -1
  283. package/dist/composables/tables/data-table/selection.js +37 -34
  284. package/dist/composables/tables/data-table/selection.js.map +1 -1
  285. package/dist/composables/theme.d.ts +4 -2
  286. package/dist/composables/theme.js +18 -24
  287. package/dist/composables/theme.js.map +1 -1
  288. package/dist/i18n/keys.d.ts +2 -1
  289. package/dist/i18n/keys.js +2 -1
  290. package/dist/i18n/keys.js.map +1 -1
  291. package/dist/icons/icons_1.d.ts +8 -8
  292. package/dist/icons/icons_1.js +246 -223
  293. package/dist/icons/icons_1.js.map +1 -1
  294. package/dist/icons/icons_2.d.ts +26 -26
  295. package/dist/icons/icons_2.js +320 -400
  296. package/dist/icons/icons_2.js.map +1 -1
  297. package/dist/icons/icons_3.d.ts +46 -46
  298. package/dist/icons/icons_3.js +661 -706
  299. package/dist/icons/icons_3.js.map +1 -1
  300. package/dist/icons/icons_4.d.ts +63 -63
  301. package/dist/icons/icons_4.js +4347 -4480
  302. package/dist/icons/icons_4.js.map +1 -1
  303. package/dist/icons/icons_5.d.ts +60 -1
  304. package/dist/icons/icons_5.js +774 -31
  305. package/dist/icons/icons_5.js.map +1 -1
  306. package/dist/icons/index.d.ts +1 -1
  307. package/dist/icons/index.js +84 -25
  308. package/dist/icons/index.js.map +1 -1
  309. package/dist/index.js +11 -6
  310. package/dist/index.js.map +1 -1
  311. package/dist/style.css +94 -10
  312. package/dist/theme/index.js +1 -0
  313. package/dist/theme/index.js.map +1 -1
  314. package/dist/types/theme.d.ts +1 -1
  315. package/dist/utils/assert.js +2 -2
  316. package/dist/utils/assert.js.map +1 -1
  317. package/dist/utils/blockie.d.ts +4 -0
  318. package/dist/utils/blockie.js +8 -0
  319. package/dist/utils/blockie.js.map +1 -1
  320. package/dist/utils/helpers.d.ts +24 -18
  321. package/dist/utils/helpers.js +28 -21
  322. package/dist/utils/helpers.js.map +1 -1
  323. package/dist/utils/is-equal.d.ts +9 -0
  324. package/dist/utils/is-equal.js +22 -15
  325. package/dist/utils/is-equal.js.map +1 -1
  326. package/dist/utils/tv.d.ts +6 -2
  327. package/dist/utils/tv.js +30 -14
  328. package/dist/utils/tv.js.map +1 -1
  329. package/dist/vite-plugin/client.d.ts +1 -1
  330. package/dist/vite-plugin/index.js +29 -21
  331. package/dist/vite-plugin/index.js.map +1 -1
  332. package/dist/vite-plugin/scanner.d.ts +5 -2
  333. package/dist/vite-plugin/scanner.js +5 -2
  334. package/dist/vite-plugin/scanner.js.map +1 -1
  335. package/dist/vite-plugin/types.d.ts +4 -8
  336. package/dist/web-types.json +863 -50
  337. package/package.json +32 -33
@@ -1,8 +1,8 @@
1
1
  import type { Dayjs } from 'dayjs';
2
2
  import type { Ref, ShallowRef } from 'vue';
3
3
  import type { TimeAccuracy } from '../../consts/time-accuracy.js';
4
- import { type Segment } from '../../components/date-time-picker/segment-config.js';
5
- import { type DateTimeSegmentType } from '../../components/date-time-picker/types.js';
4
+ import { type Segment } from './segment-config.js';
5
+ import { type DateTimeSegmentType } from './types.js';
6
6
  interface KeyboardHandlerOptions {
7
7
  dateFormat: Ref<string>;
8
8
  cursorPosition: Ref<number>;
@@ -14,6 +14,7 @@ interface KeyboardHandlerOptions {
14
14
  disabled: boolean;
15
15
  readonly: boolean;
16
16
  accuracy: TimeAccuracy;
17
+ timezone: Readonly<Ref<string | undefined>>;
17
18
  }
18
19
  export declare function useKeyboardHandler(options: KeyboardHandlerOptions): {
19
20
  clear: (segmentType?: string) => void;
@@ -26,6 +27,7 @@ export declare function useKeyboardHandler(options: KeyboardHandlerOptions): {
26
27
  handleKeyDown: (event: KeyboardEvent) => void;
27
28
  handleMouseDown: (event: MouseEvent) => void;
28
29
  handlePaste: (event: ClipboardEvent) => void;
30
+ pasteRejected: Readonly<ShallowRef<boolean>>;
29
31
  selectFirstSegment: () => void;
30
32
  setSegment: (segmentType: DateTimeSegmentType) => void;
31
33
  };
@@ -2,12 +2,13 @@ import { assert } from "../../utils/assert.js";
2
2
  import { getClickPosition, parseAndSetDateValues } from "./segment-utils.js";
3
3
  import { SEGMENT_CONFIG, SEGMENT_METHODS } from "./segment-config.js";
4
4
  import { isDateTimeSegmentType } from "./types.js";
5
- import { computed, nextTick } from "vue";
5
+ import { computed, nextTick, shallowReadonly, shallowRef } from "vue";
6
6
  import { isDefined } from "@vueuse/core";
7
7
  import { get as get$1, set as set$1 } from "@vueuse/shared";
8
8
  //#region src/components/date-time-picker/use-keyboard-handler.ts
9
9
  function useKeyboardHandler(options) {
10
- const { accuracy, currentValue, cursorPosition, dateFormat, disabled, getCurrent, getDateTime, readonly, setValue, textInput } = options;
10
+ const { accuracy, currentValue, cursorPosition, dateFormat, disabled, getCurrent, getDateTime, readonly, setValue, textInput, timezone } = options;
11
+ const pasteRejected = shallowRef(false);
11
12
  const formatSegments = computed(() => {
12
13
  return get$1(dateFormat).split(/([\s./:])/g).filter(Boolean);
13
14
  });
@@ -92,12 +93,15 @@ function useKeyboardHandler(options) {
92
93
  }
93
94
  }
94
95
  }
95
- function handleDigitPressed(event, digit) {
96
- if (!(event.target instanceof HTMLInputElement)) return;
97
- const currentSegment = getCurrentSegment(event.target.selectionStart ?? 0);
98
- if (!currentSegment || isNaN(parseInt(digit))) return;
99
- const segmentType = currentSegment.type;
100
- if (!isDateTimeSegmentType(segmentType)) return;
96
+ /**
97
+ * Adds a typed digit to the segment under the caret, moving on to the next
98
+ * segment once this one can hold no more.
99
+ *
100
+ * @param segment - the segment the caret sits in
101
+ * @param segmentType - that segment's type, which states its value range
102
+ * @param digit - the digit that was typed
103
+ */
104
+ function applyDigit(segment, segmentType, digit) {
101
105
  const config = SEGMENT_CONFIG[segmentType];
102
106
  const combinedStr = `${get$1(currentValue) ?? ""}${digit}`;
103
107
  const combinedValue = parseInt(combinedStr);
@@ -105,10 +109,18 @@ function useKeyboardHandler(options) {
105
109
  const minValue = config.minValue ?? 0;
106
110
  if (combinedValue >= minValue && combinedValue <= config.maxValue) {
107
111
  setValue(segmentType, combinedValue);
108
- setCursorPosition(currentSegment);
112
+ setCursorPosition(segment);
109
113
  } else if (combinedValue < minValue && combinedStr.length < maxLength) set$1(currentValue, combinedValue);
110
114
  if (parseInt(`${combinedStr}0`) > config.maxValue || combinedStr.length >= maxLength) navigateSegments("ArrowRight");
111
115
  }
116
+ function handleDigitPressed(event, digit) {
117
+ if (!(event.target instanceof HTMLInputElement)) return;
118
+ const currentSegment = getCurrentSegment(event.target.selectionStart ?? 0);
119
+ if (!currentSegment || isNaN(parseInt(digit))) return;
120
+ const segmentType = currentSegment.type;
121
+ if (!isDateTimeSegmentType(segmentType)) return;
122
+ applyDigit(currentSegment, segmentType, digit);
123
+ }
112
124
  function handleKeyboardNavigation(event) {
113
125
  if (event.key === "ArrowUp") changeSegmentValue(true);
114
126
  else if (event.key === "ArrowDown") changeSegmentValue(false);
@@ -129,19 +141,39 @@ function useKeyboardHandler(options) {
129
141
  setCursorPosition(segment);
130
142
  }
131
143
  }
132
- function handleKeyDown(event) {
133
- if (disabled || readonly) return;
134
- const { key } = event;
135
- if (event.ctrlKey || event.metaKey || event.altKey) return;
144
+ /**
145
+ * Runs the picker's own handling for a key.
146
+ *
147
+ * @param event - the keydown being handled
148
+ * @param key - the key that was pressed
149
+ * @returns whether the picker handled it, which decides if the browser's own
150
+ * handling is kept: Tab moves out of the field, Escape closes the menu and
151
+ * Enter submits the surrounding form.
152
+ */
153
+ function dispatchKey(event, key) {
136
154
  if (key === "ArrowRight" || key === "ArrowLeft") navigateSegments(key);
137
155
  else if (key === "ArrowUp" || key === "ArrowDown") handleKeyboardNavigation(event);
138
156
  else if (key === "Backspace") handleBackspace(event);
139
157
  else if (key === "Delete") onInputDeletePressed(event);
140
158
  else if (/^\d$/.test(key)) handleDigitPressed(event, key);
141
- else return;
142
- event.preventDefault();
159
+ else return false;
160
+ return true;
161
+ }
162
+ function handleKeyDown(event) {
163
+ if (disabled || readonly) return;
164
+ set$1(pasteRejected, false);
165
+ if (event.ctrlKey || event.metaKey || event.altKey) return;
166
+ if (dispatchKey(event, event.key)) event.preventDefault();
143
167
  }
144
168
  let clickedSegment;
169
+ /**
170
+ * Captures the clicked segment on mousedown, which fires before focus.
171
+ *
172
+ * The in-progress digit buffer is reset because switching segments must not
173
+ * carry typed digits over, otherwise a leftover digit from another segment
174
+ * combines with the next keystroke (type "1" in HH, click mm, type "3" and
175
+ * mm would become 13 instead of 3).
176
+ */
145
177
  function handleMouseDown(event) {
146
178
  if (disabled || readonly || !(event.target instanceof HTMLInputElement)) return;
147
179
  const currentSegment = getCurrentSegment(getClickPosition(event, event.target, true));
@@ -168,6 +200,11 @@ function useKeyboardHandler(options) {
168
200
  const firstSegment = get$1(segmentPositions)[0];
169
201
  if (firstSegment) setCursorPosition(firstSegment);
170
202
  }
203
+ /**
204
+ * Restores the selection a click asked for, which opening the menu and the
205
+ * DOM updates that follow can lose. With no click to restore, focus selects
206
+ * the first segment, unless the user is already selecting text themselves.
207
+ */
171
208
  function handleFocus() {
172
209
  if (clickedSegment) {
173
210
  setCursorPosition(clickedSegment);
@@ -178,21 +215,29 @@ function useKeyboardHandler(options) {
178
215
  if (input && input.selectionStart !== input.selectionEnd) return;
179
216
  selectFirstSegment();
180
217
  }
218
+ /**
219
+ * Forgets the cursor position and the clicked segment, so re-focusing on
220
+ * another segment does not blink through the one left behind.
221
+ */
181
222
  function handleBlur() {
182
223
  set$1(cursorPosition, 0);
183
224
  set$1(currentValue, void 0);
225
+ set$1(pasteRejected, false);
184
226
  clickedSegment = void 0;
185
227
  }
228
+ /** Text that is no date raises `pasteRejected` until the next key, paste, input or blur. */
186
229
  function handlePaste(event) {
187
230
  if (disabled || readonly) return;
188
231
  if (!(event.target instanceof HTMLInputElement)) return;
189
232
  event.preventDefault();
190
233
  const pastedText = event.clipboardData?.getData("text");
191
234
  if (!pastedText) return;
192
- parseAndSetDateValues(pastedText, get$1(dateFormat), accuracy, setValue);
235
+ const parsed = parseAndSetDateValues(pastedText, get$1(dateFormat), accuracy, setValue, get$1(timezone));
236
+ set$1(pasteRejected, !parsed);
193
237
  }
194
238
  function handleInput(event) {
195
239
  if (disabled || readonly) return;
240
+ set$1(pasteRejected, false);
196
241
  if (!(event.target instanceof HTMLInputElement)) return;
197
242
  const inputText = event.target.value;
198
243
  if (!inputText) return;
@@ -209,6 +254,7 @@ function useKeyboardHandler(options) {
209
254
  handleKeyDown,
210
255
  handleMouseDown,
211
256
  handlePaste,
257
+ pasteRejected: shallowReadonly(pasteRejected),
212
258
  selectFirstSegment,
213
259
  setSegment
214
260
  };
@@ -1 +1 @@
1
- {"version":3,"file":"use-keyboard-handler.js","names":[],"sources":["../../../src/components/date-time-picker/use-keyboard-handler.ts"],"sourcesContent":["import type { Dayjs } from 'dayjs';\nimport type { Ref, ShallowRef } from 'vue';\nimport type { TimeAccuracy } from '@/consts/time-accuracy';\nimport { type Segment, SEGMENT_CONFIG, SEGMENT_METHODS } from '@/components/date-time-picker/segment-config';\nimport { getClickPosition, parseAndSetDateValues } from '@/components/date-time-picker/segment-utils';\nimport {\n type DateTimeSegmentType,\n isDateTimeSegmentType,\n} from '@/components/date-time-picker/types';\nimport { assert } from '@/utils/assert';\n\ninterface KeyboardHandlerOptions {\n dateFormat: Ref<string>;\n cursorPosition: Ref<number>;\n currentValue: Ref<number | undefined>;\n textInput: Readonly<ShallowRef<HTMLInputElement | null>> | Ref<HTMLInputElement | undefined>;\n setValue: (segment: DateTimeSegmentType, value?: number) => void;\n getCurrent: (segment: DateTimeSegmentType) => number | undefined;\n getDateTime: () => Dayjs;\n disabled: boolean;\n readonly: boolean;\n accuracy: TimeAccuracy;\n}\n\nexport function useKeyboardHandler(options: KeyboardHandlerOptions) {\n const {\n accuracy,\n currentValue,\n cursorPosition,\n dateFormat,\n disabled,\n getCurrent,\n getDateTime,\n readonly,\n setValue,\n textInput,\n } = options;\n\n const formatSegments = computed<string[]>(() => {\n const format = get(dateFormat);\n return format.split(/([\\s./:])/g).filter(Boolean);\n });\n\n const segmentPositions = computed<Segment[]>(() => {\n const segments = get(formatSegments);\n const positions: Segment[] = [];\n let currentPosition = 0;\n\n segments.forEach((segment) => {\n if (!/[\\s./:]/.test(segment)) {\n assert(isDateTimeSegmentType(segment), `Invalid date format segment: ${segment}`);\n positions.push({\n end: currentPosition + segment.length,\n start: currentPosition,\n type: segment,\n });\n }\n currentPosition += segment.length;\n });\n\n return positions;\n });\n\n function getCurrentSegment(position: number = get(cursorPosition)) {\n const segments = get(segmentPositions);\n return segments.find(segment => position >= segment.start && position <= segment.end);\n }\n\n function setCursorPosition(segment: Segment): void {\n set(cursorPosition, segment.end);\n\n nextTick(() => {\n if (isDefined(textInput)) {\n const input = get(textInput);\n input.setSelectionRange(segment.start, segment.end);\n input.focus();\n }\n });\n }\n\n function setSegment(segmentType: DateTimeSegmentType): void {\n const segments = get(segmentPositions).find(segment => segment.type === segmentType);\n if (segments) {\n set(currentValue, undefined);\n setCursorPosition(segments);\n }\n }\n\n function clear(segmentType?: string): void {\n const currentSegment = getCurrentSegment();\n if (!segmentType && !currentSegment) {\n return;\n }\n\n const typeToUse = segmentType ?? currentSegment?.type;\n if (!typeToUse) {\n return;\n }\n\n setValue(typeToUse as DateTimeSegmentType, undefined);\n\n if (currentSegment) {\n setCursorPosition(currentSegment);\n }\n }\n\n function changeSegmentValue(increment: boolean): void {\n if (!isDefined(textInput))\n return;\n const currentSegment = getCurrentSegment();\n if (!currentSegment)\n return;\n const segmentType = currentSegment.type;\n const method = SEGMENT_METHODS[segmentType];\n const selectedDate = getDateTime();\n const updatedDate = selectedDate.set(method, selectedDate.get(method) + (increment ? 1 : -1));\n if (updatedDate.year() >= 1970) {\n setValue(\n segmentType,\n segmentType === 'MM' ? updatedDate.get(method) + 1 : updatedDate.get(method),\n );\n setCursorPosition(currentSegment);\n }\n }\n\n function navigateSegments(key: string) {\n const position = get(cursorPosition);\n const positions = get(segmentPositions);\n const currentSegmentIndex = positions.findIndex(\n segment => position >= segment.start && position <= segment.end,\n );\n\n if (currentSegmentIndex === -1) {\n return;\n }\n\n set(currentValue, undefined);\n\n let nextSegmentIndex: number;\n if (key === 'ArrowRight') {\n nextSegmentIndex = currentSegmentIndex + 1;\n if (nextSegmentIndex < positions.length) {\n const nextSegment = positions[nextSegmentIndex];\n assert(nextSegment);\n setCursorPosition(nextSegment);\n }\n }\n else {\n nextSegmentIndex = currentSegmentIndex - 1;\n if (nextSegmentIndex >= 0) {\n const nextSegment = positions[nextSegmentIndex];\n assert(nextSegment);\n setCursorPosition(nextSegment);\n }\n }\n }\n\n function handleDigitPressed(event: KeyboardEvent, digit: string): void {\n if (!(event.target instanceof HTMLInputElement))\n return;\n const position = event.target.selectionStart ?? 0;\n const currentSegment = getCurrentSegment(position);\n if (!currentSegment || isNaN(parseInt(digit)))\n return;\n const segmentType = currentSegment.type;\n if (!isDateTimeSegmentType(segmentType))\n return;\n\n const config = SEGMENT_CONFIG[segmentType];\n const value = get(currentValue) ?? '';\n const combinedStr = `${value}${digit}`;\n const combinedValue = parseInt(combinedStr);\n const maxLength = segmentType.length;\n const minValue = config.minValue ?? 0;\n\n if (combinedValue >= minValue && combinedValue <= config.maxValue) {\n setValue(segmentType, combinedValue);\n setCursorPosition(currentSegment);\n }\n else if (combinedValue < minValue && combinedStr.length < maxLength) {\n // Track digit even if below minValue, so next digit can combine (e.g., \"0\" allows \"01\")\n set(currentValue, combinedValue);\n }\n\n const willExceedMax = parseInt(`${combinedStr}0`) > config.maxValue;\n // Use string length of typed digits, not parsed number length (e.g., \"01\" has length 2)\n if (willExceedMax || combinedStr.length >= maxLength)\n navigateSegments('ArrowRight');\n }\n\n function handleKeyboardNavigation(event: KeyboardEvent): void {\n if (event.key === 'ArrowUp')\n changeSegmentValue(true);\n else if (event.key === 'ArrowDown')\n changeSegmentValue(false);\n }\n\n function handleBackspace(event: KeyboardEvent): void {\n if (!(event.target instanceof HTMLInputElement))\n return;\n const currentSegment = getCurrentSegment(event.target.selectionStart ?? 0);\n if (!currentSegment)\n return;\n const value = get(currentValue) ?? getCurrent(currentSegment.type) ?? '';\n const updatedValue = value.toString().slice(0, -1);\n setValue(currentSegment.type, updatedValue.length === 0 ? undefined : parseInt(updatedValue));\n setCursorPosition(currentSegment);\n }\n\n function onInputDeletePressed(event: KeyboardEvent): void {\n if (!(event.target instanceof HTMLInputElement))\n return;\n const segment = getCurrentSegment(event.target.selectionStart ?? 0);\n if (segment) {\n clear(segment.type);\n setCursorPosition(segment);\n }\n }\n\n function handleKeyDown(event: KeyboardEvent): void {\n if (disabled || readonly)\n return;\n const { key } = event;\n // Modifier combos belong to the browser: ctrl/cmd+c, ctrl/cmd+v, ctrl/cmd+a,\n // reload, and so on. Swallowing them made copy and paste impossible.\n if (event.ctrlKey || event.metaKey || event.altKey)\n return;\n\n if (key === 'ArrowRight' || key === 'ArrowLeft')\n navigateSegments(key);\n else if (key === 'ArrowUp' || key === 'ArrowDown')\n handleKeyboardNavigation(event);\n else if (key === 'Backspace')\n handleBackspace(event);\n else if (key === 'Delete')\n onInputDeletePressed(event);\n else if (/^\\d$/.test(key))\n handleDigitPressed(event, key);\n else\n // Tab moves out of the field, Escape closes the menu, Enter submits the\n // surrounding form: keys the picker does not own must keep their default.\n return;\n\n event.preventDefault();\n }\n\n // Track the segment that was clicked, so handleFocus can restore it after DOM updates\n let clickedSegment: Segment | undefined;\n\n // Capture clicked segment on mousedown (fires before focus event)\n function handleMouseDown(event: MouseEvent): void {\n if (disabled || readonly || !(event.target instanceof HTMLInputElement))\n return;\n const currentSegment = getCurrentSegment(getClickPosition(event, event.target, true));\n if (currentSegment) {\n // Reset in-progress digit buffer: switching segments must not carry typed digits over,\n // otherwise a leftover digit from another segment combines with the next keystroke\n // (e.g. type \"1\" in HH, click mm, type \"3\" → mm becomes 13 instead of 3).\n set(currentValue, undefined);\n clickedSegment = currentSegment;\n }\n }\n\n function handleClick(event: MouseEvent): void {\n if (disabled || readonly || !(event.target instanceof HTMLInputElement))\n return;\n const currentSegment = getCurrentSegment(getClickPosition(event, event.target, true));\n if (currentSegment) {\n set(currentValue, undefined);\n clickedSegment = currentSegment;\n set(cursorPosition, currentSegment.end);\n event.target.setSelectionRange(currentSegment.start, currentSegment.end);\n }\n }\n\n function handleInputSelection(event: Event): void {\n const target = event.target as HTMLInputElement;\n set(cursorPosition, target.selectionStart ?? 0);\n }\n\n function selectFirstSegment(): void {\n const firstSegment = get(segmentPositions)[0];\n if (firstSegment)\n setCursorPosition(firstSegment);\n }\n\n function handleFocus(): void {\n // If we just clicked on a segment, restore that selection\n // (the selection may have been lost due to menu opening/DOM updates)\n if (clickedSegment) {\n setCursorPosition(clickedSegment);\n clickedSegment = undefined;\n return;\n }\n\n // Only select first segment if no text is currently selected in the input\n const input = get(textInput);\n if (input && input.selectionStart !== input.selectionEnd)\n return;\n selectFirstSegment();\n }\n\n function handleBlur(): void {\n // Reset cursor position and clicked segment when input loses focus\n // This prevents \"blinking\" when re-focusing on a different segment\n set(cursorPosition, 0);\n set(currentValue, undefined);\n clickedSegment = undefined;\n }\n\n function handlePaste(event: ClipboardEvent): void {\n if (disabled || readonly)\n return;\n\n if (!(event.target instanceof HTMLInputElement)) {\n return;\n }\n\n event.preventDefault();\n\n const pastedText = event.clipboardData?.getData('text');\n if (!pastedText) {\n return;\n }\n parseAndSetDateValues(pastedText, get(dateFormat), accuracy, setValue);\n }\n\n function handleInput(event: Event): void {\n if (disabled || readonly)\n return;\n\n if (!(event.target instanceof HTMLInputElement)) {\n return;\n }\n\n const inputText = event.target.value;\n if (!inputText) {\n return;\n }\n\n parseAndSetDateValues(inputText, get(dateFormat), accuracy, setValue);\n }\n\n return {\n clear,\n getCurrentSegment,\n handleBlur,\n handleClick,\n handleFocus,\n handleInput,\n handleInputSelection,\n handleKeyDown,\n handleMouseDown,\n handlePaste,\n selectFirstSegment,\n setSegment,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-keyboard-handler.js","names":[],"sources":["../../../src/components/date-time-picker/use-keyboard-handler.ts"],"sourcesContent":["import type { Dayjs } from 'dayjs';\nimport type { Ref, ShallowRef } from 'vue';\nimport type { TimeAccuracy } from '@/consts/time-accuracy';\nimport { type Segment, SEGMENT_CONFIG, SEGMENT_METHODS } from '@/components/date-time-picker/segment-config';\nimport { getClickPosition, parseAndSetDateValues } from '@/components/date-time-picker/segment-utils';\nimport {\n type DateTimeSegmentType,\n isDateTimeSegmentType,\n} from '@/components/date-time-picker/types';\nimport { assert } from '@/utils/assert';\n\ninterface KeyboardHandlerOptions {\n dateFormat: Ref<string>;\n cursorPosition: Ref<number>;\n currentValue: Ref<number | undefined>;\n textInput: Readonly<ShallowRef<HTMLInputElement | null>> | Ref<HTMLInputElement | undefined>;\n setValue: (segment: DateTimeSegmentType, value?: number) => void;\n getCurrent: (segment: DateTimeSegmentType) => number | undefined;\n getDateTime: () => Dayjs;\n disabled: boolean;\n readonly: boolean;\n accuracy: TimeAccuracy;\n timezone: Readonly<Ref<string | undefined>>;\n}\n\nexport function useKeyboardHandler(options: KeyboardHandlerOptions) {\n const {\n accuracy,\n currentValue,\n cursorPosition,\n dateFormat,\n disabled,\n getCurrent,\n getDateTime,\n readonly,\n setValue,\n textInput,\n timezone,\n } = options;\n\n const pasteRejected = shallowRef<boolean>(false);\n\n const formatSegments = computed<string[]>(() => {\n const format = get(dateFormat);\n return format.split(/([\\s./:])/g).filter(Boolean);\n });\n\n const segmentPositions = computed<Segment[]>(() => {\n const segments = get(formatSegments);\n const positions: Segment[] = [];\n let currentPosition = 0;\n\n segments.forEach((segment) => {\n if (!/[\\s./:]/.test(segment)) {\n assert(isDateTimeSegmentType(segment), `Invalid date format segment: ${segment}`);\n positions.push({\n end: currentPosition + segment.length,\n start: currentPosition,\n type: segment,\n });\n }\n currentPosition += segment.length;\n });\n\n return positions;\n });\n\n function getCurrentSegment(position: number = get(cursorPosition)) {\n const segments = get(segmentPositions);\n return segments.find(segment => position >= segment.start && position <= segment.end);\n }\n\n function setCursorPosition(segment: Segment): void {\n set(cursorPosition, segment.end);\n\n nextTick(() => {\n if (isDefined(textInput)) {\n const input = get(textInput);\n input.setSelectionRange(segment.start, segment.end);\n input.focus();\n }\n });\n }\n\n function setSegment(segmentType: DateTimeSegmentType): void {\n const segments = get(segmentPositions).find(segment => segment.type === segmentType);\n if (segments) {\n set(currentValue, undefined);\n setCursorPosition(segments);\n }\n }\n\n function clear(segmentType?: string): void {\n const currentSegment = getCurrentSegment();\n if (!segmentType && !currentSegment) {\n return;\n }\n\n const typeToUse = segmentType ?? currentSegment?.type;\n if (!typeToUse) {\n return;\n }\n\n setValue(typeToUse as DateTimeSegmentType, undefined);\n\n if (currentSegment) {\n setCursorPosition(currentSegment);\n }\n }\n\n function changeSegmentValue(increment: boolean): void {\n if (!isDefined(textInput))\n return;\n const currentSegment = getCurrentSegment();\n if (!currentSegment)\n return;\n const segmentType = currentSegment.type;\n const method = SEGMENT_METHODS[segmentType];\n const selectedDate = getDateTime();\n const updatedDate = selectedDate.set(method, selectedDate.get(method) + (increment ? 1 : -1));\n if (updatedDate.year() >= 1970) {\n setValue(\n segmentType,\n segmentType === 'MM' ? updatedDate.get(method) + 1 : updatedDate.get(method),\n );\n setCursorPosition(currentSegment);\n }\n }\n\n function navigateSegments(key: string) {\n const position = get(cursorPosition);\n const positions = get(segmentPositions);\n const currentSegmentIndex = positions.findIndex(\n segment => position >= segment.start && position <= segment.end,\n );\n\n if (currentSegmentIndex === -1) {\n return;\n }\n\n set(currentValue, undefined);\n\n let nextSegmentIndex: number;\n if (key === 'ArrowRight') {\n nextSegmentIndex = currentSegmentIndex + 1;\n if (nextSegmentIndex < positions.length) {\n const nextSegment = positions[nextSegmentIndex];\n assert(nextSegment);\n setCursorPosition(nextSegment);\n }\n }\n else {\n nextSegmentIndex = currentSegmentIndex - 1;\n if (nextSegmentIndex >= 0) {\n const nextSegment = positions[nextSegmentIndex];\n assert(nextSegment);\n setCursorPosition(nextSegment);\n }\n }\n }\n\n /**\n * Adds a typed digit to the segment under the caret, moving on to the next\n * segment once this one can hold no more.\n *\n * @param segment - the segment the caret sits in\n * @param segmentType - that segment's type, which states its value range\n * @param digit - the digit that was typed\n */\n function applyDigit(segment: Segment, segmentType: DateTimeSegmentType, digit: string): void {\n const config = SEGMENT_CONFIG[segmentType];\n const value = get(currentValue) ?? '';\n const combinedStr = `${value}${digit}`;\n const combinedValue = parseInt(combinedStr);\n const maxLength = segmentType.length;\n const minValue = config.minValue ?? 0;\n\n if (combinedValue >= minValue && combinedValue <= config.maxValue) {\n setValue(segmentType, combinedValue);\n setCursorPosition(segment);\n }\n else if (combinedValue < minValue && combinedStr.length < maxLength) {\n // Track digit even if below minValue, so next digit can combine (e.g., \"0\" allows \"01\")\n set(currentValue, combinedValue);\n }\n\n const willExceedMax = parseInt(`${combinedStr}0`) > config.maxValue;\n // Use string length of typed digits, not parsed number length (e.g., \"01\" has length 2)\n if (willExceedMax || combinedStr.length >= maxLength)\n navigateSegments('ArrowRight');\n }\n\n function handleDigitPressed(event: KeyboardEvent, digit: string): void {\n if (!(event.target instanceof HTMLInputElement))\n return;\n\n const currentSegment = getCurrentSegment(event.target.selectionStart ?? 0);\n if (!currentSegment || isNaN(parseInt(digit)))\n return;\n\n const segmentType = currentSegment.type;\n if (!isDateTimeSegmentType(segmentType))\n return;\n\n applyDigit(currentSegment, segmentType, digit);\n }\n\n function handleKeyboardNavigation(event: KeyboardEvent): void {\n if (event.key === 'ArrowUp')\n changeSegmentValue(true);\n else if (event.key === 'ArrowDown')\n changeSegmentValue(false);\n }\n\n function handleBackspace(event: KeyboardEvent): void {\n if (!(event.target instanceof HTMLInputElement))\n return;\n const currentSegment = getCurrentSegment(event.target.selectionStart ?? 0);\n if (!currentSegment)\n return;\n const value = get(currentValue) ?? getCurrent(currentSegment.type) ?? '';\n const updatedValue = value.toString().slice(0, -1);\n setValue(currentSegment.type, updatedValue.length === 0 ? undefined : parseInt(updatedValue));\n setCursorPosition(currentSegment);\n }\n\n function onInputDeletePressed(event: KeyboardEvent): void {\n if (!(event.target instanceof HTMLInputElement))\n return;\n const segment = getCurrentSegment(event.target.selectionStart ?? 0);\n if (segment) {\n clear(segment.type);\n setCursorPosition(segment);\n }\n }\n\n /**\n * Runs the picker's own handling for a key.\n *\n * @param event - the keydown being handled\n * @param key - the key that was pressed\n * @returns whether the picker handled it, which decides if the browser's own\n * handling is kept: Tab moves out of the field, Escape closes the menu and\n * Enter submits the surrounding form.\n */\n function dispatchKey(event: KeyboardEvent, key: string): boolean {\n if (key === 'ArrowRight' || key === 'ArrowLeft')\n navigateSegments(key);\n else if (key === 'ArrowUp' || key === 'ArrowDown')\n handleKeyboardNavigation(event);\n else if (key === 'Backspace')\n handleBackspace(event);\n else if (key === 'Delete')\n onInputDeletePressed(event);\n else if (/^\\d$/.test(key))\n handleDigitPressed(event, key);\n else\n return false;\n\n return true;\n }\n\n function handleKeyDown(event: KeyboardEvent): void {\n if (disabled || readonly)\n return;\n\n set(pasteRejected, false);\n // Modifier combos belong to the browser: swallowing them made copy and paste impossible\n if (event.ctrlKey || event.metaKey || event.altKey)\n return;\n\n if (dispatchKey(event, event.key))\n event.preventDefault();\n }\n\n // Track the segment that was clicked, so handleFocus can restore it after DOM updates\n let clickedSegment: Segment | undefined;\n\n /**\n * Captures the clicked segment on mousedown, which fires before focus.\n *\n * The in-progress digit buffer is reset because switching segments must not\n * carry typed digits over, otherwise a leftover digit from another segment\n * combines with the next keystroke (type \"1\" in HH, click mm, type \"3\" and\n * mm would become 13 instead of 3).\n */\n function handleMouseDown(event: MouseEvent): void {\n if (disabled || readonly || !(event.target instanceof HTMLInputElement))\n return;\n const currentSegment = getCurrentSegment(getClickPosition(event, event.target, true));\n if (currentSegment) {\n set(currentValue, undefined);\n clickedSegment = currentSegment;\n }\n }\n\n function handleClick(event: MouseEvent): void {\n if (disabled || readonly || !(event.target instanceof HTMLInputElement))\n return;\n const currentSegment = getCurrentSegment(getClickPosition(event, event.target, true));\n if (currentSegment) {\n set(currentValue, undefined);\n clickedSegment = currentSegment;\n set(cursorPosition, currentSegment.end);\n event.target.setSelectionRange(currentSegment.start, currentSegment.end);\n }\n }\n\n function handleInputSelection(event: Event): void {\n const target = event.target as HTMLInputElement;\n set(cursorPosition, target.selectionStart ?? 0);\n }\n\n function selectFirstSegment(): void {\n const firstSegment = get(segmentPositions)[0];\n if (firstSegment)\n setCursorPosition(firstSegment);\n }\n\n /**\n * Restores the selection a click asked for, which opening the menu and the\n * DOM updates that follow can lose. With no click to restore, focus selects\n * the first segment, unless the user is already selecting text themselves.\n */\n function handleFocus(): void {\n if (clickedSegment) {\n setCursorPosition(clickedSegment);\n clickedSegment = undefined;\n return;\n }\n\n const input = get(textInput);\n if (input && input.selectionStart !== input.selectionEnd)\n return;\n selectFirstSegment();\n }\n\n /**\n * Forgets the cursor position and the clicked segment, so re-focusing on\n * another segment does not blink through the one left behind.\n */\n function handleBlur(): void {\n set(cursorPosition, 0);\n set(currentValue, undefined);\n set(pasteRejected, false);\n clickedSegment = undefined;\n }\n\n /** Text that is no date raises `pasteRejected` until the next key, paste, input or blur. */\n function handlePaste(event: ClipboardEvent): void {\n if (disabled || readonly)\n return;\n\n if (!(event.target instanceof HTMLInputElement)) {\n return;\n }\n\n event.preventDefault();\n\n const pastedText = event.clipboardData?.getData('text');\n if (!pastedText) {\n return;\n }\n const parsed = parseAndSetDateValues(pastedText, get(dateFormat), accuracy, setValue, get(timezone));\n set(pasteRejected, !parsed);\n }\n\n function handleInput(event: Event): void {\n if (disabled || readonly)\n return;\n set(pasteRejected, false);\n\n if (!(event.target instanceof HTMLInputElement)) {\n return;\n }\n\n const inputText = event.target.value;\n if (!inputText) {\n return;\n }\n\n parseAndSetDateValues(inputText, get(dateFormat), accuracy, setValue);\n }\n\n return {\n clear,\n getCurrentSegment,\n handleBlur,\n handleClick,\n handleFocus,\n handleInput,\n handleInputSelection,\n handleKeyDown,\n handleMouseDown,\n handlePaste,\n pasteRejected: shallowReadonly(pasteRejected),\n selectFirstSegment,\n setSegment,\n };\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { TimeAccuracy } from '../../consts/time-accuracy.js';
2
- import '../../components/date-time-picker/dayjs-setup.js';
2
+ import './dayjs-setup.js';
3
3
  export declare function guessTimezone(): string | undefined;
4
4
  export declare function includeSeconds(accuracy: TimeAccuracy): boolean;
5
5
  export declare function includeMilliseconds(accuracy: TimeAccuracy): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":[],"sources":["../../../src/components/date-time-picker/utils.ts"],"sourcesContent":["import dayjs from 'dayjs';\nimport { timezones } from '@/components/date-time-picker/timezones';\nimport { TimeAccuracy } from '@/consts/time-accuracy';\nimport '@/components/date-time-picker/dayjs-setup';\n\nexport function guessTimezone() {\n const timezone = dayjs.tz.guess();\n return timezones.find(tz => tz === timezone);\n}\n\nexport function includeSeconds(accuracy: TimeAccuracy): boolean {\n return accuracy === TimeAccuracy.SECOND || accuracy === TimeAccuracy.MILLISECOND;\n}\n\nexport function includeMilliseconds(accuracy: TimeAccuracy): boolean {\n return accuracy === TimeAccuracy.MILLISECOND;\n}\n\n/**\n * Formats the picked date and time as a timezone-less wall-clock reading, so it\n * can be parsed in the selected timezone and pick up that date's own UTC offset.\n */\nexport function formatWallClock(date: Date, time: Date, accuracy: TimeAccuracy): string {\n const pad = (value: number, length = 2): string => value.toString().padStart(length, '0');\n\n // the year has to be padded too: while a year is being typed it is briefly 2,\n // 20 or 202, and `2-01-15T…` is not a date string any parser accepts\n const day = `${pad(date.getFullYear(), 4)}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;\n const seconds = includeSeconds(accuracy) ? time.getSeconds() : 0;\n const milliseconds = includeMilliseconds(accuracy) ? time.getMilliseconds() : 0;\n\n return `${day}T${pad(time.getHours())}:${pad(time.getMinutes())}:${pad(seconds)}.${pad(milliseconds, 3)}`;\n}\n"],"mappings":";;;;;AAKA,SAAgB,gBAAgB;CAC9B,MAAM,WAAW,MAAM,GAAG,MAAM;CAChC,OAAO,UAAU,MAAK,OAAM,OAAO,QAAQ;AAC7C;AAEA,SAAgB,eAAe,UAAiC;CAC9D,OAAO,aAAa,aAAa,UAAU,aAAa,aAAa;AACvE;AAEA,SAAgB,oBAAoB,UAAiC;CACnE,OAAO,aAAa,aAAa;AACnC;;;;;AAMA,SAAgB,gBAAgB,MAAY,MAAY,UAAgC;CACtF,MAAM,OAAO,OAAe,SAAS,MAAc,MAAM,SAAS,CAAC,CAAC,SAAS,QAAQ,GAAG;CAIxF,MAAM,MAAM,GAAG,IAAI,KAAK,YAAY,GAAG,CAAC,EAAE,GAAG,IAAI,KAAK,SAAS,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,QAAQ,CAAC;CAC3F,MAAM,UAAU,eAAe,QAAQ,IAAI,KAAK,WAAW,IAAI;CAC/D,MAAM,eAAe,oBAAoB,QAAQ,IAAI,KAAK,gBAAgB,IAAI;CAE9E,OAAO,GAAG,IAAI,GAAG,IAAI,KAAK,SAAS,CAAC,EAAE,GAAG,IAAI,KAAK,WAAW,CAAC,EAAE,GAAG,IAAI,OAAO,EAAE,GAAG,IAAI,cAAc,CAAC;AACxG"}
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../../../src/components/date-time-picker/utils.ts"],"sourcesContent":["import dayjs from 'dayjs';\nimport { timezones } from '@/components/date-time-picker/timezones';\nimport { TimeAccuracy } from '@/consts/time-accuracy';\nimport '@/components/date-time-picker/dayjs-setup';\n\nexport function guessTimezone() {\n const timezone = dayjs.tz.guess();\n return timezones.find(tz => tz === timezone);\n}\n\nexport function includeSeconds(accuracy: TimeAccuracy): boolean {\n return accuracy === TimeAccuracy.SECOND || accuracy === TimeAccuracy.MILLISECOND;\n}\n\nexport function includeMilliseconds(accuracy: TimeAccuracy): boolean {\n return accuracy === TimeAccuracy.MILLISECOND;\n}\n\n/**\n * Formats the picked date and time as a timezone-less wall-clock reading, so it\n * can be parsed in the selected timezone and pick up that date's own UTC offset.\n */\nexport function formatWallClock(date: Date, time: Date, accuracy: TimeAccuracy): string {\n const pad = (value: number, length = 2): string => value.toString().padStart(length, '0');\n\n // A year being typed is briefly 2, 20 or 202, and `2-01-15T...` is a date string no parser accepts\n const day = `${pad(date.getFullYear(), 4)}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;\n const seconds = includeSeconds(accuracy) ? time.getSeconds() : 0;\n const milliseconds = includeMilliseconds(accuracy) ? time.getMilliseconds() : 0;\n\n return `${day}T${pad(time.getHours())}:${pad(time.getMinutes())}:${pad(seconds)}.${pad(milliseconds, 3)}`;\n}\n"],"mappings":";;;;;AAKA,SAAgB,gBAAgB;CAC9B,MAAM,WAAW,MAAM,GAAG,MAAM;CAChC,OAAO,UAAU,MAAK,OAAM,OAAO,QAAQ;AAC7C;AAEA,SAAgB,eAAe,UAAiC;CAC9D,OAAO,aAAa,aAAa,UAAU,aAAa,aAAa;AACvE;AAEA,SAAgB,oBAAoB,UAAiC;CACnE,OAAO,aAAa,aAAa;AACnC;;;;;AAMA,SAAgB,gBAAgB,MAAY,MAAY,UAAgC;CACtF,MAAM,OAAO,OAAe,SAAS,MAAc,MAAM,SAAS,CAAC,CAAC,SAAS,QAAQ,GAAG;CAGxF,MAAM,MAAM,GAAG,IAAI,KAAK,YAAY,GAAG,CAAC,EAAE,GAAG,IAAI,KAAK,SAAS,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,QAAQ,CAAC;CAC3F,MAAM,UAAU,eAAe,QAAQ,IAAI,KAAK,WAAW,IAAI;CAC/D,MAAM,eAAe,oBAAoB,QAAQ,IAAI,KAAK,gBAAgB,IAAI;CAE9E,OAAO,GAAG,IAAI,GAAG,IAAI,KAAK,SAAS,CAAC,EAAE,GAAG,IAAI,KAAK,WAAW,CAAC,EAAE,GAAG,IAAI,OAAO,EAAE,GAAG,IAAI,cAAc,CAAC;AACxG"}
@@ -1 +1 @@
1
- {"version":3,"file":"RuiDivider.vue_vue_type_script_setup_true_lang.js","names":["$attrs"],"sources":["../../../src/components/divider/RuiDivider.vue"],"sourcesContent":["<script setup lang=\"ts\">\nexport interface Props {\n vertical?: boolean;\n}\n\ndefineOptions({\n name: 'RuiDivider',\n inheritAttrs: false,\n});\n\nconst { vertical = false } = defineProps<Props>();\n</script>\n\n<template>\n <div\n :class=\"vertical ? 'border-l' : 'border-t'\"\n class=\"border-default\"\n role=\"separator\"\n :aria-orientation=\"vertical ? 'vertical' : 'horizontal'\"\n v-bind=\"$attrs\"\n />\n</template>\n"],"mappings":";;;;;;;;;;;;;uBAcE,mBAME,OANF,WAME;IALC,OAAK,CAAE,QAAA,WAAQ,aAAA,YACV,gBAAgB;IACtB,MAAK;IACJ,oBAAkB,QAAA,WAAQ,aAAA;MACnBA,KAAAA,MAAM,GAAA,MAAA,IAAA,UAAA"}
1
+ {"version":3,"file":"RuiDivider.vue_vue_type_script_setup_true_lang.js","names":["$attrs"],"sources":["../../../src/components/divider/RuiDivider.vue"],"sourcesContent":["<script setup lang=\"ts\">\nexport interface Props {\n vertical?: boolean;\n}\n\ndefineOptions({\n name: 'RuiDivider',\n inheritAttrs: false,\n});\n\nconst { vertical = false } = defineProps<Props>();\n</script>\n\n<template>\n <div\n :class=\"vertical ? 'border-l' : 'border-t'\"\n class=\"border-default\"\n role=\"separator\"\n :aria-orientation=\"vertical ? 'vertical' : 'horizontal'\"\n v-bind=\"$attrs\"\n />\n</template>\n"],"mappings":";;;;;;;;;;;;;GAcE,OAAA,UAAA,GAAA,mBAME,OANF,WAME;IALC,OAAK,CAAE,QAAA,WAAQ,aAAA,YACV,gBAAgB;IACtB,MAAK;IACJ,oBAAkB,QAAA,WAAQ,aAAA;GACnBA,GAAAA,KAAAA,MAAM,GAAA,MAAA,IAAA,UAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"RuiAutoComplete.js","names":[],"sources":["../../../../src/components/forms/auto-complete/RuiAutoComplete.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"TValue, TItem\">\nimport type { VueClassValue } from '@/types/class-value';\nimport RuiButton from '@/components/buttons/button/RuiButton.vue';\nimport RuiChip from '@/components/chips/RuiChip.vue';\nimport { autoCompleteStyles, type AutoCompleteVariant } from '@/components/forms/auto-complete/auto-complete-styles';\nimport RuiIcon from '@/components/icons/RuiIcon.vue';\nimport RuiMenu, { type MenuProps } from '@/components/overlays/menu/RuiMenu.vue';\nimport RuiProgress from '@/components/progress/RuiProgress.vue';\nimport {\n type GroupBy,\n type ItemDisabled,\n type KeyOfType,\n useDropdownMenu,\n useDropdownOptionProperty,\n} from '@/composables/dropdown-menu';\nimport { type FloatingOptions, Placement } from '@/composables/floating';\nimport {\n useAutoCompleteFocus,\n useAutoCompleteKeyboardNavigation,\n useAutoCompleteSearch,\n useAutoCompleteValue,\n} from '@/composables/forms/auto-complete';\nimport { useFormTextDetail } from '@/utils/form-text-detail';\nimport { getNonRootAttrs, getRootAttrs, getTextToken } from '@/utils/helpers';\nimport { isEqual } from '@/utils/is-equal';\nimport { cn } from '@/utils/tv';\n\nexport type AutoCompleteModelValue<TValue> =\n TValue extends Array<infer U> ? U[] : TValue | undefined;\n\nexport interface RuiAutoCompleteClassNames {\n root?: VueClassValue;\n label?: VueClassValue;\n menu?: VueClassValue;\n}\n\nexport interface AutoCompleteProps<TValue, TItem> {\n options?: TItem[];\n keyAttr?: KeyOfType<TItem, TValue extends Array<infer U> ? U : TValue>;\n textAttr?: keyof TItem;\n disabled?: boolean;\n loading?: boolean;\n readOnly?: boolean;\n dense?: boolean;\n clearable?: boolean;\n label?: string;\n menuOptions?: MenuProps;\n classNames?: RuiAutoCompleteClassNames;\n /** @deprecated Use `classNames.label` instead */\n labelClass?: string;\n /** @deprecated Use `classNames.menu` instead */\n menuClass?: string;\n prependWidth?: number;\n appendWidth?: number;\n itemHeight?: number;\n variant?: AutoCompleteVariant;\n hint?: string;\n errorMessages?: string | string[];\n successMessages?: string | string[];\n hideDetails?: boolean;\n autoSelectFirst?: boolean;\n chips?: boolean;\n noFilter?: boolean;\n hideNoData?: boolean;\n noDataText?: string;\n /**\n * Custom search predicate. Receives the resolved group label as a third\n * argument when `groupBy` is set, so callers don't have to re-run the\n * `groupBy` resolver themselves.\n */\n filter?: (item: TItem, queryText: string, group?: string) => boolean;\n hideSelected?: boolean;\n placeholder?: string;\n returnObject?: boolean;\n customValue?: boolean;\n hideCustomValue?: boolean;\n required?: boolean;\n hideSearchInput?: boolean;\n hideSelectionWrapper?: boolean;\n groupBy?: GroupBy<TItem>;\n itemDisabled?: ItemDisabled<TItem>;\n /**\n * When true and `groupBy` is set, the default search predicate also matches\n * against the resolved group label. Items belonging to a group whose label\n * matches the query stay visible (group header included), even when the\n * items themselves don't match. No effect when a custom `filter` is supplied\n * or when `groupBy` is undefined.\n */\n searchIncludesGroupLabel?: boolean;\n}\n\ndefineOptions({\n name: 'RuiAutoComplete',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<AutoCompleteModelValue<TValue>>({ required: true });\n\nconst searchInputModel = defineModel<string>('searchInput', { default: '' });\n\nconst {\n options = [],\n disabled = false,\n loading = false,\n readOnly = false,\n dense = false,\n clearable = false,\n hideDetails = false,\n chips = false,\n label = 'Select',\n menuOptions,\n classNames,\n labelClass,\n menuClass,\n variant = 'default',\n hint,\n keyAttr,\n textAttr,\n itemHeight,\n errorMessages = [],\n successMessages = [],\n autoSelectFirst = false,\n noFilter = false,\n hideNoData = false,\n noDataText = 'No data available',\n filter,\n hideSelected = false,\n placeholder = '',\n returnObject = false,\n customValue = false,\n hideCustomValue = false,\n required = false,\n hideSearchInput = false,\n hideSelectionWrapper = false,\n groupBy,\n itemDisabled,\n searchIncludesGroupLabel = false,\n} = defineProps<AutoCompleteProps<TValue, TItem>>();\n\nconst slots = defineSlots<{\n 'activator'?: (props: {\n disabled: boolean;\n value: TItem[];\n variant: string;\n readOnly: boolean;\n attrs: Record<string, unknown>;\n open: boolean;\n hasError: boolean;\n hasSuccess: boolean;\n }) => any;\n 'activator.label'?: (props: { value: TItem[] }) => any;\n 'selection.prepend'?: (props: { index: number; item: TItem }) => any;\n 'selection'?: (props: { index: number; item: TItem; chipAttrs: Record<string, unknown> }) => any;\n 'item.prepend'?: (props: { disabled: boolean; item: TItem; active: boolean }) => any;\n 'item'?: (props: { disabled: boolean; item: TItem; active: boolean }) => any;\n 'item.append'?: (props: { disabled: boolean; item: TItem; active: boolean }) => any;\n 'group-header'?: (props: { group: string; items: TItem[] }) => any;\n 'no-data'?: () => any;\n 'placeholder'?: (props: { disabled: boolean; readOnly: boolean }) => any;\n 'footer'?: () => any;\n}>();\n\nconst { getText, getIdentifier } = useDropdownOptionProperty<TValue, TItem>({\n keyAttr,\n textAttr,\n});\n\nconst textInput = useTemplateRef<HTMLInputElement>('textInput');\nconst activator = useTemplateRef<HTMLDivElement>('activator');\nconst menuRef = useTemplateRef<HTMLDivElement>('menuRef');\nconst menuWrapperRef = useTemplateRef<HTMLDivElement>('menuWrapperRef');\n\nconst { focused: activatorFocusedWithin } = useFocusWithin(activator);\nconst { focused: menuWrapperFocusedWithin } = useFocusWithin(menuWrapperRef);\nconst { focused: searchInputFocused } = useFocus(textInput);\nconst { focused: activatorFocused } = useFocus(activator);\n\nconst {\n internalSearch,\n filteredOptions,\n justOpened,\n updateInternalSearch,\n textValueToProperValue,\n} = useAutoCompleteSearch<TItem>(\n () => options,\n searchInputModel,\n {\n keyAttr: () => keyAttr,\n textAttr: () => textAttr,\n noFilter: () => noFilter,\n filter: () => filter,\n customValue: () => customValue,\n hideCustomValue: () => hideCustomValue,\n returnObject: () => returnObject,\n groupBy: () => groupBy,\n searchIncludesGroupLabel: () => searchIncludesGroupLabel,\n },\n);\n\nconst isOpen = ref<boolean>(false);\nconst isHovered = ref<boolean>(false);\n\n// Calculate multiple from modelValue directly to avoid circular dependency\nconst multiple = computed<boolean>(() => Array.isArray(get(modelValue)));\n\nconst shouldApplyValueAsSearch = computed<boolean>(\n () => !(slots.selection || get(multiple) || chips),\n);\n\nconst { resolveIn, value, setSelected } = useAutoCompleteValue<AutoCompleteModelValue<TValue>, TItem>(\n modelValue,\n () => options,\n {\n keyAttr: () => keyAttr,\n returnObject: () => returnObject,\n customValue: () => customValue,\n },\n {\n getIdentifier,\n getText,\n textValueToProperValue,\n shouldApplyValueAsSearch,\n isOpen,\n multiple,\n updateInternalSearch,\n },\n);\n\nconst resolvedItemHeight = itemHeight ?? (dense ? 30 : 48);\n\nconst {\n containerProps,\n wrapperProps,\n renderedData,\n menuWidth,\n isActiveItem,\n itemIndexInValue,\n highlightedIndex,\n moveHighlight,\n applyHighlighted,\n optionsWithSelectedHidden,\n userNavigated,\n groupedOptions,\n isGrouped,\n isItemDisabled,\n} = useDropdownMenu<TValue, TItem>({\n itemHeight: resolvedItemHeight,\n keyAttr,\n textAttr,\n options: filteredOptions,\n dense: () => dense,\n value,\n menuRef,\n setValue,\n autoSelectFirst,\n hideSelected,\n isOpen,\n getText,\n getIdentifier,\n groupBy: () => groupBy,\n itemDisabled: () => itemDisabled,\n});\n\nconst {\n focusedValueIndex,\n moveSelectedValueHighlight,\n onEnter,\n onInputDeletePressed,\n onTab,\n setValueFocus,\n} = useAutoCompleteKeyboardNavigation<TItem>(\n {\n chips: () => chips,\n customValue: () => customValue,\n multiple,\n },\n {\n activator,\n applyHighlighted,\n clear,\n filteredOptions,\n getText,\n highlightedIndex,\n internalSearch,\n isOpen,\n removeValue: (item: TItem): void => { setValue(item); },\n searchInputFocused,\n setSearchAsValue,\n userNavigated,\n value,\n },\n);\n\nconst {\n anyFocused: focusAnyFocused,\n inputClass: focusInputClass,\n onActivatorFocused: focusOnActivatorFocused,\n onInputFocused: focusOnInputFocused,\n setInputFocus: focusSetInputFocus,\n} = useAutoCompleteFocus(\n {\n customValue: () => customValue,\n disabled: () => disabled,\n shouldApplyValueAsSearch,\n },\n {\n activatorFocused,\n activatorFocusedWithin,\n focusedValueIndex,\n internalSearch,\n isOpen,\n justOpened,\n menuWrapperFocusedWithin,\n searchInputFocused,\n setSearchAsValue,\n textInput,\n updateInternalSearch,\n },\n);\n\nconst menuMinHeight = computed<number>(\n () => Math.min(5, get(optionsWithSelectedHidden).length) * resolvedItemHeight,\n);\n\nconst { hasError, hasSuccess } = useFormTextDetail(\n () => errorMessages,\n () => successMessages,\n);\n\nconst valueSet = computed<boolean>(() => get(value).length > 0);\n\n// True when the consumer's #placeholder slot is taking over the resting\n// content area, so the outlined/resting label must hide to avoid overlapping\n// the slot content.\nconst placeholderSlotActive = computed<boolean>(() => Boolean(slots.placeholder) && !get(valueSet) && !get(searchInputFocused));\n\nconst usedPlaceholder = computed<string>(() => {\n if (get(searchInputFocused))\n return placeholder;\n return '';\n});\n\nconst outlined = computed<boolean>(() => variant === 'outlined');\nconst float = computed<boolean>(() => (get(isOpen) || get(valueSet) || get(searchInputFocused)) && get(outlined));\n\nconst legendText = computed<string>(() => {\n if (!get(float) || !label)\n return '';\n return required ? `${label} ﹡` : label;\n});\n\nconst ui = computed<ReturnType<typeof autoCompleteStyles>>(() => autoCompleteStyles({\n filled: variant === 'filled',\n outlined: get(outlined),\n float: get(float),\n opened: get(isOpen),\n hovered: get(isHovered),\n dense,\n disabled,\n readonly: readOnly,\n hasError: get(hasError),\n hasSuccess: get(hasSuccess) && !get(hasError),\n}));\n\nconst highlightedClass = autoCompleteStyles({}).highlighted();\n\nfunction updateSearchInput(event: Event): void {\n const target = event.target;\n if (!(target instanceof HTMLInputElement))\n return;\n\n const value = target.value;\n set(isOpen, true);\n updateInternalSearch(value);\n set(justOpened, false);\n}\n\nasync function setValue(val: TItem, skipRefocused = false): Promise<void> {\n const isMultiple = get(multiple);\n\n if (isMultiple) {\n const newValue = [...get(value)];\n const indexInValue = itemIndexInValue(val);\n if (indexInValue === -1) {\n updateInternalSearch();\n newValue.push(val);\n }\n else {\n newValue.splice(indexInValue, 1);\n }\n set(value, newValue);\n }\n else {\n if (get(shouldApplyValueAsSearch))\n updateInternalSearch(getText(val));\n else updateInternalSearch();\n\n set(value, [val]);\n }\n\n if (!isMultiple) {\n if (!skipRefocused) {\n set(activatorFocused, true);\n get(activator)?.focus();\n await nextTick(() => {\n set(isOpen, false);\n });\n }\n else {\n set(isOpen, false);\n }\n }\n else if (!skipRefocused) {\n set(searchInputFocused, true);\n }\n}\n\nfunction setSearchAsValue(): void {\n const searchToBeValue = get(internalSearch);\n if (!searchToBeValue)\n return;\n\n const newValue: TItem = textValueToProperValue(searchToBeValue);\n setValue(newValue, true);\n}\n\nfunction clear(): void {\n updateInternalSearch();\n set(modelValue, (Array.isArray(get(modelValue)) ? [] : undefined) as AutoCompleteModelValue<TValue>);\n}\n\nfunction chipAttrs(item: TItem, index: number): Record<string, unknown> {\n return {\n 'data-index': index,\n 'data-value': getIdentifier(item),\n 'onKeydown': (event: KeyboardEvent): void => {\n const { key } = event;\n if (['Backspace', 'Delete'].includes(key)) {\n event.stopPropagation();\n event.preventDefault();\n // Alt/Option + delete converts the chip back into editable search text\n // instead of removing it outright. Only meaningful when custom values\n // are accepted, since the restored text has to be re-selectable.\n if (event.altKey && customValue) {\n const text = getText(item) ?? '';\n setValue(item);\n updateInternalSearch(text);\n }\n else {\n setValue(item);\n }\n }\n },\n 'onClick': (e: MouseEvent): void => {\n e.stopPropagation();\n setValueFocus(index);\n },\n 'onClick:close': (): void => {\n setValue(item);\n },\n };\n}\n\nfunction setSelectionRange(start: number, end: number): void {\n set(searchInputFocused, true);\n get(textInput)?.setSelectionRange?.(start, end);\n}\n\nfunction arrowClicked(event: MouseEvent): void {\n if (get(isOpen)) {\n set(isOpen, false);\n event.stopPropagation();\n }\n}\n\nfunction openMenu(): void {\n set(isOpen, true);\n}\n\nfunction closeMenu(): void {\n set(isOpen, false);\n}\n\n// Optimize options watcher with shallow comparison first\nwatch(() => options, (curr, old) => {\n if (curr === old || customValue)\n return;\n\n // Only do deep comparison if reference changed\n if (isEqual(curr, old))\n return;\n\n // Only reconcile a selection the previous options could actually resolve. A value\n // that was already unresolvable is one the consumer set before its options arrived\n // (async lists start empty), so clearing it here would discard a legitimate value.\n if (!get(multiple) && resolveIn(old).length === 0)\n return;\n\n setSelected(get(value));\n});\n\nconst menuFloatingOptions = computed<FloatingOptions>(() => ({\n placement: Placement.bottomStart,\n ...menuOptions?.options,\n}));\n\ndefineExpose({\n closeMenu,\n focus: focusSetInputFocus,\n openMenu,\n setSelectionRange,\n});\n</script>\n\n<template>\n <RuiMenu\n v-model=\"isOpen\"\n v-bind=\"{ ...getRootAttrs($attrs, []), ...menuOptions }\"\n :class=\"ui.wrapper({ class: cn($attrs.class) })\"\n :options=\"menuFloatingOptions\"\n :close-on-content-click=\"false\"\n :full-width=\"true\"\n :persist-on-activator-click=\"true\"\n :menu-class=\"[\n { hidden: optionsWithSelectedHidden.length === 0 && customValue && !slots['no-data'] },\n menuOptions?.menuClass,\n ]\"\n :error-messages=\"errorMessages\"\n :success-messages=\"successMessages\"\n :hint=\"hint\"\n :dense=\"dense\"\n :show-details=\"!hideDetails\"\n :disabled=\"disabled\"\n disable-auto-focus\n >\n <template #activator=\"{ attrs, open, hasError: slotHasError, hasSuccess: slotHasSuccess }\">\n <slot\n name=\"activator\"\n v-bind=\"{ disabled, value, variant, readOnly, attrs, open, hasError: slotHasError, hasSuccess: slotHasSuccess }\"\n >\n <div\n ref=\"activator\"\n :class=\"ui.activator({ class: cn(classNames?.label) ?? labelClass })\"\n v-bind=\"{\n ...getNonRootAttrs($attrs, ['onClick', 'class']),\n ...(readOnly ? {} : attrs),\n }\"\n role=\"combobox\"\n :aria-expanded=\"open\"\n :aria-disabled=\"disabled || undefined\"\n :aria-readonly=\"readOnly || undefined\"\n :aria-required=\"required || undefined\"\n :aria-busy=\"loading || undefined\"\n data-id=\"activator\"\n :aria-invalid=\"hasError\"\n :tabindex=\"disabled || readOnly ? -1 : 0\"\n @mouseenter=\"isHovered = true\"\n @mouseleave=\"isHovered = false\"\n @click=\"focusSetInputFocus()\"\n @focus=\"focusOnActivatorFocused()\"\n @keydown.enter=\"onEnter($event)\"\n @keydown.tab=\"onTab($event)\"\n @keydown.left=\"moveSelectedValueHighlight($event, false)\"\n @keydown.right=\"moveSelectedValueHighlight($event, true)\"\n @keydown.up.prevent=\"moveHighlight(true)\"\n @keydown.down.prevent=\"moveHighlight(false)\"\n @keydown.home.prevent=\"highlightedIndex = 0\"\n @keydown.end.prevent=\"highlightedIndex = optionsWithSelectedHidden.length - 1\"\n >\n <span\n v-if=\"(outlined || (!valueSet && !searchInputFocused)) && !placeholderSlotActive\"\n :class=\"[\n ui.label(),\n { 'pr-2': !valueSet && !open && outlined },\n ]\"\n >\n <slot\n name=\"activator.label\"\n v-bind=\"{ value }\"\n >\n {{ label }}\n </slot>\n <span\n v-if=\"required\"\n :class=\"ui.required()\"\n >\n ﹡\n </span>\n </span>\n <div\n data-id=\"value\"\n :class=\"ui.value()\"\n >\n <!--\n Placeholder slot occupies the same flex space the input takes\n when focused, so transitioning into the focused state doesn't\n shift the activator's content. pointer-events-none is required\n so clicks pass through to the activator (otherwise the slot\n swallows the first click and the menu needs two taps to open).\n -->\n <div\n v-if=\"!valueSet && !searchInputFocused && slots.placeholder\"\n data-id=\"placeholder\"\n class=\"flex-1 min-w-0 pointer-events-none\"\n >\n <slot\n name=\"placeholder\"\n v-bind=\"{ disabled, readOnly }\"\n />\n </div>\n <template\n v-for=\"(item, i) in value\"\n :key=\"getIdentifier(item)\"\n >\n <RuiChip\n v-if=\"chips\"\n :key=\"getTextToken(getIdentifier(item))\"\n tabindex=\"-1\"\n :size=\"dense ? 'sm' : 'md'\"\n closeable\n :class=\"{ 'leading-3': dense }\"\n clickable\n v-bind=\"chipAttrs(item, i)\"\n >\n <div class=\"flex\">\n <slot\n name=\"selection.prepend\"\n :index=\"i\"\n v-bind=\"{ item }\"\n />\n <slot\n :index=\"i\"\n name=\"selection\"\n v-bind=\"{ item, chipAttrs: chipAttrs(item, i) }\"\n >\n {{ getText(item) }}\n </slot>\n </div>\n </RuiChip>\n <div\n v-else-if=\"\n multiple\n || (!searchInputFocused && (slots['selection.prepend'] || slots.selection))\n \"\n :class=\"hideSelectionWrapper ? 'contents' : 'flex'\"\n >\n <slot\n name=\"selection.prepend\"\n :index=\"i\"\n v-bind=\"{ item }\"\n />\n <slot\n v-if=\"multiple || slots.selection\"\n :index=\"i\"\n name=\"selection\"\n v-bind=\"{ item, chipAttrs: chipAttrs(item, i) }\"\n >\n {{ getText(item) }}\n </slot>\n </div>\n </template>\n <input\n ref=\"textInput\"\n :disabled=\"disabled\"\n :value=\"internalSearch\"\n class=\"bg-transparent outline-none\"\n type=\"text\"\n :placeholder=\"usedPlaceholder\"\n :class=\"[focusInputClass, { hidden: hideSearchInput }]\"\n :aria-invalid=\"hasError\"\n aria-autocomplete=\"list\"\n @keydown.delete=\"onInputDeletePressed()\"\n @input.stop=\"updateSearchInput($event)\"\n @focus=\"focusOnInputFocused()\"\n />\n </div>\n\n <RuiButton\n v-if=\"clearable && valueSet && !disabled\"\n variant=\"text\"\n icon\n size=\"sm\"\n tabindex=\"-1\"\n color=\"error\"\n data-id=\"clear\"\n :class=\"[\n ui.clear(),\n focusAnyFocused && '!visible',\n { 'mr-2': !dense },\n ]\"\n @click.stop.prevent=\"clear()\"\n >\n <RuiIcon\n name=\"lu-x\"\n size=\"18\"\n />\n </RuiButton>\n\n <span\n :class=\"ui.iconWrapper()\"\n @click=\"arrowClicked($event)\"\n >\n <RuiIcon\n :class=\"ui.icon()\"\n :size=\"dense ? 16 : 24\"\n name=\"lu-chevron-down\"\n />\n </span>\n\n <RuiProgress\n v-if=\"loading\"\n :class=\"ui.progress()\"\n color=\"primary\"\n thickness=\"3\"\n variant=\"indeterminate\"\n />\n </div>\n <fieldset\n v-if=\"outlined\"\n :class=\"ui.fieldset()\"\n >\n <legend :class=\"ui.legend()\">\n {{ legendText }}\n </legend>\n </fieldset>\n </slot>\n </template>\n <template #default=\"{ width }\">\n <div ref=\"menuWrapperRef\">\n <div\n v-if=\"optionsWithSelectedHidden.length > 0\"\n :ref=\"containerProps.ref\"\n :class=\"ui.menu({ class: cn(classNames?.menu) ?? menuClass })\"\n :style=\"[containerProps.style, { width: `${width}px`, minWidth: menuWidth, minHeight: `${menuMinHeight}px` }]\"\n @scroll=\"containerProps.onScroll\"\n @keydown.up.prevent=\"moveHighlight(true)\"\n @keydown.down.prevent=\"moveHighlight(false)\"\n >\n <div\n v-if=\"isGrouped\"\n ref=\"menuRef\"\n >\n <template\n v-for=\"(bucket, bucketIndex) in groupedOptions\"\n :key=\"bucket.group || `group-${bucketIndex}`\"\n >\n <div\n class=\"sticky top-0 z-10 bg-white dark:bg-rui-grey-900\"\n data-id=\"group-header\"\n >\n <slot\n name=\"group-header\"\n v-bind=\"{ group: bucket.group, items: bucket.items }\"\n >\n <div class=\"px-3 py-1 text-xs uppercase tracking-wide text-rui-text-secondary\">\n {{ bucket.group }}\n </div>\n </slot>\n </div>\n <RuiButton\n v-for=\"item in bucket.items\"\n :key=\"getIdentifier(item)?.toString()\"\n :active=\"isActiveItem(item)\"\n :aria-selected=\"isActiveItem(item)\"\n :size=\"dense ? 'sm' : undefined\"\n :disabled=\"isItemDisabled(item)\"\n tabindex=\"0\"\n variant=\"list\"\n :data-highlighted=\"optionsWithSelectedHidden.indexOf(item) === highlightedIndex\"\n :data-disabled=\"isItemDisabled(item) || undefined\"\n :class=\"{\n [highlightedClass]: !isActiveItem(item) && optionsWithSelectedHidden.indexOf(item) === highlightedIndex,\n }\"\n @click=\"!isItemDisabled(item) && setValue(item)\"\n >\n <template #prepend>\n <slot\n name=\"item.prepend\"\n v-bind=\"{ disabled: isItemDisabled(item), item, active: isActiveItem(item) }\"\n />\n </template>\n <slot\n name=\"item\"\n v-bind=\"{ disabled: isItemDisabled(item), item, active: isActiveItem(item) }\"\n >\n {{ getText(item) }}\n </slot>\n <template #append>\n <slot\n name=\"item.append\"\n v-bind=\"{ disabled: isItemDisabled(item), item, active: isActiveItem(item) }\"\n />\n </template>\n </RuiButton>\n </template>\n </div>\n <div\n v-else\n v-bind=\"wrapperProps\"\n ref=\"menuRef\"\n >\n <RuiButton\n v-for=\"{ item, _index } in renderedData\"\n :key=\"getIdentifier(item)?.toString()\"\n :active=\"isActiveItem(item)\"\n :aria-selected=\"isActiveItem(item)\"\n :size=\"dense ? 'sm' : undefined\"\n :disabled=\"isItemDisabled(item)\"\n tabindex=\"0\"\n variant=\"list\"\n :data-highlighted=\"highlightedIndex === _index\"\n :data-disabled=\"isItemDisabled(item) || undefined\"\n :class=\"{\n [highlightedClass]: !isActiveItem(item) && highlightedIndex === _index,\n }\"\n @click=\"!isItemDisabled(item) && setValue(item)\"\n >\n <template #prepend>\n <slot\n name=\"item.prepend\"\n v-bind=\"{ disabled: isItemDisabled(item), item, active: isActiveItem(item) }\"\n />\n </template>\n <slot\n name=\"item\"\n v-bind=\"{ disabled: isItemDisabled(item), item, active: isActiveItem(item) }\"\n >\n {{ getText(item) }}\n </slot>\n <template #append>\n <slot\n name=\"item.append\"\n v-bind=\"{ disabled: isItemDisabled(item), item, active: isActiveItem(item) }\"\n />\n </template>\n </RuiButton>\n </div>\n </div>\n\n <div\n v-else-if=\"!hideNoData\"\n :style=\"{ width: `${width}px`, minWidth: menuWidth }\"\n :class=\"classNames?.menu ?? menuClass\"\n >\n <slot name=\"no-data\">\n <div\n v-if=\"!customValue\"\n class=\"p-4\"\n data-id=\"no-data\"\n >\n {{ noDataText }}\n </div>\n </slot>\n </div>\n <!--\n The scroll container above reserves ~15px on the right for the\n scrollbar gutter. We render an equivalent right-padding here so the\n footer's content aligns with the option rows' content rather than\n the menu's outer edge. `pr-[var(--rui-scrollbar-gutter,15px)]`\n lets consumers override if their theme reserves a different width.\n -->\n <div\n v-if=\"slots.footer\"\n class=\"bg-white dark:bg-rui-grey-900 border-t border-black/[0.12] dark:border-white/[0.12] pr-[var(--rui-scrollbar-gutter,15px)] -mb-2\"\n data-id=\"footer\"\n >\n <slot name=\"footer\" />\n </div>\n </div>\n </template>\n </RuiMenu>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"RuiAutoComplete.js","names":[],"sources":["../../../../src/components/forms/auto-complete/RuiAutoComplete.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"TValue, TItem\">\nimport type { VueClassValue } from '@/types/class-value';\nimport RuiButton from '@/components/buttons/button/RuiButton.vue';\nimport { autoCompleteStyles, type AutoCompleteVariant } from '@/components/forms/auto-complete/auto-complete-styles';\nimport RuiAutoCompleteOptionList from '@/components/forms/auto-complete/RuiAutoCompleteOptionList.vue';\nimport RuiAutoCompleteSelection from '@/components/forms/auto-complete/RuiAutoCompleteSelection.vue';\nimport RuiIcon from '@/components/icons/RuiIcon.vue';\nimport RuiMenu, { type MenuProps } from '@/components/overlays/menu/RuiMenu.vue';\nimport RuiProgress from '@/components/progress/RuiProgress.vue';\nimport {\n type GroupBy,\n type ItemDisabled,\n type KeyOfType,\n useDropdownMenu,\n useDropdownOptionProperty,\n} from '@/composables/dropdown-menu';\nimport { type FloatingOptions, Placement } from '@/composables/floating';\nimport {\n useAutoCompleteFocus,\n useAutoCompleteKeyboardNavigation,\n useAutoCompleteSearch,\n useAutoCompleteValue,\n} from '@/composables/forms/auto-complete';\nimport { useFormTextDetail } from '@/utils/form-text-detail';\nimport { getNonRootAttrs, getRootAttrs } from '@/utils/helpers';\nimport { isEqual } from '@/utils/is-equal';\nimport { cn } from '@/utils/tv';\n\nexport type AutoCompleteModelValue<TValue> =\n TValue extends Array<infer U> ? U[] : TValue | undefined;\n\nexport interface RuiAutoCompleteClassNames {\n root?: VueClassValue;\n label?: VueClassValue;\n menu?: VueClassValue;\n}\n\nexport interface AutoCompleteProps<TValue, TItem> {\n options?: TItem[];\n keyAttr?: KeyOfType<TItem, TValue extends Array<infer U> ? U : TValue>;\n textAttr?: keyof TItem;\n disabled?: boolean;\n loading?: boolean;\n readOnly?: boolean;\n dense?: boolean;\n clearable?: boolean;\n label?: string;\n menuOptions?: MenuProps;\n classNames?: RuiAutoCompleteClassNames;\n /** @deprecated Use `classNames.label` instead */\n labelClass?: string;\n /** @deprecated Use `classNames.menu` instead */\n menuClass?: string;\n prependWidth?: number;\n appendWidth?: number;\n itemHeight?: number;\n variant?: AutoCompleteVariant;\n hint?: string;\n errorMessages?: string | string[];\n successMessages?: string | string[];\n hideDetails?: boolean;\n autoSelectFirst?: boolean;\n chips?: boolean;\n noFilter?: boolean;\n hideNoData?: boolean;\n noDataText?: string;\n /**\n * Custom search predicate. Receives the resolved group label as a third\n * argument when `groupBy` is set, so callers don't have to re-run the\n * `groupBy` resolver themselves.\n */\n filter?: (item: TItem, queryText: string, group?: string) => boolean;\n hideSelected?: boolean;\n placeholder?: string;\n returnObject?: boolean;\n customValue?: boolean;\n hideCustomValue?: boolean;\n required?: boolean;\n hideSearchInput?: boolean;\n hideSelectionWrapper?: boolean;\n groupBy?: GroupBy<TItem>;\n itemDisabled?: ItemDisabled<TItem>;\n /**\n * When true and `groupBy` is set, the default search predicate also matches\n * against the resolved group label. Items belonging to a group whose label\n * matches the query stay visible (group header included), even when the\n * items themselves don't match. No effect when a custom `filter` is supplied\n * or when `groupBy` is undefined.\n */\n searchIncludesGroupLabel?: boolean;\n}\n\ndefineOptions({\n name: 'RuiAutoComplete',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<AutoCompleteModelValue<TValue>>({ required: true });\n\nconst searchInputModel = defineModel<string>('searchInput', { default: '' });\n\nconst {\n options = [],\n disabled = false,\n loading = false,\n readOnly = false,\n dense = false,\n clearable = false,\n hideDetails = false,\n chips = false,\n label = 'Select',\n menuOptions,\n classNames,\n labelClass,\n menuClass,\n variant = 'default',\n hint,\n keyAttr,\n textAttr,\n itemHeight,\n prependWidth,\n appendWidth,\n errorMessages = [],\n successMessages = [],\n autoSelectFirst = false,\n noFilter = false,\n hideNoData = false,\n noDataText = 'No data available',\n filter,\n hideSelected = false,\n placeholder = '',\n returnObject = false,\n customValue = false,\n hideCustomValue = false,\n required = false,\n hideSearchInput = false,\n hideSelectionWrapper = false,\n groupBy,\n itemDisabled,\n searchIncludesGroupLabel = false,\n} = defineProps<AutoCompleteProps<TValue, TItem>>();\n\nconst slots = defineSlots<{\n 'activator'?: (props: {\n disabled: boolean;\n value: TItem[];\n variant: string;\n readOnly: boolean;\n attrs: Record<string, unknown>;\n open: boolean;\n hasError: boolean;\n hasSuccess: boolean;\n }) => any;\n 'activator.label'?: (props: { value: TItem[] }) => any;\n 'selection.prepend'?: (props: { index: number; item: TItem }) => any;\n 'selection'?: (props: { index: number; item: TItem; chipAttrs: Record<string, unknown> }) => any;\n 'item.prepend'?: (props: { disabled: boolean; item: TItem; active: boolean }) => any;\n 'item'?: (props: { disabled: boolean; item: TItem; active: boolean }) => any;\n 'item.append'?: (props: { disabled: boolean; item: TItem; active: boolean }) => any;\n 'group-header'?: (props: { group: string; items: TItem[] }) => any;\n 'no-data'?: () => any;\n 'placeholder'?: (props: { disabled: boolean; readOnly: boolean }) => any;\n 'footer'?: () => any;\n}>();\n\nconst { getText, getIdentifier } = useDropdownOptionProperty<TValue, TItem>({\n keyAttr,\n textAttr,\n});\n\nconst textInput = useTemplateRef<HTMLInputElement>('textInput');\nconst activator = useTemplateRef<HTMLDivElement>('activator');\n// Owned by the option list, so it arrives through a ref callback rather than this template\nconst menuRef = shallowRef<HTMLElement | null>(null);\n\nfunction setMenuRef(element: Element | ComponentPublicInstance | null): void {\n set(menuRef, element instanceof HTMLElement ? element : null);\n}\nconst menuWrapperRef = useTemplateRef<HTMLDivElement>('menuWrapperRef');\n\nconst { focused: activatorFocusedWithin } = useFocusWithin(activator);\nconst { focused: menuWrapperFocusedWithin } = useFocusWithin(menuWrapperRef);\nconst { focused: searchInputFocused } = useFocus(textInput);\nconst { focused: activatorFocused } = useFocus(activator);\n\nconst {\n internalSearch,\n filteredOptions,\n justOpened,\n updateInternalSearch,\n textValueToProperValue,\n} = useAutoCompleteSearch<TItem>(\n () => options,\n searchInputModel,\n {\n keyAttr: () => keyAttr,\n textAttr: () => textAttr,\n noFilter: () => noFilter,\n filter: () => filter,\n customValue: () => customValue,\n hideCustomValue: () => hideCustomValue,\n returnObject: () => returnObject,\n groupBy: () => groupBy,\n searchIncludesGroupLabel: () => searchIncludesGroupLabel,\n },\n);\n\nconst isOpen = ref<boolean>(false);\nconst isHovered = ref<boolean>(false);\n\n// Calculate multiple from modelValue directly to avoid circular dependency\nconst multiple = computed<boolean>(() => Array.isArray(get(modelValue)));\n\nconst shouldApplyValueAsSearch = computed<boolean>(\n () => !(slots.selection || get(multiple) || chips),\n);\n\nconst { resolveIn, value, setSelected } = useAutoCompleteValue<AutoCompleteModelValue<TValue>, TItem>(\n modelValue,\n () => options,\n {\n keyAttr: () => keyAttr,\n returnObject: () => returnObject,\n customValue: () => customValue,\n },\n {\n getIdentifier,\n getText,\n textValueToProperValue,\n shouldApplyValueAsSearch,\n isOpen,\n multiple,\n updateInternalSearch,\n },\n);\n\nconst resolvedItemHeight = itemHeight ?? (dense ? 30 : 48);\n\nconst {\n containerProps,\n wrapperProps,\n renderedData,\n menuWidth,\n isActiveItem,\n itemIndexInValue,\n modelHighlightedIndex,\n moveHighlight,\n applyHighlighted,\n optionsWithSelectedHidden,\n modelUserNavigated,\n groupedOptions,\n isGrouped,\n isItemDisabled,\n} = useDropdownMenu<TValue, TItem>({\n itemHeight: resolvedItemHeight,\n keyAttr,\n textAttr,\n options: filteredOptions,\n dense: () => dense,\n value,\n menuRef,\n setValue,\n autoSelectFirst,\n hideSelected,\n isOpen,\n getText,\n getIdentifier,\n groupBy: () => groupBy,\n itemDisabled: () => itemDisabled,\n prependWidth,\n appendWidth,\n});\n\nconst {\n focusedValueIndex,\n moveSelectedValueHighlight,\n onEnter,\n onInputDeletePressed,\n onTab,\n setValueFocus,\n} = useAutoCompleteKeyboardNavigation<TItem>(\n {\n chips: () => chips,\n customValue: () => customValue,\n multiple,\n },\n {\n activator,\n applyHighlighted,\n clear,\n filteredOptions,\n getText,\n highlightedIndex: modelHighlightedIndex,\n internalSearch,\n isOpen,\n removeValue: (item: TItem): void => { setValue(item); },\n searchInputFocused,\n setSearchAsValue,\n userNavigated: modelUserNavigated,\n value,\n },\n);\n\nconst {\n anyFocused: focusAnyFocused,\n inputClass: focusInputClass,\n onActivatorFocused: focusOnActivatorFocused,\n onInputFocused: focusOnInputFocused,\n setInputFocus: focusSetInputFocus,\n} = useAutoCompleteFocus(\n {\n customValue: () => customValue,\n disabled: () => disabled,\n shouldApplyValueAsSearch,\n },\n {\n activatorFocused,\n activatorFocusedWithin,\n focusedValueIndex,\n internalSearch,\n isOpen,\n justOpened,\n menuWrapperFocusedWithin,\n searchInputFocused,\n setSearchAsValue,\n textInput,\n updateInternalSearch,\n },\n);\n\nconst menuMinHeight = computed<number>(\n () => Math.min(5, get(optionsWithSelectedHidden).length) * resolvedItemHeight,\n);\n\nconst { hasError, hasSuccess } = useFormTextDetail(\n () => errorMessages,\n () => successMessages,\n);\n\nconst valueSet = computed<boolean>(() => get(value).length > 0);\n\n/**\n * True while the consumer's `#placeholder` slot holds the resting content\n * area, where the resting label would overlap it and so hides instead.\n */\nconst placeholderSlotActive = computed<boolean>(() => Boolean(slots.placeholder) && !get(valueSet) && !get(searchInputFocused));\n\nconst usedPlaceholder = computed<string>(() => {\n if (get(searchInputFocused))\n return placeholder;\n return '';\n});\n\nconst outlined = computed<boolean>(() => variant === 'outlined');\nconst float = computed<boolean>(() => (get(isOpen) || get(valueSet) || get(searchInputFocused)) && get(outlined));\n\nconst legendText = computed<string>(() => {\n if (!get(float) || !label)\n return '';\n return required ? `${label} ﹡` : label;\n});\n\nconst ui = computed<ReturnType<typeof autoCompleteStyles>>(() => autoCompleteStyles({\n filled: variant === 'filled',\n outlined: get(outlined),\n float: get(float),\n opened: get(isOpen),\n hovered: get(isHovered),\n dense,\n disabled,\n readonly: readOnly,\n hasError: get(hasError),\n hasSuccess: get(hasSuccess) && !get(hasError),\n}));\n\nconst highlightedClass = autoCompleteStyles({}).highlighted();\n\nfunction updateSearchInput(event: Event): void {\n const target = event.target;\n if (!(target instanceof HTMLInputElement))\n return;\n\n const value = target.value;\n set(isOpen, true);\n updateInternalSearch(value);\n set(justOpened, false);\n}\n\nasync function setValue(val: TItem, skipRefocused = false): Promise<void> {\n const isMultiple = get(multiple);\n\n if (isMultiple) {\n const newValue = [...get(value)];\n const indexInValue = itemIndexInValue(val);\n if (indexInValue === -1) {\n updateInternalSearch();\n newValue.push(val);\n }\n else {\n newValue.splice(indexInValue, 1);\n }\n set(value, newValue);\n }\n else {\n if (get(shouldApplyValueAsSearch))\n updateInternalSearch(getText(val));\n else updateInternalSearch();\n\n set(value, [val]);\n }\n\n if (!isMultiple) {\n if (!skipRefocused) {\n set(activatorFocused, true);\n get(activator)?.focus();\n await nextTick(() => {\n set(isOpen, false);\n });\n }\n else {\n set(isOpen, false);\n }\n }\n else if (!skipRefocused) {\n set(searchInputFocused, true);\n }\n}\n\nfunction setSearchAsValue(): void {\n const searchToBeValue = get(internalSearch);\n if (!searchToBeValue)\n return;\n\n const newValue: TItem = textValueToProperValue(searchToBeValue);\n setValue(newValue, true);\n}\n\nfunction clear(): void {\n updateInternalSearch();\n set(modelValue, (Array.isArray(get(modelValue)) ? [] : undefined) as AutoCompleteModelValue<TValue>);\n}\n\nfunction chipAttrs(item: TItem, index: number): Record<string, unknown> {\n return {\n 'data-index': index,\n 'data-value': getIdentifier(item),\n 'onKeydown': (event: KeyboardEvent): void => {\n const { key } = event;\n if (['Backspace', 'Delete'].includes(key)) {\n event.stopPropagation();\n event.preventDefault();\n // Alt + delete restores the chip as search text, which only helps where custom values are accepted\n if (event.altKey && customValue) {\n const text = getText(item) ?? '';\n setValue(item);\n updateInternalSearch(text);\n }\n else {\n setValue(item);\n }\n }\n },\n 'onClick': (e: MouseEvent): void => {\n e.stopPropagation();\n setValueFocus(index);\n },\n 'onClick:close': (): void => {\n setValue(item);\n },\n };\n}\n\nfunction setSelectionRange(start: number, end: number): void {\n set(searchInputFocused, true);\n get(textInput)?.setSelectionRange?.(start, end);\n}\n\nfunction arrowClicked(event: MouseEvent): void {\n if (get(isOpen)) {\n set(isOpen, false);\n event.stopPropagation();\n }\n}\n\nfunction openMenu(): void {\n set(isOpen, true);\n}\n\nfunction closeMenu(): void {\n set(isOpen, false);\n}\n\n/**\n * Reconciles the selection against a new set of options, comparing by\n * reference before by value so an unchanged list costs nothing.\n *\n * Only a selection the previous options could resolve is reconciled: a value\n * that was already unresolvable is one the consumer set before its options\n * arrived, since an async list starts empty, and clearing it here would\n * discard a legitimate value.\n */\nfunction onOptionsChanged(curr: TItem[], old: TItem[]): void {\n if (curr === old || customValue || isEqual(curr, old))\n return;\n\n if (!get(multiple) && resolveIn(old).length === 0)\n return;\n\n setSelected(get(value));\n}\n\nwatch(() => options, onOptionsChanged);\n\nconst menuFloatingOptions = computed<FloatingOptions>(() => ({\n placement: Placement.bottomStart,\n ...menuOptions?.options,\n}));\n\ndefineExpose({\n closeMenu,\n focus: focusSetInputFocus,\n openMenu,\n setSelectionRange,\n});\n</script>\n\n<template>\n <RuiMenu\n v-model=\"isOpen\"\n v-bind=\"{ ...getRootAttrs($attrs, []), ...menuOptions }\"\n :class=\"ui.wrapper({ class: cn($attrs.class) })\"\n :options=\"menuFloatingOptions\"\n :close-on-content-click=\"false\"\n full-width\n persist-on-activator-click\n :menu-class=\"[\n { hidden: optionsWithSelectedHidden.length === 0 && customValue && !slots['no-data'] },\n menuOptions?.menuClass,\n ]\"\n :error-messages=\"errorMessages\"\n :success-messages=\"successMessages\"\n :hint=\"hint\"\n :dense=\"dense\"\n :show-details=\"!hideDetails\"\n :disabled=\"disabled\"\n disable-auto-focus\n >\n <template #activator=\"{ attrs, open, hasError: slotHasError, hasSuccess: slotHasSuccess }\">\n <slot\n name=\"activator\"\n v-bind=\"{ disabled, value, variant, readOnly, attrs, open, hasError: slotHasError, hasSuccess: slotHasSuccess }\"\n >\n <div\n ref=\"activator\"\n :class=\"ui.activator({ class: cn(classNames?.label) ?? labelClass })\"\n v-bind=\"{\n ...getNonRootAttrs($attrs, ['onClick', 'class']),\n ...(readOnly ? {} : attrs),\n }\"\n role=\"combobox\"\n :aria-expanded=\"open\"\n :aria-disabled=\"disabled || undefined\"\n :aria-readonly=\"readOnly || undefined\"\n :aria-required=\"required || undefined\"\n :aria-busy=\"loading || undefined\"\n data-id=\"activator\"\n :aria-invalid=\"hasError\"\n :tabindex=\"disabled || readOnly ? -1 : 0\"\n @mouseenter=\"isHovered = true\"\n @mouseleave=\"isHovered = false\"\n @click=\"focusSetInputFocus()\"\n @focus=\"focusOnActivatorFocused()\"\n @keydown.enter=\"onEnter($event)\"\n @keydown.tab=\"onTab($event)\"\n @keydown.left=\"moveSelectedValueHighlight($event, false)\"\n @keydown.right=\"moveSelectedValueHighlight($event, true)\"\n @keydown.up.prevent=\"moveHighlight(true)\"\n @keydown.down.prevent=\"moveHighlight(false)\"\n @keydown.home.prevent=\"modelHighlightedIndex = 0\"\n @keydown.end.prevent=\"modelHighlightedIndex = optionsWithSelectedHidden.length - 1\"\n >\n <span\n v-if=\"(outlined || (!valueSet && !searchInputFocused)) && !placeholderSlotActive\"\n :class=\"[\n ui.label(),\n { 'pr-2': !valueSet && !open && outlined },\n ]\"\n >\n <slot\n name=\"activator.label\"\n v-bind=\"{ value }\"\n >\n {{ label }}\n </slot>\n <span\n v-if=\"required\"\n :class=\"ui.required()\"\n >\n ﹡\n </span>\n </span>\n <div\n data-id=\"value\"\n :class=\"ui.value()\"\n >\n <!--\n Placeholder slot occupies the same flex space the input takes\n when focused, so transitioning into the focused state doesn't\n shift the activator's content. pointer-events-none is required\n so clicks pass through to the activator (otherwise the slot\n swallows the first click and the menu needs two taps to open).\n -->\n <div\n v-if=\"!valueSet && !searchInputFocused && slots.placeholder\"\n data-id=\"placeholder\"\n class=\"flex-1 min-w-0 pointer-events-none\"\n >\n <slot\n name=\"placeholder\"\n v-bind=\"{ disabled, readOnly }\"\n />\n </div>\n <RuiAutoCompleteSelection\n :items=\"value\"\n :chips=\"chips\"\n :dense=\"dense\"\n :multiple=\"multiple\"\n :search-input-focused=\"searchInputFocused\"\n :hide-selection-wrapper=\"hideSelectionWrapper\"\n :get-identifier=\"getIdentifier\"\n :get-text=\"getText\"\n :chip-attrs=\"chipAttrs\"\n >\n <template\n v-if=\"slots['selection.prepend']\"\n #prepend=\"slotProps\"\n >\n <slot\n name=\"selection.prepend\"\n v-bind=\"slotProps\"\n />\n </template>\n <template\n v-if=\"slots.selection\"\n #default=\"slotProps\"\n >\n <slot\n name=\"selection\"\n v-bind=\"slotProps\"\n />\n </template>\n </RuiAutoCompleteSelection>\n <input\n ref=\"textInput\"\n :disabled=\"disabled\"\n :value=\"internalSearch\"\n class=\"bg-transparent outline-none\"\n type=\"text\"\n :placeholder=\"usedPlaceholder\"\n :class=\"[focusInputClass, { hidden: hideSearchInput }]\"\n :aria-invalid=\"hasError\"\n aria-autocomplete=\"list\"\n @keydown.delete=\"onInputDeletePressed()\"\n @input.stop=\"updateSearchInput($event)\"\n @focus=\"focusOnInputFocused()\"\n />\n </div>\n\n <RuiButton\n v-if=\"clearable && valueSet && !disabled\"\n variant=\"text\"\n icon\n size=\"sm\"\n tabindex=\"-1\"\n color=\"error\"\n data-id=\"clear\"\n :class=\"[\n ui.clear(),\n focusAnyFocused && '!visible',\n { 'mr-2': !dense },\n ]\"\n @click.stop.prevent=\"clear()\"\n >\n <RuiIcon\n name=\"lu-x\"\n size=\"18\"\n />\n </RuiButton>\n\n <span\n :class=\"ui.iconWrapper()\"\n @click=\"arrowClicked($event)\"\n >\n <RuiIcon\n :class=\"ui.icon()\"\n :size=\"dense ? 16 : 24\"\n name=\"lu-chevron-down\"\n />\n </span>\n\n <RuiProgress\n v-if=\"loading\"\n :class=\"ui.progress()\"\n color=\"primary\"\n thickness=\"3\"\n variant=\"indeterminate\"\n />\n </div>\n <fieldset\n v-if=\"outlined\"\n :class=\"ui.fieldset()\"\n >\n <legend :class=\"ui.legend()\">\n {{ legendText }}\n </legend>\n </fieldset>\n </slot>\n </template>\n <template #default=\"{ width }\">\n <div ref=\"menuWrapperRef\">\n <RuiAutoCompleteOptionList\n v-if=\"optionsWithSelectedHidden.length > 0\"\n :container-props=\"containerProps\"\n :wrapper-props=\"wrapperProps\"\n :set-menu-ref=\"setMenuRef\"\n :is-grouped=\"isGrouped\"\n :grouped-options=\"groupedOptions\"\n :rendered-data=\"renderedData\"\n :options=\"optionsWithSelectedHidden\"\n :highlighted-index=\"modelHighlightedIndex\"\n :highlighted-class=\"highlightedClass\"\n :dense=\"dense\"\n :menu-class=\"ui.menu({ class: cn(classNames?.menu) ?? menuClass })\"\n :menu-style=\"{ width: `${width}px`, minWidth: menuWidth, minHeight: `${menuMinHeight}px` }\"\n :get-identifier=\"getIdentifier\"\n :get-text=\"getText\"\n :is-active-item=\"isActiveItem\"\n :is-item-disabled=\"isItemDisabled\"\n @select=\"setValue($event)\"\n @move-highlight=\"moveHighlight($event)\"\n >\n <template\n v-if=\"slots['group-header']\"\n #group-header=\"slotProps\"\n >\n <slot\n name=\"group-header\"\n v-bind=\"slotProps\"\n />\n </template>\n <template\n v-if=\"slots['item.prepend']\"\n #item.prepend=\"slotProps\"\n >\n <slot\n name=\"item.prepend\"\n v-bind=\"slotProps\"\n />\n </template>\n <template\n v-if=\"slots.item\"\n #item=\"slotProps\"\n >\n <slot\n name=\"item\"\n v-bind=\"slotProps\"\n />\n </template>\n <template\n v-if=\"slots['item.append']\"\n #item.append=\"slotProps\"\n >\n <slot\n name=\"item.append\"\n v-bind=\"slotProps\"\n />\n </template>\n </RuiAutoCompleteOptionList>\n\n <div\n v-else-if=\"!hideNoData\"\n :style=\"{ width: `${width}px`, minWidth: menuWidth }\"\n :class=\"classNames?.menu ?? menuClass\"\n >\n <slot name=\"no-data\">\n <div\n v-if=\"!customValue\"\n class=\"p-4\"\n data-id=\"no-data\"\n >\n {{ noDataText }}\n </div>\n </slot>\n </div>\n <!--\n The scroll container above reserves ~15px on the right for the\n scrollbar gutter. We render an equivalent right-padding here so the\n footer's content aligns with the option rows' content rather than\n the menu's outer edge. `pr-[var(--rui-scrollbar-gutter,15px)]`\n lets consumers override if their theme reserves a different width.\n -->\n <div\n v-if=\"slots.footer\"\n class=\"bg-white dark:bg-rui-grey-900 border-t border-black/[0.12] dark:border-white/[0.12] pr-[var(--rui-scrollbar-gutter,15px)] -mb-2\"\n data-id=\"footer\"\n >\n <slot name=\"footer\" />\n </div>\n </div>\n </template>\n </RuiMenu>\n</template>\n"],"mappings":""}
@@ -1,6 +1,6 @@
1
1
  import type { VueClassValue } from '../../../types/class-value';
2
- import { type AutoCompleteVariant } from '../../../components/forms/auto-complete/auto-complete-styles.js';
3
- import { type MenuProps } from '../../../components/overlays/menu/RuiMenu.vue';
2
+ import { type AutoCompleteVariant } from './auto-complete-styles.js';
3
+ import { type MenuProps } from '../../overlays/menu/RuiMenu.vue';
4
4
  import { type GroupBy, type ItemDisabled, type KeyOfType } from '../../../composables/dropdown-menu.js';
5
5
  export type AutoCompleteModelValue<TValue> = TValue extends Array<infer U> ? U[] : TValue | undefined;
6
6
  export interface RuiAutoCompleteClassNames {