@autoafleveren/ui 1.3.2 → 1.3.3

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 (315) hide show
  1. package/dist/config/tailwind/config.cjs +1 -0
  2. package/dist/icons.cjs +17 -17
  3. package/dist/icons.js +1710 -1644
  4. package/dist/types/composables/index.d.ts +1 -1
  5. package/dist/types/composables/useActionBar/index.d.ts +3 -3
  6. package/dist/ui.cjs +36 -36
  7. package/dist/ui.js +6766 -6696
  8. package/package.json +3 -2
  9. package/src/App.vue +15 -0
  10. package/src/Playground.vue.example +9 -0
  11. package/src/config/eslint.cjs +199 -0
  12. package/src/config/tailwind/config.cjs +229 -0
  13. package/src/config/tailwind/screens.json +9 -0
  14. package/src/css/build.css +52 -0
  15. package/src/css/main.css +4 -0
  16. package/src/css/theme.css +208 -0
  17. package/src/css/tinymce.css +58 -0
  18. package/src/main.ts +34 -0
  19. package/src/modules/components/AppActionBar/AppActionBar.vue +96 -0
  20. package/src/modules/components/AppActionBar/AppActionBarItem.vue +123 -0
  21. package/src/modules/components/AppActionBar/AppActionBarSubMenu.vue +89 -0
  22. package/src/modules/components/AppActionBar/Components/Error.vue +11 -0
  23. package/src/modules/components/AppActionBar/Components/Loading.vue +9 -0
  24. package/src/modules/components/AppActionBar/Components/MultiSelect.vue +102 -0
  25. package/src/modules/components/AppActionBar/Components/__tests__/multi-select.spec.ts +74 -0
  26. package/src/modules/components/AppActionBar/__mocks__/index.ts +36 -0
  27. package/src/modules/components/AppActionBar/__tests__/app-action-bar-item.spec.ts +134 -0
  28. package/src/modules/components/AppActionBar/__tests__/app-action-bar-sub-menu.spec.ts +45 -0
  29. package/src/modules/components/AppActionBar/__tests__/app-action-bar.spec.ts +92 -0
  30. package/src/modules/components/AppActionBar/index.d.ts +29 -0
  31. package/src/modules/components/AppActionBar/index.ts +18 -0
  32. package/src/modules/components/AppAlert/AppAlert.vue +69 -0
  33. package/src/modules/components/AppAlert/__tests__/app-alert.spec.ts +67 -0
  34. package/src/modules/components/AppAlert/index.d.ts +3 -0
  35. package/src/modules/components/AppAlert/index.ts +18 -0
  36. package/src/modules/components/AppAvatar/AppAvatar.vue +30 -0
  37. package/src/modules/components/AppAvatar/DefaultAvatar.vue +187 -0
  38. package/src/modules/components/AppAvatar/__tests__/app-avatar.spec.ts +70 -0
  39. package/src/modules/components/AppAvatar/index.d.ts +9 -0
  40. package/src/modules/components/AppAvatar/index.ts +9 -0
  41. package/src/modules/components/AppBackButton/AppBackButton.vue +51 -0
  42. package/src/modules/components/AppBackButton/__tests__/app-back-button.spec.ts +70 -0
  43. package/src/modules/components/AppBadge/AppBadge.vue +65 -0
  44. package/src/modules/components/AppBadge/__tests__/app-badge.spec.ts +64 -0
  45. package/src/modules/components/AppBadge/index.d.ts +13 -0
  46. package/src/modules/components/AppBadge/index.ts +29 -0
  47. package/src/modules/components/AppButton/AppButton.vue +53 -0
  48. package/src/modules/components/AppButton/ButtonIconSlot.vue +26 -0
  49. package/src/modules/components/AppButton/__tests__/app-button.spec.ts +145 -0
  50. package/src/modules/components/AppButton/__tests__/button-icon-slot.spec.ts +30 -0
  51. package/src/modules/components/AppButton/index.d.ts +16 -0
  52. package/src/modules/components/AppButton/index.ts +57 -0
  53. package/src/modules/components/AppCard/AppCard.vue +88 -0
  54. package/src/modules/components/AppCard/CardAction.vue +101 -0
  55. package/src/modules/components/AppCard/CardIconSlot.vue +65 -0
  56. package/src/modules/components/AppCard/__tests__/app-card.spec.ts +109 -0
  57. package/src/modules/components/AppCard/__tests__/card-action.spec.ts +55 -0
  58. package/src/modules/components/AppCard/__tests__/card-icon-slot.spec.ts +27 -0
  59. package/src/modules/components/AppCard/index.d.ts +12 -0
  60. package/src/modules/components/AppCard/index.ts +5 -0
  61. package/src/modules/components/AppColor/AppColor.vue +74 -0
  62. package/src/modules/components/AppColor/__tests__/app-color.spec.ts +53 -0
  63. package/src/modules/components/AppColor/index.d.ts +10 -0
  64. package/src/modules/components/AppColorCard/AppColorCard.vue +41 -0
  65. package/src/modules/components/AppColorCard/__tests__/app-color-card.spec.ts +55 -0
  66. package/src/modules/components/AppConfirm/AppConfirm.vue +237 -0
  67. package/src/modules/components/AppConfirm/__tests__/app-confirm.spec.ts +366 -0
  68. package/src/modules/components/AppConfirm/index.d.ts +31 -0
  69. package/src/modules/components/AppConfirm/index.ts +1 -0
  70. package/src/modules/components/AppContextMenu/AppContextMenu.vue +100 -0
  71. package/src/modules/components/AppContextMenu/ShortcutItem.vue +37 -0
  72. package/src/modules/components/AppContextMenu/__mocks__/index.ts +25 -0
  73. package/src/modules/components/AppContextMenu/__tests__/app-context-menu.spec.ts +71 -0
  74. package/src/modules/components/AppContextMenu/__tests__/shortcut-item.spec.ts +29 -0
  75. package/src/modules/components/AppContextMenu/index.d.ts +23 -0
  76. package/src/modules/components/AppDataTable/AppDataTable.vue +323 -0
  77. package/src/modules/components/AppDataTable/AppDataTableFooter.vue +91 -0
  78. package/src/modules/components/AppDataTable/__mocks__/index.ts +71 -0
  79. package/src/modules/components/AppDataTable/__tests__/app-data-table-footer.spec.ts +107 -0
  80. package/src/modules/components/AppDataTable/__tests__/app-data-table.spec.ts +153 -0
  81. package/src/modules/components/AppDataTable/index.d.ts +29 -0
  82. package/src/modules/components/AppDefinitionList/AppDefinitionItem.vue +57 -0
  83. package/src/modules/components/AppDefinitionList/AppDefinitionList.vue +31 -0
  84. package/src/modules/components/AppDefinitionList/__mocks__/index.ts +31 -0
  85. package/src/modules/components/AppDefinitionList/__tests__/app-definition-item.spec.ts +93 -0
  86. package/src/modules/components/AppDefinitionList/__tests__/app-definition-list.spec.ts +35 -0
  87. package/src/modules/components/AppDefinitionList/index.d.ts +8 -0
  88. package/src/modules/components/AppDisclosure/AppDisclosure.vue +19 -0
  89. package/src/modules/components/AppDisclosure/AppDisclosureButton.vue +43 -0
  90. package/src/modules/components/AppDisclosure/AppDisclosurePanel.vue +31 -0
  91. package/src/modules/components/AppDisclosure/__tests__/app-disclosure-button.spec.ts +70 -0
  92. package/src/modules/components/AppDisclosure/__tests__/app-disclosure-panel.spec.ts +64 -0
  93. package/src/modules/components/AppDisclosure/__tests__/app-disclosure.spec.ts +41 -0
  94. package/src/modules/components/AppDrawer/AppDrawer.vue +149 -0
  95. package/src/modules/components/AppDrawer/__tests__/app-drawer.spec.ts +120 -0
  96. package/src/modules/components/AppDrawer/index.d.ts +27 -0
  97. package/src/modules/components/AppDropdownButton/AppDropdownButton.vue +82 -0
  98. package/src/modules/components/AppDropdownButton/AppDropdownItem.vue +67 -0
  99. package/src/modules/components/AppDropdownButton/__mocks__/index.ts +25 -0
  100. package/src/modules/components/AppDropdownButton/__tests__/app-dropdown-button.spec.ts +81 -0
  101. package/src/modules/components/AppDropdownButton/__tests__/app-dropdown-item.spec.ts +108 -0
  102. package/src/modules/components/AppDropdownButton/index.d.ts +26 -0
  103. package/src/modules/components/AppDropdownButton/index.ts +8 -0
  104. package/src/modules/components/AppError/AppError.vue +233 -0
  105. package/src/modules/components/AppError/__tests__/app-error.spec.ts +366 -0
  106. package/src/modules/components/AppError/index.d.ts +30 -0
  107. package/src/modules/components/AppError/index.ts +1 -0
  108. package/src/modules/components/AppImageDropzone/AppImageDropzone.vue +130 -0
  109. package/src/modules/components/AppImageDropzone/__tests__/app-image-dropzone.spec.ts +92 -0
  110. package/src/modules/components/AppImageDropzone/index.d.ts +8 -0
  111. package/src/modules/components/AppInput/AppInput.vue +247 -0
  112. package/src/modules/components/AppInput/FileInput.vue +58 -0
  113. package/src/modules/components/AppInput/Input.vue +141 -0
  114. package/src/modules/components/AppInput/InputIconSlot.vue +27 -0
  115. package/src/modules/components/AppInput/LocationInput.vue +150 -0
  116. package/src/modules/components/AppInput/__mocks__/location.ts +13 -0
  117. package/src/modules/components/AppInput/__tests__/app-input.spec.ts +255 -0
  118. package/src/modules/components/AppInput/__tests__/file-input.spec.ts +48 -0
  119. package/src/modules/components/AppInput/__tests__/input-icon-slot.spec.ts +27 -0
  120. package/src/modules/components/AppInput/__tests__/input.spec.ts +260 -0
  121. package/src/modules/components/AppInput/__tests__/location-input.spec.ts +159 -0
  122. package/src/modules/components/AppInput/choice.ts +24 -0
  123. package/src/modules/components/AppInput/datepicker.ts +62 -0
  124. package/src/modules/components/AppInput/index.d.ts +68 -0
  125. package/src/modules/components/AppInput/index.ts +133 -0
  126. package/src/modules/components/AppInput/location.ts +8 -0
  127. package/src/modules/components/AppInput/richText.ts +45 -0
  128. package/src/modules/components/AppInputLabel/AppInputLabel.vue +15 -0
  129. package/src/modules/components/AppInputLabel/__tests__/app-input-label.spec.ts +38 -0
  130. package/src/modules/components/AppInputLabel/index.d.ts +6 -0
  131. package/src/modules/components/AppLicensePlate/AppLicensePlate.vue +34 -0
  132. package/src/modules/components/AppLicensePlate/__tests__/app-license-plate.spec.ts +46 -0
  133. package/src/modules/components/AppLicensePlate/index.d.ts +1 -0
  134. package/src/modules/components/AppLoader/AppLoader.vue +37 -0
  135. package/src/modules/components/AppLoader/index.d.ts +1 -0
  136. package/src/modules/components/AppLoader/index.ts +8 -0
  137. package/src/modules/components/AppMaps/AppMaps.vue +105 -0
  138. package/src/modules/components/AppMaps/index.ts +44 -0
  139. package/src/modules/components/AppMenu/AppMenu.vue +79 -0
  140. package/src/modules/components/AppMenu/AppMenuItem.vue +40 -0
  141. package/src/modules/components/AppMenu/__mocks__/index.ts +23 -0
  142. package/src/modules/components/AppMenu/__tests__/app-menu-item.spec.ts +47 -0
  143. package/src/modules/components/AppMenu/__tests__/app-menu.spec.ts +53 -0
  144. package/src/modules/components/AppMenu/index.d.ts +15 -0
  145. package/src/modules/components/AppModal/AppModal.vue +261 -0
  146. package/src/modules/components/AppModal/__tests__/app-modal.spec.ts +282 -0
  147. package/src/modules/components/AppModal/index.d.ts +36 -0
  148. package/src/modules/components/AppNavigationMenu/AppNavigationMenu.vue +95 -0
  149. package/src/modules/components/AppNavigationMenu/Mobile.vue +126 -0
  150. package/src/modules/components/AppNavigationMenu/NavigationItem.vue +82 -0
  151. package/src/modules/components/AppNavigationMenu/SupportItem.vue +29 -0
  152. package/src/modules/components/AppNavigationMenu/__tests__/app-navigation-menu.spec.ts +104 -0
  153. package/src/modules/components/AppNavigationMenu/__tests__/mobile.spec.ts +155 -0
  154. package/src/modules/components/AppNavigationMenu/__tests__/navigation-item.spec.ts +91 -0
  155. package/src/modules/components/AppNavigationMenu/__tests__/support-item.spec.ts +48 -0
  156. package/src/modules/components/AppPagination/AppPagination.vue +133 -0
  157. package/src/modules/components/AppPagination/AppPaginationItem.vue +28 -0
  158. package/src/modules/components/AppPagination/__mocks__/index.ts +20 -0
  159. package/src/modules/components/AppPagination/__tests__/app-pagination.spec.ts +143 -0
  160. package/src/modules/components/AppPagination/index.d.ts +24 -0
  161. package/src/modules/components/AppProgressBar/AppProgressBar.vue +93 -0
  162. package/src/modules/components/AppProgressBar/AppProgressBarStep.vue +5 -0
  163. package/src/modules/components/AppProgressBar/__mocks__/index.ts +17 -0
  164. package/src/modules/components/AppProgressBar/__tests__/app-progress-bar-step.spec.ts +18 -0
  165. package/src/modules/components/AppProgressBar/__tests__/app-progress-bar.spec.ts +77 -0
  166. package/src/modules/components/AppProgressBar/index.d.ts +21 -0
  167. package/src/modules/components/AppRating/AppRating.vue +42 -0
  168. package/src/modules/components/AppRating/VueStarRating/Star.vue +215 -0
  169. package/src/modules/components/AppRating/VueStarRating/StarRating.vue +231 -0
  170. package/src/modules/components/AppRating/VueStarRating/classes/AlphaColor.ts +68 -0
  171. package/src/modules/components/AppRating/VueStarRating/readme.md +279 -0
  172. package/src/modules/components/AppRating/__tests__/app-rating.spec.ts +36 -0
  173. package/src/modules/components/AppSection/AppSection.vue +35 -0
  174. package/src/modules/components/AppSection/__tests__/app-section.spec.ts +53 -0
  175. package/src/modules/components/AppSelect/AppSelect.vue +176 -0
  176. package/src/modules/components/AppSelect/__mocks__/index.ts +24 -0
  177. package/src/modules/components/AppSelect/__tests__/app-select.spec.ts +73 -0
  178. package/src/modules/components/AppSelect/index.d.ts +43 -0
  179. package/src/modules/components/AppSelect/index.ts +69 -0
  180. package/src/modules/components/AppStepper/AppStepper.vue +79 -0
  181. package/src/modules/components/AppStepper/__tests__/app-stepper.spec.ts +59 -0
  182. package/src/modules/components/AppTable/AppTable.vue +40 -0
  183. package/src/modules/components/AppTimeline/AppTimeline.vue +22 -0
  184. package/src/modules/components/AppTimeline/AppTimelineItem.vue +97 -0
  185. package/src/modules/components/AppTimeline/AppTimelineItemIcon.vue +55 -0
  186. package/src/modules/components/AppTimeline/__mocks__/timeline.ts +29 -0
  187. package/src/modules/components/AppTimeline/__tests__/app-timeline-item-Icon.spec.ts +35 -0
  188. package/src/modules/components/AppTimeline/__tests__/app-timeline-item.spec.ts +121 -0
  189. package/src/modules/components/AppTimeline/__tests__/app-timeline.spec.ts +55 -0
  190. package/src/modules/components/AppTimeline/index.d.ts +30 -0
  191. package/src/modules/components/AppTimeline/index.ts +13 -0
  192. package/src/modules/components/AppToggle/AppToggle.vue +36 -0
  193. package/src/modules/components/AppToggle/__tests__/app-toggle.spec.ts +54 -0
  194. package/src/modules/components/AppToggle/index.d.ts +3 -0
  195. package/src/modules/components/AppToggleCard/AppToggleCard.vue +45 -0
  196. package/src/modules/components/AppToggleCard/__tests__/app-toggle-card.spec.ts +55 -0
  197. package/src/modules/components/index.ts +43 -0
  198. package/src/modules/composables/index.ts +13 -0
  199. package/src/modules/composables/useActionBar/__mocks__/index.ts +17 -0
  200. package/src/modules/composables/useActionBar/__tests__/index.spec.ts +62 -0
  201. package/src/modules/composables/useActionBar/index.d.ts +1 -0
  202. package/src/modules/composables/useActionBar/index.ts +67 -0
  203. package/src/modules/composables/useComputedPosition/index.d.ts +16 -0
  204. package/src/modules/composables/useComputedPosition/index.ts +199 -0
  205. package/src/modules/composables/useConfirm/__tests__/index.spec.ts +29 -0
  206. package/src/modules/composables/useConfirm/index.ts +63 -0
  207. package/src/modules/composables/useContextMenu/index.ts +127 -0
  208. package/src/modules/composables/useDrawer/__tests__/index.spec.ts +34 -0
  209. package/src/modules/composables/useDrawer/index.ts +136 -0
  210. package/src/modules/composables/useEcho/index.ts +167 -0
  211. package/src/modules/composables/useError/__tests__/index.spec.ts +29 -0
  212. package/src/modules/composables/useError/index.ts +61 -0
  213. package/src/modules/composables/useGoogleApi/__tests__/index.spec.ts +39 -0
  214. package/src/modules/composables/useGoogleApi/index.ts +26 -0
  215. package/src/modules/composables/useLayout/__tests__/index.spec.ts +34 -0
  216. package/src/modules/composables/useLayout/index.d.ts +1 -0
  217. package/src/modules/composables/useLayout/index.ts +68 -0
  218. package/src/modules/composables/useModal/__tests__/index.spec.ts +34 -0
  219. package/src/modules/composables/useModal/index.ts +97 -0
  220. package/src/modules/composables/useNavigation/__mocks__/navigation.ts +22 -0
  221. package/src/modules/composables/useNavigation/__tests__/index.spec.ts +88 -0
  222. package/src/modules/composables/useNavigation/index.d.ts +17 -0
  223. package/src/modules/composables/useNavigation/index.ts +97 -0
  224. package/src/modules/icons/BuildingCircleCheck.vue +32 -0
  225. package/src/modules/icons/BuildingCircleXmark.vue +20 -0
  226. package/src/modules/icons/CarsIcon.vue +29 -0
  227. package/src/modules/icons/ChatPersonRoundedIcon.vue +184 -0
  228. package/src/modules/icons/CompanyIcon.vue +18 -0
  229. package/src/modules/icons/HeroGirlIcon.vue +246 -0
  230. package/src/modules/icons/HeroPersonIcon.vue +402 -0
  231. package/src/modules/icons/HeroPersonRoundedIcon.vue +412 -0
  232. package/src/modules/icons/HeroPersonWithBgIcon.vue +4503 -0
  233. package/src/modules/icons/LocationMarkerIcon.vue +33 -0
  234. package/src/modules/icons/PartyPopperIcon.vue +146 -0
  235. package/src/modules/icons/index.ts +32 -0
  236. package/src/modules/icons/status/ErrorIcon.vue +24 -0
  237. package/src/modules/icons/status/SuccessIcon.vue +24 -0
  238. package/src/modules/icons/status/WarningIcon.vue +27 -0
  239. package/src/modules/icons/status/index.ts +3 -0
  240. package/src/modules/index.ts +8 -0
  241. package/src/modules/layouts/Auth/Auth.vue +36 -0
  242. package/src/modules/layouts/Auth/__tests__/auth.spec.ts +63 -0
  243. package/src/modules/layouts/Base/Base.vue +69 -0
  244. package/src/modules/layouts/Base/__tests__/base.spec.ts +56 -0
  245. package/src/modules/layouts/Platform/Platform.vue +96 -0
  246. package/src/modules/layouts/Platform/__tests__/platform.spec.ts +56 -0
  247. package/src/modules/layouts/index.ts +9 -0
  248. package/src/modules/plugins/Sentry/index.d.ts +16 -0
  249. package/src/modules/plugins/Sentry/index.ts +65 -0
  250. package/src/modules/plugins/Sentry/language/nl.ts +13 -0
  251. package/src/modules/plugins/TinyMCE/lang/nl.js +430 -0
  252. package/src/modules/plugins/Toast/Toast.vue +58 -0
  253. package/src/modules/plugins/Toast/__tests__/toast.spec.ts +90 -0
  254. package/src/modules/plugins/Toast/index.ts +36 -0
  255. package/src/modules/plugins/Toast/types.d.ts +265 -0
  256. package/src/modules/plugins/index.ts +63 -0
  257. package/src/stories/Introduction.mdx +4 -0
  258. package/src/stories/assets/code-brackets.svg +1 -0
  259. package/src/stories/assets/colors.svg +1 -0
  260. package/src/stories/assets/comments.svg +1 -0
  261. package/src/stories/assets/direction.svg +1 -0
  262. package/src/stories/assets/flow.svg +1 -0
  263. package/src/stories/assets/images/logo.png +0 -0
  264. package/src/stories/assets/images/road.png +0 -0
  265. package/src/stories/assets/plugin.svg +1 -0
  266. package/src/stories/assets/repo.svg +1 -0
  267. package/src/stories/assets/stackalt.svg +1 -0
  268. package/src/stories/components/ActionBar/ActionBar.stories.ts +67 -0
  269. package/src/stories/components/Alert/Alert.stories.ts +53 -0
  270. package/src/stories/components/Avatar/Avatar.stories.ts +44 -0
  271. package/src/stories/components/BackButton/BackButton.stories.ts +39 -0
  272. package/src/stories/components/Badge/Badge.stories.ts +42 -0
  273. package/src/stories/components/Button/Button.stories.ts +132 -0
  274. package/src/stories/components/Card/Card.stories.ts +70 -0
  275. package/src/stories/components/Color/Color.stories.ts +41 -0
  276. package/src/stories/components/ColorCard/ColorCard.stories.ts +43 -0
  277. package/src/stories/components/Confirm/Confirm.stories.ts +110 -0
  278. package/src/stories/components/ContextMenu/ContextMenu.stories.ts +85 -0
  279. package/src/stories/components/DefinitionList/DefinitionList.stories.ts +32 -0
  280. package/src/stories/components/Disclosure/Disclosure.stories.ts +61 -0
  281. package/src/stories/components/DropdownButton/DropdownButton.stories.ts +121 -0
  282. package/src/stories/components/Error/Error.stories.ts +106 -0
  283. package/src/stories/components/ImageDropzone/ImageDropzone.stories.ts +41 -0
  284. package/src/stories/components/Input/Input.stories.ts +180 -0
  285. package/src/stories/components/Input/LocationInput.stories.ts +77 -0
  286. package/src/stories/components/LicensePlate/LicensePlate.stories.ts +39 -0
  287. package/src/stories/components/Maps/Maps.stories.ts +36 -0
  288. package/src/stories/components/Menu/Menu.stories.ts +41 -0
  289. package/src/stories/components/Modal/Modal.stories.ts +68 -0
  290. package/src/stories/components/Navigation/Navigation.stories.ts +62 -0
  291. package/src/stories/components/Pagination/Pagination.stories.ts +62 -0
  292. package/src/stories/components/ProgressBar/ProgressBar.stories.ts +48 -0
  293. package/src/stories/components/Rating/Rating.stories.ts +38 -0
  294. package/src/stories/components/Section/Section.stories.ts +44 -0
  295. package/src/stories/components/Select/Select.stories.ts +90 -0
  296. package/src/stories/components/Stepper/Stepper.stories.ts +38 -0
  297. package/src/stories/components/Table/DataTable.stories.ts +96 -0
  298. package/src/stories/components/Table/Table.stories.ts +45 -0
  299. package/src/stories/components/Timeline/Timeline.stories.ts +46 -0
  300. package/src/stories/components/Toast/Toast.stories.ts +47 -0
  301. package/src/stories/components/Toggle/Toggle.stories.ts +41 -0
  302. package/src/stories/components/ToggleCard/ToggleCard.stories.ts +43 -0
  303. package/src/stories/layouts/Auth.stories.ts +43 -0
  304. package/src/stories/layouts/Base.stories.ts +70 -0
  305. package/src/tests/mocks/resize-observer.ts +13 -0
  306. package/src/tests/stubs/AppSelect.ts +89 -0
  307. package/src/tests/stubs/HeadlessUiDialogStub.ts +24 -0
  308. package/src/tests/stubs/HeadlessUiTransitionChildStub.ts +20 -0
  309. package/src/tests/stubs/HeadlessUiTransitionRootStub.ts +25 -0
  310. package/src/tests/stubs/IconStub.ts +9 -0
  311. package/src/tests/stubs/Vue3EasyDataTableStub.ts +53 -0
  312. package/src/typings/plugin.d.ts +5 -0
  313. package/src/typings/shims-vue.d.ts +13 -0
  314. package/src/typings/utilities.d.ts +4 -0
  315. package/src/typings/vite-environment.d.ts +12 -0
@@ -0,0 +1,126 @@
1
+ <script lang="ts" setup>
2
+ import { computed } from 'vue';
3
+ import { Dialog, TransitionChild, TransitionRoot } from '@headlessui/vue';
4
+ import { useNavigation } from '~composables/useNavigation';
5
+ import { Bars3Icon, XMarkIcon } from '~icons';
6
+ import NavigationItem from './NavigationItem.vue';
7
+ import SupportItem from './SupportItem.vue';
8
+
9
+ const {
10
+ logo,
11
+ avatar,
12
+ navigationItems,
13
+ mobileMenuOpen,
14
+ mobileMenuOpenTransition,
15
+ openMobileMenu,
16
+ closeMobileMenu,
17
+ } = useNavigation();
18
+
19
+ const menuIcon = computed(() => {
20
+ if (mobileMenuOpen.value) {
21
+ return XMarkIcon;
22
+ }
23
+
24
+ return Bars3Icon;
25
+ });
26
+
27
+ function close(): void {
28
+ closeMobileMenu();
29
+
30
+ setTimeout(() => {
31
+ mobileMenuOpenTransition.value = false;
32
+ }, 100);
33
+ }
34
+
35
+ function open(): void {
36
+ if (!mobileMenuOpenTransition.value) {
37
+ openMobileMenu();
38
+
39
+ mobileMenuOpenTransition.value = true;
40
+ }
41
+ }
42
+ </script>
43
+
44
+ <template>
45
+ <header class="app-mobile-menu flex h-18 items-center justify-between bg-zinc-50 px-4 text-black md:hidden">
46
+ <div
47
+ class="inline-flex w-10 grow-0 cursor-pointer items-center justify-start rounded-sm !py-2
48
+ hover:text-primary focus:outline-hidden"
49
+ data-test-menu-icon-wrapper
50
+ @click.stop="open"
51
+ >
52
+ <Component
53
+ :is="menuIcon"
54
+ class="block size-6 text-black"
55
+ aria-hidden="true"
56
+ />
57
+ </div>
58
+
59
+ <div
60
+ class="flex h-full max-w-[70%] grow justify-center py-4"
61
+ data-test-logo-wrapper
62
+ v-html="logo"
63
+ ></div>
64
+
65
+ <div
66
+ class="flex w-10 grow-0 justify-end"
67
+ data-test-avatar-wrapper
68
+ >
69
+ <Component
70
+ :is="avatar"
71
+ v-if="avatar"
72
+ />
73
+ </div>
74
+
75
+ <TransitionRoot
76
+ :show="mobileMenuOpen"
77
+ as="template"
78
+ >
79
+ <Dialog
80
+ as="div"
81
+ class="app-mobile-menu-dialog fixed inset-0 top-18 z-50 flex lg:hidden"
82
+ @close="close"
83
+ >
84
+ <TransitionChild
85
+ as="template"
86
+ enter="transition ease-in-out duration-300 transform"
87
+ enter-from="translate-y-full"
88
+ enter-to="translate-y-0"
89
+ leave="transition ease-in-out duration-300 transform"
90
+ leave-from="translate-y-0"
91
+ leave-to="translate-y-full"
92
+ >
93
+ <div
94
+ class="relative flex size-full flex-1 flex-col
95
+ bg-white focus:outline-hidden"
96
+ data-test-navigation-wrapper
97
+ >
98
+ <div
99
+ class="h-0 flex-1 overflow-y-auto p-4"
100
+ data-test-navigation-links-wrapper
101
+ >
102
+ <nav
103
+ aria-label="MainMenu"
104
+ class="mt-5"
105
+ >
106
+ <ul class="mb-auto">
107
+ <li
108
+ v-for="item in navigationItems.filter(item => item.visible !== false)"
109
+ :key="item.name"
110
+ data-test-navigation-item
111
+ >
112
+ <NavigationItem :item="item" />
113
+ </li>
114
+ </ul>
115
+ </nav>
116
+
117
+ <SupportItem />
118
+ </div>
119
+ </div>
120
+ </TransitionChild>
121
+ </Dialog>
122
+ </TransitionRoot>
123
+
124
+ <SupportItem />
125
+ </header>
126
+ </template>
@@ -0,0 +1,82 @@
1
+ <script lang="ts" setup>
2
+ import { computed, ref } from 'vue';
3
+ import { useRouter } from 'vue-router';
4
+ import { useNavigation } from '~composables';
5
+ import { AppLoader } from '~components';
6
+
7
+ import type { Component } from 'vue';
8
+ import type { NavigationItem } from '~composables/useNavigation';
9
+
10
+ const props = defineProps<{
11
+ item: NavigationItem;
12
+ linkClasses?: string;
13
+ }>();
14
+
15
+ const { navigationComponent, closeMobileMenu, expanded } = useNavigation();
16
+ const router = useRouter();
17
+ const isLoading = ref(false);
18
+
19
+ const iconIsComponent = computed((): boolean => {
20
+ return isLoading.value || typeof props.item.icon !== 'string';
21
+ });
22
+ const icon = computed((): string | Component => {
23
+ return isLoading.value ? AppLoader : props.item.icon;
24
+ });
25
+ const href = computed((): string => {
26
+ // @ts-expect-error unknown RouteLocation generic
27
+ return props.item.href ?? router.resolve(props.item.to)?.href ?? '';
28
+ });
29
+
30
+ async function onClick(event: Event): Promise<void> {
31
+ closeMobileMenu();
32
+
33
+ if (!props.item?.onClick) {
34
+ return;
35
+ }
36
+
37
+ event.preventDefault();
38
+
39
+ isLoading.value = true;
40
+
41
+ await Promise.resolve(props.item?.onClick?.());
42
+
43
+ isLoading.value = false;
44
+ }
45
+ </script>
46
+
47
+ <template>
48
+ <Component
49
+ :is="navigationComponent"
50
+ :to="item.to"
51
+ :href="href"
52
+ :class="[{
53
+ 'md:bg-primary md:text-white!': item.active ?? false,
54
+ 'rounded-full!': item.rounded ?? false,
55
+ 'mb-3': !item.bottom,
56
+ 'mt-3': item.bottom,
57
+ 'md:w-10 md:justify-center': !expanded,
58
+ 'md:px-6': expanded,
59
+ }, linkClasses]"
60
+ class="group/item flex h-10 w-full cursor-pointer rounded-lg transition-colors hover:bg-primary
61
+ md:items-center md:text-center md:text-zinc-400 md:hover:text-white"
62
+ @click="onClick"
63
+ >
64
+ <Component
65
+ :is="iconIsComponent ? icon : 'span'"
66
+ :class="{ 'h-6!': !iconIsComponent, 'md:text-white!': item.active }"
67
+ :size="isLoading ? 'extra-small' : undefined"
68
+ class="app-navigation-item size-5 stroke-2 text-black md:size-4 md:text-zinc-400 md:group-hover/item:text-white"
69
+ data-test-icon
70
+ >
71
+ {{ !iconIsComponent ? item.icon : '' }}
72
+ </Component>
73
+
74
+ <span
75
+ :class="{ 'md:w-0 md:p-0': !expanded }"
76
+ class="overflow-hidden whitespace-nowrap pl-7 text-lg font-semibold md:text-base md:font-normal"
77
+ data-test-name
78
+ >
79
+ {{ item.name }}
80
+ </span>
81
+ </Component>
82
+ </template>
@@ -0,0 +1,29 @@
1
+ <script lang="ts" setup>
2
+ import { useNavigation } from '~composables';
3
+
4
+ const { contactRoute, contactIcon, navigationComponent, closeMobileMenu } = useNavigation();
5
+ </script>
6
+
7
+ <template>
8
+ <Component
9
+ :is="navigationComponent"
10
+ v-if="contactRoute"
11
+ :to="navigationComponent !== 'a' ? contactRoute : undefined"
12
+ :href="navigationComponent ? contactRoute : undefined"
13
+ class="app-support-item fixed bottom-5 right-5 z-50 mt-2 flex size-10 justify-center rounded-full bg-primary
14
+ py-2 text-white transition-colors hover:bg-primary-active focus-visible:outline-hidden"
15
+ data-test-help-icon
16
+ @click="closeMobileMenu"
17
+ >
18
+ <template v-if="typeof contactIcon === 'string'">
19
+ {{ contactIcon }}
20
+ </template>
21
+
22
+ <template v-else>
23
+ <Component
24
+ :is="contactIcon"
25
+ class="size-full"
26
+ />
27
+ </template>
28
+ </Component>
29
+ </template>
@@ -0,0 +1,104 @@
1
+ import {
2
+ describe,
3
+ it,
4
+ expect,
5
+ beforeEach,
6
+ } from 'vitest';
7
+ import { shallowMount } from '@vue/test-utils';
8
+ import { useNavigation } from '~/modules/composables';
9
+ import AppNavigationMenu from '../AppNavigationMenu.vue';
10
+ import NavigationItem from '~components/AppNavigationMenu/NavigationItem.vue';
11
+ import { navigationItem as navigationItemMock } from '~composables/useNavigation/__mocks__/navigation';
12
+ import SupportItem from '../SupportItem.vue';
13
+ import Mobile from '../Mobile.vue';
14
+
15
+ const navigation = useNavigation();
16
+
17
+ describe('the App Navigation Menu component', () => {
18
+ beforeEach(() => {
19
+ navigation.closeMainMenu();
20
+ });
21
+
22
+ it('should hide main menu by default', () => {
23
+ const wrapper = shallowMount(AppNavigationMenu);
24
+
25
+ const mainMenu = wrapper.find('[data-test-main-menu]');
26
+ expect(mainMenu.classes('hidden')).toBe(true);
27
+ expect(mainMenu.classes('md:flex!')).toBe(false);
28
+ });
29
+
30
+ it('can show main menu', () => {
31
+ navigation.openMainMenu();
32
+
33
+ const wrapper = shallowMount(AppNavigationMenu);
34
+
35
+ const mainMenu = wrapper.find('[data-test-main-menu]');
36
+ expect(mainMenu.classes('hidden')).toBe(true);
37
+ expect(mainMenu.classes('md:flex')).toBe(true);
38
+ });
39
+
40
+ it('should render the MainMenuMobile', () => {
41
+ const wrapper = shallowMount(AppNavigationMenu);
42
+
43
+ expect(wrapper.findComponent(Mobile).exists()).toBe(true);
44
+ });
45
+
46
+ it('should render the top navigation items', () => {
47
+ navigation.setNavigationItems([
48
+ navigationItemMock,
49
+ {
50
+ ...navigationItemMock,
51
+ name: 'Contact',
52
+ },
53
+ {
54
+ ...navigationItemMock,
55
+ name: 'Not visible',
56
+ visible: false,
57
+ },
58
+ ]);
59
+
60
+ const wrapper = shallowMount(AppNavigationMenu);
61
+ const navigationItems = wrapper.findAll('[data-test-top-navigation-item]');
62
+
63
+ expect(navigationItems).toHaveLength(2);
64
+
65
+ const firstNavigationItem = navigationItems[0].findComponent(NavigationItem);
66
+ expect(firstNavigationItem.props('item')).toBe(navigation.navigationItems.value[0]);
67
+
68
+ const secondNavigationItem = navigationItems[1].findComponent(NavigationItem);
69
+ expect(secondNavigationItem.props('item')).toBe(navigation.navigationItems.value[1]);
70
+ });
71
+
72
+ it('should render the top & bottom navigation items', () => {
73
+ navigation.setNavigationItems([
74
+ navigationItemMock,
75
+ {
76
+ ...navigationItemMock,
77
+ bottom: true,
78
+ name: 'Contact',
79
+ },
80
+ {
81
+ ...navigationItemMock,
82
+ bottom: true,
83
+ visible: false,
84
+ name: 'Not visible',
85
+ },
86
+ ]);
87
+
88
+ const wrapper = shallowMount(AppNavigationMenu);
89
+ const topNavigationItems = wrapper.findAll('[data-test-top-navigation-item]');
90
+ expect(topNavigationItems).toHaveLength(1);
91
+
92
+ const bottomNavigationItems = wrapper.findAll('[data-test-bottom-navigation-item]');
93
+ expect(bottomNavigationItems).toHaveLength(1);
94
+
95
+ const firstBottomNavigationItem = bottomNavigationItems[0].findComponent(NavigationItem);
96
+ expect(firstBottomNavigationItem.props('item')).toBe(navigation.navigationItems.value[1]);
97
+ });
98
+
99
+ it('should render the SupportItem in bottom navigation', () => {
100
+ const wrapper = shallowMount(AppNavigationMenu);
101
+
102
+ expect(wrapper.findComponent(SupportItem).exists()).toBe(true);
103
+ });
104
+ });
@@ -0,0 +1,155 @@
1
+ import {
2
+ describe,
3
+ it,
4
+ expect,
5
+ beforeEach,
6
+ } from 'vitest';
7
+ import { Dialog, TransitionRoot } from '@headlessui/vue';
8
+ import { flushPromises, shallowMount } from '@vue/test-utils';
9
+ import { navigationItem as navigationItemMock } from '~composables/useNavigation/__mocks__/navigation';
10
+ import NavigationItem from '~components/AppNavigationMenu/NavigationItem.vue';
11
+ import { Bars3Icon, XMarkIcon } from '~/modules/icons';
12
+ import { useNavigation } from '~/modules/composables';
13
+ import SupportItem from '../SupportItem.vue';
14
+ import Mobile from '../Mobile.vue';
15
+
16
+ const navigation = useNavigation();
17
+
18
+ describe('the Mobile Navigation component', () => {
19
+ beforeEach(() => {
20
+ navigation.closeMobileMenu();
21
+ navigation.mobileMenuOpenTransition.value = false;
22
+ });
23
+
24
+ it('should only visible after md breakpoint', () => {
25
+ const wrapper = shallowMount(Mobile);
26
+ expect(wrapper.classes('flex')).toBe(true);
27
+ expect(wrapper.classes('md:hidden')).toBe(true);
28
+ });
29
+
30
+ it('should render the toggle menu icon', () => {
31
+ const wrapper = shallowMount(Mobile);
32
+
33
+ const iconWrapper = wrapper.find('[data-test-menu-icon-wrapper]');
34
+ expect(iconWrapper.exists()).toBe(true);
35
+
36
+ const icon = iconWrapper.findComponent(Bars3Icon);
37
+ expect(icon.exists()).toBe(true);
38
+ });
39
+
40
+ it('should render the close menu icon when menu is open', () => {
41
+ navigation.openMobileMenu();
42
+
43
+ const wrapper = shallowMount(Mobile);
44
+
45
+ const iconWrapper = wrapper.find('[data-test-menu-icon-wrapper]');
46
+ expect(iconWrapper.exists()).toBe(true);
47
+
48
+ const icon = iconWrapper.findComponent(XMarkIcon);
49
+ expect(icon.exists()).toBe(true);
50
+ });
51
+
52
+ it('should render the logo', () => {
53
+ const logoHtml = 'logo with <span>html</span>';
54
+ navigation.setLogo(logoHtml);
55
+
56
+ const wrapper = shallowMount(Mobile);
57
+
58
+ const logoWrapper = wrapper.find('[data-test-logo-wrapper]');
59
+ expect(logoWrapper.exists()).toBe(true);
60
+ expect(logoWrapper.element.innerHTML).toBe(logoHtml);
61
+ });
62
+
63
+ it('should render the support item for desktop', () => {
64
+ const wrapper = shallowMount(Mobile);
65
+
66
+ const supportItem = wrapper.findAllComponents(SupportItem);
67
+ expect(supportItem).toHaveLength(2);
68
+ });
69
+
70
+ it('should render the support item for mobile', async () => {
71
+ expect.assertions(3);
72
+
73
+ const wrapper = shallowMount(Mobile);
74
+ const iconWrapper = wrapper.find('[data-test-menu-icon-wrapper]');
75
+
76
+ await iconWrapper.trigger('click');
77
+
78
+ const transitionRoot = wrapper.findComponent(TransitionRoot);
79
+ expect(transitionRoot.exists()).toBe(true);
80
+
81
+ await flushPromises();
82
+
83
+ expect(transitionRoot.props('show')).toBe(true);
84
+
85
+ const dialog = transitionRoot.findComponent(Dialog);
86
+
87
+ const supportItem = dialog.findComponent(SupportItem);
88
+ expect(supportItem.exists()).toBe(true);
89
+ });
90
+
91
+ it('should render the navigation items', () => {
92
+ navigation.setNavigationItems([
93
+ navigationItemMock,
94
+ {
95
+ ...navigationItemMock,
96
+ name: 'Contact',
97
+ },
98
+ {
99
+ ...navigationItemMock,
100
+ name: 'Not visible',
101
+ visible: false,
102
+ },
103
+ ]);
104
+
105
+ const wrapper = shallowMount(Mobile);
106
+
107
+ const navigationItems = wrapper.findAll('[data-test-navigation-item]');
108
+ expect(navigationItems).toHaveLength(2);
109
+
110
+ const firstNavigationItem = navigationItems[0].findComponent(NavigationItem);
111
+ expect(firstNavigationItem.props('item')).toBe(navigation.navigationItems.value[0]);
112
+
113
+ const secondNavigationItem = navigationItems[1].findComponent(NavigationItem);
114
+ expect(secondNavigationItem.props('item')).toBe(navigation.navigationItems.value[1]);
115
+ });
116
+
117
+ it('should open the mobile main menu on icon element click', async () => {
118
+ expect.assertions(3);
119
+
120
+ const wrapper = shallowMount(Mobile);
121
+ const iconWrapper = wrapper.find('[data-test-menu-icon-wrapper]');
122
+
123
+ const transitionRoot = wrapper.findComponent(TransitionRoot);
124
+ expect(transitionRoot.exists()).toBe(true);
125
+ expect(transitionRoot.props('show')).toBe(false);
126
+
127
+ await iconWrapper.trigger('click');
128
+ await flushPromises();
129
+
130
+ expect(transitionRoot.props('show')).toBe(true);
131
+ });
132
+
133
+ it('should close the mobile main menu on dialog close', async () => {
134
+ expect.assertions(4);
135
+
136
+ const wrapper = shallowMount(Mobile);
137
+ const iconWrapper = wrapper.find('[data-test-menu-icon-wrapper]');
138
+
139
+ await iconWrapper.trigger('click');
140
+ await flushPromises();
141
+
142
+ const transitionRoot = wrapper.findComponent(TransitionRoot);
143
+ expect(transitionRoot.exists()).toBe(true);
144
+ expect(transitionRoot.props('show')).toBe(true);
145
+
146
+ const dialog = transitionRoot.findComponent(Dialog);
147
+ expect(dialog.exists()).toBe(true);
148
+
149
+ dialog.vm.$emit('close', true);
150
+
151
+ await flushPromises();
152
+
153
+ expect(transitionRoot.props('show')).toBe(false);
154
+ });
155
+ });
@@ -0,0 +1,91 @@
1
+ import {
2
+ describe,
3
+ it,
4
+ expect,
5
+ vi,
6
+ beforeEach,
7
+ } from 'vitest';
8
+ import { flushPromises, RouterLinkStub, shallowMount } from '@vue/test-utils';
9
+ import { useNavigation } from '~/modules/composables';
10
+ import { AppLoader } from '~/modules/components';
11
+ import NavigationItem from '../NavigationItem.vue';
12
+ import { navigationItem as navigationItemMock } from '~composables/useNavigation/__mocks__/navigation';
13
+
14
+ import type { HomeIcon } from '@heroicons/vue/24/outline';
15
+ import type { VueWrapper } from '@vue/test-utils';
16
+ import type { NavigationItem as NavigationItemType } from '~composables/useNavigation';
17
+
18
+ function createWrapper(mockData: Partial<NavigationItemType> = {}): VueWrapper<InstanceType<typeof NavigationItem>> {
19
+ return shallowMount(NavigationItem, {
20
+ props: {
21
+ item: { ...navigationItemMock, ...mockData },
22
+ },
23
+ });
24
+ }
25
+
26
+ describe('the NavigationItem component', () => {
27
+ beforeEach(() => {
28
+ vi.useFakeTimers();
29
+ });
30
+
31
+ it('should render an "a" element as root element based on useNavigation', () => {
32
+ const wrapper = createWrapper();
33
+ expect(wrapper.element).toBeInstanceOf(HTMLAnchorElement);
34
+ expect(wrapper.attributes('href')).toBe(navigationItemMock.href);
35
+ });
36
+
37
+ it('should render an "router" element as root element based on useNavigation', () => {
38
+ const navigation = useNavigation();
39
+ navigation.setNavigationComponent(RouterLinkStub);
40
+
41
+ const wrapper = createWrapper();
42
+
43
+ const routerLink = wrapper.findComponent(RouterLinkStub);
44
+ expect(routerLink.exists()).toBe(true);
45
+ expect(routerLink.attributes('href')).toBe(navigationItemMock.href);
46
+ expect(routerLink.props('to')).toStrictEqual(navigationItemMock.to);
47
+ });
48
+
49
+ it('should render an icon', () => {
50
+ const wrapper = createWrapper();
51
+
52
+ const icon = wrapper.findComponent<typeof HomeIcon>('[data-test-icon]');
53
+ expect(icon.exists()).toBe(true);
54
+ });
55
+
56
+ it('should render the name', () => {
57
+ const wrapper = createWrapper();
58
+
59
+ const name = wrapper.find('[data-test-name]');
60
+ expect(name.text()).toBe(navigationItemMock.name);
61
+ });
62
+
63
+ it('should render a loader when onClick provides a promise', async () => {
64
+ expect.assertions(4);
65
+
66
+ const clickMock = vi.fn();
67
+ const wrapper = createWrapper({
68
+ onClick: async (): Promise<void> => {
69
+ clickMock();
70
+
71
+ await new Promise(resolve => setTimeout(resolve, 500));
72
+ },
73
+ });
74
+
75
+ let icon = wrapper.findComponent(AppLoader);
76
+ expect(icon.exists()).toBe(false);
77
+
78
+ await wrapper.trigger('click');
79
+
80
+ icon = wrapper.findComponent(AppLoader);
81
+ expect(icon.exists()).toBe(true);
82
+
83
+ vi.advanceTimersByTime(500);
84
+
85
+ expect(clickMock).toHaveBeenCalledTimes(1);
86
+ await flushPromises();
87
+
88
+ icon = wrapper.findComponent(AppLoader);
89
+ expect(icon.exists()).toBe(false);
90
+ });
91
+ });
@@ -0,0 +1,48 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { RouterLinkStub, shallowMount } from '@vue/test-utils';
3
+ import { useNavigation } from '~/modules/composables';
4
+ import SupportItem from '../SupportItem.vue';
5
+
6
+ import type { VueWrapper } from '@vue/test-utils';
7
+
8
+ function createWrapper(): VueWrapper<InstanceType<typeof SupportItem>> {
9
+ return shallowMount(SupportItem);
10
+ }
11
+
12
+ const navigation = useNavigation();
13
+
14
+ describe('the SupportItem component', () => {
15
+ it('should render nothing when contactRoute is set empty', () => {
16
+ navigation.contactRoute.value = null;
17
+
18
+ const wrapper = createWrapper();
19
+ expect(wrapper.element.innerHTML).toBeUndefined();
20
+ });
21
+
22
+ it('should render an question mark', () => {
23
+ navigation.contactRoute.value = 'bla';
24
+
25
+ const wrapper = createWrapper();
26
+ expect(wrapper.text()).toBe('?');
27
+ });
28
+
29
+ it('should render an "a" element as root element based on useNavigation', () => {
30
+ navigation.contactRoute.value = 'bla';
31
+
32
+ const wrapper = createWrapper();
33
+ expect(wrapper.element).toBeInstanceOf(HTMLAnchorElement);
34
+ expect(wrapper.attributes('href')).toBe(navigation.contactRoute.value);
35
+ });
36
+
37
+ it('should render an "router" element as root element based on useNavigation', () => {
38
+ navigation.setNavigationComponent(RouterLinkStub);
39
+ navigation.contactRoute.value = 'bla';
40
+
41
+ const wrapper = createWrapper();
42
+
43
+ const routerLink = wrapper.findComponent(RouterLinkStub);
44
+ expect(routerLink.exists()).toBe(true);
45
+ expect(routerLink.attributes('href')).toBe(navigation.contactRoute.value);
46
+ expect(routerLink.props('to')).toBe(navigation.contactRoute.value);
47
+ });
48
+ });