@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.
- package/dist/config/tailwind/config.cjs +1 -0
- package/dist/icons.cjs +17 -17
- package/dist/icons.js +1710 -1644
- package/dist/types/composables/index.d.ts +1 -1
- package/dist/types/composables/useActionBar/index.d.ts +3 -3
- package/dist/ui.cjs +36 -36
- package/dist/ui.js +6766 -6696
- package/package.json +3 -2
- package/src/App.vue +15 -0
- package/src/Playground.vue.example +9 -0
- package/src/config/eslint.cjs +199 -0
- package/src/config/tailwind/config.cjs +229 -0
- package/src/config/tailwind/screens.json +9 -0
- package/src/css/build.css +52 -0
- package/src/css/main.css +4 -0
- package/src/css/theme.css +208 -0
- package/src/css/tinymce.css +58 -0
- package/src/main.ts +34 -0
- package/src/modules/components/AppActionBar/AppActionBar.vue +96 -0
- package/src/modules/components/AppActionBar/AppActionBarItem.vue +123 -0
- package/src/modules/components/AppActionBar/AppActionBarSubMenu.vue +89 -0
- package/src/modules/components/AppActionBar/Components/Error.vue +11 -0
- package/src/modules/components/AppActionBar/Components/Loading.vue +9 -0
- package/src/modules/components/AppActionBar/Components/MultiSelect.vue +102 -0
- package/src/modules/components/AppActionBar/Components/__tests__/multi-select.spec.ts +74 -0
- package/src/modules/components/AppActionBar/__mocks__/index.ts +36 -0
- package/src/modules/components/AppActionBar/__tests__/app-action-bar-item.spec.ts +134 -0
- package/src/modules/components/AppActionBar/__tests__/app-action-bar-sub-menu.spec.ts +45 -0
- package/src/modules/components/AppActionBar/__tests__/app-action-bar.spec.ts +92 -0
- package/src/modules/components/AppActionBar/index.d.ts +29 -0
- package/src/modules/components/AppActionBar/index.ts +18 -0
- package/src/modules/components/AppAlert/AppAlert.vue +69 -0
- package/src/modules/components/AppAlert/__tests__/app-alert.spec.ts +67 -0
- package/src/modules/components/AppAlert/index.d.ts +3 -0
- package/src/modules/components/AppAlert/index.ts +18 -0
- package/src/modules/components/AppAvatar/AppAvatar.vue +30 -0
- package/src/modules/components/AppAvatar/DefaultAvatar.vue +187 -0
- package/src/modules/components/AppAvatar/__tests__/app-avatar.spec.ts +70 -0
- package/src/modules/components/AppAvatar/index.d.ts +9 -0
- package/src/modules/components/AppAvatar/index.ts +9 -0
- package/src/modules/components/AppBackButton/AppBackButton.vue +51 -0
- package/src/modules/components/AppBackButton/__tests__/app-back-button.spec.ts +70 -0
- package/src/modules/components/AppBadge/AppBadge.vue +65 -0
- package/src/modules/components/AppBadge/__tests__/app-badge.spec.ts +64 -0
- package/src/modules/components/AppBadge/index.d.ts +13 -0
- package/src/modules/components/AppBadge/index.ts +29 -0
- package/src/modules/components/AppButton/AppButton.vue +53 -0
- package/src/modules/components/AppButton/ButtonIconSlot.vue +26 -0
- package/src/modules/components/AppButton/__tests__/app-button.spec.ts +145 -0
- package/src/modules/components/AppButton/__tests__/button-icon-slot.spec.ts +30 -0
- package/src/modules/components/AppButton/index.d.ts +16 -0
- package/src/modules/components/AppButton/index.ts +57 -0
- package/src/modules/components/AppCard/AppCard.vue +88 -0
- package/src/modules/components/AppCard/CardAction.vue +101 -0
- package/src/modules/components/AppCard/CardIconSlot.vue +65 -0
- package/src/modules/components/AppCard/__tests__/app-card.spec.ts +109 -0
- package/src/modules/components/AppCard/__tests__/card-action.spec.ts +55 -0
- package/src/modules/components/AppCard/__tests__/card-icon-slot.spec.ts +27 -0
- package/src/modules/components/AppCard/index.d.ts +12 -0
- package/src/modules/components/AppCard/index.ts +5 -0
- package/src/modules/components/AppColor/AppColor.vue +74 -0
- package/src/modules/components/AppColor/__tests__/app-color.spec.ts +53 -0
- package/src/modules/components/AppColor/index.d.ts +10 -0
- package/src/modules/components/AppColorCard/AppColorCard.vue +41 -0
- package/src/modules/components/AppColorCard/__tests__/app-color-card.spec.ts +55 -0
- package/src/modules/components/AppConfirm/AppConfirm.vue +237 -0
- package/src/modules/components/AppConfirm/__tests__/app-confirm.spec.ts +366 -0
- package/src/modules/components/AppConfirm/index.d.ts +31 -0
- package/src/modules/components/AppConfirm/index.ts +1 -0
- package/src/modules/components/AppContextMenu/AppContextMenu.vue +100 -0
- package/src/modules/components/AppContextMenu/ShortcutItem.vue +37 -0
- package/src/modules/components/AppContextMenu/__mocks__/index.ts +25 -0
- package/src/modules/components/AppContextMenu/__tests__/app-context-menu.spec.ts +71 -0
- package/src/modules/components/AppContextMenu/__tests__/shortcut-item.spec.ts +29 -0
- package/src/modules/components/AppContextMenu/index.d.ts +23 -0
- package/src/modules/components/AppDataTable/AppDataTable.vue +323 -0
- package/src/modules/components/AppDataTable/AppDataTableFooter.vue +91 -0
- package/src/modules/components/AppDataTable/__mocks__/index.ts +71 -0
- package/src/modules/components/AppDataTable/__tests__/app-data-table-footer.spec.ts +107 -0
- package/src/modules/components/AppDataTable/__tests__/app-data-table.spec.ts +153 -0
- package/src/modules/components/AppDataTable/index.d.ts +29 -0
- package/src/modules/components/AppDefinitionList/AppDefinitionItem.vue +57 -0
- package/src/modules/components/AppDefinitionList/AppDefinitionList.vue +31 -0
- package/src/modules/components/AppDefinitionList/__mocks__/index.ts +31 -0
- package/src/modules/components/AppDefinitionList/__tests__/app-definition-item.spec.ts +93 -0
- package/src/modules/components/AppDefinitionList/__tests__/app-definition-list.spec.ts +35 -0
- package/src/modules/components/AppDefinitionList/index.d.ts +8 -0
- package/src/modules/components/AppDisclosure/AppDisclosure.vue +19 -0
- package/src/modules/components/AppDisclosure/AppDisclosureButton.vue +43 -0
- package/src/modules/components/AppDisclosure/AppDisclosurePanel.vue +31 -0
- package/src/modules/components/AppDisclosure/__tests__/app-disclosure-button.spec.ts +70 -0
- package/src/modules/components/AppDisclosure/__tests__/app-disclosure-panel.spec.ts +64 -0
- package/src/modules/components/AppDisclosure/__tests__/app-disclosure.spec.ts +41 -0
- package/src/modules/components/AppDrawer/AppDrawer.vue +149 -0
- package/src/modules/components/AppDrawer/__tests__/app-drawer.spec.ts +120 -0
- package/src/modules/components/AppDrawer/index.d.ts +27 -0
- package/src/modules/components/AppDropdownButton/AppDropdownButton.vue +82 -0
- package/src/modules/components/AppDropdownButton/AppDropdownItem.vue +67 -0
- package/src/modules/components/AppDropdownButton/__mocks__/index.ts +25 -0
- package/src/modules/components/AppDropdownButton/__tests__/app-dropdown-button.spec.ts +81 -0
- package/src/modules/components/AppDropdownButton/__tests__/app-dropdown-item.spec.ts +108 -0
- package/src/modules/components/AppDropdownButton/index.d.ts +26 -0
- package/src/modules/components/AppDropdownButton/index.ts +8 -0
- package/src/modules/components/AppError/AppError.vue +233 -0
- package/src/modules/components/AppError/__tests__/app-error.spec.ts +366 -0
- package/src/modules/components/AppError/index.d.ts +30 -0
- package/src/modules/components/AppError/index.ts +1 -0
- package/src/modules/components/AppImageDropzone/AppImageDropzone.vue +130 -0
- package/src/modules/components/AppImageDropzone/__tests__/app-image-dropzone.spec.ts +92 -0
- package/src/modules/components/AppImageDropzone/index.d.ts +8 -0
- package/src/modules/components/AppInput/AppInput.vue +247 -0
- package/src/modules/components/AppInput/FileInput.vue +58 -0
- package/src/modules/components/AppInput/Input.vue +141 -0
- package/src/modules/components/AppInput/InputIconSlot.vue +27 -0
- package/src/modules/components/AppInput/LocationInput.vue +150 -0
- package/src/modules/components/AppInput/__mocks__/location.ts +13 -0
- package/src/modules/components/AppInput/__tests__/app-input.spec.ts +255 -0
- package/src/modules/components/AppInput/__tests__/file-input.spec.ts +48 -0
- package/src/modules/components/AppInput/__tests__/input-icon-slot.spec.ts +27 -0
- package/src/modules/components/AppInput/__tests__/input.spec.ts +260 -0
- package/src/modules/components/AppInput/__tests__/location-input.spec.ts +159 -0
- package/src/modules/components/AppInput/choice.ts +24 -0
- package/src/modules/components/AppInput/datepicker.ts +62 -0
- package/src/modules/components/AppInput/index.d.ts +68 -0
- package/src/modules/components/AppInput/index.ts +133 -0
- package/src/modules/components/AppInput/location.ts +8 -0
- package/src/modules/components/AppInput/richText.ts +45 -0
- package/src/modules/components/AppInputLabel/AppInputLabel.vue +15 -0
- package/src/modules/components/AppInputLabel/__tests__/app-input-label.spec.ts +38 -0
- package/src/modules/components/AppInputLabel/index.d.ts +6 -0
- package/src/modules/components/AppLicensePlate/AppLicensePlate.vue +34 -0
- package/src/modules/components/AppLicensePlate/__tests__/app-license-plate.spec.ts +46 -0
- package/src/modules/components/AppLicensePlate/index.d.ts +1 -0
- package/src/modules/components/AppLoader/AppLoader.vue +37 -0
- package/src/modules/components/AppLoader/index.d.ts +1 -0
- package/src/modules/components/AppLoader/index.ts +8 -0
- package/src/modules/components/AppMaps/AppMaps.vue +105 -0
- package/src/modules/components/AppMaps/index.ts +44 -0
- package/src/modules/components/AppMenu/AppMenu.vue +79 -0
- package/src/modules/components/AppMenu/AppMenuItem.vue +40 -0
- package/src/modules/components/AppMenu/__mocks__/index.ts +23 -0
- package/src/modules/components/AppMenu/__tests__/app-menu-item.spec.ts +47 -0
- package/src/modules/components/AppMenu/__tests__/app-menu.spec.ts +53 -0
- package/src/modules/components/AppMenu/index.d.ts +15 -0
- package/src/modules/components/AppModal/AppModal.vue +261 -0
- package/src/modules/components/AppModal/__tests__/app-modal.spec.ts +282 -0
- package/src/modules/components/AppModal/index.d.ts +36 -0
- package/src/modules/components/AppNavigationMenu/AppNavigationMenu.vue +95 -0
- package/src/modules/components/AppNavigationMenu/Mobile.vue +126 -0
- package/src/modules/components/AppNavigationMenu/NavigationItem.vue +82 -0
- package/src/modules/components/AppNavigationMenu/SupportItem.vue +29 -0
- package/src/modules/components/AppNavigationMenu/__tests__/app-navigation-menu.spec.ts +104 -0
- package/src/modules/components/AppNavigationMenu/__tests__/mobile.spec.ts +155 -0
- package/src/modules/components/AppNavigationMenu/__tests__/navigation-item.spec.ts +91 -0
- package/src/modules/components/AppNavigationMenu/__tests__/support-item.spec.ts +48 -0
- package/src/modules/components/AppPagination/AppPagination.vue +133 -0
- package/src/modules/components/AppPagination/AppPaginationItem.vue +28 -0
- package/src/modules/components/AppPagination/__mocks__/index.ts +20 -0
- package/src/modules/components/AppPagination/__tests__/app-pagination.spec.ts +143 -0
- package/src/modules/components/AppPagination/index.d.ts +24 -0
- package/src/modules/components/AppProgressBar/AppProgressBar.vue +93 -0
- package/src/modules/components/AppProgressBar/AppProgressBarStep.vue +5 -0
- package/src/modules/components/AppProgressBar/__mocks__/index.ts +17 -0
- package/src/modules/components/AppProgressBar/__tests__/app-progress-bar-step.spec.ts +18 -0
- package/src/modules/components/AppProgressBar/__tests__/app-progress-bar.spec.ts +77 -0
- package/src/modules/components/AppProgressBar/index.d.ts +21 -0
- package/src/modules/components/AppRating/AppRating.vue +42 -0
- package/src/modules/components/AppRating/VueStarRating/Star.vue +215 -0
- package/src/modules/components/AppRating/VueStarRating/StarRating.vue +231 -0
- package/src/modules/components/AppRating/VueStarRating/classes/AlphaColor.ts +68 -0
- package/src/modules/components/AppRating/VueStarRating/readme.md +279 -0
- package/src/modules/components/AppRating/__tests__/app-rating.spec.ts +36 -0
- package/src/modules/components/AppSection/AppSection.vue +35 -0
- package/src/modules/components/AppSection/__tests__/app-section.spec.ts +53 -0
- package/src/modules/components/AppSelect/AppSelect.vue +176 -0
- package/src/modules/components/AppSelect/__mocks__/index.ts +24 -0
- package/src/modules/components/AppSelect/__tests__/app-select.spec.ts +73 -0
- package/src/modules/components/AppSelect/index.d.ts +43 -0
- package/src/modules/components/AppSelect/index.ts +69 -0
- package/src/modules/components/AppStepper/AppStepper.vue +79 -0
- package/src/modules/components/AppStepper/__tests__/app-stepper.spec.ts +59 -0
- package/src/modules/components/AppTable/AppTable.vue +40 -0
- package/src/modules/components/AppTimeline/AppTimeline.vue +22 -0
- package/src/modules/components/AppTimeline/AppTimelineItem.vue +97 -0
- package/src/modules/components/AppTimeline/AppTimelineItemIcon.vue +55 -0
- package/src/modules/components/AppTimeline/__mocks__/timeline.ts +29 -0
- package/src/modules/components/AppTimeline/__tests__/app-timeline-item-Icon.spec.ts +35 -0
- package/src/modules/components/AppTimeline/__tests__/app-timeline-item.spec.ts +121 -0
- package/src/modules/components/AppTimeline/__tests__/app-timeline.spec.ts +55 -0
- package/src/modules/components/AppTimeline/index.d.ts +30 -0
- package/src/modules/components/AppTimeline/index.ts +13 -0
- package/src/modules/components/AppToggle/AppToggle.vue +36 -0
- package/src/modules/components/AppToggle/__tests__/app-toggle.spec.ts +54 -0
- package/src/modules/components/AppToggle/index.d.ts +3 -0
- package/src/modules/components/AppToggleCard/AppToggleCard.vue +45 -0
- package/src/modules/components/AppToggleCard/__tests__/app-toggle-card.spec.ts +55 -0
- package/src/modules/components/index.ts +43 -0
- package/src/modules/composables/index.ts +13 -0
- package/src/modules/composables/useActionBar/__mocks__/index.ts +17 -0
- package/src/modules/composables/useActionBar/__tests__/index.spec.ts +62 -0
- package/src/modules/composables/useActionBar/index.d.ts +1 -0
- package/src/modules/composables/useActionBar/index.ts +67 -0
- package/src/modules/composables/useComputedPosition/index.d.ts +16 -0
- package/src/modules/composables/useComputedPosition/index.ts +199 -0
- package/src/modules/composables/useConfirm/__tests__/index.spec.ts +29 -0
- package/src/modules/composables/useConfirm/index.ts +63 -0
- package/src/modules/composables/useContextMenu/index.ts +127 -0
- package/src/modules/composables/useDrawer/__tests__/index.spec.ts +34 -0
- package/src/modules/composables/useDrawer/index.ts +136 -0
- package/src/modules/composables/useEcho/index.ts +167 -0
- package/src/modules/composables/useError/__tests__/index.spec.ts +29 -0
- package/src/modules/composables/useError/index.ts +61 -0
- package/src/modules/composables/useGoogleApi/__tests__/index.spec.ts +39 -0
- package/src/modules/composables/useGoogleApi/index.ts +26 -0
- package/src/modules/composables/useLayout/__tests__/index.spec.ts +34 -0
- package/src/modules/composables/useLayout/index.d.ts +1 -0
- package/src/modules/composables/useLayout/index.ts +68 -0
- package/src/modules/composables/useModal/__tests__/index.spec.ts +34 -0
- package/src/modules/composables/useModal/index.ts +97 -0
- package/src/modules/composables/useNavigation/__mocks__/navigation.ts +22 -0
- package/src/modules/composables/useNavigation/__tests__/index.spec.ts +88 -0
- package/src/modules/composables/useNavigation/index.d.ts +17 -0
- package/src/modules/composables/useNavigation/index.ts +97 -0
- package/src/modules/icons/BuildingCircleCheck.vue +32 -0
- package/src/modules/icons/BuildingCircleXmark.vue +20 -0
- package/src/modules/icons/CarsIcon.vue +29 -0
- package/src/modules/icons/ChatPersonRoundedIcon.vue +184 -0
- package/src/modules/icons/CompanyIcon.vue +18 -0
- package/src/modules/icons/HeroGirlIcon.vue +246 -0
- package/src/modules/icons/HeroPersonIcon.vue +402 -0
- package/src/modules/icons/HeroPersonRoundedIcon.vue +412 -0
- package/src/modules/icons/HeroPersonWithBgIcon.vue +4503 -0
- package/src/modules/icons/LocationMarkerIcon.vue +33 -0
- package/src/modules/icons/PartyPopperIcon.vue +146 -0
- package/src/modules/icons/index.ts +32 -0
- package/src/modules/icons/status/ErrorIcon.vue +24 -0
- package/src/modules/icons/status/SuccessIcon.vue +24 -0
- package/src/modules/icons/status/WarningIcon.vue +27 -0
- package/src/modules/icons/status/index.ts +3 -0
- package/src/modules/index.ts +8 -0
- package/src/modules/layouts/Auth/Auth.vue +36 -0
- package/src/modules/layouts/Auth/__tests__/auth.spec.ts +63 -0
- package/src/modules/layouts/Base/Base.vue +69 -0
- package/src/modules/layouts/Base/__tests__/base.spec.ts +56 -0
- package/src/modules/layouts/Platform/Platform.vue +96 -0
- package/src/modules/layouts/Platform/__tests__/platform.spec.ts +56 -0
- package/src/modules/layouts/index.ts +9 -0
- package/src/modules/plugins/Sentry/index.d.ts +16 -0
- package/src/modules/plugins/Sentry/index.ts +65 -0
- package/src/modules/plugins/Sentry/language/nl.ts +13 -0
- package/src/modules/plugins/TinyMCE/lang/nl.js +430 -0
- package/src/modules/plugins/Toast/Toast.vue +58 -0
- package/src/modules/plugins/Toast/__tests__/toast.spec.ts +90 -0
- package/src/modules/plugins/Toast/index.ts +36 -0
- package/src/modules/plugins/Toast/types.d.ts +265 -0
- package/src/modules/plugins/index.ts +63 -0
- package/src/stories/Introduction.mdx +4 -0
- package/src/stories/assets/code-brackets.svg +1 -0
- package/src/stories/assets/colors.svg +1 -0
- package/src/stories/assets/comments.svg +1 -0
- package/src/stories/assets/direction.svg +1 -0
- package/src/stories/assets/flow.svg +1 -0
- package/src/stories/assets/images/logo.png +0 -0
- package/src/stories/assets/images/road.png +0 -0
- package/src/stories/assets/plugin.svg +1 -0
- package/src/stories/assets/repo.svg +1 -0
- package/src/stories/assets/stackalt.svg +1 -0
- package/src/stories/components/ActionBar/ActionBar.stories.ts +67 -0
- package/src/stories/components/Alert/Alert.stories.ts +53 -0
- package/src/stories/components/Avatar/Avatar.stories.ts +44 -0
- package/src/stories/components/BackButton/BackButton.stories.ts +39 -0
- package/src/stories/components/Badge/Badge.stories.ts +42 -0
- package/src/stories/components/Button/Button.stories.ts +132 -0
- package/src/stories/components/Card/Card.stories.ts +70 -0
- package/src/stories/components/Color/Color.stories.ts +41 -0
- package/src/stories/components/ColorCard/ColorCard.stories.ts +43 -0
- package/src/stories/components/Confirm/Confirm.stories.ts +110 -0
- package/src/stories/components/ContextMenu/ContextMenu.stories.ts +85 -0
- package/src/stories/components/DefinitionList/DefinitionList.stories.ts +32 -0
- package/src/stories/components/Disclosure/Disclosure.stories.ts +61 -0
- package/src/stories/components/DropdownButton/DropdownButton.stories.ts +121 -0
- package/src/stories/components/Error/Error.stories.ts +106 -0
- package/src/stories/components/ImageDropzone/ImageDropzone.stories.ts +41 -0
- package/src/stories/components/Input/Input.stories.ts +180 -0
- package/src/stories/components/Input/LocationInput.stories.ts +77 -0
- package/src/stories/components/LicensePlate/LicensePlate.stories.ts +39 -0
- package/src/stories/components/Maps/Maps.stories.ts +36 -0
- package/src/stories/components/Menu/Menu.stories.ts +41 -0
- package/src/stories/components/Modal/Modal.stories.ts +68 -0
- package/src/stories/components/Navigation/Navigation.stories.ts +62 -0
- package/src/stories/components/Pagination/Pagination.stories.ts +62 -0
- package/src/stories/components/ProgressBar/ProgressBar.stories.ts +48 -0
- package/src/stories/components/Rating/Rating.stories.ts +38 -0
- package/src/stories/components/Section/Section.stories.ts +44 -0
- package/src/stories/components/Select/Select.stories.ts +90 -0
- package/src/stories/components/Stepper/Stepper.stories.ts +38 -0
- package/src/stories/components/Table/DataTable.stories.ts +96 -0
- package/src/stories/components/Table/Table.stories.ts +45 -0
- package/src/stories/components/Timeline/Timeline.stories.ts +46 -0
- package/src/stories/components/Toast/Toast.stories.ts +47 -0
- package/src/stories/components/Toggle/Toggle.stories.ts +41 -0
- package/src/stories/components/ToggleCard/ToggleCard.stories.ts +43 -0
- package/src/stories/layouts/Auth.stories.ts +43 -0
- package/src/stories/layouts/Base.stories.ts +70 -0
- package/src/tests/mocks/resize-observer.ts +13 -0
- package/src/tests/stubs/AppSelect.ts +89 -0
- package/src/tests/stubs/HeadlessUiDialogStub.ts +24 -0
- package/src/tests/stubs/HeadlessUiTransitionChildStub.ts +20 -0
- package/src/tests/stubs/HeadlessUiTransitionRootStub.ts +25 -0
- package/src/tests/stubs/IconStub.ts +9 -0
- package/src/tests/stubs/Vue3EasyDataTableStub.ts +53 -0
- package/src/typings/plugin.d.ts +5 -0
- package/src/typings/shims-vue.d.ts +13 -0
- package/src/typings/utilities.d.ts +4 -0
- package/src/typings/vite-environment.d.ts +12 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/* eslint-disable max-classes-per-file, class-methods-use-this */
|
|
2
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
3
|
+
import { flushPromises, shallowMount } from '@vue/test-utils';
|
|
4
|
+
import { location as locationMock } from '../__mocks__/location';
|
|
5
|
+
import LocationInput from '../LocationInput.vue';
|
|
6
|
+
|
|
7
|
+
import type { VueWrapper } from '@vue/test-utils';
|
|
8
|
+
import type { LocationInputProps } from '../index.d';
|
|
9
|
+
|
|
10
|
+
const googleEventListenerMock = vi.fn();
|
|
11
|
+
let googleEventListenerHandler: () => void = () => undefined;
|
|
12
|
+
|
|
13
|
+
const importLibrary = vi.fn().mockResolvedValue({
|
|
14
|
+
Autocomplete: class {
|
|
15
|
+
private readonly input: HTMLInputElement | null = null;
|
|
16
|
+
private readonly options: google.maps.places.AutocompleteOptions | null = null;
|
|
17
|
+
|
|
18
|
+
private constructor(input: HTMLInputElement, options: google.maps.places.AutocompleteOptions | null) {
|
|
19
|
+
this.input = input;
|
|
20
|
+
this.options = options;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public addListener(eventName: string, handler: () => void) {
|
|
24
|
+
googleEventListenerMock(eventName, handler);
|
|
25
|
+
googleEventListenerHandler = handler;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public getPlace() {
|
|
29
|
+
return {
|
|
30
|
+
geometry: {
|
|
31
|
+
location: {
|
|
32
|
+
lat: () => 51.000_000_3,
|
|
33
|
+
lng: () => 24.214_905_4,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
37
|
+
address_components: [
|
|
38
|
+
{
|
|
39
|
+
types: ['postal_code'],
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
41
|
+
long_name: '0000 AB',
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
43
|
+
short_name: '0000 AB',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
types: ['administrative_area_level_1'],
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
48
|
+
long_name: 'Gelderland',
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
50
|
+
short_name: 'GE',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
types: ['route'],
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
55
|
+
long_name: 'johndoelane',
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
57
|
+
short_name: 'johndoelane',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
types: ['street_number'],
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
62
|
+
long_name: '4a',
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
64
|
+
short_name: '4a',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
types: ['locality'],
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
69
|
+
long_name: 'Chicago',
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
71
|
+
short_name: 'CH',
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// @ts-expect-error google does not exists on window
|
|
80
|
+
window.google = { maps: { importLibrary } };
|
|
81
|
+
|
|
82
|
+
function createWrapper(props?: Partial<LocationInputProps>): VueWrapper<InstanceType<typeof LocationInput>> {
|
|
83
|
+
return shallowMount(LocationInput, {
|
|
84
|
+
props: {
|
|
85
|
+
apiKey: 'apiKey',
|
|
86
|
+
...props,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
describe('the LocationInput component', () => {
|
|
92
|
+
beforeEach(() => {
|
|
93
|
+
importLibrary.mockClear();
|
|
94
|
+
googleEventListenerMock.mockClear();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should render the default elements', () => {
|
|
98
|
+
const wrapper = createWrapper();
|
|
99
|
+
|
|
100
|
+
expect(wrapper.find('input').exists()).toBe(true);
|
|
101
|
+
expect(wrapper.find('[data-test-location-labels]').exists()).toBe(false);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should pass props and attrs to the input', () => {
|
|
105
|
+
const wrapper = createWrapper({ placeholder: 'placeholder' });
|
|
106
|
+
|
|
107
|
+
const input = wrapper.find('input');
|
|
108
|
+
expect(input.exists()).toBe(true);
|
|
109
|
+
expect(input.attributes('placeholder')).toBe('placeholder');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should execute all google handlers on mount', async () => {
|
|
113
|
+
expect.assertions(6);
|
|
114
|
+
|
|
115
|
+
expect(importLibrary).toHaveBeenCalledTimes(0);
|
|
116
|
+
expect(googleEventListenerMock).toHaveBeenCalledTimes(0);
|
|
117
|
+
|
|
118
|
+
createWrapper();
|
|
119
|
+
|
|
120
|
+
await flushPromises();
|
|
121
|
+
|
|
122
|
+
expect(importLibrary).toHaveBeenCalledTimes(1);
|
|
123
|
+
expect(importLibrary).toHaveBeenCalledWith('places');
|
|
124
|
+
|
|
125
|
+
expect(googleEventListenerMock).toHaveBeenCalledTimes(1);
|
|
126
|
+
expect(googleEventListenerMock).toHaveBeenCalledWith('place_changed', expect.any(Function));
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('emits an event if Google fires listener \'event_changed\'', async () => {
|
|
130
|
+
expect.assertions(3);
|
|
131
|
+
|
|
132
|
+
const wrapper = createWrapper();
|
|
133
|
+
|
|
134
|
+
expect(wrapper.emitted()).not.toHaveProperty('update:modelValue');
|
|
135
|
+
|
|
136
|
+
await flushPromises();
|
|
137
|
+
|
|
138
|
+
googleEventListenerHandler();
|
|
139
|
+
|
|
140
|
+
expect(wrapper.emitted()).toHaveProperty('update:modelValue');
|
|
141
|
+
expect(wrapper.emitted('update:modelValue')?.[0]?.[0]).toStrictEqual(locationMock);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('shows custom location labels when input has value', () => {
|
|
145
|
+
const wrapper = createWrapper({
|
|
146
|
+
modelValue: locationMock,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
expect(wrapper.find('[data-test-location-labels]').exists()).toBe(true);
|
|
150
|
+
|
|
151
|
+
expect(wrapper.find('[data-test-street-label]').exists()).toBe(true);
|
|
152
|
+
expect(wrapper.find('[data-test-street-label]').text()).toBe(
|
|
153
|
+
`${locationMock.street} ${locationMock.number}${locationMock.numberSuffix}`,
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
expect(wrapper.find('[data-test-postcode-label]').exists()).toBe(true);
|
|
157
|
+
expect(wrapper.find('[data-test-postcode-label]').text()).toBe(locationMock.postcode);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ChoiceType, InputType } from './index.d';
|
|
2
|
+
|
|
3
|
+
export const choiceInputTypes = ['radio', 'checkbox'] as const;
|
|
4
|
+
|
|
5
|
+
export function isChoiceInputCheck(inputType: InputType): inputType is ChoiceType {
|
|
6
|
+
// @ts-expect-error type-check function should not cause type error
|
|
7
|
+
return choiceInputTypes.includes(inputType);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const defaultChoiceInputDomClasses = `peer text-zinc-700 appearance-none h-5 w-5 border
|
|
11
|
+
border-zinc-300 cursor-pointer checked:border-[5px]! checked:border-primary disabled:border-10
|
|
12
|
+
disabled:border-zinc-100! disabled:cursor-not-allowed focus:border-2 focus:border-primary
|
|
13
|
+
focus-visible:outline-hidden`;
|
|
14
|
+
|
|
15
|
+
export const defaultCheckboxInputDomClasses = 'rounded-md bg-white checked:bg-primary';
|
|
16
|
+
|
|
17
|
+
export function getChoiceInputDomClasses(inputType: InputType, hasError: boolean): Record<string, boolean> {
|
|
18
|
+
return {
|
|
19
|
+
[defaultChoiceInputDomClasses]: true,
|
|
20
|
+
[defaultCheckboxInputDomClasses]: inputType === 'checkbox',
|
|
21
|
+
'rounded-full': inputType === 'radio',
|
|
22
|
+
'border-error!': hasError,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { nl } from 'date-fns/locale';
|
|
2
|
+
|
|
3
|
+
import type { VueDatePickerProps } from '@vuepic/vue-datepicker';
|
|
4
|
+
import type { DatePickerType, InputType } from './index.d';
|
|
5
|
+
|
|
6
|
+
export const datePickerTypes = ['date', 'datetime', 'time', 'year', 'month', 'week'] as const;
|
|
7
|
+
|
|
8
|
+
export const datePickerIconPerType: Record<DatePickerType, string> = {
|
|
9
|
+
time: 'clock',
|
|
10
|
+
week: 'calendar',
|
|
11
|
+
date: 'calendar',
|
|
12
|
+
year: 'calendar',
|
|
13
|
+
month: 'calendar',
|
|
14
|
+
datetime: 'calendar',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function isDatePickerCheck(inputType: InputType): inputType is DatePickerType {
|
|
18
|
+
// @ts-expect-error type-check function should not cause type error
|
|
19
|
+
return datePickerTypes.includes(inputType);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function getDatePickerFormat(datePickerType: DatePickerType): string {
|
|
23
|
+
switch (datePickerType) {
|
|
24
|
+
case 'datetime':
|
|
25
|
+
return 'd LLLL yyyy HH:mm';
|
|
26
|
+
case 'time':
|
|
27
|
+
return 'HH:mm';
|
|
28
|
+
case 'year':
|
|
29
|
+
return 'yyyy';
|
|
30
|
+
case 'month':
|
|
31
|
+
return 'LLLL';
|
|
32
|
+
case 'week':
|
|
33
|
+
return 'd LLLL yyyy';
|
|
34
|
+
case 'date':
|
|
35
|
+
default:
|
|
36
|
+
return 'd LLLL yyyy';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function getDatePickerProps(
|
|
41
|
+
datePickerType: DatePickerType,
|
|
42
|
+
inputUuid: string,
|
|
43
|
+
): VueDatePickerProps {
|
|
44
|
+
return {
|
|
45
|
+
locale: 'nl',
|
|
46
|
+
uid: inputUuid,
|
|
47
|
+
autoApply: true,
|
|
48
|
+
clearable: false,
|
|
49
|
+
formatLocale: nl,
|
|
50
|
+
format: getDatePickerFormat(datePickerType),
|
|
51
|
+
timePicker: datePickerType === 'time',
|
|
52
|
+
weekPicker: datePickerType === 'week',
|
|
53
|
+
yearPicker: datePickerType === 'year',
|
|
54
|
+
monthPicker: datePickerType === 'month',
|
|
55
|
+
enableTimePicker: ['time', 'datetime'].includes(datePickerType),
|
|
56
|
+
teleport: true,
|
|
57
|
+
textInput: {
|
|
58
|
+
...(datePickerType === 'time' ? { format: 'HH:mm' } : {}),
|
|
59
|
+
...(datePickerType === 'date' ? { format: 'dd-MM-yyyy' } : {}),
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { IPropTypes } from '@tinymce/tinymce-vue/lib/cjs/main/ts/components/EditorPropTypes';
|
|
2
|
+
import type { generalInputTypes } from '.';
|
|
3
|
+
import type { choiceInputTypes } from './choice';
|
|
4
|
+
import type { datePickerTypes } from './datepicker';
|
|
5
|
+
import type { locationTypes } from './location';
|
|
6
|
+
import type { richTextTypes } from './richText';
|
|
7
|
+
|
|
8
|
+
export type ChoiceType = typeof choiceInputTypes[number];
|
|
9
|
+
export type DatePickerType = typeof datePickerTypes[number];
|
|
10
|
+
export type LocationType = typeof locationTypes[number];
|
|
11
|
+
export type RichTextType = typeof richTextTypes[number];
|
|
12
|
+
export type GeneralInputTypes = typeof generalInputTypes[number];
|
|
13
|
+
export type InputType = GeneralInputTypes | ChoiceType | DatePickerType | LocationType | RichTextType | 'file' | 'license' | 'color';
|
|
14
|
+
export type IconPosition = 'leading' | 'trailing';
|
|
15
|
+
|
|
16
|
+
export interface AppInputProps<ModelValue> {
|
|
17
|
+
type: InputType;
|
|
18
|
+
modelValue: ModelValue;
|
|
19
|
+
modelModifiers?: {
|
|
20
|
+
dotToComma?: boolean;
|
|
21
|
+
};
|
|
22
|
+
readonly?: boolean;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
loading?: boolean;
|
|
25
|
+
custom?: boolean;
|
|
26
|
+
required?: boolean;
|
|
27
|
+
hasError?: boolean;
|
|
28
|
+
plain?: boolean;
|
|
29
|
+
errorMessage?: string;
|
|
30
|
+
label?: string;
|
|
31
|
+
tabindex?: number | string;
|
|
32
|
+
wrapperClasses?: string;
|
|
33
|
+
errorWrapperClasses?: string;
|
|
34
|
+
inputWrapperClasses?: string;
|
|
35
|
+
iconClasses?: string;
|
|
36
|
+
labelClasses?: string;
|
|
37
|
+
init?: Partial<IPropTypes & Record<string, unknown>>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type InputProps<ModelValue> = Pick<AppInputProps<ModelValue>, 'modelValue' | 'tabindex' | 'type' | 'custom'>;
|
|
41
|
+
|
|
42
|
+
export interface LocationModelValue {
|
|
43
|
+
postcode?: string;
|
|
44
|
+
city?: string;
|
|
45
|
+
street?: string;
|
|
46
|
+
number?: number;
|
|
47
|
+
numberSuffix?: string;
|
|
48
|
+
province?: string;
|
|
49
|
+
provinceShort?: string;
|
|
50
|
+
lat?: number;
|
|
51
|
+
lng?: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface LocationInputProps {
|
|
55
|
+
placeholder?: string;
|
|
56
|
+
placeOptions?: google.maps.places.AutocompleteOptions | null;
|
|
57
|
+
modelValue?: LocationModelValue | null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface FileInputProps {
|
|
61
|
+
modelValue: File | File[] | null;
|
|
62
|
+
multiple?: boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface RichtextProps {
|
|
66
|
+
apiKey: string;
|
|
67
|
+
init: Partial<IPropTypes & Record<string, unknown>>;
|
|
68
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import VueDatePicker from '@vuepic/vue-datepicker';
|
|
2
|
+
import Editor from '@tinymce/tinymce-vue';
|
|
3
|
+
import { datePickerTypes, isDatePickerCheck } from './datepicker';
|
|
4
|
+
import { isLocationInputCheck } from './location';
|
|
5
|
+
import { isRichTextCheck } from './richText';
|
|
6
|
+
import { choiceInputTypes, getChoiceInputDomClasses, isChoiceInputCheck } from './choice';
|
|
7
|
+
import LocationInput from './LocationInput.vue';
|
|
8
|
+
import FileInput from './FileInput.vue';
|
|
9
|
+
|
|
10
|
+
import type { Component, Slots, InputHTMLAttributes } from 'vue';
|
|
11
|
+
import type { IconPosition, InputType } from './index.d';
|
|
12
|
+
|
|
13
|
+
export const generalInputTypes = ['email', 'number', 'search', 'tel', 'text', 'url', 'password', 'textarea'] as const;
|
|
14
|
+
export const inputTypes = [...generalInputTypes, ...choiceInputTypes, ...datePickerTypes, 'file', 'license'] as const;
|
|
15
|
+
|
|
16
|
+
export const appInputPropDefaults = {
|
|
17
|
+
disabled: false,
|
|
18
|
+
readonly: false,
|
|
19
|
+
loading: false,
|
|
20
|
+
required: false,
|
|
21
|
+
multiple: false,
|
|
22
|
+
hasError: false,
|
|
23
|
+
label: undefined,
|
|
24
|
+
plain: false,
|
|
25
|
+
custom: false,
|
|
26
|
+
errorMessage: '',
|
|
27
|
+
modelModifiers: () => ({}),
|
|
28
|
+
} as const;
|
|
29
|
+
|
|
30
|
+
export function getInputComponent(inputType: InputType): string | Component {
|
|
31
|
+
if (isDatePickerCheck(inputType)) {
|
|
32
|
+
return VueDatePicker;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (isRichTextCheck(inputType)) {
|
|
36
|
+
return Editor;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (isLocationInputCheck(inputType)) {
|
|
40
|
+
return LocationInput;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (inputType === 'file') {
|
|
44
|
+
return FileInput;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (inputType === 'textarea') {
|
|
48
|
+
return 'textarea';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return 'input';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function isLicenseInputCheck(inputType: InputType): boolean {
|
|
55
|
+
return inputType === 'license';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function mustRenderDefaultSlot(inputType: InputType, slots: Slots, label?: string): boolean {
|
|
59
|
+
return isChoiceInputCheck(inputType) && (!!slots.default || !!label);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function mustRenderIconSlot(
|
|
63
|
+
position: IconPosition,
|
|
64
|
+
inputType: InputType,
|
|
65
|
+
isLoading: boolean,
|
|
66
|
+
plain: boolean,
|
|
67
|
+
disabled: boolean,
|
|
68
|
+
readonly: boolean,
|
|
69
|
+
slots: Slots,
|
|
70
|
+
): boolean {
|
|
71
|
+
if (isChoiceInputCheck(inputType) || isLicenseInputCheck(inputType)) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (position === 'leading' && isLocationInputCheck(inputType)) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (position === 'trailing') {
|
|
80
|
+
return !!slots.trailingIcon
|
|
81
|
+
|| (isDatePickerCheck(inputType) && !plain && !disabled && !readonly)
|
|
82
|
+
|| (isLocationInputCheck(inputType) && !plain)
|
|
83
|
+
|| (inputType === 'search' && !plain)
|
|
84
|
+
|| (isLoading && !slots.leadingIcon);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return !!slots[`${position}Icon`];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const defaultInputDomClasses = `block w-full appearance-none rounded-lg
|
|
91
|
+
placeholder:text-zinc-300 focus:outline-hidden text-base
|
|
92
|
+
disabled:cursor-not-allowed disabled:border-zinc-100 disabled:!bg-zinc-50`;
|
|
93
|
+
|
|
94
|
+
export function getInputDomClasses(
|
|
95
|
+
inputType: InputType,
|
|
96
|
+
isDisabled: boolean,
|
|
97
|
+
isReadonly: boolean,
|
|
98
|
+
loading: boolean,
|
|
99
|
+
hasError: boolean,
|
|
100
|
+
isOpen: boolean,
|
|
101
|
+
plain: boolean,
|
|
102
|
+
slots: Slots,
|
|
103
|
+
attributes: InputHTMLAttributes,
|
|
104
|
+
): Record<string, boolean> {
|
|
105
|
+
if (isChoiceInputCheck(inputType)) {
|
|
106
|
+
return getChoiceInputDomClasses(inputType, hasError);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const inputTextCenter = (attributes?.class ?? '').includes('text-center');
|
|
110
|
+
const leadingIcon = mustRenderIconSlot('leading', inputType, loading, plain, isDisabled, isReadonly, slots);
|
|
111
|
+
const trailingIcon = mustRenderIconSlot('trailing', inputType, loading, plain, isDisabled, isReadonly, slots);
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
'border-zinc-300': !hasError,
|
|
115
|
+
'border-zinc-100! bg-zinc-50!': isDisabled,
|
|
116
|
+
'px-10': inputTextCenter && (leadingIcon || trailingIcon),
|
|
117
|
+
'pl-10 pr-5 group-aria-expanded:pl-7': leadingIcon && !inputTextCenter,
|
|
118
|
+
'pr-10 pl-3': trailingIcon && !inputTextCenter,
|
|
119
|
+
'px-3': !leadingIcon && !trailingIcon,
|
|
120
|
+
'pr-0!': isDatePickerCheck(inputType),
|
|
121
|
+
'pl-0!': !leadingIcon && isDatePickerCheck(inputType),
|
|
122
|
+
[defaultInputDomClasses]: !plain,
|
|
123
|
+
'block w-full appearance-none bg-transparent focus:outline-hidden focus-visible:outline-hidden': plain,
|
|
124
|
+
'py-3': !isDatePickerCheck(inputType),
|
|
125
|
+
'h-[42px]': inputType !== 'textarea',
|
|
126
|
+
'h-24': inputType === 'textarea',
|
|
127
|
+
'border-error text-error placeholder-error focus:ring-error focus:border-error': hasError,
|
|
128
|
+
'text-center bg-transparent text-lg uppercase': isLicenseInputCheck(inputType),
|
|
129
|
+
'border bg-white focus:ring-1 focus:ring-zinc-300 hover:bg-zinc-100!': !isLicenseInputCheck(inputType) && !plain,
|
|
130
|
+
'border ring-1 ring-zinc-300': isOpen && !plain,
|
|
131
|
+
'read-only:cursor-default read-only:border-zinc-300 read-only:bg-zinc-50': !isDatePickerCheck(inputType),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LocationType, InputType } from './index.d';
|
|
2
|
+
|
|
3
|
+
export const locationTypes = ['location'] as const;
|
|
4
|
+
|
|
5
|
+
export function isLocationInputCheck(inputType: InputType): inputType is LocationType {
|
|
6
|
+
// @ts-expect-error type-check function should not cause type error
|
|
7
|
+
return locationTypes.includes(inputType);
|
|
8
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
2
|
+
import type Editor from '@tinymce/tinymce-vue';
|
|
3
|
+
import type { RichTextType, InputType, RichtextProps } from './index.d';
|
|
4
|
+
|
|
5
|
+
export const richTextTypes = ['richText'] as const;
|
|
6
|
+
|
|
7
|
+
export function isRichTextCheck(inputType: InputType): inputType is RichTextType {
|
|
8
|
+
// @ts-expect-error type-check function should not cause type error
|
|
9
|
+
return richTextTypes.includes(inputType);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function getRichTextProps(apiKey: string): RichtextProps {
|
|
13
|
+
return {
|
|
14
|
+
apiKey,
|
|
15
|
+
init: {
|
|
16
|
+
plugins: 'link',
|
|
17
|
+
toolbar: 'bold italic underline | link',
|
|
18
|
+
link_title: false,
|
|
19
|
+
theme: 'silver',
|
|
20
|
+
menubar: false,
|
|
21
|
+
statusbar: false,
|
|
22
|
+
resize: true,
|
|
23
|
+
language: 'nl',
|
|
24
|
+
language_url: '/src/modules/plugins/TinyMCE/lang/nl.js',
|
|
25
|
+
valid_elements: 'p,b,strong,i,em,u,a[href|target],span[style|text-decoration=underline]',
|
|
26
|
+
content_style: 'html, body { height: calc(100% - 10px); }',
|
|
27
|
+
setup: (editor: typeof Editor): void => {
|
|
28
|
+
editor.editorManager.IconManager.add('default', {
|
|
29
|
+
icons: {
|
|
30
|
+
bold: '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 384 512"><path d="M0 56C0 42.7 10.7 32 24 32l48 0 16 0 124 0c68.5 0 124 55.5 124 124c0 34.7-14.3 66.2-37.3 88.7C339.7 264.9 368 307.1 368 356c0 68.5-55.5 124-124 124L88 480l-16 0-48 0c-13.3 0-24-10.7-24-24s10.7-24 24-24l24 0 0-176L48 80 24 80C10.7 80 0 69.3 0 56zM212 232c42 0 76-34 76-76s-34-76-76-76L96 80l0 152 116 0zM96 280l0 152 148 0c42 0 76-34 76-76s-34-76-76-76l-32 0L96 280z"/></svg>',
|
|
31
|
+
underline: '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 448 512"><path d="M16 56c0-13.3 10.7-24 24-24l96 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-24 0 0 144c0 61.9 50.1 112 112 112s112-50.1 112-112l0-144-24 0c-13.3 0-24-10.7-24-24s10.7-24 24-24l96 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-24 0 0 144c0 88.4-71.6 160-160 160s-160-71.6-160-160L64 80 40 80C26.7 80 16 69.3 16 56zM0 456c0-13.3 10.7-24 24-24l400 0c13.3 0 24 10.7 24 24s-10.7 24-24 24L24 480c-13.3 0-24-10.7-24-24z"/></svg>',
|
|
32
|
+
italic: '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 384 512"><path d="M128 56c0-13.3 10.7-24 24-24l208 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-68.7 0L144.7 432l87.3 0c13.3 0 24 10.7 24 24s-10.7 24-24 24L24 480c-13.3 0-24-10.7-24-24s10.7-24 24-24l68.7 0L239.3 80 152 80c-13.3 0-24-10.7-24-24z"/></svg>',
|
|
33
|
+
link: '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 640 512"><path d="M580.3 267.2c56.2-56.2 56.2-147.3 0-203.5C526.8 10.2 440.9 7.3 383.9 57.2l-6.1 5.4c-10 8.7-11 23.9-2.3 33.9s23.9 11 33.9 2.3l6.1-5.4c38-33.2 95.2-31.3 130.9 4.4c37.4 37.4 37.4 98.1 0 135.6L433.1 346.6c-37.4 37.4-98.2 37.4-135.6 0c-35.7-35.7-37.6-92.9-4.4-130.9l4.7-5.4c8.7-10 7.7-25.1-2.3-33.9s-25.1-7.7-33.9 2.3l-4.7 5.4c-49.8 57-46.9 142.9 6.6 196.4c56.2 56.2 147.3 56.2 203.5 0L580.3 267.2zM59.7 244.8C3.5 301 3.5 392.1 59.7 448.2c53.6 53.6 139.5 56.4 196.5 6.5l6.1-5.4c10-8.7 11-23.9 2.3-33.9s-23.9-11-33.9-2.3l-6.1 5.4c-38 33.2-95.2 31.3-130.9-4.4c-37.4-37.4-37.4-98.1 0-135.6L207 165.4c37.4-37.4 98.1-37.4 135.6 0c35.7 35.7 37.6 92.9 4.4 130.9l-5.4 6.1c-8.7 10-7.7 25.1 2.3 33.9s25.1 7.7 33.9-2.3l5.4-6.1c49.9-57 47-142.9-6.5-196.5c-56.2-56.2-147.3-56.2-203.5 0L59.7 244.8z"/></svg>',
|
|
34
|
+
'chevron-left': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 320 512"><path d="M15 239c-9.4 9.4-9.4 24.6 0 33.9L207 465c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9L65.9 256 241 81c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0L15 239z"/></svg>',
|
|
35
|
+
'chevron-right': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 320 512"><path d="M305 239c9.4 9.4 9.4 24.6 0 33.9L113 465c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l175-175L79 81c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0L305 239z"/></svg>',
|
|
36
|
+
'chevron-up': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 512 512"><path d="M239 111c9.4-9.4 24.6-9.4 33.9 0L465 303c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-175-175L81 337c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9L239 111z"/></svg>',
|
|
37
|
+
'chevron-down': '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 512 512"><path d="M239 401c9.4 9.4 24.6 9.4 33.9 0L465 209c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-175 175L81 175c-9.4-9.4-24.6-9.4-33.9 0s-9.4 24.6 0 33.9L239 401z"/></svg>',
|
|
38
|
+
close: '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 384 512"><path d="M345 137c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-119 119L73 103c-9.4-9.4-24.6-9.4-33.9 0s-9.4 24.6 0 33.9l119 119L39 375c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l119-119L311 409c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-119-119L345 137z"/></svg>',
|
|
39
|
+
checkmark: '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 448 512"><path d="M441 103c9.4 9.4 9.4 24.6 0 33.9L177 401c-9.4 9.4-24.6 9.4-33.9 0L7 265c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l119 119L407 103c9.4-9.4 24.6-9.4 33.9 0z"/></svg>',
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { Props } from './index.d';
|
|
3
|
+
|
|
4
|
+
defineProps<Props>();
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<label
|
|
9
|
+
:class="{ 'text-error': hasError, 'select-none text-zinc-300': disabled }"
|
|
10
|
+
:data-error="hasError ? 'label' : undefined"
|
|
11
|
+
class="mb-2 block text-base font-semibold text-zinc-900"
|
|
12
|
+
>
|
|
13
|
+
<slot></slot>
|
|
14
|
+
</label>
|
|
15
|
+
</template>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { shallowMount } from '@vue/test-utils';
|
|
3
|
+
import AppInputLabel from '../AppInputLabel.vue';
|
|
4
|
+
|
|
5
|
+
import type { VueWrapper } from '@vue/test-utils';
|
|
6
|
+
import type { Props } from '../index.d';
|
|
7
|
+
|
|
8
|
+
function createWrapper(
|
|
9
|
+
props: Props = {},
|
|
10
|
+
): VueWrapper<InstanceType<typeof AppInputLabel>> {
|
|
11
|
+
return shallowMount(AppInputLabel, { props, slots: { default: 'label' } });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe('the AppInputLabel component', () => {
|
|
15
|
+
it('renders default slot', () => {
|
|
16
|
+
const wrapper = createWrapper();
|
|
17
|
+
|
|
18
|
+
expect(wrapper.text()).toBe('label');
|
|
19
|
+
expect(wrapper.classes('text-error')).toBe(false);
|
|
20
|
+
expect(wrapper.classes('select-none')).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should add classes when has error', () => {
|
|
24
|
+
const wrapper = createWrapper({ hasError: true });
|
|
25
|
+
|
|
26
|
+
expect(wrapper.text()).toBe('label');
|
|
27
|
+
expect(wrapper.classes('text-error')).toBe(true);
|
|
28
|
+
expect(wrapper.classes('select-none')).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should add classes when disabled', () => {
|
|
32
|
+
const wrapper = createWrapper({ disabled: true });
|
|
33
|
+
|
|
34
|
+
expect(wrapper.text()).toBe('label');
|
|
35
|
+
expect(wrapper.classes('text-error')).toBe(false);
|
|
36
|
+
expect(wrapper.classes('select-none')).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { Country } from './index.d';
|
|
3
|
+
|
|
4
|
+
withDefaults(defineProps<{
|
|
5
|
+
license?: string;
|
|
6
|
+
country?: Country;
|
|
7
|
+
licensePlateClasses?: string;
|
|
8
|
+
}>(), {
|
|
9
|
+
license: undefined,
|
|
10
|
+
country: 'NL',
|
|
11
|
+
licensePlateClasses: undefined,
|
|
12
|
+
});
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<div class="flex text-sm font-bold">
|
|
17
|
+
<span
|
|
18
|
+
class="flex items-center rounded-l-lg bg-indigo-900 px-2 py-[0.188rem] text-white"
|
|
19
|
+
data-test-country-code
|
|
20
|
+
>
|
|
21
|
+
{{ country }}
|
|
22
|
+
</span>
|
|
23
|
+
|
|
24
|
+
<span
|
|
25
|
+
:class="licensePlateClasses"
|
|
26
|
+
class="w-full rounded-r-lg bg-yellow-400 px-2 py-[0.188rem] uppercase"
|
|
27
|
+
data-test-license-plate
|
|
28
|
+
>
|
|
29
|
+
<slot>
|
|
30
|
+
{{ license }}
|
|
31
|
+
</slot>
|
|
32
|
+
</span>
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { shallowMount } from '@vue/test-utils';
|
|
3
|
+
import AppLicensePlate from '../AppLicensePlate.vue';
|
|
4
|
+
|
|
5
|
+
const licensePlate = '7-SNZ-01';
|
|
6
|
+
|
|
7
|
+
describe('the AppLicensePlate component', () => {
|
|
8
|
+
it('should render the country code', () => {
|
|
9
|
+
const wrapper = shallowMount(AppLicensePlate);
|
|
10
|
+
|
|
11
|
+
const countryCodeElement = wrapper.find('[data-test-country-code]');
|
|
12
|
+
expect(countryCodeElement.exists()).toBe(true);
|
|
13
|
+
expect(countryCodeElement.text()).toBe('NL');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should render the license plate by prop', () => {
|
|
17
|
+
const wrapper = shallowMount(AppLicensePlate, {
|
|
18
|
+
props: { license: licensePlate },
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const licensePlateElement = wrapper.find('[data-test-license-plate]');
|
|
22
|
+
expect(licensePlateElement.exists()).toBe(true);
|
|
23
|
+
expect(licensePlateElement.text()).toBe(licensePlate);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should render the license plate by slot', () => {
|
|
27
|
+
const wrapper = shallowMount(AppLicensePlate, {
|
|
28
|
+
slots: { default: licensePlate },
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const licensePlateElement = wrapper.find('[data-test-license-plate]');
|
|
32
|
+
expect(licensePlateElement.exists()).toBe(true);
|
|
33
|
+
expect(licensePlateElement.text()).toBe(licensePlate);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should render the additional classes', () => {
|
|
37
|
+
const wrapper = shallowMount(AppLicensePlate, {
|
|
38
|
+
props: {
|
|
39
|
+
licensePlateClasses: 'extra-class',
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const licensePlateElement = wrapper.find('[data-test-license-plate]');
|
|
44
|
+
expect(licensePlateElement.classes('extra-class')).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type Country = 'NL';
|