@rotki/ui-library 3.1.6 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/dist/components/accordions/accordion/RuiAccordion.js.map +1 -1
  2. package/dist/components/accordions/accordion/RuiAccordion.vue_vue_type_script_setup_true_lang.js +3 -3
  3. package/dist/components/accordions/accordion/RuiAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
  4. package/dist/components/accordions/accordion/accordion-styles.d.ts +1 -0
  5. package/dist/components/accordions/accordion/accordion-styles.js +7 -0
  6. package/dist/components/accordions/accordion/accordion-styles.js.map +1 -0
  7. package/dist/components/alerts/RuiAlert.js.map +1 -1
  8. package/dist/components/alerts/RuiAlert.vue_vue_type_script_setup_true_lang.js +1 -65
  9. package/dist/components/alerts/RuiAlert.vue_vue_type_script_setup_true_lang.js.map +1 -1
  10. package/dist/components/alerts/alert-styles.d.ts +145 -0
  11. package/dist/components/alerts/alert-styles.js +70 -0
  12. package/dist/components/alerts/alert-styles.js.map +1 -0
  13. package/dist/components/avatars/RuiAvatar.js.map +1 -1
  14. package/dist/components/avatars/RuiAvatar.vue_vue_type_script_setup_true_lang.js +1 -38
  15. package/dist/components/avatars/RuiAvatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  16. package/dist/components/avatars/RuiAvatarGroup.js.map +1 -1
  17. package/dist/components/avatars/RuiAvatarGroup.vue_vue_type_script_setup_true_lang.js +1 -13
  18. package/dist/components/avatars/RuiAvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  19. package/dist/components/avatars/avatar-group-styles.d.ts +49 -0
  20. package/dist/components/avatars/avatar-group-styles.js +18 -0
  21. package/dist/components/avatars/avatar-group-styles.js.map +1 -0
  22. package/dist/components/avatars/avatar-styles.d.ts +181 -0
  23. package/dist/components/avatars/avatar-styles.js +43 -0
  24. package/dist/components/avatars/avatar-styles.js.map +1 -0
  25. package/dist/components/buttons/button/button-styles.js +1 -1
  26. package/dist/components/buttons/button/button-styles.js.map +1 -1
  27. package/dist/components/buttons/button-group/RuiButtonGroup.js.map +1 -1
  28. package/dist/components/buttons/button-group/RuiButtonGroup.vue_vue_type_script_setup_true_lang.js +2 -138
  29. package/dist/components/buttons/button-group/RuiButtonGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  30. package/dist/components/buttons/button-group/button-group-styles.d.ts +142 -0
  31. package/dist/components/buttons/button-group/button-group-styles.js +143 -0
  32. package/dist/components/buttons/button-group/button-group-styles.js.map +1 -0
  33. package/dist/components/calendar/RuiCalendar.js.map +1 -1
  34. package/dist/components/calendar/RuiCalendar.vue_vue_type_script_setup_true_lang.js +1 -8
  35. package/dist/components/calendar/RuiCalendar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  36. package/dist/components/calendar/RuiCalendarGrid.js.map +1 -1
  37. package/dist/components/calendar/RuiCalendarGrid.vue_vue_type_script_setup_true_lang.js +2 -22
  38. package/dist/components/calendar/RuiCalendarGrid.vue_vue_type_script_setup_true_lang.js.map +1 -1
  39. package/dist/components/calendar/RuiCalendarMenu.js.map +1 -1
  40. package/dist/components/calendar/RuiCalendarMenu.vue_vue_type_script_setup_true_lang.js +3 -14
  41. package/dist/components/calendar/RuiCalendarMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  42. package/dist/components/calendar/calendar-grid-styles.d.ts +43 -0
  43. package/dist/components/calendar/calendar-grid-styles.js +26 -0
  44. package/dist/components/calendar/calendar-grid-styles.js.map +1 -0
  45. package/dist/components/calendar/calendar-menu-styles.d.ts +34 -0
  46. package/dist/components/calendar/calendar-menu-styles.js +17 -0
  47. package/dist/components/calendar/calendar-menu-styles.js.map +1 -0
  48. package/dist/components/calendar/calendar-styles.d.ts +16 -0
  49. package/dist/components/calendar/calendar-styles.js +13 -0
  50. package/dist/components/calendar/calendar-styles.js.map +1 -0
  51. package/dist/components/cards/RuiCard.js.map +1 -1
  52. package/dist/components/cards/RuiCard.vue_vue_type_script_setup_true_lang.js +3 -58
  53. package/dist/components/cards/RuiCard.vue_vue_type_script_setup_true_lang.js.map +1 -1
  54. package/dist/components/cards/RuiCardHeader.js.map +1 -1
  55. package/dist/components/cards/RuiCardHeader.vue_vue_type_script_setup_true_lang.js +2 -20
  56. package/dist/components/cards/RuiCardHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
  57. package/dist/components/cards/card-header-styles.d.ts +46 -0
  58. package/dist/components/cards/card-header-styles.js +24 -0
  59. package/dist/components/cards/card-header-styles.js.map +1 -0
  60. package/dist/components/cards/card-styles.d.ts +175 -0
  61. package/dist/components/cards/card-styles.js +62 -0
  62. package/dist/components/cards/card-styles.js.map +1 -0
  63. package/dist/components/chips/RuiChip.js.map +1 -1
  64. package/dist/components/chips/RuiChip.vue_vue_type_script_setup_true_lang.js +2 -241
  65. package/dist/components/chips/RuiChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
  66. package/dist/components/chips/chip-styles.d.ts +223 -0
  67. package/dist/components/chips/chip-styles.js +246 -0
  68. package/dist/components/chips/chip-styles.js.map +1 -0
  69. package/dist/components/color-picker/RuiColorBoard.js.map +1 -1
  70. package/dist/components/color-picker/RuiColorBoard.vue_vue_type_script_setup_true_lang.js +3 -3
  71. package/dist/components/color-picker/RuiColorBoard.vue_vue_type_script_setup_true_lang.js.map +1 -1
  72. package/dist/components/color-picker/RuiColorHue.js.map +1 -1
  73. package/dist/components/color-picker/RuiColorHue.vue_vue_type_script_setup_true_lang.js +3 -3
  74. package/dist/components/color-picker/RuiColorHue.vue_vue_type_script_setup_true_lang.js.map +1 -1
  75. package/dist/components/color-picker/RuiColorPicker.js.map +1 -1
  76. package/dist/components/color-picker/RuiColorPicker.vue_vue_type_script_setup_true_lang.js +3 -3
  77. package/dist/components/color-picker/RuiColorPicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  78. package/dist/components/color-picker/color-board-styles.d.ts +1 -0
  79. package/dist/components/color-picker/color-board-styles.js +7 -0
  80. package/dist/components/color-picker/color-board-styles.js.map +1 -0
  81. package/dist/components/color-picker/color-hue-styles.d.ts +1 -0
  82. package/dist/components/color-picker/color-hue-styles.js +7 -0
  83. package/dist/components/color-picker/color-hue-styles.js.map +1 -0
  84. package/dist/components/color-picker/color-picker-styles.d.ts +1 -0
  85. package/dist/components/color-picker/color-picker-styles.js +7 -0
  86. package/dist/components/color-picker/color-picker-styles.js.map +1 -0
  87. package/dist/components/forms/field-label/RuiFieldLabel.js.map +1 -1
  88. package/dist/components/forms/field-label/RuiFieldLabel.vue_vue_type_script_setup_true_lang.js +1 -11
  89. package/dist/components/forms/field-label/RuiFieldLabel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  90. package/dist/components/forms/field-label/field-label-styles.d.ts +43 -0
  91. package/dist/components/forms/field-label/field-label-styles.js +16 -0
  92. package/dist/components/forms/field-label/field-label-styles.js.map +1 -0
  93. package/dist/components/forms/select/RuiMenuSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
  94. package/dist/components/forms/select/RuiSimpleSelect.js.map +1 -1
  95. package/dist/components/forms/select/RuiSimpleSelect.vue_vue_type_script_setup_true_lang.js +2 -11
  96. package/dist/components/forms/select/RuiSimpleSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
  97. package/dist/components/forms/select/simple-select-styles.d.ts +2 -0
  98. package/dist/components/forms/select/simple-select-styles.js +15 -0
  99. package/dist/components/forms/select/simple-select-styles.js.map +1 -0
  100. package/dist/components/forms/switch/RuiSwitch.js.map +1 -1
  101. package/dist/components/forms/switch/RuiSwitch.vue_vue_type_script_setup_true_lang.js +1 -126
  102. package/dist/components/forms/switch/RuiSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
  103. package/dist/components/forms/switch/switch-styles.d.ts +151 -0
  104. package/dist/components/forms/switch/switch-styles.js +131 -0
  105. package/dist/components/forms/switch/switch-styles.js.map +1 -0
  106. package/dist/components/icons/RuiIcon.js.map +1 -1
  107. package/dist/components/icons/RuiIcon.vue_vue_type_script_setup_true_lang.js +2 -28
  108. package/dist/components/icons/RuiIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
  109. package/dist/components/icons/icon-styles.d.ts +44 -0
  110. package/dist/components/icons/icon-styles.js +33 -0
  111. package/dist/components/icons/icon-styles.js.map +1 -0
  112. package/dist/components/loaders/RuiSkeletonBase.js.map +1 -1
  113. package/dist/components/loaders/RuiSkeletonBase.vue_vue_type_script_setup_true_lang.js +2 -12
  114. package/dist/components/loaders/RuiSkeletonBase.vue_vue_type_script_setup_true_lang.js.map +1 -1
  115. package/dist/components/loaders/RuiSkeletonLoader.js.map +1 -1
  116. package/dist/components/loaders/RuiSkeletonLoader.vue_vue_type_script_setup_true_lang.js +3 -13
  117. package/dist/components/loaders/RuiSkeletonLoader.vue_vue_type_script_setup_true_lang.js.map +1 -1
  118. package/dist/components/loaders/skeleton-base-styles.d.ts +25 -0
  119. package/dist/components/loaders/skeleton-base-styles.js +16 -0
  120. package/dist/components/loaders/skeleton-base-styles.js.map +1 -0
  121. package/dist/components/loaders/skeleton-loader-styles.d.ts +37 -0
  122. package/dist/components/loaders/skeleton-loader-styles.js +18 -0
  123. package/dist/components/loaders/skeleton-loader-styles.js.map +1 -0
  124. package/dist/components/overlays/badge/RuiBadge.js.map +1 -1
  125. package/dist/components/overlays/badge/RuiBadge.vue_vue_type_script_setup_true_lang.js +1 -83
  126. package/dist/components/overlays/badge/RuiBadge.vue_vue_type_script_setup_true_lang.js.map +1 -1
  127. package/dist/components/overlays/badge/badge-styles.d.ts +193 -0
  128. package/dist/components/overlays/badge/badge-styles.js +88 -0
  129. package/dist/components/overlays/badge/badge-styles.js.map +1 -0
  130. package/dist/components/overlays/dialog/RuiDialog.js.map +1 -1
  131. package/dist/components/overlays/dialog/RuiDialog.vue_vue_type_script_setup_true_lang.js +3 -14
  132. package/dist/components/overlays/dialog/RuiDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
  133. package/dist/components/overlays/dialog/dialog-styles.d.ts +40 -0
  134. package/dist/components/overlays/dialog/dialog-styles.js +18 -0
  135. package/dist/components/overlays/dialog/dialog-styles.js.map +1 -0
  136. package/dist/components/overlays/menu/RuiMenu.js.map +1 -1
  137. package/dist/components/overlays/menu/RuiMenu.vue.d.ts +9 -0
  138. package/dist/components/overlays/menu/RuiMenu.vue_vue_type_script_setup_true_lang.js +113 -58
  139. package/dist/components/overlays/menu/RuiMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  140. package/dist/components/overlays/menu/menu-styles.d.ts +58 -0
  141. package/dist/components/overlays/menu/menu-styles.js +25 -0
  142. package/dist/components/overlays/menu/menu-styles.js.map +1 -0
  143. package/dist/components/overlays/navigation-drawer/RuiNavigationDrawer.js.map +1 -1
  144. package/dist/components/overlays/navigation-drawer/RuiNavigationDrawer.vue_vue_type_script_setup_true_lang.js +4 -69
  145. package/dist/components/overlays/navigation-drawer/RuiNavigationDrawer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  146. package/dist/components/overlays/navigation-drawer/navigation-drawer-styles.d.ts +76 -0
  147. package/dist/components/overlays/navigation-drawer/navigation-drawer-styles.js +72 -0
  148. package/dist/components/overlays/navigation-drawer/navigation-drawer-styles.js.map +1 -0
  149. package/dist/components/overlays/notification/RuiNotification.js.map +1 -1
  150. package/dist/components/overlays/notification/RuiNotification.vue_vue_type_script_setup_true_lang.js +3 -3
  151. package/dist/components/overlays/notification/RuiNotification.vue_vue_type_script_setup_true_lang.js.map +1 -1
  152. package/dist/components/overlays/notification/notification-styles.d.ts +1 -0
  153. package/dist/components/overlays/notification/notification-styles.js +7 -0
  154. package/dist/components/overlays/notification/notification-styles.js.map +1 -0
  155. package/dist/components/overlays/tooltip/RuiTooltip.js.map +1 -1
  156. package/dist/components/overlays/tooltip/RuiTooltip.vue.d.ts +4 -2
  157. package/dist/components/overlays/tooltip/RuiTooltip.vue_vue_type_script_setup_true_lang.js +42 -25
  158. package/dist/components/overlays/tooltip/RuiTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
  159. package/dist/components/overlays/tooltip/tooltip-styles.d.ts +2 -0
  160. package/dist/components/overlays/tooltip/tooltip-styles.js +3 -1
  161. package/dist/components/overlays/tooltip/tooltip-styles.js.map +1 -1
  162. package/dist/components/progress/RuiProgress.js.map +1 -1
  163. package/dist/components/progress/RuiProgress.vue_vue_type_script_setup_true_lang.js +1 -133
  164. package/dist/components/progress/RuiProgress.vue_vue_type_script_setup_true_lang.js.map +1 -1
  165. package/dist/components/progress/progress-styles.d.ts +181 -0
  166. package/dist/components/progress/progress-styles.js +139 -0
  167. package/dist/components/progress/progress-styles.js.map +1 -0
  168. package/dist/components/steppers/RuiFooterStepper.js.map +1 -1
  169. package/dist/components/steppers/RuiFooterStepper.vue_vue_type_script_setup_true_lang.js +3 -13
  170. package/dist/components/steppers/RuiFooterStepper.vue_vue_type_script_setup_true_lang.js.map +1 -1
  171. package/dist/components/steppers/RuiStepper.js.map +1 -1
  172. package/dist/components/steppers/RuiStepper.vue_vue_type_script_setup_true_lang.js +4 -94
  173. package/dist/components/steppers/RuiStepper.vue_vue_type_script_setup_true_lang.js.map +1 -1
  174. package/dist/components/steppers/RuiStepperIcon.js.map +1 -1
  175. package/dist/components/steppers/RuiStepperIcon.vue_vue_type_script_setup_true_lang.js +2 -34
  176. package/dist/components/steppers/RuiStepperIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
  177. package/dist/components/steppers/footer-stepper-styles.d.ts +28 -0
  178. package/dist/components/steppers/footer-stepper-styles.js +16 -0
  179. package/dist/components/steppers/footer-stepper-styles.js.map +1 -0
  180. package/dist/components/steppers/stepper-icon-styles.d.ts +60 -0
  181. package/dist/components/steppers/stepper-icon-styles.js +39 -0
  182. package/dist/components/steppers/stepper-icon-styles.js.map +1 -0
  183. package/dist/components/steppers/stepper-styles.d.ts +202 -0
  184. package/dist/components/steppers/stepper-styles.js +98 -0
  185. package/dist/components/steppers/stepper-styles.js.map +1 -0
  186. package/dist/components/tables/RuiTable.js.map +1 -1
  187. package/dist/components/tables/RuiTable.vue_vue_type_script_setup_true_lang.js +1 -32
  188. package/dist/components/tables/RuiTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
  189. package/dist/components/tables/RuiTableEmptyState.js.map +1 -1
  190. package/dist/components/tables/RuiTableEmptyState.vue_vue_type_script_setup_true_lang.js +1 -15
  191. package/dist/components/tables/RuiTableEmptyState.vue_vue_type_script_setup_true_lang.js.map +1 -1
  192. package/dist/components/tables/RuiTableErrorState.js.map +1 -1
  193. package/dist/components/tables/RuiTableErrorState.vue_vue_type_script_setup_true_lang.js +2 -5
  194. package/dist/components/tables/RuiTableErrorState.vue_vue_type_script_setup_true_lang.js.map +1 -1
  195. package/dist/components/tables/RuiTableHead.js.map +1 -1
  196. package/dist/components/tables/RuiTableHead.vue_vue_type_script_setup_true_lang.js +1 -34
  197. package/dist/components/tables/RuiTableHead.vue_vue_type_script_setup_true_lang.js.map +1 -1
  198. package/dist/components/tables/RuiTableLoadingState.js.map +1 -1
  199. package/dist/components/tables/RuiTableLoadingState.vue_vue_type_script_setup_true_lang.js +1 -8
  200. package/dist/components/tables/RuiTableLoadingState.vue_vue_type_script_setup_true_lang.js.map +1 -1
  201. package/dist/components/tables/RuiTablePagination.js.map +1 -1
  202. package/dist/components/tables/RuiTablePagination.vue_vue_type_script_setup_true_lang.js +1 -30
  203. package/dist/components/tables/RuiTablePagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
  204. package/dist/components/tables/table-empty-state-styles.d.ts +43 -0
  205. package/dist/components/tables/table-empty-state-styles.js +20 -0
  206. package/dist/components/tables/table-empty-state-styles.js.map +1 -0
  207. package/dist/components/tables/table-error-state-styles.d.ts +36 -0
  208. package/dist/components/tables/table-error-state-styles.js +15 -0
  209. package/dist/components/tables/table-error-state-styles.js.map +1 -0
  210. package/dist/components/tables/table-head-styles.d.ts +91 -0
  211. package/dist/components/tables/table-head-styles.js +39 -0
  212. package/dist/components/tables/table-head-styles.js.map +1 -0
  213. package/dist/components/tables/table-loading-state-styles.d.ts +34 -0
  214. package/dist/components/tables/table-loading-state-styles.js +13 -0
  215. package/dist/components/tables/table-loading-state-styles.js.map +1 -0
  216. package/dist/components/tables/table-pagination-styles.d.ts +82 -0
  217. package/dist/components/tables/table-pagination-styles.js +35 -0
  218. package/dist/components/tables/table-pagination-styles.js.map +1 -0
  219. package/dist/components/tables/table-styles.d.ts +62 -0
  220. package/dist/components/tables/table-styles.js +37 -0
  221. package/dist/components/tables/table-styles.js.map +1 -0
  222. package/dist/components/tabs/tab/RuiTab.js.map +1 -1
  223. package/dist/components/tabs/tab/RuiTab.vue_vue_type_script_setup_true_lang.js +3 -84
  224. package/dist/components/tabs/tab/RuiTab.vue_vue_type_script_setup_true_lang.js.map +1 -1
  225. package/dist/components/tabs/tab/tab-styles.d.ts +153 -0
  226. package/dist/components/tabs/tab/tab-styles.js +89 -0
  227. package/dist/components/tabs/tab/tab-styles.js.map +1 -0
  228. package/dist/components/tabs/tabs/RuiTabs.js.map +1 -1
  229. package/dist/components/tabs/tabs/RuiTabs.vue_vue_type_script_setup_true_lang.js +2 -137
  230. package/dist/components/tabs/tabs/RuiTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
  231. package/dist/components/tabs/tabs/tabs-styles.d.ts +168 -0
  232. package/dist/components/tabs/tabs/tabs-styles.js +142 -0
  233. package/dist/components/tabs/tabs/tabs-styles.js.map +1 -0
  234. package/dist/composables/floating.d.ts +3 -1
  235. package/dist/composables/floating.js +8 -9
  236. package/dist/composables/floating.js.map +1 -1
  237. package/dist/icons/icons_1.d.ts +1 -1
  238. package/dist/icons/icons_1.js +10 -9
  239. package/dist/icons/icons_1.js.map +1 -1
  240. package/dist/icons/icons_2.d.ts +1 -1
  241. package/dist/icons/icons_2.js +9 -11
  242. package/dist/icons/icons_2.js.map +1 -1
  243. package/dist/icons/icons_3.d.ts +1 -1
  244. package/dist/icons/icons_3.js +11 -5
  245. package/dist/icons/icons_3.js.map +1 -1
  246. package/dist/icons/icons_4.d.ts +1 -1
  247. package/dist/icons/icons_4.js +5 -10
  248. package/dist/icons/icons_4.js.map +1 -1
  249. package/dist/icons/icons_5.d.ts +1 -0
  250. package/dist/icons/icons_5.js +10 -1
  251. package/dist/icons/icons_5.js.map +1 -1
  252. package/dist/icons/index.d.ts +1 -1
  253. package/dist/icons/index.js +7 -6
  254. package/dist/icons/index.js.map +1 -1
  255. package/dist/index.js +6 -6
  256. package/dist/style.css +8 -0
  257. package/dist/utils/form-text-detail.d.ts +2 -0
  258. package/dist/utils/form-text-detail.js +5 -1
  259. package/dist/utils/form-text-detail.js.map +1 -1
  260. package/dist/web-types.json +11 -1
  261. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { get, set } from "../../../vendor/@vueuse/shared/dist/index.js";
2
- import { cn, tv } from "../../../utils/tv.js";
2
+ import { cn } from "../../../utils/tv.js";
3
3
  import { ButtonGroupKey } from "./button-group-context.js";
4
+ import { buttonGroupStyles } from "./button-group-styles.js";
4
5
  import { computed, createElementBlock, defineComponent, mergeModels, mergeProps, openBlock, provide, renderSlot, unref, useModel } from "vue";
5
6
  //#region src/components/buttons/button-group/RuiButtonGroup.vue?vue&type=script&setup=true&lang.ts
6
7
  var RuiButtonGroup_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
@@ -32,143 +33,6 @@ var RuiButtonGroup_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
32
33
  emits: ["update:modelValue"],
33
34
  setup(__props) {
34
35
  const modelValue = useModel(__props, "modelValue");
35
- const buttonGroupStyles = tv({
36
- slots: {
37
- root: "inline-flex w-fit max-w-full rounded-rui-control between:border-l between:border-r-0 between:border-rui-divider outline-solid outline-1 outline-transparent -outline-offset-1",
38
- button: "border-0 inset-ring-0 focus:z-1"
39
- },
40
- variants: {
41
- vertical: {
42
- true: {
43
- root: "flex-col items-start between:border-l-0 between:border-t between:border-b-0 *:w-full",
44
- button: "w-full"
45
- },
46
- false: {}
47
- },
48
- gap: {
49
- none: { button: "rounded-none!" },
50
- sm: {
51
- root: "between:border-0 outline-0 gap-2",
52
- button: "inset-ring"
53
- },
54
- md: {
55
- root: "between:border-0 outline-0 gap-4",
56
- button: "inset-ring"
57
- },
58
- lg: {
59
- root: "between:border-0 outline-0 gap-6",
60
- button: "inset-ring"
61
- }
62
- },
63
- variant: {
64
- default: {},
65
- outlined: { root: "outline-rui-outline between:border-rui-outline" },
66
- text: {},
67
- segmented: {
68
- root: "rounded-rui-panel bg-rui-neutral-200 p-0.5 gap-0.5 outline-0 between:border-0 dark:bg-rui-neutral-800",
69
- button: ["h-8 px-3 text-rui-text-secondary transition-colors hover:text-rui-text focus-visible:-outline-offset-2", "data-[active]:bg-rui-surface data-[active]:text-rui-text data-[active]:shadow-rui-control dark:data-[active]:bg-rui-neutral-700"].join(" ")
70
- }
71
- },
72
- color: {
73
- primary: {},
74
- secondary: {},
75
- error: {},
76
- warning: {},
77
- info: {},
78
- success: {}
79
- }
80
- },
81
- compoundVariants: [
82
- {
83
- gap: "none",
84
- vertical: false,
85
- class: { button: "[&:is([data-button-group]>:first-child,[data-button-group]>:first-child_*)]:rounded-l-rui-control! [&:is([data-button-group]>:last-child,[data-button-group]>:last-child_*)]:rounded-r-rui-control!" }
86
- },
87
- {
88
- gap: "none",
89
- vertical: true,
90
- class: { button: "[&:is([data-button-group]>:first-child,[data-button-group]>:first-child_*)]:rounded-t-rui-control! [&:is([data-button-group]>:last-child,[data-button-group]>:last-child_*)]:rounded-b-rui-control!" }
91
- },
92
- {
93
- gap: "none",
94
- variant: [
95
- "default",
96
- "outlined",
97
- "text"
98
- ],
99
- class: { button: "focus-visible:ring-2 focus-visible:ring-rui-surface" }
100
- },
101
- {
102
- variant: "segmented",
103
- class: { button: "rounded-rui-control!" }
104
- },
105
- {
106
- color: "primary",
107
- variant: ["outlined", "text"],
108
- class: { root: "between:border-rui-primary/50" }
109
- },
110
- {
111
- color: "secondary",
112
- variant: ["outlined", "text"],
113
- class: { root: "between:border-rui-secondary/50" }
114
- },
115
- {
116
- color: "error",
117
- variant: ["outlined", "text"],
118
- class: { root: "between:border-rui-error/50" }
119
- },
120
- {
121
- color: "warning",
122
- variant: ["outlined", "text"],
123
- class: { root: "between:border-rui-warning/50" }
124
- },
125
- {
126
- color: "info",
127
- variant: ["outlined", "text"],
128
- class: { root: "between:border-rui-info/50" }
129
- },
130
- {
131
- color: "success",
132
- variant: ["outlined", "text"],
133
- class: { root: "between:border-rui-success/50" }
134
- },
135
- {
136
- color: "primary",
137
- variant: "outlined",
138
- class: { root: "outline-rui-primary/50" }
139
- },
140
- {
141
- color: "secondary",
142
- variant: "outlined",
143
- class: { root: "outline-rui-secondary/50" }
144
- },
145
- {
146
- color: "error",
147
- variant: "outlined",
148
- class: { root: "outline-rui-error/50" }
149
- },
150
- {
151
- color: "warning",
152
- variant: "outlined",
153
- class: { root: "outline-rui-warning/50" }
154
- },
155
- {
156
- color: "info",
157
- variant: "outlined",
158
- class: { root: "outline-rui-info/50" }
159
- },
160
- {
161
- color: "success",
162
- variant: "outlined",
163
- class: { root: "outline-rui-success/50" }
164
- }
165
- ],
166
- defaultVariants: {
167
- vertical: false,
168
- gap: "none",
169
- variant: "default"
170
- }
171
- });
172
36
  const ui = computed(() => buttonGroupStyles({
173
37
  vertical: __props.vertical,
174
38
  gap: __props.gap ?? "none",
@@ -1 +1 @@
1
- {"version":3,"file":"RuiButtonGroup.vue_vue_type_script_setup_true_lang.js","names":["$attrs","_useModel","_openBlock","_createElementBlock","_mergeProps","_unref","_renderSlot"],"sources":["../../../../src/components/buttons/button-group/RuiButtonGroup.vue"],"sourcesContent":["<script lang=\"ts\" generic=\"T = undefined\" setup>\nimport type { ButtonSize } from '@/components/buttons/button/button-props';\nimport type { ContextColorsType } from '@/consts/colors';\nimport { type ButtonGroupContext, ButtonGroupKey } from '@/components/buttons/button-group/button-group-context';\nimport { cn, tv } from '@/utils/tv';\n\nexport interface Props {\n vertical?: boolean;\n color?: ContextColorsType;\n activeColor?: ContextColorsType;\n /**\n * `segmented` draws the options as `RuiTabs variant=\"segmented\"` does: a neutral track whose active\n * option is a raised surface. It is neutral, so it ignores `color` and `activeColor`.\n */\n variant?: 'default' | 'outlined' | 'text' | 'segmented';\n size?: ButtonSize;\n gap?: 'sm' | 'md' | 'lg';\n required?: boolean;\n disabled?: boolean;\n}\n\ndefineOptions({\n name: 'RuiButtonGroup',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<T | T[]>();\n\nconst {\n vertical = false,\n color,\n activeColor,\n variant = 'default',\n size,\n gap,\n required = false,\n disabled = false,\n} = defineProps<Props>();\n\ndefineSlots<{\n default?: () => any;\n}>();\n\nconst buttonGroupStyles = tv({\n slots: {\n /*\n * `w-fit`: a flex column stretches its children, inline-flex or not, which drew an outlined\n * group's frame across the whole row. A consumer's own width still wins through the class merge.\n * Between filled buttons a separator only needs to part the fills, so it takes the light divider.\n */\n root: 'inline-flex w-fit max-w-full rounded-rui-control between:border-l between:border-r-0 between:border-rui-divider outline-solid outline-1 outline-transparent -outline-offset-1',\n button: 'border-0 inset-ring-0 focus:z-1',\n },\n variants: {\n vertical: {\n true: {\n root: 'flex-col items-start between:border-l-0 between:border-t between:border-b-0 *:w-full',\n button: 'w-full',\n },\n false: {},\n },\n gap: {\n none: {\n button: 'rounded-none!',\n },\n sm: {\n root: 'between:border-0 outline-0 gap-2',\n button: 'inset-ring',\n },\n md: {\n root: 'between:border-0 outline-0 gap-4',\n button: 'inset-ring',\n },\n lg: {\n root: 'between:border-0 outline-0 gap-6',\n button: 'inset-ring',\n },\n },\n variant: {\n default: {},\n outlined: {\n // the control edge, matching RuiButton's colourless outlined treatment\n root: 'outline-rui-outline between:border-rui-outline',\n },\n text: {},\n // the segmented tabs' track and pill; the 32px options make a 36px control, a field's height\n segmented: {\n root: 'rounded-rui-panel bg-rui-neutral-200 p-0.5 gap-0.5 outline-0 between:border-0 dark:bg-rui-neutral-800',\n button: [\n 'h-8 px-3 text-rui-text-secondary transition-colors hover:text-rui-text focus-visible:-outline-offset-2',\n 'data-[active]:bg-rui-surface data-[active]:text-rui-text data-[active]:shadow-rui-control dark:data-[active]:bg-rui-neutral-700',\n ].join(' '),\n },\n },\n color: {\n primary: {},\n secondary: {},\n error: {},\n warning: {},\n info: {},\n success: {},\n },\n },\n compoundVariants: [\n /*\n * The outer corners go to the button that is, or sits inside, the group's first or last item, so a\n * button wrapped in a tooltip or a menu activator rounds like a direct child.\n */\n { gap: 'none', vertical: false, class: { button: '[&:is([data-button-group]>:first-child,[data-button-group]>:first-child_*)]:rounded-l-rui-control! [&:is([data-button-group]>:last-child,[data-button-group]>:last-child_*)]:rounded-r-rui-control!' } },\n { gap: 'none', vertical: true, class: { button: '[&:is([data-button-group]>:first-child,[data-button-group]>:first-child_*)]:rounded-t-rui-control! [&:is([data-button-group]>:last-child,[data-button-group]>:last-child_*)]:rounded-b-rui-control!' } },\n /*\n * In a joined group the focus outline's sides fall on the neighbours, and on a primary neighbour a\n * primary outline vanishes. A surface ring fills the outline's offset, so the raised segment's\n * ring is parted from its neighbours on every side.\n */\n { gap: 'none', variant: ['default', 'outlined', 'text'], class: { button: 'focus-visible:ring-2 focus-visible:ring-rui-surface' } },\n // each segment is its own rounded pill inside the track, not a slice of one joined bar\n { variant: 'segmented', class: { button: 'rounded-rui-control!' } },\n\n // Color dividers for outlined/text (overrides darker dividers above)\n { color: 'primary', variant: ['outlined', 'text'], class: { root: 'between:border-rui-primary/50' } },\n { color: 'secondary', variant: ['outlined', 'text'], class: { root: 'between:border-rui-secondary/50' } },\n { color: 'error', variant: ['outlined', 'text'], class: { root: 'between:border-rui-error/50' } },\n { color: 'warning', variant: ['outlined', 'text'], class: { root: 'between:border-rui-warning/50' } },\n { color: 'info', variant: ['outlined', 'text'], class: { root: 'between:border-rui-info/50' } },\n { color: 'success', variant: ['outlined', 'text'], class: { root: 'between:border-rui-success/50' } },\n\n // Color outline for outlined variant\n { color: 'primary', variant: 'outlined', class: { root: 'outline-rui-primary/50' } },\n { color: 'secondary', variant: 'outlined', class: { root: 'outline-rui-secondary/50' } },\n { color: 'error', variant: 'outlined', class: { root: 'outline-rui-error/50' } },\n { color: 'warning', variant: 'outlined', class: { root: 'outline-rui-warning/50' } },\n { color: 'info', variant: 'outlined', class: { root: 'outline-rui-info/50' } },\n { color: 'success', variant: 'outlined', class: { root: 'outline-rui-success/50' } },\n ],\n defaultVariants: {\n vertical: false,\n gap: 'none',\n variant: 'default',\n },\n});\n\nconst ui = computed<ReturnType<typeof buttonGroupStyles>>(() => buttonGroupStyles({\n vertical,\n gap: gap ?? 'none',\n variant,\n color,\n}));\n\n/**\n * The color a button takes: the pressed one's `activeColor` when set, otherwise the group's. The\n * segmented variant is neutral, like the segmented tabs, so its buttons take none.\n *\n * @param active - whether the button is the pressed one\n * @returns the color to set, or undefined to leave the button grey\n */\nfunction buttonColor(active: boolean): ContextColorsType | undefined {\n if (variant === 'segmented')\n return undefined;\n return active && activeColor ? activeColor : color;\n}\n\nfunction isActive(id: T, selected?: T | T[]): boolean {\n if (Array.isArray(selected))\n return selected.includes(id);\n\n return selected === id;\n}\n\nfunction onClick(id: T): void {\n const selected = get(modelValue);\n\n if (Array.isArray(selected)) {\n const index = selected.indexOf(id);\n if (index >= 0) {\n if (required && selected.length === 1)\n return;\n\n set(modelValue, selected.filter((_, i) => i !== index));\n }\n else {\n set(modelValue, [...selected, id]);\n }\n }\n else if (required) {\n set(modelValue, id);\n }\n else {\n set(modelValue, isActive(id, selected) ? undefined : id);\n }\n}\n\n// a button that sets its own size keeps it; the rest take the group's\nprovide(ButtonGroupKey, {\n variant: () => variant === 'segmented' ? 'text' : variant,\n size: () => size,\n disabled: () => disabled,\n color: buttonColor,\n itemClass: () => get(ui).button(),\n isActive: (value: T) => isActive(value, get(modelValue)),\n toggle: onClick,\n} satisfies ButtonGroupContext<T>);\n</script>\n\n<template>\n <div\n :class=\"ui.root({ class: cn($attrs.class) })\"\n data-button-group\n v-bind=\"{ ...$attrs, class: undefined }\"\n >\n <slot />\n </div>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"RuiButtonGroup.vue_vue_type_script_setup_true_lang.js","names":["$attrs","_useModel","_openBlock","_createElementBlock","_mergeProps","_unref","_renderSlot"],"sources":["../../../../src/components/buttons/button-group/RuiButtonGroup.vue"],"sourcesContent":["<script lang=\"ts\" generic=\"T = undefined\" setup>\nimport type { ButtonSize } from '@/components/buttons/button/button-props';\nimport type { ContextColorsType } from '@/consts/colors';\nimport { type ButtonGroupContext, ButtonGroupKey } from '@/components/buttons/button-group/button-group-context';\nimport { cn } from '@/utils/tv';\nimport { buttonGroupStyles } from './button-group-styles';\n\nexport interface Props {\n vertical?: boolean;\n color?: ContextColorsType;\n activeColor?: ContextColorsType;\n /**\n * `segmented` draws the options as `RuiTabs variant=\"segmented\"` does: a neutral track whose active\n * option is a raised surface. It is neutral, so it ignores `color` and `activeColor`.\n */\n variant?: 'default' | 'outlined' | 'text' | 'segmented';\n size?: ButtonSize;\n gap?: 'sm' | 'md' | 'lg';\n required?: boolean;\n disabled?: boolean;\n}\n\ndefineOptions({\n name: 'RuiButtonGroup',\n inheritAttrs: false,\n});\n\nconst modelValue = defineModel<T | T[]>();\n\nconst {\n vertical = false,\n color,\n activeColor,\n variant = 'default',\n size,\n gap,\n required = false,\n disabled = false,\n} = defineProps<Props>();\n\ndefineSlots<{\n default?: () => any;\n}>();\n\nconst ui = computed<ReturnType<typeof buttonGroupStyles>>(() => buttonGroupStyles({\n vertical,\n gap: gap ?? 'none',\n variant,\n color,\n}));\n\n/**\n * The color a button takes: the pressed one's `activeColor` when set, otherwise the group's. The\n * segmented variant is neutral, like the segmented tabs, so its buttons take none.\n *\n * @param active - whether the button is the pressed one\n * @returns the color to set, or undefined to leave the button grey\n */\nfunction buttonColor(active: boolean): ContextColorsType | undefined {\n if (variant === 'segmented')\n return undefined;\n return active && activeColor ? activeColor : color;\n}\n\nfunction isActive(id: T, selected?: T | T[]): boolean {\n if (Array.isArray(selected))\n return selected.includes(id);\n\n return selected === id;\n}\n\nfunction onClick(id: T): void {\n const selected = get(modelValue);\n\n if (Array.isArray(selected)) {\n const index = selected.indexOf(id);\n if (index >= 0) {\n if (required && selected.length === 1)\n return;\n\n set(modelValue, selected.filter((_, i) => i !== index));\n }\n else {\n set(modelValue, [...selected, id]);\n }\n }\n else if (required) {\n set(modelValue, id);\n }\n else {\n set(modelValue, isActive(id, selected) ? undefined : id);\n }\n}\n\n// a button that sets its own size keeps it; the rest take the group's\nprovide(ButtonGroupKey, {\n variant: () => variant === 'segmented' ? 'text' : variant,\n size: () => size,\n disabled: () => disabled,\n color: buttonColor,\n itemClass: () => get(ui).button(),\n isActive: (value: T) => isActive(value, get(modelValue)),\n toggle: onClick,\n} satisfies ButtonGroupContext<T>);\n</script>\n\n<template>\n <div\n :class=\"ui.root({ class: cn($attrs.class) })\"\n data-button-group\n v-bind=\"{ ...$attrs, class: undefined }\"\n >\n <slot />\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BA,MAAM,aAAaC,SAAoB,SAAA,YAAC;EAiBxC,MAAM,KAAK,eAAqD,kBAAkB;GAChF,UAAO,QAAA;GACP,KAAK,QAAA,OAAO;GACZ,SAAM,QAAA;GACN,OAAI,QAAA;EACN,CAAC,CAAC;;;;;;;;EASF,SAAS,YAAY,QAAgD;GACnE,IAAI,QAAA,YAAY,aACd,OAAO,KAAA;GACT,OAAO,UAAU,QAAA,cAAc,QAAA,cAAc,QAAA;EAC/C;EAEA,SAAS,SAAS,IAAO,UAA6B;GACpD,IAAI,MAAM,QAAQ,QAAQ,GACxB,OAAO,SAAS,SAAS,EAAE;GAE7B,OAAO,aAAa;EACtB;EAEA,SAAS,QAAQ,IAAa;GAC5B,MAAM,WAAW,IAAI,UAAU;GAE/B,IAAI,MAAM,QAAQ,QAAQ,GAAG;IAC3B,MAAM,QAAQ,SAAS,QAAQ,EAAE;IACjC,IAAI,SAAS,GAAG;KACd,IAAI,QAAA,YAAY,SAAS,WAAW,GAClC;KAEF,IAAI,YAAY,SAAS,QAAQ,GAAG,MAAM,MAAM,KAAK,CAAC;IACxD,OAEE,IAAI,YAAY,CAAC,GAAG,UAAU,EAAE,CAAC;GAErC,OACK,IAAI,QAAA,UACP,IAAI,YAAY,EAAE;QAGlB,IAAI,YAAY,SAAS,IAAI,QAAQ,IAAI,KAAA,IAAY,EAAE;EAE3D;EAGA,QAAQ,gBAAgB;GACtB,eAAe,QAAA,YAAY,cAAc,SAAS,QAAA;GAClD,YAAY,QAAA;GACZ,gBAAgB,QAAA;GAChB,OAAO;GACP,iBAAiB,IAAI,EAAE,CAAC,CAAC,OAAO;GAChC,WAAW,UAAa,SAAS,OAAO,IAAI,UAAU,CAAC;GACvD,QAAQ;EACV,CAAiC;;GAI/B,OAAAC,UAAA,GAAAC,mBAMM,OANNC,WAMM;IALH,OAAOC,MAAA,EAAA,CAAE,CAAC,KAAI,EAAA,OAAUA,MAAA,EAAA,CAAE,CAACL,KAAAA,OAAO,KAAK,EAAA,CAAA;IACxC,qBAAA;GACaA,GAAAA;IAAAA,GAAAA,KAAAA;IAAM,OAAS,KAAA;GAAS,CAAA,GAAA,CAErCM,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,EAAA"}
@@ -0,0 +1,142 @@
1
+ export declare const buttonGroupStyles: import("tailwind-variants").TVReturnType<{
2
+ vertical: {
3
+ true: {
4
+ root: string;
5
+ button: string;
6
+ };
7
+ false: {};
8
+ };
9
+ gap: {
10
+ none: {
11
+ button: string;
12
+ };
13
+ sm: {
14
+ root: string;
15
+ button: string;
16
+ };
17
+ md: {
18
+ root: string;
19
+ button: string;
20
+ };
21
+ lg: {
22
+ root: string;
23
+ button: string;
24
+ };
25
+ };
26
+ variant: {
27
+ default: {};
28
+ outlined: {
29
+ root: string;
30
+ };
31
+ text: {};
32
+ segmented: {
33
+ root: string;
34
+ button: string;
35
+ };
36
+ };
37
+ color: {
38
+ primary: {};
39
+ secondary: {};
40
+ error: {};
41
+ warning: {};
42
+ info: {};
43
+ success: {};
44
+ };
45
+ }, {
46
+ root: string;
47
+ button: string;
48
+ }, undefined, {
49
+ vertical: {
50
+ true: {
51
+ root: string;
52
+ button: string;
53
+ };
54
+ false: {};
55
+ };
56
+ gap: {
57
+ none: {
58
+ button: string;
59
+ };
60
+ sm: {
61
+ root: string;
62
+ button: string;
63
+ };
64
+ md: {
65
+ root: string;
66
+ button: string;
67
+ };
68
+ lg: {
69
+ root: string;
70
+ button: string;
71
+ };
72
+ };
73
+ variant: {
74
+ default: {};
75
+ outlined: {
76
+ root: string;
77
+ };
78
+ text: {};
79
+ segmented: {
80
+ root: string;
81
+ button: string;
82
+ };
83
+ };
84
+ color: {
85
+ primary: {};
86
+ secondary: {};
87
+ error: {};
88
+ warning: {};
89
+ info: {};
90
+ success: {};
91
+ };
92
+ }, {
93
+ root: string;
94
+ button: string;
95
+ }, import("tailwind-variants").TVReturnTypeLike<{
96
+ vertical: {
97
+ true: {
98
+ root: string;
99
+ button: string;
100
+ };
101
+ false: {};
102
+ };
103
+ gap: {
104
+ none: {
105
+ button: string;
106
+ };
107
+ sm: {
108
+ root: string;
109
+ button: string;
110
+ };
111
+ md: {
112
+ root: string;
113
+ button: string;
114
+ };
115
+ lg: {
116
+ root: string;
117
+ button: string;
118
+ };
119
+ };
120
+ variant: {
121
+ default: {};
122
+ outlined: {
123
+ root: string;
124
+ };
125
+ text: {};
126
+ segmented: {
127
+ root: string;
128
+ button: string;
129
+ };
130
+ };
131
+ color: {
132
+ primary: {};
133
+ secondary: {};
134
+ error: {};
135
+ warning: {};
136
+ info: {};
137
+ success: {};
138
+ };
139
+ }, {
140
+ root: string;
141
+ button: string;
142
+ }>>;
@@ -0,0 +1,143 @@
1
+ import { tv } from "../../../utils/tv.js";
2
+ //#region src/components/buttons/button-group/button-group-styles.ts
3
+ var buttonGroupStyles = tv({
4
+ slots: {
5
+ root: "inline-flex w-fit max-w-full rounded-rui-control between:border-l between:border-r-0 between:border-rui-divider outline-solid outline-1 outline-transparent -outline-offset-1",
6
+ button: "border-0 inset-ring-0 focus:z-1"
7
+ },
8
+ variants: {
9
+ vertical: {
10
+ true: {
11
+ root: "flex-col items-start between:border-l-0 between:border-t between:border-b-0 *:w-full",
12
+ button: "w-full"
13
+ },
14
+ false: {}
15
+ },
16
+ gap: {
17
+ none: { button: "rounded-none!" },
18
+ sm: {
19
+ root: "between:border-0 outline-0 gap-2",
20
+ button: "inset-ring"
21
+ },
22
+ md: {
23
+ root: "between:border-0 outline-0 gap-4",
24
+ button: "inset-ring"
25
+ },
26
+ lg: {
27
+ root: "between:border-0 outline-0 gap-6",
28
+ button: "inset-ring"
29
+ }
30
+ },
31
+ variant: {
32
+ default: {},
33
+ outlined: { root: "outline-rui-outline between:border-rui-outline" },
34
+ text: {},
35
+ segmented: {
36
+ root: "rounded-rui-panel bg-rui-neutral-200 p-0.5 gap-0.5 outline-0 between:border-0 dark:bg-rui-neutral-800",
37
+ button: ["h-8 px-3 text-rui-text-secondary transition-colors hover:text-rui-text focus-visible:-outline-offset-2", "data-[active]:bg-rui-surface data-[active]:text-rui-text data-[active]:shadow-rui-control dark:data-[active]:bg-rui-neutral-700"].join(" ")
38
+ }
39
+ },
40
+ color: {
41
+ primary: {},
42
+ secondary: {},
43
+ error: {},
44
+ warning: {},
45
+ info: {},
46
+ success: {}
47
+ }
48
+ },
49
+ compoundVariants: [
50
+ {
51
+ gap: "none",
52
+ vertical: false,
53
+ class: { button: "[&:is([data-button-group]>:first-child,[data-button-group]>:first-child_*)]:rounded-l-rui-control! [&:is([data-button-group]>:last-child,[data-button-group]>:last-child_*)]:rounded-r-rui-control!" }
54
+ },
55
+ {
56
+ gap: "none",
57
+ vertical: true,
58
+ class: { button: "[&:is([data-button-group]>:first-child,[data-button-group]>:first-child_*)]:rounded-t-rui-control! [&:is([data-button-group]>:last-child,[data-button-group]>:last-child_*)]:rounded-b-rui-control!" }
59
+ },
60
+ {
61
+ gap: "none",
62
+ variant: [
63
+ "default",
64
+ "outlined",
65
+ "text"
66
+ ],
67
+ class: { button: "focus-visible:ring-2 focus-visible:ring-rui-surface" }
68
+ },
69
+ {
70
+ variant: "segmented",
71
+ class: { button: "rounded-rui-control!" }
72
+ },
73
+ {
74
+ color: "primary",
75
+ variant: ["outlined", "text"],
76
+ class: { root: "between:border-rui-primary/50" }
77
+ },
78
+ {
79
+ color: "secondary",
80
+ variant: ["outlined", "text"],
81
+ class: { root: "between:border-rui-secondary/50" }
82
+ },
83
+ {
84
+ color: "error",
85
+ variant: ["outlined", "text"],
86
+ class: { root: "between:border-rui-error/50" }
87
+ },
88
+ {
89
+ color: "warning",
90
+ variant: ["outlined", "text"],
91
+ class: { root: "between:border-rui-warning/50" }
92
+ },
93
+ {
94
+ color: "info",
95
+ variant: ["outlined", "text"],
96
+ class: { root: "between:border-rui-info/50" }
97
+ },
98
+ {
99
+ color: "success",
100
+ variant: ["outlined", "text"],
101
+ class: { root: "between:border-rui-success/50" }
102
+ },
103
+ {
104
+ color: "primary",
105
+ variant: "outlined",
106
+ class: { root: "outline-rui-primary/50" }
107
+ },
108
+ {
109
+ color: "secondary",
110
+ variant: "outlined",
111
+ class: { root: "outline-rui-secondary/50" }
112
+ },
113
+ {
114
+ color: "error",
115
+ variant: "outlined",
116
+ class: { root: "outline-rui-error/50" }
117
+ },
118
+ {
119
+ color: "warning",
120
+ variant: "outlined",
121
+ class: { root: "outline-rui-warning/50" }
122
+ },
123
+ {
124
+ color: "info",
125
+ variant: "outlined",
126
+ class: { root: "outline-rui-info/50" }
127
+ },
128
+ {
129
+ color: "success",
130
+ variant: "outlined",
131
+ class: { root: "outline-rui-success/50" }
132
+ }
133
+ ],
134
+ defaultVariants: {
135
+ vertical: false,
136
+ gap: "none",
137
+ variant: "default"
138
+ }
139
+ });
140
+ //#endregion
141
+ export { buttonGroupStyles };
142
+
143
+ //# sourceMappingURL=button-group-styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button-group-styles.js","names":[],"sources":["../../../../src/components/buttons/button-group/button-group-styles.ts"],"sourcesContent":["import { tv } from '@/utils/tv';\n\nexport const buttonGroupStyles = tv({\n slots: {\n /*\n * `w-fit`: a flex column stretches its children, inline-flex or not, which drew an outlined\n * group's frame across the whole row. A consumer's own width still wins through the class merge.\n * Between filled buttons a separator only needs to part the fills, so it takes the light divider.\n */\n root: 'inline-flex w-fit max-w-full rounded-rui-control between:border-l between:border-r-0 between:border-rui-divider outline-solid outline-1 outline-transparent -outline-offset-1',\n button: 'border-0 inset-ring-0 focus:z-1',\n },\n variants: {\n vertical: {\n true: {\n root: 'flex-col items-start between:border-l-0 between:border-t between:border-b-0 *:w-full',\n button: 'w-full',\n },\n false: {},\n },\n gap: {\n none: {\n button: 'rounded-none!',\n },\n sm: {\n root: 'between:border-0 outline-0 gap-2',\n button: 'inset-ring',\n },\n md: {\n root: 'between:border-0 outline-0 gap-4',\n button: 'inset-ring',\n },\n lg: {\n root: 'between:border-0 outline-0 gap-6',\n button: 'inset-ring',\n },\n },\n variant: {\n default: {},\n outlined: {\n // the control edge, matching RuiButton's colourless outlined treatment\n root: 'outline-rui-outline between:border-rui-outline',\n },\n text: {},\n // the segmented tabs' track and pill; the 32px options make a 36px control, a field's height\n segmented: {\n root: 'rounded-rui-panel bg-rui-neutral-200 p-0.5 gap-0.5 outline-0 between:border-0 dark:bg-rui-neutral-800',\n button: [\n 'h-8 px-3 text-rui-text-secondary transition-colors hover:text-rui-text focus-visible:-outline-offset-2',\n 'data-[active]:bg-rui-surface data-[active]:text-rui-text data-[active]:shadow-rui-control dark:data-[active]:bg-rui-neutral-700',\n ].join(' '),\n },\n },\n color: {\n primary: {},\n secondary: {},\n error: {},\n warning: {},\n info: {},\n success: {},\n },\n },\n compoundVariants: [\n /*\n * The outer corners go to the button that is, or sits inside, the group's first or last item, so a\n * button wrapped in a tooltip or a menu activator rounds like a direct child.\n */\n { gap: 'none', vertical: false, class: { button: '[&:is([data-button-group]>:first-child,[data-button-group]>:first-child_*)]:rounded-l-rui-control! [&:is([data-button-group]>:last-child,[data-button-group]>:last-child_*)]:rounded-r-rui-control!' } },\n { gap: 'none', vertical: true, class: { button: '[&:is([data-button-group]>:first-child,[data-button-group]>:first-child_*)]:rounded-t-rui-control! [&:is([data-button-group]>:last-child,[data-button-group]>:last-child_*)]:rounded-b-rui-control!' } },\n /*\n * In a joined group the focus outline's sides fall on the neighbours, and on a primary neighbour a\n * primary outline vanishes. A surface ring fills the outline's offset, so the raised segment's\n * ring is parted from its neighbours on every side.\n */\n { gap: 'none', variant: ['default', 'outlined', 'text'], class: { button: 'focus-visible:ring-2 focus-visible:ring-rui-surface' } },\n // each segment is its own rounded pill inside the track, not a slice of one joined bar\n { variant: 'segmented', class: { button: 'rounded-rui-control!' } },\n\n // Color dividers for outlined/text (overrides darker dividers above)\n { color: 'primary', variant: ['outlined', 'text'], class: { root: 'between:border-rui-primary/50' } },\n { color: 'secondary', variant: ['outlined', 'text'], class: { root: 'between:border-rui-secondary/50' } },\n { color: 'error', variant: ['outlined', 'text'], class: { root: 'between:border-rui-error/50' } },\n { color: 'warning', variant: ['outlined', 'text'], class: { root: 'between:border-rui-warning/50' } },\n { color: 'info', variant: ['outlined', 'text'], class: { root: 'between:border-rui-info/50' } },\n { color: 'success', variant: ['outlined', 'text'], class: { root: 'between:border-rui-success/50' } },\n\n // Color outline for outlined variant\n { color: 'primary', variant: 'outlined', class: { root: 'outline-rui-primary/50' } },\n { color: 'secondary', variant: 'outlined', class: { root: 'outline-rui-secondary/50' } },\n { color: 'error', variant: 'outlined', class: { root: 'outline-rui-error/50' } },\n { color: 'warning', variant: 'outlined', class: { root: 'outline-rui-warning/50' } },\n { color: 'info', variant: 'outlined', class: { root: 'outline-rui-info/50' } },\n { color: 'success', variant: 'outlined', class: { root: 'outline-rui-success/50' } },\n ],\n defaultVariants: {\n vertical: false,\n gap: 'none',\n variant: 'default',\n },\n});\n"],"mappings":";;AAEA,IAAa,oBAAoB,GAAG;CAClC,OAAO;EAML,MAAM;EACN,QAAQ;CACV;CACA,UAAU;EACR,UAAU;GACR,MAAM;IACJ,MAAM;IACN,QAAQ;GACV;GACA,OAAO,CAAC;EACV;EACA,KAAK;GACH,MAAM,EACJ,QAAQ,gBACV;GACA,IAAI;IACF,MAAM;IACN,QAAQ;GACV;GACA,IAAI;IACF,MAAM;IACN,QAAQ;GACV;GACA,IAAI;IACF,MAAM;IACN,QAAQ;GACV;EACF;EACA,SAAS;GACP,SAAS,CAAC;GACV,UAAU,EAER,MAAM,iDACR;GACA,MAAM,CAAC;GAEP,WAAW;IACT,MAAM;IACN,QAAQ,CACN,0GACA,iIACF,CAAC,CAAC,KAAK,GAAG;GACZ;EACF;EACA,OAAO;GACL,SAAS,CAAC;GACV,WAAW,CAAC;GACZ,OAAO,CAAC;GACR,SAAS,CAAC;GACV,MAAM,CAAC;GACP,SAAS,CAAC;EACZ;CACF;CACA,kBAAkB;EAKhB;GAAE,KAAK;GAAQ,UAAU;GAAO,OAAO,EAAE,QAAQ,sMAAsM;EAAE;EACzP;GAAE,KAAK;GAAQ,UAAU;GAAM,OAAO,EAAE,QAAQ,sMAAsM;EAAE;EAMxP;GAAE,KAAK;GAAQ,SAAS;IAAC;IAAW;IAAY;GAAM;GAAG,OAAO,EAAE,QAAQ,sDAAsD;EAAE;EAElI;GAAE,SAAS;GAAa,OAAO,EAAE,QAAQ,uBAAuB;EAAE;EAGlE;GAAE,OAAO;GAAW,SAAS,CAAC,YAAY,MAAM;GAAG,OAAO,EAAE,MAAM,gCAAgC;EAAE;EACpG;GAAE,OAAO;GAAa,SAAS,CAAC,YAAY,MAAM;GAAG,OAAO,EAAE,MAAM,kCAAkC;EAAE;EACxG;GAAE,OAAO;GAAS,SAAS,CAAC,YAAY,MAAM;GAAG,OAAO,EAAE,MAAM,8BAA8B;EAAE;EAChG;GAAE,OAAO;GAAW,SAAS,CAAC,YAAY,MAAM;GAAG,OAAO,EAAE,MAAM,gCAAgC;EAAE;EACpG;GAAE,OAAO;GAAQ,SAAS,CAAC,YAAY,MAAM;GAAG,OAAO,EAAE,MAAM,6BAA6B;EAAE;EAC9F;GAAE,OAAO;GAAW,SAAS,CAAC,YAAY,MAAM;GAAG,OAAO,EAAE,MAAM,gCAAgC;EAAE;EAGpG;GAAE,OAAO;GAAW,SAAS;GAAY,OAAO,EAAE,MAAM,yBAAyB;EAAE;EACnF;GAAE,OAAO;GAAa,SAAS;GAAY,OAAO,EAAE,MAAM,2BAA2B;EAAE;EACvF;GAAE,OAAO;GAAS,SAAS;GAAY,OAAO,EAAE,MAAM,uBAAuB;EAAE;EAC/E;GAAE,OAAO;GAAW,SAAS;GAAY,OAAO,EAAE,MAAM,yBAAyB;EAAE;EACnF;GAAE,OAAO;GAAQ,SAAS;GAAY,OAAO,EAAE,MAAM,sBAAsB;EAAE;EAC7E;GAAE,OAAO;GAAW,SAAS;GAAY,OAAO,EAAE,MAAM,yBAAyB;EAAE;CACrF;CACA,iBAAiB;EACf,UAAU;EACV,KAAK;EACL,SAAS;CACX;AACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"RuiCalendar.js","names":["_sfc_main"],"sources":["../../../src/components/calendar/RuiCalendar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { get, isDefined, set } from '@vueuse/core';\nimport { computed, provide, ref, watch } from 'vue';\nimport {\n CalendarStateSymbol,\n type MonthYearSelection,\n type RuiCalendarState,\n} from '@/components/calendar/state';\nimport { useRotkiTheme } from '@/composables/theme';\nimport { tv } from '@/utils/tv';\nimport RuiCalendarGrid from './RuiCalendarGrid.vue';\nimport RuiCalendarHeader from './RuiCalendarHeader.vue';\n\nexport interface CalendarProps {\n maxDate?: Date | number;\n minDate?: Date | number;\n allowEmpty?: boolean;\n borderless?: boolean;\n}\n\ndefineOptions({\n name: 'RuiCalendar',\n inheritAttrs: false,\n});\n\nconst model = defineModel<Date | undefined>({ required: false });\nconst isMenuOpen = defineModel<boolean>('menu-open', { required: false, default: false });\n\nconst { maxDate, minDate, allowEmpty = false, borderless = false } = defineProps<CalendarProps>();\n\nconst emit = defineEmits<{\n 'update:pages': [{ title: string }[]];\n}>();\n\nconst currentDate = ref<Date>(isDefined(model) ? new Date(get(model)) : new Date());\nconst selectedDate = ref<Date | undefined>(isDefined(model) ? new Date(get(model)) : undefined);\nconst viewMonth = ref<number>(get(currentDate).getMonth());\nconst viewYear = ref<number>(get(currentDate).getFullYear());\n\nconst { isDark } = useRotkiTheme();\n\nconst calendarStyles = tv({\n base: 'w-75 overflow-hidden',\n variants: {\n // standalone it sits on the card surface; borderless it lives inside a menu\n bordered: {\n true: 'bg-rui-surface rounded-rui-panel border border-rui-divider',\n false: 'bg-rui-menu',\n },\n },\n});\n\nconst ui = computed<string>(() => calendarStyles({ bordered: !borderless }));\n\nconst monthTitle = computed<string>(() => {\n const date = new Date(get(viewYear), get(viewMonth));\n return date.toLocaleString('default', { month: 'long', year: 'numeric' });\n});\n\nprovide(CalendarStateSymbol.valueOf(), {\n viewMonth,\n viewYear,\n selectedDate,\n maxDate: computed(() => (maxDate ? new Date(maxDate) : undefined)),\n minDate: computed(() => (minDate ? new Date(minDate) : undefined)),\n isDark,\n allowEmpty,\n} satisfies RuiCalendarState);\n\n// The grid's keyboard navigation also turns the view, so the title follows the view itself\nwatch(monthTitle, (title) => {\n emit('update:pages', [{ title }]);\n});\n\nfunction moveMonth(delta: number): void {\n let newMonth = get(viewMonth) + delta;\n let newYear = get(viewYear);\n\n if (newMonth > 11) {\n newMonth = 0;\n newYear++;\n }\n else if (newMonth < 0) {\n newMonth = 11;\n newYear--;\n }\n\n set(viewMonth, newMonth);\n set(viewYear, newYear);\n}\n\nfunction move(date: Date | number): void {\n const newDate = new Date(date);\n set(viewMonth, newDate.getMonth());\n set(viewYear, newDate.getFullYear());\n}\n\nfunction selectMonth(selection: MonthYearSelection): void {\n set(viewMonth, selection.month);\n set(viewYear, selection.year);\n\n // If there's a selected date, update it with the new year/month\n if (isDefined(selectedDate)) {\n const current = get(selectedDate);\n const currentDay = current.getDate();\n // Handle day overflow (e.g., Jan 31 -> Feb 28) by checking BEFORE setting month\n const daysInNewMonth = new Date(selection.year, selection.month + 1, 0).getDate();\n const adjustedDay = Math.min(currentDay, daysInNewMonth);\n\n const newDate = new Date(current);\n newDate.setFullYear(selection.year);\n newDate.setDate(1); // Set to 1st to avoid overflow when changing month\n newDate.setMonth(selection.month);\n newDate.setDate(adjustedDay);\n set(selectedDate, newDate);\n }\n}\n\nwatch(selectedDate, (date) => {\n if (!date && !allowEmpty)\n return;\n\n if (date) {\n set(model, new Date(date));\n\n if (get(viewMonth) !== date.getMonth()) {\n set(viewMonth, date.getMonth());\n }\n\n if (get(viewYear) !== date.getFullYear()) {\n set(viewYear, date.getFullYear());\n }\n }\n else {\n set(model, undefined);\n }\n});\n\nwatch(model, (newValue) => {\n if (newValue === undefined) {\n set(selectedDate, undefined);\n return;\n }\n\n const date = new Date(newValue);\n\n if (isDefined(selectedDate) && get(selectedDate).getTime() !== date.getTime()) {\n set(selectedDate, new Date(newValue));\n set(viewMonth, date.getMonth());\n set(viewYear, date.getFullYear());\n }\n});\n\ndefineExpose({\n move,\n});\n</script>\n\n<template>\n <div :class=\"ui\">\n <RuiCalendarHeader\n v-model:menu-open=\"isMenuOpen\"\n :title=\"monthTitle\"\n :view-month=\"viewMonth\"\n :view-year=\"viewYear\"\n @prev-month=\"moveMonth(-1)\"\n @next-month=\"moveMonth(1)\"\n @select-month=\"selectMonth($event)\"\n />\n\n <RuiCalendarGrid\n v-model=\"selectedDate\"\n :view-month=\"viewMonth\"\n :view-year=\"viewYear\"\n />\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"RuiCalendar.js","names":["_sfc_main"],"sources":["../../../src/components/calendar/RuiCalendar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { get, isDefined, set } from '@vueuse/core';\nimport { computed, provide, ref, watch } from 'vue';\nimport {\n CalendarStateSymbol,\n type MonthYearSelection,\n type RuiCalendarState,\n} from '@/components/calendar/state';\nimport { useRotkiTheme } from '@/composables/theme';\nimport { calendarStyles } from './calendar-styles';\nimport RuiCalendarGrid from './RuiCalendarGrid.vue';\nimport RuiCalendarHeader from './RuiCalendarHeader.vue';\n\nexport interface CalendarProps {\n maxDate?: Date | number;\n minDate?: Date | number;\n allowEmpty?: boolean;\n borderless?: boolean;\n}\n\ndefineOptions({\n name: 'RuiCalendar',\n inheritAttrs: false,\n});\n\nconst model = defineModel<Date | undefined>({ required: false });\nconst isMenuOpen = defineModel<boolean>('menu-open', { required: false, default: false });\n\nconst { maxDate, minDate, allowEmpty = false, borderless = false } = defineProps<CalendarProps>();\n\nconst emit = defineEmits<{\n 'update:pages': [{ title: string }[]];\n}>();\n\nconst currentDate = ref<Date>(isDefined(model) ? new Date(get(model)) : new Date());\nconst selectedDate = ref<Date | undefined>(isDefined(model) ? new Date(get(model)) : undefined);\nconst viewMonth = ref<number>(get(currentDate).getMonth());\nconst viewYear = ref<number>(get(currentDate).getFullYear());\n\nconst { isDark } = useRotkiTheme();\n\nconst ui = computed<string>(() => calendarStyles({ bordered: !borderless }));\n\nconst monthTitle = computed<string>(() => {\n const date = new Date(get(viewYear), get(viewMonth));\n return date.toLocaleString('default', { month: 'long', year: 'numeric' });\n});\n\nprovide(CalendarStateSymbol.valueOf(), {\n viewMonth,\n viewYear,\n selectedDate,\n maxDate: computed(() => (maxDate ? new Date(maxDate) : undefined)),\n minDate: computed(() => (minDate ? new Date(minDate) : undefined)),\n isDark,\n allowEmpty,\n} satisfies RuiCalendarState);\n\n// The grid's keyboard navigation also turns the view, so the title follows the view itself\nwatch(monthTitle, (title) => {\n emit('update:pages', [{ title }]);\n});\n\nfunction moveMonth(delta: number): void {\n let newMonth = get(viewMonth) + delta;\n let newYear = get(viewYear);\n\n if (newMonth > 11) {\n newMonth = 0;\n newYear++;\n }\n else if (newMonth < 0) {\n newMonth = 11;\n newYear--;\n }\n\n set(viewMonth, newMonth);\n set(viewYear, newYear);\n}\n\nfunction move(date: Date | number): void {\n const newDate = new Date(date);\n set(viewMonth, newDate.getMonth());\n set(viewYear, newDate.getFullYear());\n}\n\nfunction selectMonth(selection: MonthYearSelection): void {\n set(viewMonth, selection.month);\n set(viewYear, selection.year);\n\n // If there's a selected date, update it with the new year/month\n if (isDefined(selectedDate)) {\n const current = get(selectedDate);\n const currentDay = current.getDate();\n // Handle day overflow (e.g., Jan 31 -> Feb 28) by checking BEFORE setting month\n const daysInNewMonth = new Date(selection.year, selection.month + 1, 0).getDate();\n const adjustedDay = Math.min(currentDay, daysInNewMonth);\n\n const newDate = new Date(current);\n newDate.setFullYear(selection.year);\n newDate.setDate(1); // Set to 1st to avoid overflow when changing month\n newDate.setMonth(selection.month);\n newDate.setDate(adjustedDay);\n set(selectedDate, newDate);\n }\n}\n\nwatch(selectedDate, (date) => {\n if (!date && !allowEmpty)\n return;\n\n if (date) {\n set(model, new Date(date));\n\n if (get(viewMonth) !== date.getMonth()) {\n set(viewMonth, date.getMonth());\n }\n\n if (get(viewYear) !== date.getFullYear()) {\n set(viewYear, date.getFullYear());\n }\n }\n else {\n set(model, undefined);\n }\n});\n\nwatch(model, (newValue) => {\n if (newValue === undefined) {\n set(selectedDate, undefined);\n return;\n }\n\n const date = new Date(newValue);\n\n if (isDefined(selectedDate) && get(selectedDate).getTime() !== date.getTime()) {\n set(selectedDate, new Date(newValue));\n set(viewMonth, date.getMonth());\n set(viewYear, date.getFullYear());\n }\n});\n\ndefineExpose({\n move,\n});\n</script>\n\n<template>\n <div :class=\"ui\">\n <RuiCalendarHeader\n v-model:menu-open=\"isMenuOpen\"\n :title=\"monthTitle\"\n :view-month=\"viewMonth\"\n :view-year=\"viewYear\"\n @prev-month=\"moveMonth(-1)\"\n @next-month=\"moveMonth(1)\"\n @select-month=\"selectMonth($event)\"\n />\n\n <RuiCalendarGrid\n v-model=\"selectedDate\"\n :view-month=\"viewMonth\"\n :view-year=\"viewYear\"\n />\n </div>\n</template>\n"],"mappings":""}
@@ -1,7 +1,7 @@
1
1
  import { get, isDefined, set } from "../../vendor/@vueuse/shared/dist/index.js";
2
2
  import { useRotkiTheme } from "../../composables/theme.js";
3
- import { tv } from "../../utils/tv.js";
4
3
  import { CalendarStateSymbol } from "./state.js";
4
+ import { calendarStyles } from "./calendar-styles.js";
5
5
  import RuiCalendarGrid_default from "./RuiCalendarGrid.js";
6
6
  import RuiCalendarHeader_default from "./RuiCalendarHeader.js";
7
7
  import { computed, createElementBlock, createVNode, defineComponent, mergeModels, normalizeClass, openBlock, provide, ref, useModel, watch } from "vue";
@@ -41,13 +41,6 @@ var RuiCalendar_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
41
41
  const viewMonth = ref(get(currentDate).getMonth());
42
42
  const viewYear = ref(get(currentDate).getFullYear());
43
43
  const { isDark } = useRotkiTheme();
44
- const calendarStyles = tv({
45
- base: "w-75 overflow-hidden",
46
- variants: { bordered: {
47
- true: "bg-rui-surface rounded-rui-panel border border-rui-divider",
48
- false: "bg-rui-menu"
49
- } }
50
- });
51
44
  const ui = computed(() => calendarStyles({ bordered: !__props.borderless }));
52
45
  const monthTitle = computed(() => {
53
46
  return new Date(get(viewYear), get(viewMonth)).toLocaleString("default", {
@@ -1 +1 @@
1
- {"version":3,"file":"RuiCalendar.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_normalizeClass","_createVNode","RuiCalendarHeader","RuiCalendarGrid"],"sources":["../../../src/components/calendar/RuiCalendar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { get, isDefined, set } from '@vueuse/core';\nimport { computed, provide, ref, watch } from 'vue';\nimport {\n CalendarStateSymbol,\n type MonthYearSelection,\n type RuiCalendarState,\n} from '@/components/calendar/state';\nimport { useRotkiTheme } from '@/composables/theme';\nimport { tv } from '@/utils/tv';\nimport RuiCalendarGrid from './RuiCalendarGrid.vue';\nimport RuiCalendarHeader from './RuiCalendarHeader.vue';\n\nexport interface CalendarProps {\n maxDate?: Date | number;\n minDate?: Date | number;\n allowEmpty?: boolean;\n borderless?: boolean;\n}\n\ndefineOptions({\n name: 'RuiCalendar',\n inheritAttrs: false,\n});\n\nconst model = defineModel<Date | undefined>({ required: false });\nconst isMenuOpen = defineModel<boolean>('menu-open', { required: false, default: false });\n\nconst { maxDate, minDate, allowEmpty = false, borderless = false } = defineProps<CalendarProps>();\n\nconst emit = defineEmits<{\n 'update:pages': [{ title: string }[]];\n}>();\n\nconst currentDate = ref<Date>(isDefined(model) ? new Date(get(model)) : new Date());\nconst selectedDate = ref<Date | undefined>(isDefined(model) ? new Date(get(model)) : undefined);\nconst viewMonth = ref<number>(get(currentDate).getMonth());\nconst viewYear = ref<number>(get(currentDate).getFullYear());\n\nconst { isDark } = useRotkiTheme();\n\nconst calendarStyles = tv({\n base: 'w-75 overflow-hidden',\n variants: {\n // standalone it sits on the card surface; borderless it lives inside a menu\n bordered: {\n true: 'bg-rui-surface rounded-rui-panel border border-rui-divider',\n false: 'bg-rui-menu',\n },\n },\n});\n\nconst ui = computed<string>(() => calendarStyles({ bordered: !borderless }));\n\nconst monthTitle = computed<string>(() => {\n const date = new Date(get(viewYear), get(viewMonth));\n return date.toLocaleString('default', { month: 'long', year: 'numeric' });\n});\n\nprovide(CalendarStateSymbol.valueOf(), {\n viewMonth,\n viewYear,\n selectedDate,\n maxDate: computed(() => (maxDate ? new Date(maxDate) : undefined)),\n minDate: computed(() => (minDate ? new Date(minDate) : undefined)),\n isDark,\n allowEmpty,\n} satisfies RuiCalendarState);\n\n// The grid's keyboard navigation also turns the view, so the title follows the view itself\nwatch(monthTitle, (title) => {\n emit('update:pages', [{ title }]);\n});\n\nfunction moveMonth(delta: number): void {\n let newMonth = get(viewMonth) + delta;\n let newYear = get(viewYear);\n\n if (newMonth > 11) {\n newMonth = 0;\n newYear++;\n }\n else if (newMonth < 0) {\n newMonth = 11;\n newYear--;\n }\n\n set(viewMonth, newMonth);\n set(viewYear, newYear);\n}\n\nfunction move(date: Date | number): void {\n const newDate = new Date(date);\n set(viewMonth, newDate.getMonth());\n set(viewYear, newDate.getFullYear());\n}\n\nfunction selectMonth(selection: MonthYearSelection): void {\n set(viewMonth, selection.month);\n set(viewYear, selection.year);\n\n // If there's a selected date, update it with the new year/month\n if (isDefined(selectedDate)) {\n const current = get(selectedDate);\n const currentDay = current.getDate();\n // Handle day overflow (e.g., Jan 31 -> Feb 28) by checking BEFORE setting month\n const daysInNewMonth = new Date(selection.year, selection.month + 1, 0).getDate();\n const adjustedDay = Math.min(currentDay, daysInNewMonth);\n\n const newDate = new Date(current);\n newDate.setFullYear(selection.year);\n newDate.setDate(1); // Set to 1st to avoid overflow when changing month\n newDate.setMonth(selection.month);\n newDate.setDate(adjustedDay);\n set(selectedDate, newDate);\n }\n}\n\nwatch(selectedDate, (date) => {\n if (!date && !allowEmpty)\n return;\n\n if (date) {\n set(model, new Date(date));\n\n if (get(viewMonth) !== date.getMonth()) {\n set(viewMonth, date.getMonth());\n }\n\n if (get(viewYear) !== date.getFullYear()) {\n set(viewYear, date.getFullYear());\n }\n }\n else {\n set(model, undefined);\n }\n});\n\nwatch(model, (newValue) => {\n if (newValue === undefined) {\n set(selectedDate, undefined);\n return;\n }\n\n const date = new Date(newValue);\n\n if (isDefined(selectedDate) && get(selectedDate).getTime() !== date.getTime()) {\n set(selectedDate, new Date(newValue));\n set(viewMonth, date.getMonth());\n set(viewYear, date.getFullYear());\n }\n});\n\ndefineExpose({\n move,\n});\n</script>\n\n<template>\n <div :class=\"ui\">\n <RuiCalendarHeader\n v-model:menu-open=\"isMenuOpen\"\n :title=\"monthTitle\"\n :view-month=\"viewMonth\"\n :view-year=\"viewYear\"\n @prev-month=\"moveMonth(-1)\"\n @next-month=\"moveMonth(1)\"\n @select-month=\"selectMonth($event)\"\n />\n\n <RuiCalendarGrid\n v-model=\"selectedDate\"\n :view-month=\"viewMonth\"\n :view-year=\"viewYear\"\n />\n </div>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"RuiCalendar.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_normalizeClass","_createVNode","RuiCalendarHeader","RuiCalendarGrid"],"sources":["../../../src/components/calendar/RuiCalendar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { get, isDefined, set } from '@vueuse/core';\nimport { computed, provide, ref, watch } from 'vue';\nimport {\n CalendarStateSymbol,\n type MonthYearSelection,\n type RuiCalendarState,\n} from '@/components/calendar/state';\nimport { useRotkiTheme } from '@/composables/theme';\nimport { calendarStyles } from './calendar-styles';\nimport RuiCalendarGrid from './RuiCalendarGrid.vue';\nimport RuiCalendarHeader from './RuiCalendarHeader.vue';\n\nexport interface CalendarProps {\n maxDate?: Date | number;\n minDate?: Date | number;\n allowEmpty?: boolean;\n borderless?: boolean;\n}\n\ndefineOptions({\n name: 'RuiCalendar',\n inheritAttrs: false,\n});\n\nconst model = defineModel<Date | undefined>({ required: false });\nconst isMenuOpen = defineModel<boolean>('menu-open', { required: false, default: false });\n\nconst { maxDate, minDate, allowEmpty = false, borderless = false } = defineProps<CalendarProps>();\n\nconst emit = defineEmits<{\n 'update:pages': [{ title: string }[]];\n}>();\n\nconst currentDate = ref<Date>(isDefined(model) ? new Date(get(model)) : new Date());\nconst selectedDate = ref<Date | undefined>(isDefined(model) ? new Date(get(model)) : undefined);\nconst viewMonth = ref<number>(get(currentDate).getMonth());\nconst viewYear = ref<number>(get(currentDate).getFullYear());\n\nconst { isDark } = useRotkiTheme();\n\nconst ui = computed<string>(() => calendarStyles({ bordered: !borderless }));\n\nconst monthTitle = computed<string>(() => {\n const date = new Date(get(viewYear), get(viewMonth));\n return date.toLocaleString('default', { month: 'long', year: 'numeric' });\n});\n\nprovide(CalendarStateSymbol.valueOf(), {\n viewMonth,\n viewYear,\n selectedDate,\n maxDate: computed(() => (maxDate ? new Date(maxDate) : undefined)),\n minDate: computed(() => (minDate ? new Date(minDate) : undefined)),\n isDark,\n allowEmpty,\n} satisfies RuiCalendarState);\n\n// The grid's keyboard navigation also turns the view, so the title follows the view itself\nwatch(monthTitle, (title) => {\n emit('update:pages', [{ title }]);\n});\n\nfunction moveMonth(delta: number): void {\n let newMonth = get(viewMonth) + delta;\n let newYear = get(viewYear);\n\n if (newMonth > 11) {\n newMonth = 0;\n newYear++;\n }\n else if (newMonth < 0) {\n newMonth = 11;\n newYear--;\n }\n\n set(viewMonth, newMonth);\n set(viewYear, newYear);\n}\n\nfunction move(date: Date | number): void {\n const newDate = new Date(date);\n set(viewMonth, newDate.getMonth());\n set(viewYear, newDate.getFullYear());\n}\n\nfunction selectMonth(selection: MonthYearSelection): void {\n set(viewMonth, selection.month);\n set(viewYear, selection.year);\n\n // If there's a selected date, update it with the new year/month\n if (isDefined(selectedDate)) {\n const current = get(selectedDate);\n const currentDay = current.getDate();\n // Handle day overflow (e.g., Jan 31 -> Feb 28) by checking BEFORE setting month\n const daysInNewMonth = new Date(selection.year, selection.month + 1, 0).getDate();\n const adjustedDay = Math.min(currentDay, daysInNewMonth);\n\n const newDate = new Date(current);\n newDate.setFullYear(selection.year);\n newDate.setDate(1); // Set to 1st to avoid overflow when changing month\n newDate.setMonth(selection.month);\n newDate.setDate(adjustedDay);\n set(selectedDate, newDate);\n }\n}\n\nwatch(selectedDate, (date) => {\n if (!date && !allowEmpty)\n return;\n\n if (date) {\n set(model, new Date(date));\n\n if (get(viewMonth) !== date.getMonth()) {\n set(viewMonth, date.getMonth());\n }\n\n if (get(viewYear) !== date.getFullYear()) {\n set(viewYear, date.getFullYear());\n }\n }\n else {\n set(model, undefined);\n }\n});\n\nwatch(model, (newValue) => {\n if (newValue === undefined) {\n set(selectedDate, undefined);\n return;\n }\n\n const date = new Date(newValue);\n\n if (isDefined(selectedDate) && get(selectedDate).getTime() !== date.getTime()) {\n set(selectedDate, new Date(newValue));\n set(viewMonth, date.getMonth());\n set(viewYear, date.getFullYear());\n }\n});\n\ndefineExpose({\n move,\n});\n</script>\n\n<template>\n <div :class=\"ui\">\n <RuiCalendarHeader\n v-model:menu-open=\"isMenuOpen\"\n :title=\"monthTitle\"\n :view-month=\"viewMonth\"\n :view-year=\"viewYear\"\n @prev-month=\"moveMonth(-1)\"\n @next-month=\"moveMonth(1)\"\n @select-month=\"selectMonth($event)\"\n />\n\n <RuiCalendarGrid\n v-model=\"selectedDate\"\n :view-month=\"viewMonth\"\n :view-year=\"viewYear\"\n />\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBA,MAAM,QAAQA,SAA6B,SAAA,YAAoB;EAC/D,MAAM,aAAaA,SAAoB,SAAC,WAAgD;EAIxF,MAAM,OAAO;EAIb,MAAM,cAAc,IAAU,UAAU,KAAK,IAAI,IAAI,KAAK,IAAI,KAAK,CAAC,oBAAI,IAAI,KAAK,CAAC;EAClF,MAAM,eAAe,IAAsB,UAAU,KAAK,IAAI,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAA,CAAS;EAC9F,MAAM,YAAY,IAAY,IAAI,WAAW,CAAC,CAAC,SAAS,CAAC;EACzD,MAAM,WAAW,IAAY,IAAI,WAAW,CAAC,CAAC,YAAY,CAAC;EAE3D,MAAM,EAAE,WAAW,cAAc;EAEjC,MAAM,KAAK,eAAuB,eAAe,EAAE,UAAU,CAAC,QAAA,WAAW,CAAC,CAAC;EAE3E,MAAM,aAAa,eAAuB;GAExC,OAAO,IADU,KAAK,IAAI,QAAQ,GAAG,IAAI,SAAS,CAC3C,CAAA,CAAK,eAAe,WAAW;IAAE,OAAO;IAAQ,MAAM;GAAU,CAAC;EAC1E,CAAC;EAED,QAAQ,oBAAoB,QAAQ,GAAG;GACrC;GACA;GACA;GACA,SAAS,eAAgB,QAAA,UAAU,IAAI,KAAK,QAAA,OAAO,IAAI,KAAA,CAAU;GACjE,SAAS,eAAgB,QAAA,UAAU,IAAI,KAAK,QAAA,OAAO,IAAI,KAAA,CAAU;GACjE;GACA,YAAS,QAAA;EACX,CAA4B;EAG5B,MAAM,aAAa,UAAU;GAC3B,KAAK,gBAAgB,CAAC,EAAE,MAAM,CAAC,CAAC;EAClC,CAAC;EAED,SAAS,UAAU,OAAqB;GACtC,IAAI,WAAW,IAAI,SAAS,IAAI;GAChC,IAAI,UAAU,IAAI,QAAQ;GAE1B,IAAI,WAAW,IAAI;IACjB,WAAW;IACX;GACF,OACK,IAAI,WAAW,GAAG;IACrB,WAAW;IACX;GACF;GAEA,IAAI,WAAW,QAAQ;GACvB,IAAI,UAAU,OAAO;EACvB;EAEA,SAAS,KAAK,MAA2B;GACvC,MAAM,UAAU,IAAI,KAAK,IAAI;GAC7B,IAAI,WAAW,QAAQ,SAAS,CAAC;GACjC,IAAI,UAAU,QAAQ,YAAY,CAAC;EACrC;EAEA,SAAS,YAAY,WAAqC;GACxD,IAAI,WAAW,UAAU,KAAK;GAC9B,IAAI,UAAU,UAAU,IAAI;GAG5B,IAAI,UAAU,YAAY,GAAG;IAC3B,MAAM,UAAU,IAAI,YAAY;IAChC,MAAM,aAAa,QAAQ,QAAQ;IAEnC,MAAM,iBAAiB,IAAI,KAAK,UAAU,MAAM,UAAU,QAAQ,GAAG,CAAC,CAAC,CAAC,QAAQ;IAChF,MAAM,cAAc,KAAK,IAAI,YAAY,cAAc;IAEvD,MAAM,UAAU,IAAI,KAAK,OAAO;IAChC,QAAQ,YAAY,UAAU,IAAI;IAClC,QAAQ,QAAQ,CAAC;IACjB,QAAQ,SAAS,UAAU,KAAK;IAChC,QAAQ,QAAQ,WAAW;IAC3B,IAAI,cAAc,OAAO;GAC3B;EACF;EAEA,MAAM,eAAe,SAAS;GAC5B,IAAI,CAAC,QAAQ,CAAC,QAAA,YACZ;GAEF,IAAI,MAAM;IACR,IAAI,OAAO,IAAI,KAAK,IAAI,CAAC;IAEzB,IAAI,IAAI,SAAS,MAAM,KAAK,SAAS,GACnC,IAAI,WAAW,KAAK,SAAS,CAAC;IAGhC,IAAI,IAAI,QAAQ,MAAM,KAAK,YAAY,GACrC,IAAI,UAAU,KAAK,YAAY,CAAC;GAEpC,OAEE,IAAI,OAAO,KAAA,CAAS;EAExB,CAAC;EAED,MAAM,QAAQ,aAAa;GACzB,IAAI,aAAa,KAAA,GAAW;IAC1B,IAAI,cAAc,KAAA,CAAS;IAC3B;GACF;GAEA,MAAM,OAAO,IAAI,KAAK,QAAQ;GAE9B,IAAI,UAAU,YAAY,KAAK,IAAI,YAAY,CAAC,CAAC,QAAQ,MAAM,KAAK,QAAQ,GAAG;IAC7E,IAAI,cAAc,IAAI,KAAK,QAAQ,CAAC;IACpC,IAAI,WAAW,KAAK,SAAS,CAAC;IAC9B,IAAI,UAAU,KAAK,YAAY,CAAC;GAClC;EACF,CAAC;EAED,SAAa,EACX,KACF,CAAC;;GAIC,OAAAC,UAAA,GAAAC,mBAgBM,OAAA,EAhBA,OAAKC,eAAE,GAAA,KAAE,EAAA,GAAA,CACbC,YAQEC,2BAAA;IAPQ,aAAW,WAAA;IAAA,qBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,WAAU,QAAA;IAC5B,OAAO,WAAA;IACP,cAAY,UAAA;IACZ,aAAW,SAAA;IACX,aAAU,OAAA,OAAA,OAAA,MAAA,WAAE,UAAS,EAAA;IACrB,aAAU,OAAA,OAAA,OAAA,MAAA,WAAE,UAAS,CAAA;IACrB,eAAY,OAAA,OAAA,OAAA,MAAA,WAAE,YAAY,MAAM;;;;;;GAGnCD,CAAAA,GAAAA,YAIEE,yBAAA;IAHS,YAAA,aAAA;IAAA,uBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,aAAY,QAAA;IACpB,cAAY,UAAA;IACZ,aAAW,SAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"RuiCalendarGrid.js","names":["_sfc_main"],"sources":["../../../src/components/calendar/RuiCalendarGrid.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { get, isDefined, set } from '@vueuse/core';\nimport { computed, inject, nextTick, ref, useTemplateRef, watch } from 'vue';\nimport {\n CalendarStateSymbol,\n getDaysOfWeek,\n type RuiCalendarState,\n} from '@/components/calendar/state';\nimport { tv } from '@/utils/tv';\n\ndefineOptions({\n name: 'RuiCalendarGrid',\n inheritAttrs: false,\n});\n\nconst model = defineModel<Date | undefined>();\n\nconst { viewMonth, viewYear } = defineProps<{\n viewMonth: number;\n viewYear: number;\n}>();\n\nconst calendarState = inject<RuiCalendarState>(CalendarStateSymbol) as RuiCalendarState;\n\n/**\n * The `YYYY-MM-DD` key a day is tracked and focused by.\n *\n * @param date - the day to key\n * @returns its key\n */\nfunction createDateKey(date: Date): string {\n return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;\n}\n\n// Pre-calculated constants\nconst daysOfWeek = getDaysOfWeek();\nconst today = new Date();\nconst todayKey = createDateKey(today);\n\nconst dayButton = tv({\n base: 'h-9 w-full flex items-center justify-center text-sm rounded-rui-control mx-auto max-w-9 transition-colors duration-150 ease-in-out border-none outline-hidden cursor-pointer focus-visible:focus-ring',\n variants: {\n selected: {\n true: 'bg-rui-primary-fill text-rui-primary-foreground hover:bg-rui-primary-fill hover:state-layer-pressed',\n },\n // the neighbouring months' days are a step quieter but still pickable, so they keep 4.5:1\n currentMonth: {\n true: 'text-rui-neutral-800 dark:text-rui-neutral-100',\n false: 'text-rui-neutral-500 dark:text-rui-neutral-400',\n },\n inRange: {\n false: 'opacity-50 cursor-not-allowed hover:bg-transparent',\n },\n today: {\n true: 'inset-ring inset-ring-rui-outline font-semibold',\n },\n },\n compoundVariants: [\n // restated under `dark:`, which the current-month day color uses and would otherwise win\n {\n selected: true,\n class: 'text-rui-primary-foreground dark:text-rui-primary-foreground',\n },\n // only a pickable, unselected day takes the grey hover; on the selected one it replaced the fill\n { selected: false, inRange: true, class: 'hover:bg-rui-hover' },\n ],\n});\n\n// Pre-calculated arrays for performance - using refs for better control\nconst calendarDays = ref<\n Array<{\n date: Date;\n isCurrentMonth: boolean;\n isInRange: boolean;\n isSelected: boolean;\n isToday: boolean;\n key: string;\n dayNumber: number;\n }>\n>([]);\n\nfunction createDayData(\n date: Date,\n isCurrentMonth: boolean,\n modelValue: Date | null | undefined,\n maxDateValue: Date | null,\n minDateValue: Date | null,\n): {\n date: Date;\n isCurrentMonth: boolean;\n isInRange: boolean;\n isSelected: boolean;\n isToday: boolean;\n key: string;\n dayNumber: number;\n} {\n const key = createDateKey(date);\n return {\n date,\n isCurrentMonth,\n isInRange: isDateInRangeCheck(date, maxDateValue, minDateValue),\n isSelected: modelValue ? isDateSelectedCheck(date, modelValue) : false,\n isToday: key === todayKey,\n key,\n dayNumber: date.getDate(),\n };\n}\n\n/** Rebuilds the days the grid draws for the current view month. */\nfunction calculateCalendarDays(): void {\n const firstDayOfMonth = new Date(viewYear, viewMonth, 1);\n const lastDayOfMonth = new Date(viewYear, viewMonth + 1, 0);\n const daysInMonth = lastDayOfMonth.getDate();\n const startingDayOfWeek = firstDayOfMonth.getDay();\n\n const { maxDate, minDate } = calendarState;\n const modelValue = get(model);\n const maxDateValue = isDefined(maxDate) ? get(maxDate) : null;\n const minDateValue = isDefined(minDate) ? get(minDate) : null;\n\n const result = [];\n\n // Previous month days\n if (startingDayOfWeek > 0) {\n const prevMonthLastDay = new Date(viewYear, viewMonth, 0).getDate();\n for (let i = startingDayOfWeek - 1; i >= 0; i--) {\n const date = new Date(viewYear, viewMonth - 1, prevMonthLastDay - i, 12, 0, 0, 0);\n result.push(createDayData(date, false, modelValue, maxDateValue, minDateValue));\n }\n }\n\n // Current month days\n for (let i = 1; i <= daysInMonth; i++) {\n const date = new Date(viewYear, viewMonth, i, 12, 0, 0, 0);\n result.push(createDayData(date, true, modelValue, maxDateValue, minDateValue));\n }\n\n // Next month days\n const totalDaysSoFar = result.length;\n const daysToAdd = 42 - totalDaysSoFar;\n for (let i = 1; i <= daysToAdd; i++) {\n const date = new Date(viewYear, viewMonth + 1, i, 12, 0, 0, 0);\n result.push(createDayData(date, false, modelValue, maxDateValue, minDateValue));\n }\n\n set(calendarDays, result);\n}\n\nfunction isDateInRangeCheck(\n date: Date,\n maxDateValue: Date | null,\n minDateValue: Date | null,\n): boolean {\n if (maxDateValue && date > maxDateValue)\n return false;\n if (minDateValue && date < minDateValue)\n return false;\n return true;\n}\n\nfunction isDateSelectedCheck(date: Date, modelValue: Date): boolean {\n return (\n date.getFullYear() === modelValue.getFullYear() &&\n date.getMonth() === modelValue.getMonth() &&\n date.getDate() === modelValue.getDate()\n );\n}\n\nfunction selectDate(dayData: { date: Date; isInRange: boolean; isSelected: boolean }): void {\n if (!dayData.isInRange)\n return;\n\n let updateModel: Date | undefined;\n\n if (dayData.isSelected && calendarState.allowEmpty) {\n updateModel = undefined;\n }\n else if (isDefined(model)) {\n const modelValue = get(model);\n const newDate = new Date(dayData.date);\n newDate.setHours(modelValue.getHours());\n newDate.setMinutes(modelValue.getMinutes());\n newDate.setSeconds(modelValue.getSeconds());\n updateModel = newDate;\n }\n else {\n updateModel = new Date(dayData.date);\n }\n set(model, updateModel);\n}\n\n// Keyboard navigation: a roving tabindex, so crossing the calendar costs one Tab instead of 42\nconst gridRef = useTemplateRef<HTMLDivElement>('grid');\nconst activeKey = ref<string>('');\n\nconst dayLabelFormatter = new Intl.DateTimeFormat('en-US', { dateStyle: 'full' });\n\nconst KEY_DAY_OFFSETS: Record<string, number> = {\n ArrowDown: 7,\n ArrowLeft: -1,\n ArrowRight: 1,\n ArrowUp: -7,\n};\n\nconst weeks = computed<Array<typeof calendarDays.value>>(() => {\n const days = get(calendarDays);\n const result = [];\n for (let i = 0; i < days.length; i += 7)\n result.push(days.slice(i, i + 7));\n return result;\n});\n\nfunction preferredActiveKey(): string {\n const days = get(calendarDays);\n const selected = days.find(day => day.isSelected && day.isInRange);\n const todayInView = days.find(day => day.isToday && day.isCurrentMonth && day.isInRange);\n const firstSelectable = days.find(day => day.isCurrentMonth && day.isInRange);\n return (selected ?? todayInView ?? firstSelectable ?? days[0])?.key ?? '';\n}\n\nfunction syncActiveKey(): void {\n const days = get(calendarDays);\n if (!days.some(day => day.key === get(activeKey)))\n set(activeKey, preferredActiveKey());\n}\n\nfunction keyToDate(key: string): Date {\n const [year, month, day] = key.split('-').map(Number);\n return new Date(year ?? 0, (month ?? 1) - 1, day ?? 1, 12, 0, 0, 0);\n}\n\nfunction focusKey(key: string): void {\n set(activeKey, key);\n nextTick(() => {\n get(gridRef)?.querySelector<HTMLButtonElement>(`[data-id=\"${key}\"]`)?.focus();\n });\n}\n\nfunction moveTo(target: Date): void {\n const { maxDate, minDate } = calendarState;\n const maxDateValue = isDefined(maxDate) ? get(maxDate) : null;\n const minDateValue = isDefined(minDate) ? get(minDate) : null;\n\n // min/max bound a contiguous range, so a blocked step means the edge is here\n if (!isDateInRangeCheck(target, maxDateValue, minDateValue))\n return;\n\n const key = createDateKey(target);\n\n // Even a day drawn as a spill day turns the page, so header and focus agree on the month\n if (target.getMonth() === viewMonth && target.getFullYear() === viewYear) {\n focusKey(key);\n return;\n }\n\n set(calendarState.viewMonth, target.getMonth());\n set(calendarState.viewYear, target.getFullYear());\n nextTick(() => {\n focusKey(key);\n });\n}\n\nfunction onKeydown(event: KeyboardEvent): void {\n const active = get(activeKey);\n if (!active)\n return;\n\n const current = keyToDate(active);\n const dayOffset = KEY_DAY_OFFSETS[event.key];\n\n if (dayOffset !== undefined) {\n event.preventDefault();\n moveTo(new Date(current.getFullYear(), current.getMonth(), current.getDate() + dayOffset, 12, 0, 0, 0));\n }\n else if (event.key === 'Home' || event.key === 'End') {\n event.preventDefault();\n const offset = event.key === 'Home' ? -current.getDay() : 6 - current.getDay();\n moveTo(new Date(current.getFullYear(), current.getMonth(), current.getDate() + offset, 12, 0, 0, 0));\n }\n else if (event.key === 'PageUp' || event.key === 'PageDown') {\n event.preventDefault();\n const delta = event.key === 'PageUp' ? -1 : 1;\n moveTo(new Date(current.getFullYear(), current.getMonth() + delta, current.getDate(), 12, 0, 0, 0));\n }\n}\n\n// Initial calculation\ncalculateCalendarDays();\nsyncActiveKey();\n\n// Watchers for recalculation only when needed\nwatch([() => viewMonth, () => viewYear], () => {\n calculateCalendarDays();\n syncActiveKey();\n});\n\nwatch(model, () => {\n calculateCalendarDays();\n syncActiveKey();\n});\n\nwatch(\n [() => calendarState.maxDate, () => calendarState.minDate],\n () => {\n calculateCalendarDays();\n syncActiveKey();\n },\n);\n</script>\n\n<template>\n <div class=\"w-full p-2 pt-0\">\n <div\n ref=\"grid\"\n role=\"grid\"\n class=\"grid grid-cols-7 gap-0.5\"\n @keydown=\"onKeydown($event)\"\n >\n <div\n role=\"row\"\n class=\"contents\"\n >\n <span\n v-for=\"day in daysOfWeek\"\n :key=\"day\"\n role=\"columnheader\"\n class=\"py-2 pb-4 text-xs font-medium text-center text-rui-neutral-500 dark:text-rui-neutral-400\"\n >\n {{ day }}\n </span>\n </div>\n\n <div\n v-for=\"(week, index) in weeks\"\n :key=\"index\"\n role=\"row\"\n class=\"contents\"\n >\n <button\n v-for=\"dayData in week\"\n :key=\"dayData.key\"\n type=\"button\"\n role=\"gridcell\"\n :data-id=\"dayData.key\"\n :data-current-month=\"dayData.isCurrentMonth || undefined\"\n :data-selected=\"dayData.isSelected || undefined\"\n :data-today=\"(dayData.isToday && !dayData.isSelected) || undefined\"\n :class=\"dayButton({\n selected: dayData.isSelected,\n currentMonth: !dayData.isSelected && dayData.isCurrentMonth,\n inRange: dayData.isInRange,\n today: dayData.isToday && !dayData.isSelected,\n })\"\n :disabled=\"!dayData.isInRange\"\n :tabindex=\"dayData.key === activeKey ? 0 : -1\"\n :aria-label=\"dayLabelFormatter.format(dayData.date)\"\n :aria-selected=\"dayData.isSelected\"\n :aria-current=\"dayData.isToday ? 'date' : undefined\"\n @click.stop=\"selectDate(dayData)\"\n @focus=\"activeKey = dayData.key\"\n >\n {{ dayData.dayNumber }}\n </button>\n </div>\n </div>\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"RuiCalendarGrid.js","names":["_sfc_main"],"sources":["../../../src/components/calendar/RuiCalendarGrid.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { get, isDefined, set } from '@vueuse/core';\nimport { computed, inject, nextTick, ref, useTemplateRef, watch } from 'vue';\nimport {\n CalendarStateSymbol,\n getDaysOfWeek,\n type RuiCalendarState,\n} from '@/components/calendar/state';\nimport { dayButtonStyles } from './calendar-grid-styles';\n\ndefineOptions({\n name: 'RuiCalendarGrid',\n inheritAttrs: false,\n});\n\nconst model = defineModel<Date | undefined>();\n\nconst { viewMonth, viewYear } = defineProps<{\n viewMonth: number;\n viewYear: number;\n}>();\n\nconst calendarState = inject<RuiCalendarState>(CalendarStateSymbol) as RuiCalendarState;\n\n/**\n * The `YYYY-MM-DD` key a day is tracked and focused by.\n *\n * @param date - the day to key\n * @returns its key\n */\nfunction createDateKey(date: Date): string {\n return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;\n}\n\n// Pre-calculated constants\nconst daysOfWeek = getDaysOfWeek();\nconst today = new Date();\nconst todayKey = createDateKey(today);\n\n// Pre-calculated arrays for performance - using refs for better control\nconst calendarDays = ref<\n Array<{\n date: Date;\n isCurrentMonth: boolean;\n isInRange: boolean;\n isSelected: boolean;\n isToday: boolean;\n key: string;\n dayNumber: number;\n }>\n>([]);\n\nfunction createDayData(\n date: Date,\n isCurrentMonth: boolean,\n modelValue: Date | null | undefined,\n maxDateValue: Date | null,\n minDateValue: Date | null,\n): {\n date: Date;\n isCurrentMonth: boolean;\n isInRange: boolean;\n isSelected: boolean;\n isToday: boolean;\n key: string;\n dayNumber: number;\n} {\n const key = createDateKey(date);\n return {\n date,\n isCurrentMonth,\n isInRange: isDateInRangeCheck(date, maxDateValue, minDateValue),\n isSelected: modelValue ? isDateSelectedCheck(date, modelValue) : false,\n isToday: key === todayKey,\n key,\n dayNumber: date.getDate(),\n };\n}\n\n/** Rebuilds the days the grid draws for the current view month. */\nfunction calculateCalendarDays(): void {\n const firstDayOfMonth = new Date(viewYear, viewMonth, 1);\n const lastDayOfMonth = new Date(viewYear, viewMonth + 1, 0);\n const daysInMonth = lastDayOfMonth.getDate();\n const startingDayOfWeek = firstDayOfMonth.getDay();\n\n const { maxDate, minDate } = calendarState;\n const modelValue = get(model);\n const maxDateValue = isDefined(maxDate) ? get(maxDate) : null;\n const minDateValue = isDefined(minDate) ? get(minDate) : null;\n\n const result = [];\n\n // Previous month days\n if (startingDayOfWeek > 0) {\n const prevMonthLastDay = new Date(viewYear, viewMonth, 0).getDate();\n for (let i = startingDayOfWeek - 1; i >= 0; i--) {\n const date = new Date(viewYear, viewMonth - 1, prevMonthLastDay - i, 12, 0, 0, 0);\n result.push(createDayData(date, false, modelValue, maxDateValue, minDateValue));\n }\n }\n\n // Current month days\n for (let i = 1; i <= daysInMonth; i++) {\n const date = new Date(viewYear, viewMonth, i, 12, 0, 0, 0);\n result.push(createDayData(date, true, modelValue, maxDateValue, minDateValue));\n }\n\n // Next month days\n const totalDaysSoFar = result.length;\n const daysToAdd = 42 - totalDaysSoFar;\n for (let i = 1; i <= daysToAdd; i++) {\n const date = new Date(viewYear, viewMonth + 1, i, 12, 0, 0, 0);\n result.push(createDayData(date, false, modelValue, maxDateValue, minDateValue));\n }\n\n set(calendarDays, result);\n}\n\nfunction isDateInRangeCheck(\n date: Date,\n maxDateValue: Date | null,\n minDateValue: Date | null,\n): boolean {\n if (maxDateValue && date > maxDateValue)\n return false;\n if (minDateValue && date < minDateValue)\n return false;\n return true;\n}\n\nfunction isDateSelectedCheck(date: Date, modelValue: Date): boolean {\n return (\n date.getFullYear() === modelValue.getFullYear() &&\n date.getMonth() === modelValue.getMonth() &&\n date.getDate() === modelValue.getDate()\n );\n}\n\nfunction selectDate(dayData: { date: Date; isInRange: boolean; isSelected: boolean }): void {\n if (!dayData.isInRange)\n return;\n\n let updateModel: Date | undefined;\n\n if (dayData.isSelected && calendarState.allowEmpty) {\n updateModel = undefined;\n }\n else if (isDefined(model)) {\n const modelValue = get(model);\n const newDate = new Date(dayData.date);\n newDate.setHours(modelValue.getHours());\n newDate.setMinutes(modelValue.getMinutes());\n newDate.setSeconds(modelValue.getSeconds());\n updateModel = newDate;\n }\n else {\n updateModel = new Date(dayData.date);\n }\n set(model, updateModel);\n}\n\n// Keyboard navigation: a roving tabindex, so crossing the calendar costs one Tab instead of 42\nconst gridRef = useTemplateRef<HTMLDivElement>('grid');\nconst activeKey = ref<string>('');\n\nconst dayLabelFormatter = new Intl.DateTimeFormat('en-US', { dateStyle: 'full' });\n\nconst KEY_DAY_OFFSETS: Record<string, number> = {\n ArrowDown: 7,\n ArrowLeft: -1,\n ArrowRight: 1,\n ArrowUp: -7,\n};\n\nconst weeks = computed<Array<typeof calendarDays.value>>(() => {\n const days = get(calendarDays);\n const result = [];\n for (let i = 0; i < days.length; i += 7)\n result.push(days.slice(i, i + 7));\n return result;\n});\n\nfunction preferredActiveKey(): string {\n const days = get(calendarDays);\n const selected = days.find(day => day.isSelected && day.isInRange);\n const todayInView = days.find(day => day.isToday && day.isCurrentMonth && day.isInRange);\n const firstSelectable = days.find(day => day.isCurrentMonth && day.isInRange);\n return (selected ?? todayInView ?? firstSelectable ?? days[0])?.key ?? '';\n}\n\nfunction syncActiveKey(): void {\n const days = get(calendarDays);\n if (!days.some(day => day.key === get(activeKey)))\n set(activeKey, preferredActiveKey());\n}\n\nfunction keyToDate(key: string): Date {\n const [year, month, day] = key.split('-').map(Number);\n return new Date(year ?? 0, (month ?? 1) - 1, day ?? 1, 12, 0, 0, 0);\n}\n\nfunction focusKey(key: string): void {\n set(activeKey, key);\n nextTick(() => {\n get(gridRef)?.querySelector<HTMLButtonElement>(`[data-id=\"${key}\"]`)?.focus();\n });\n}\n\nfunction moveTo(target: Date): void {\n const { maxDate, minDate } = calendarState;\n const maxDateValue = isDefined(maxDate) ? get(maxDate) : null;\n const minDateValue = isDefined(minDate) ? get(minDate) : null;\n\n // min/max bound a contiguous range, so a blocked step means the edge is here\n if (!isDateInRangeCheck(target, maxDateValue, minDateValue))\n return;\n\n const key = createDateKey(target);\n\n // Even a day drawn as a spill day turns the page, so header and focus agree on the month\n if (target.getMonth() === viewMonth && target.getFullYear() === viewYear) {\n focusKey(key);\n return;\n }\n\n set(calendarState.viewMonth, target.getMonth());\n set(calendarState.viewYear, target.getFullYear());\n nextTick(() => {\n focusKey(key);\n });\n}\n\nfunction onKeydown(event: KeyboardEvent): void {\n const active = get(activeKey);\n if (!active)\n return;\n\n const current = keyToDate(active);\n const dayOffset = KEY_DAY_OFFSETS[event.key];\n\n if (dayOffset !== undefined) {\n event.preventDefault();\n moveTo(new Date(current.getFullYear(), current.getMonth(), current.getDate() + dayOffset, 12, 0, 0, 0));\n }\n else if (event.key === 'Home' || event.key === 'End') {\n event.preventDefault();\n const offset = event.key === 'Home' ? -current.getDay() : 6 - current.getDay();\n moveTo(new Date(current.getFullYear(), current.getMonth(), current.getDate() + offset, 12, 0, 0, 0));\n }\n else if (event.key === 'PageUp' || event.key === 'PageDown') {\n event.preventDefault();\n const delta = event.key === 'PageUp' ? -1 : 1;\n moveTo(new Date(current.getFullYear(), current.getMonth() + delta, current.getDate(), 12, 0, 0, 0));\n }\n}\n\n// Initial calculation\ncalculateCalendarDays();\nsyncActiveKey();\n\n// Watchers for recalculation only when needed\nwatch([() => viewMonth, () => viewYear], () => {\n calculateCalendarDays();\n syncActiveKey();\n});\n\nwatch(model, () => {\n calculateCalendarDays();\n syncActiveKey();\n});\n\nwatch(\n [() => calendarState.maxDate, () => calendarState.minDate],\n () => {\n calculateCalendarDays();\n syncActiveKey();\n },\n);\n</script>\n\n<template>\n <div class=\"w-full p-2 pt-0\">\n <div\n ref=\"grid\"\n role=\"grid\"\n class=\"grid grid-cols-7 gap-0.5\"\n @keydown=\"onKeydown($event)\"\n >\n <div\n role=\"row\"\n class=\"contents\"\n >\n <span\n v-for=\"day in daysOfWeek\"\n :key=\"day\"\n role=\"columnheader\"\n class=\"py-2 pb-4 text-xs font-medium text-center text-rui-neutral-500 dark:text-rui-neutral-400\"\n >\n {{ day }}\n </span>\n </div>\n\n <div\n v-for=\"(week, index) in weeks\"\n :key=\"index\"\n role=\"row\"\n class=\"contents\"\n >\n <button\n v-for=\"dayData in week\"\n :key=\"dayData.key\"\n type=\"button\"\n role=\"gridcell\"\n :data-id=\"dayData.key\"\n :data-current-month=\"dayData.isCurrentMonth || undefined\"\n :data-selected=\"dayData.isSelected || undefined\"\n :data-today=\"(dayData.isToday && !dayData.isSelected) || undefined\"\n :class=\"dayButtonStyles({\n selected: dayData.isSelected,\n currentMonth: !dayData.isSelected && dayData.isCurrentMonth,\n inRange: dayData.isInRange,\n today: dayData.isToday && !dayData.isSelected,\n })\"\n :disabled=\"!dayData.isInRange\"\n :tabindex=\"dayData.key === activeKey ? 0 : -1\"\n :aria-label=\"dayLabelFormatter.format(dayData.date)\"\n :aria-selected=\"dayData.isSelected\"\n :aria-current=\"dayData.isToday ? 'date' : undefined\"\n @click.stop=\"selectDate(dayData)\"\n @focus=\"activeKey = dayData.key\"\n >\n {{ dayData.dayNumber }}\n </button>\n </div>\n </div>\n </div>\n</template>\n"],"mappings":""}