vueless 1.0.2-beta.8 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/bin/commands/copy.js +2 -2
- package/bin/commands/create.js +2 -2
- package/bin/commands/init.js +64 -5
- package/bin/constants.js +27 -17
- package/composables/tests/useUI.test.ts +494 -0
- package/constants.js +7 -2
- package/directives/clickOutside/storybook/docs.mdx +0 -1
- package/directives/clickOutside/storybook/stories.ts +22 -16
- package/directives/tooltip/storybook/docs.mdx +0 -1
- package/directives/tooltip/storybook/stories.ts +21 -14
- package/icons/internal/home.svg +1 -0
- package/icons/storybook/account_balance.svg +1 -0
- package/icons/storybook/arrow_back.svg +1 -0
- package/icons/storybook/arrow_forward.svg +1 -0
- package/icons/storybook/asterisk.svg +1 -0
- package/icons/storybook/brightness_1.svg +1 -0
- package/icons/storybook/celebration.svg +1 -0
- package/icons/storybook/contract.svg +1 -0
- package/icons/storybook/cookie.svg +1 -0
- package/icons/storybook/credit_card.svg +1 -0
- package/icons/storybook/description.svg +1 -0
- package/icons/storybook/directions_bike.svg +1 -0
- package/icons/storybook/directions_car.svg +1 -0
- package/icons/storybook/done_all.svg +1 -0
- package/icons/storybook/east.svg +1 -0
- package/icons/storybook/handyman.svg +1 -0
- package/icons/storybook/keyboard_tab.svg +1 -0
- package/icons/storybook/keyboard_tab_rtl.svg +1 -0
- package/icons/storybook/notifications.svg +1 -0
- package/icons/storybook/question_mark.svg +1 -0
- package/icons/storybook/schedule.svg +1 -0
- package/icons/storybook/straighten.svg +1 -0
- package/icons/storybook/trending_up.svg +1 -0
- package/package.json +29 -30
- package/plugin-vite.js +52 -28
- package/tailwind.css +2 -8
- package/ui.boilerplate/UBoilerplate.vue +2 -2
- package/ui.boilerplate/storybook/stories.hidden.ts +1 -1
- package/ui.boilerplate/tests/UBoilerplate.test.ts +60 -0
- package/ui.button/storybook/stories.ts +2 -2
- package/ui.button/tests/UButton.test.ts +31 -53
- package/ui.button-link/ULink.vue +4 -4
- package/ui.button-link/storybook/stories.ts +1 -1
- package/ui.button-link/tests/ULink.test.ts +23 -51
- package/ui.button-toggle/config.ts +1 -1
- package/ui.button-toggle/storybook/stories.ts +4 -3
- package/ui.button-toggle/tests/UToggle.test.ts +76 -102
- package/ui.container-accordion/storybook/stories.ts +9 -12
- package/ui.container-accordion/tests/UAccordion.test.ts +248 -0
- package/ui.container-card/UCard.vue +5 -2
- package/ui.container-card/storybook/stories.ts +123 -81
- package/ui.container-card/tests/UCard.test.ts +229 -0
- package/ui.container-col/UCol.vue +4 -4
- package/ui.container-col/config.ts +2 -0
- package/ui.container-col/storybook/stories.ts +14 -10
- package/ui.container-col/tests/UCol.test.ts +207 -0
- package/ui.container-col/types.ts +5 -0
- package/ui.container-divider/storybook/stories.ts +23 -16
- package/ui.container-divider/tests/UDivider.test.ts +228 -0
- package/ui.container-group/storybook/stories.ts +60 -42
- package/ui.container-group/tests/UGroup.test.ts +204 -0
- package/ui.container-groups/storybook/stories.ts +41 -12
- package/ui.container-groups/tests/UGroups.test.ts +75 -0
- package/ui.container-modal/UModal.vue +27 -14
- package/ui.container-modal/config.ts +12 -4
- package/ui.container-modal/storybook/stories.ts +189 -55
- package/ui.container-modal/tests/UModal.test.ts +646 -0
- package/ui.container-modal-confirm/UModalConfirm.vue +10 -3
- package/ui.container-modal-confirm/storybook/stories.ts +57 -22
- package/ui.container-modal-confirm/tests/UModalConfirm.test.ts +506 -0
- package/ui.container-page/UPage.vue +5 -2
- package/ui.container-page/config.ts +1 -1
- package/ui.container-page/storybook/stories.ts +170 -80
- package/ui.container-page/tests/UPage.test.ts +331 -0
- package/ui.container-row/URow.vue +4 -4
- package/ui.container-row/config.ts +1 -0
- package/ui.container-row/storybook/stories.ts +4 -3
- package/ui.container-row/tests/URow.test.ts +205 -0
- package/ui.container-row/types.ts +5 -0
- package/ui.data-list/UDataList.vue +2 -13
- package/ui.data-list/config.ts +0 -1
- package/ui.data-list/storybook/docs.mdx +3 -4
- package/ui.data-list/storybook/stories.ts +89 -71
- package/ui.data-list/tests/UDataList.test.ts +391 -0
- package/ui.data-list/types.ts +0 -6
- package/ui.data-table/UTable.vue +2 -2
- package/ui.data-table/UTableRow.vue +7 -7
- package/ui.data-table/config.ts +2 -2
- package/ui.data-table/storybook/docs.mdx +23 -9
- package/ui.data-table/storybook/stories.ts +374 -182
- package/ui.data-table/tests/UTable.test.ts +612 -0
- package/ui.data-table/tests/UTableRow.test.ts +545 -0
- package/ui.data-table/types.ts +2 -2
- package/ui.dropdown-badge/UDropdownBadge.vue +13 -2
- package/ui.dropdown-badge/config.ts +3 -12
- package/ui.dropdown-badge/storybook/stories.ts +5 -4
- package/ui.dropdown-badge/tests/UDropdownBadge.test.ts +421 -0
- package/ui.dropdown-button/UDropdownButton.vue +13 -2
- package/ui.dropdown-button/config.ts +4 -10
- package/ui.dropdown-button/storybook/stories.ts +9 -2
- package/ui.dropdown-button/tests/UDropdownButton.test.ts +449 -0
- package/ui.dropdown-link/UDropdownLink.vue +8 -1
- package/ui.dropdown-link/config.ts +6 -12
- package/ui.dropdown-link/storybook/stories.ts +15 -4
- package/ui.dropdown-link/tests/UDropdownLink.test.ts +454 -0
- package/ui.form-calendar/UCalendar.vue +107 -57
- package/ui.form-calendar/UCalendarDayView.vue +60 -21
- package/ui.form-calendar/UCalendarMonthView.vue +10 -14
- package/ui.form-calendar/UCalendarYearView.vue +33 -52
- package/ui.form-calendar/config.ts +3 -3
- package/ui.form-calendar/constants.ts +2 -0
- package/ui.form-calendar/storybook/stories.ts +40 -48
- package/ui.form-calendar/tests/UCalendar.test.ts +656 -0
- package/ui.form-calendar/tests/UCalendarDayView.test.ts +401 -0
- package/ui.form-calendar/tests/UCalendarMonthView.test.ts +214 -0
- package/ui.form-calendar/tests/UCalendarYearView.test.ts +226 -0
- package/ui.form-calendar/types.ts +2 -2
- package/ui.form-calendar/utilCalendar.ts +3 -7
- package/ui.form-checkbox/UCheckbox.vue +20 -5
- package/ui.form-checkbox/config.ts +4 -2
- package/ui.form-checkbox/storybook/stories.ts +30 -41
- package/ui.form-checkbox/tests/UCheckbox.test.ts +314 -0
- package/ui.form-checkbox/types.ts +1 -1
- package/ui.form-checkbox-group/UCheckboxGroup.vue +3 -3
- package/ui.form-checkbox-group/storybook/stories.ts +50 -26
- package/ui.form-checkbox-group/tests/UCheckboxGroup.test.ts +267 -0
- package/ui.form-checkbox-multi-state/UCheckboxMultiState.vue +2 -1
- package/ui.form-checkbox-multi-state/storybook/stories.ts +2 -2
- package/ui.form-checkbox-multi-state/tests/UCheckboxMultiState.test.ts +224 -0
- package/ui.form-color-picker/UColorPicker.vue +4 -3
- package/ui.form-color-picker/storybook/stories.ts +19 -19
- package/ui.form-color-picker/tests/UColorPicker.test.ts +142 -0
- package/ui.form-date-picker/UDatePicker.vue +4 -1
- package/ui.form-date-picker/storybook/stories.ts +178 -53
- package/ui.form-date-picker/tests/UDatePicker.test.ts +518 -0
- package/ui.form-date-picker-range/UDatePickerRange.vue +39 -20
- package/ui.form-date-picker-range/UDatePickerRangePeriodMenu.vue +4 -2
- package/ui.form-date-picker-range/storybook/stories.ts +93 -51
- package/ui.form-date-picker-range/tests/UDatePickerRange.test.ts +574 -0
- package/ui.form-date-picker-range/types.ts +1 -0
- package/ui.form-input/UInput.vue +27 -11
- package/ui.form-input/config.ts +18 -9
- package/ui.form-input/storybook/stories.ts +71 -22
- package/ui.form-input/tests/UInput.test.ts +606 -0
- package/ui.form-input/types.ts +2 -2
- package/ui.form-input-counter/UInputCounter.vue +5 -2
- package/ui.form-input-counter/config.ts +3 -2
- package/ui.form-input-counter/storybook/stories.ts +1 -1
- package/ui.form-input-counter/tests/UInputCounter.test.ts +268 -0
- package/ui.form-input-file/UInputFile.vue +4 -3
- package/ui.form-input-file/config.ts +2 -2
- package/ui.form-input-file/storybook/stories.ts +38 -19
- package/ui.form-input-file/tests/UInputFile.test.ts +511 -0
- package/ui.form-input-number/UInputNumber.vue +3 -3
- package/ui.form-input-number/storybook/stories.ts +60 -17
- package/ui.form-input-number/tests/UInputNumber.test.ts +454 -0
- package/ui.form-input-number/useFormatNumber.ts +1 -0
- package/ui.form-input-password/UInputPassword.vue +9 -0
- package/ui.form-input-password/storybook/stories.ts +65 -21
- package/ui.form-input-password/tests/UInputPassword.test.ts +303 -0
- package/ui.form-input-rating/UInputRating.vue +1 -1
- package/ui.form-input-rating/storybook/stories.ts +16 -4
- package/ui.form-input-rating/tests/UInputRating.test.ts +272 -0
- package/ui.form-input-search/config.ts +1 -1
- package/ui.form-input-search/storybook/stories.ts +66 -24
- package/ui.form-input-search/tests/UInputSearch.test.ts +372 -0
- package/ui.form-label/ULabel.vue +12 -15
- package/ui.form-label/config.ts +8 -9
- package/ui.form-label/storybook/stories.ts +31 -15
- package/ui.form-label/tests/ULabel.test.ts +374 -0
- package/ui.form-label/types.ts +0 -5
- package/ui.form-listbox/UListbox.vue +39 -43
- package/ui.form-listbox/config.ts +15 -11
- package/ui.form-listbox/storybook/stories.ts +18 -10
- package/ui.form-listbox/tests/UListbox.test.ts +811 -0
- package/ui.form-radio/URadio.vue +2 -5
- package/ui.form-radio/config.ts +2 -2
- package/ui.form-radio/storybook/stories.ts +42 -20
- package/ui.form-radio/tests/URadio.test.ts +226 -0
- package/ui.form-radio-group/storybook/stories.ts +21 -21
- package/ui.form-radio-group/tests/URadioGroup.test.ts +277 -0
- package/ui.form-select/USelect.vue +50 -23
- package/ui.form-select/config.ts +12 -16
- package/ui.form-select/storybook/assets/images/alex-johnson.png +0 -0
- package/ui.form-select/storybook/assets/images/emily-davis.png +0 -0
- package/ui.form-select/storybook/assets/images/john-doe.png +0 -0
- package/ui.form-select/storybook/assets/images/pat-morgan.png +0 -0
- package/ui.form-select/storybook/stories.ts +392 -152
- package/ui.form-select/tests/USelect.test.ts +824 -0
- package/ui.form-select/types.ts +5 -0
- package/ui.form-switch/USwitch.vue +0 -1
- package/ui.form-switch/storybook/stories.ts +18 -17
- package/ui.form-switch/tests/USwitch.test.ts +239 -0
- package/ui.form-textarea/UTextarea.vue +76 -60
- package/ui.form-textarea/config.ts +22 -9
- package/ui.form-textarea/storybook/stories.ts +30 -19
- package/ui.form-textarea/tests/UTextarea.test.ts +546 -0
- package/ui.form-textarea/types.ts +13 -8
- package/ui.image-avatar/config.ts +1 -1
- package/ui.image-avatar/storybook/stories.ts +1 -1
- package/ui.image-avatar/tests/UAvatar.test.ts +240 -0
- package/ui.image-icon/UIcon.vue +9 -1
- package/ui.image-icon/config.ts +1 -0
- package/ui.image-icon/storybook/stories.ts +2 -10
- package/ui.image-icon/tests/UIcon.test.ts +224 -0
- package/ui.image-icon/tests/assets/test-icon.svg +1 -0
- package/ui.loader/storybook/stories.ts +1 -8
- package/ui.loader/tests/ULoader.test.ts +146 -0
- package/ui.loader-overlay/storybook/stories.ts +10 -4
- package/ui.loader-overlay/tests/ULoaderOverlay.test.ts +168 -0
- package/ui.loader-progress/storybook/stories.ts +6 -6
- package/ui.loader-progress/tests/ULoaderProgress.test.ts +165 -0
- package/ui.navigation-breadcrumbs/UBreadcrumbs.vue +17 -4
- package/ui.navigation-breadcrumbs/config.ts +1 -0
- package/ui.navigation-breadcrumbs/storybook/stories.ts +36 -34
- package/ui.navigation-breadcrumbs/tests/UBreadcrumbs.test.ts +439 -0
- package/ui.navigation-breadcrumbs/types.ts +2 -2
- package/ui.navigation-pagination/UPagination.vue +1 -1
- package/ui.navigation-pagination/storybook/stories.ts +27 -43
- package/ui.navigation-pagination/tests/UPagination.test.ts +442 -0
- package/ui.navigation-progress/UProgress.vue +8 -3
- package/ui.navigation-progress/UStepperProgress.vue +8 -3
- package/ui.navigation-progress/storybook/stories.ts +7 -5
- package/ui.navigation-progress/tests/UProgress.test.ts +250 -0
- package/ui.navigation-tab/UTab.vue +1 -1
- package/ui.navigation-tab/config.ts +6 -1
- package/ui.navigation-tab/storybook/assets/john-doe.png +0 -0
- package/ui.navigation-tab/storybook/stories.ts +12 -5
- package/ui.navigation-tab/tests/UTab.test.ts +486 -0
- package/ui.navigation-tabs/storybook/stories.ts +19 -16
- package/ui.navigation-tabs/tests/UTabs.test.ts +339 -0
- package/ui.other-chip/UChip.vue +2 -2
- package/ui.other-chip/config.ts +12 -1
- package/ui.other-chip/storybook/stories.ts +4 -4
- package/ui.other-chip/tests/UChip.test.ts +254 -0
- package/ui.other-chip/types.ts +1 -1
- package/ui.other-dot/config.ts +0 -3
- package/ui.other-dot/storybook/stories.ts +1 -8
- package/ui.other-dot/tests/UDot.test.ts +83 -0
- package/ui.other-dot/types.ts +1 -1
- package/ui.other-theme-color-toggle/UThemeColorToggle.vue +10 -3
- package/ui.other-theme-color-toggle/storybook/stories.ts +1 -1
- package/ui.other-theme-color-toggle/tests/UThemeColorToggle.test.ts +249 -0
- package/ui.skeleton/USkeleton.vue +1 -0
- package/ui.skeleton/storybook/stories.ts +7 -12
- package/ui.skeleton/tests/USkeleton.test.ts +61 -0
- package/ui.skeleton-choice/USkeletonChoice.vue +1 -0
- package/ui.skeleton-choice/config.ts +15 -19
- package/ui.skeleton-choice/storybook/stories.ts +19 -22
- package/ui.skeleton-choice/tests/USkeletonChoice.test.ts +194 -0
- package/ui.skeleton-input/USkeletonInput.vue +10 -2
- package/ui.skeleton-input/config.ts +36 -46
- package/ui.skeleton-input/storybook/stories.ts +32 -31
- package/ui.skeleton-input/tests/USkeletonInput.test.ts +256 -0
- package/ui.skeleton-text/USkeletonText.vue +2 -2
- package/ui.skeleton-text/config.ts +1 -1
- package/ui.skeleton-text/storybook/stories.ts +12 -25
- package/ui.skeleton-text/tests/USkeletonText.test.ts +130 -0
- package/ui.text-alert/UAlert.vue +2 -2
- package/ui.text-alert/config.ts +1 -1
- package/ui.text-alert/storybook/stories.ts +61 -32
- package/ui.text-alert/tests/UAlert.test.ts +331 -0
- package/ui.text-badge/UBadge.vue +3 -1
- package/ui.text-badge/storybook/stories.ts +14 -24
- package/ui.text-badge/types.ts +5 -0
- package/ui.text-block/UText.vue +4 -4
- package/ui.text-block/config.ts +30 -1
- package/ui.text-block/storybook/stories.ts +88 -37
- package/ui.text-block/tests/UText.test.ts +74 -11
- package/ui.text-block/types.ts +33 -2
- package/ui.text-empty/config.ts +1 -1
- package/ui.text-empty/storybook/assets/empty-inbox.png +0 -0
- package/ui.text-empty/storybook/stories.ts +19 -11
- package/ui.text-file/UFile.vue +24 -22
- package/ui.text-file/config.ts +2 -2
- package/ui.text-file/storybook/assets/imageURL.png +0 -0
- package/ui.text-file/storybook/stories.ts +19 -11
- package/ui.text-file/tests/UFile.test.ts +257 -0
- package/ui.text-files/UFiles.vue +22 -22
- package/ui.text-files/config.ts +0 -1
- package/ui.text-files/storybook/stories.ts +16 -15
- package/ui.text-files/tests/UFiles.test.ts +307 -0
- package/ui.text-files/types.ts +0 -5
- package/ui.text-header/UHeader.vue +1 -0
- package/ui.text-header/config.ts +25 -2
- package/ui.text-header/storybook/stories.ts +29 -9
- package/ui.text-header/tests/UHeader.test.ts +46 -1
- package/ui.text-header/types.ts +13 -1
- package/ui.text-notify/UNotify.vue +22 -9
- package/ui.text-notify/constants.ts +0 -1
- package/ui.text-notify/storybook/docs.mdx +16 -16
- package/ui.text-notify/storybook/stories.ts +264 -52
- package/ui.text-notify/tests/UNotify.test.ts +276 -0
- package/ui.text-notify/types.ts +13 -0
- package/ui.text-notify/utilNotify.ts +41 -30
- package/ui.text-number/storybook/stories.ts +31 -52
- package/ui.text-number/tests/UNumber.test.ts +351 -0
- package/utils/helper.ts +12 -1
- package/utils/node/dynamicProps.js +8 -2
- package/utils/node/helper.js +71 -1
- package/utils/node/loaderIcon.js +54 -43
- package/utils/node/tailwindSafelist.js +3 -1
- package/utils/node/vuelessConfig.js +4 -1
- package/utils/storybook.ts +5 -1
- package/icons/storybook/heart_plus.svg +0 -1
- package/icons/storybook/label.svg +0 -1
- package/icons/storybook/warning.svg +0 -1
- /package/bin/utils/{dataUtils.js → data.js} +0 -0
- /package/bin/utils/{formatUtil.js → format.js} +0 -0
package/README.md
CHANGED
|
@@ -26,6 +26,7 @@ Vueless is simple enough for everyday use and powerful enough for advanced scena
|
|
|
26
26
|
- ♿️ Accessibility (a11y)
|
|
27
27
|
- ⚙️ Server-side rendering (SSR) friendly
|
|
28
28
|
- 🖼️ 1000+ built-in SVG icons
|
|
29
|
+
- 🧪️ 1200+ unit tests ensuring consistent logic
|
|
29
30
|
- 🛡️ Full TypeScript support with type safety
|
|
30
31
|
|
|
31
32
|
### Advanced Features
|
package/bin/commands/copy.js
CHANGED
|
@@ -7,8 +7,8 @@ import { cp, readFile, writeFile, rename } from "node:fs/promises";
|
|
|
7
7
|
import { styleText } from "node:util";
|
|
8
8
|
|
|
9
9
|
import { getDirFiles } from "../../utils/node/helper.js";
|
|
10
|
-
import { replaceRelativeImports } from "../utils/
|
|
11
|
-
import { getStorybookId, getStoryMetaKeyIndex } from "../utils/
|
|
10
|
+
import { replaceRelativeImports } from "../utils/format.js";
|
|
11
|
+
import { getStorybookId, getStoryMetaKeyIndex } from "../utils/data.js";
|
|
12
12
|
|
|
13
13
|
import { SRC_COMPONENTS_PATH, COMPONENTS_PATH } from "../constants.js";
|
|
14
14
|
import { COMPONENTS, VUELESS_PACKAGE_DIR, VUELESS_LOCAL_DIR } from "../../constants.js";
|
package/bin/commands/create.js
CHANGED
|
@@ -7,8 +7,8 @@ import { readFile, writeFile, rename, mkdir, readdir, copyFile } from "node:fs/p
|
|
|
7
7
|
import { styleText } from "node:util";
|
|
8
8
|
|
|
9
9
|
import { getDirFiles } from "../../utils/node/helper.js";
|
|
10
|
-
import { replaceRelativeImports } from "../utils/
|
|
11
|
-
import { getStorybookId } from "../utils/
|
|
10
|
+
import { replaceRelativeImports } from "../utils/format.js";
|
|
11
|
+
import { getStorybookId } from "../utils/data.js";
|
|
12
12
|
|
|
13
13
|
import { SRC_COMPONENTS_PATH, COMPONENTS_PATH } from "../constants.js";
|
|
14
14
|
|
package/bin/commands/init.js
CHANGED
|
@@ -2,15 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
import { cwd } from "node:process";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import { existsSync } from "node:fs";
|
|
6
|
-
import { writeFile, rename } from "node:fs/promises";
|
|
5
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
6
|
+
import { writeFile, rename, readFile } from "node:fs/promises";
|
|
7
7
|
import { styleText } from "node:util";
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
|
|
9
|
+
import {
|
|
10
|
+
SUPPRESS_TS_CHECK,
|
|
11
|
+
COMPONENTS_INDEX_EXPORT,
|
|
12
|
+
COMPONENTS_INDEX_COMMENT,
|
|
13
|
+
DEFAULT_VUELESS_CONFIG_CONTENT,
|
|
14
|
+
} from "../constants.js";
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
JAVASCRIPT_EXT,
|
|
18
|
+
TYPESCRIPT_EXT,
|
|
19
|
+
CONFIG_INDEX_FILE_NAME,
|
|
20
|
+
VUELESS_CONFIG_FILE_NAME,
|
|
21
|
+
} from "../../constants.js";
|
|
11
22
|
|
|
12
23
|
const vuelessInitOptions = ["--ts", "--js"];
|
|
13
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Initializes Vueless in the project by creating a default config file and .vueless directory.
|
|
27
|
+
* @param {string[]} options - The function options.
|
|
28
|
+
* @param {boolean} options.includes("--ts") - If true, creates a TypeScript config file.
|
|
29
|
+
* @param {boolean} options.includes("--js") - If true, creates a JavaScript config file.
|
|
30
|
+
*/
|
|
14
31
|
export async function vuelessInit(options) {
|
|
15
32
|
const isValidOptions = options.every((option) => vuelessInitOptions.includes(option));
|
|
16
33
|
|
|
@@ -20,13 +37,16 @@ export async function vuelessInit(options) {
|
|
|
20
37
|
return;
|
|
21
38
|
}
|
|
22
39
|
|
|
23
|
-
const
|
|
40
|
+
const hasTypeScript = await detectTypeScript();
|
|
41
|
+
const fileExt = options.includes("--ts") || hasTypeScript ? TYPESCRIPT_EXT : JAVASCRIPT_EXT;
|
|
42
|
+
|
|
24
43
|
const formattedDestPath = path.format({
|
|
25
44
|
dir: cwd(),
|
|
26
45
|
name: VUELESS_CONFIG_FILE_NAME,
|
|
27
46
|
ext: fileExt,
|
|
28
47
|
});
|
|
29
48
|
|
|
49
|
+
/* Backup existing config if it exists. */
|
|
30
50
|
if (existsSync(formattedDestPath)) {
|
|
31
51
|
const timestamp = new Date().valueOf();
|
|
32
52
|
const renamedTarget = `${VUELESS_CONFIG_FILE_NAME}-backup-${timestamp}${fileExt}`;
|
|
@@ -42,6 +62,7 @@ export async function vuelessInit(options) {
|
|
|
42
62
|
);
|
|
43
63
|
}
|
|
44
64
|
|
|
65
|
+
/* Create a default config file. */
|
|
45
66
|
await writeFile(formattedDestPath, DEFAULT_VUELESS_CONFIG_CONTENT, "utf-8");
|
|
46
67
|
|
|
47
68
|
console.log(
|
|
@@ -50,4 +71,42 @@ export async function vuelessInit(options) {
|
|
|
50
71
|
`The '${formattedDestPath.split(path.sep).at(-1)}' was created in the project root directory.`,
|
|
51
72
|
),
|
|
52
73
|
);
|
|
74
|
+
|
|
75
|
+
/* Create .vueless directory and index file. */
|
|
76
|
+
const vuelessDir = path.join(cwd(), ".vueless");
|
|
77
|
+
const destPath = path.join(vuelessDir, `${CONFIG_INDEX_FILE_NAME}${fileExt}`);
|
|
78
|
+
|
|
79
|
+
if (!existsSync(vuelessDir)) {
|
|
80
|
+
mkdirSync(vuelessDir);
|
|
81
|
+
console.log(
|
|
82
|
+
styleText("green", "The '.vueless' directory was created in the project root directory."),
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const suppressTsCheck = fileExt === TYPESCRIPT_EXT ? `${SUPPRESS_TS_CHECK}\n` : "";
|
|
87
|
+
|
|
88
|
+
await writeFile(
|
|
89
|
+
destPath,
|
|
90
|
+
`${suppressTsCheck}${COMPONENTS_INDEX_COMMENT}\n${COMPONENTS_INDEX_EXPORT}\n`,
|
|
91
|
+
"utf-8",
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Detects if TypeScript is a dependency in the project's package.json
|
|
97
|
+
* @returns {Promise<boolean>} True if TypeScript is found in dependencies or devDependencies
|
|
98
|
+
*/
|
|
99
|
+
async function detectTypeScript() {
|
|
100
|
+
try {
|
|
101
|
+
const packageJsonPath = path.join(cwd(), "package.json");
|
|
102
|
+
const packageJsonContent = await readFile(packageJsonPath, "utf-8");
|
|
103
|
+
const pkg = JSON.parse(packageJsonContent);
|
|
104
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
105
|
+
|
|
106
|
+
return Boolean(deps.typescript);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error("Failed to detect TypeScript:", error);
|
|
109
|
+
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
53
112
|
}
|
package/bin/constants.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export const SRC_COMPONENTS_PATH = "/src/components";
|
|
2
2
|
export const COMPONENTS_PATH = "/components";
|
|
3
3
|
|
|
4
|
-
export const DEFAULT_VUELESS_CONFIG_CONTENT = `
|
|
4
|
+
export const DEFAULT_VUELESS_CONFIG_CONTENT = `import { componentConfigs } from "./.vueless";
|
|
5
|
+
|
|
5
6
|
export default {
|
|
6
7
|
/**
|
|
7
8
|
* Global settings.
|
|
@@ -14,6 +15,18 @@ export default {
|
|
|
14
15
|
disabledOpacity: 50,
|
|
15
16
|
colorMode: "auto",
|
|
16
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Component settings.
|
|
20
|
+
*/
|
|
21
|
+
components: /*tw*/ {
|
|
22
|
+
...componentConfigs,
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Directive settings.
|
|
27
|
+
*/
|
|
28
|
+
directives: {},
|
|
29
|
+
|
|
17
30
|
/**
|
|
18
31
|
* Light theme CSS variable settings.
|
|
19
32
|
*/
|
|
@@ -153,22 +166,19 @@ export default {
|
|
|
153
166
|
"--vl-bg-accented": "--vl-neutral-700",
|
|
154
167
|
"--vl-bg-inverted": "--vl-neutral-100",
|
|
155
168
|
},
|
|
169
|
+
};
|
|
170
|
+
`;
|
|
156
171
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
*/
|
|
160
|
-
directives: {},
|
|
172
|
+
export const SUPPRESS_TS_CHECK = `// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
173
|
+
// @ts-nocheck`;
|
|
161
174
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
175
|
+
export const COMPONENTS_INDEX_COMMENT = `/**
|
|
176
|
+
* ⚠️ This file is auto-generated — do not edit it manually.
|
|
177
|
+
* It gets updated automatically whenever the Vite server restarts.
|
|
178
|
+
*
|
|
179
|
+
* This file imports all component config files from the current directory.
|
|
180
|
+
* Only files following the naming pattern "U[Component].config.[ts|js]" will be included.
|
|
181
|
+
* Example: "UButton.config.ts"
|
|
182
|
+
*/`;
|
|
166
183
|
|
|
167
|
-
|
|
168
|
-
* TailwindMerge settings for custom Tailwind CSS classes.
|
|
169
|
-
* All lists of rules available here:
|
|
170
|
-
* https://github.com/dcastil/tailwind-merge/blob/main/src/lib/default-config.ts
|
|
171
|
-
*/
|
|
172
|
-
tailwindMerge: {},
|
|
173
|
-
};
|
|
174
|
-
`;
|
|
184
|
+
export const COMPONENTS_INDEX_EXPORT = `export const componentConfigs = {};`;
|
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { computed, nextTick } from "vue";
|
|
3
|
+
import { mount } from "@vue/test-utils";
|
|
4
|
+
|
|
5
|
+
// TODO: Autogenerated, need to be reviewed
|
|
6
|
+
|
|
7
|
+
// Mock the ui utils
|
|
8
|
+
vi.mock("../../utils/ui.ts", () => ({
|
|
9
|
+
cx: vi.fn((classes) => (Array.isArray(classes) ? classes.filter(Boolean).join(" ") : classes)),
|
|
10
|
+
cva: vi.fn((config) => {
|
|
11
|
+
// Return a spy function that can be called and tracked
|
|
12
|
+
const cvaSpy = vi.fn((props) => {
|
|
13
|
+
if (!config.variants) return config.base || "";
|
|
14
|
+
|
|
15
|
+
let classes = config.base || "";
|
|
16
|
+
|
|
17
|
+
// Apply variants
|
|
18
|
+
Object.entries(config.variants).forEach(([key, variants]) => {
|
|
19
|
+
const value = props[key];
|
|
20
|
+
|
|
21
|
+
if (value && variants[value]) {
|
|
22
|
+
classes += ` ${variants[value]}`;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return classes.trim();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return cvaSpy;
|
|
30
|
+
}),
|
|
31
|
+
setColor: vi.fn((classes, color) => classes?.replace(/{color}/g, color)),
|
|
32
|
+
vuelessConfig: { components: {}, unstyled: false },
|
|
33
|
+
getMergedConfig: vi.fn((args) => {
|
|
34
|
+
// Create a spy function that returns the expected merged config
|
|
35
|
+
const { defaultConfig, globalConfig, propsConfig } = args;
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
...defaultConfig,
|
|
39
|
+
...globalConfig,
|
|
40
|
+
...propsConfig,
|
|
41
|
+
};
|
|
42
|
+
}),
|
|
43
|
+
}));
|
|
44
|
+
|
|
45
|
+
// Mock Vue functions
|
|
46
|
+
vi.mock("vue", async () => {
|
|
47
|
+
const actual = await vi.importActual("vue");
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
...actual,
|
|
51
|
+
getCurrentInstance: vi.fn(),
|
|
52
|
+
useAttrs: vi.fn(),
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
import useUI from "../useUI.ts";
|
|
57
|
+
import * as uiUtils from "../../utils/ui.ts";
|
|
58
|
+
import { getCurrentInstance, useAttrs } from "vue";
|
|
59
|
+
|
|
60
|
+
// Test component for integration testing
|
|
61
|
+
const TestComponent = {
|
|
62
|
+
template: '<div :data-test="getDataTest()" v-bind="bodyAttrs">Test</div>',
|
|
63
|
+
setup() {
|
|
64
|
+
const defaultConfig = {
|
|
65
|
+
body: {
|
|
66
|
+
base: "base-class",
|
|
67
|
+
variants: {
|
|
68
|
+
variant: {
|
|
69
|
+
primary: "primary-class",
|
|
70
|
+
secondary: "secondary-class",
|
|
71
|
+
},
|
|
72
|
+
size: {
|
|
73
|
+
sm: "small-class",
|
|
74
|
+
md: "medium-class",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
defaults: {
|
|
79
|
+
variant: "primary",
|
|
80
|
+
size: "md",
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return useUI(defaultConfig);
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
describe("useUI", () => {
|
|
89
|
+
beforeEach(() => {
|
|
90
|
+
vi.clearAllMocks();
|
|
91
|
+
// Reset vuelessConfig
|
|
92
|
+
uiUtils.vuelessConfig.components = {};
|
|
93
|
+
uiUtils.vuelessConfig.unstyled = false;
|
|
94
|
+
|
|
95
|
+
// Setup default mocks
|
|
96
|
+
vi.mocked(getCurrentInstance).mockReturnValue({
|
|
97
|
+
type: { __name: "TestComponent" },
|
|
98
|
+
props: { dataTest: "test", color: "primary", config: {} },
|
|
99
|
+
parent: null,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
vi.mocked(useAttrs).mockReturnValue({
|
|
103
|
+
class: "",
|
|
104
|
+
style: "",
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
afterEach(() => {
|
|
109
|
+
vi.restoreAllMocks();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe("Basic Functionality", () => {
|
|
113
|
+
it("should return config, getDataTest, and attribute objects", () => {
|
|
114
|
+
const defaultConfig = {
|
|
115
|
+
body: { base: "test-class" },
|
|
116
|
+
defaults: { variant: "primary" },
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const result = useUI(defaultConfig);
|
|
120
|
+
|
|
121
|
+
expect(result).toHaveProperty("config");
|
|
122
|
+
expect(result).toHaveProperty("getDataTest");
|
|
123
|
+
expect(result).toHaveProperty("bodyAttrs");
|
|
124
|
+
expect(typeof result.getDataTest).toBe("function");
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("should merge default config with global and props config", async () => {
|
|
128
|
+
const defaultConfig = {
|
|
129
|
+
body: { base: "default-class" },
|
|
130
|
+
defaults: { variant: "primary" },
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const globalConfig = {
|
|
134
|
+
body: { base: "global-class" },
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const propsConfig = {
|
|
138
|
+
body: { base: "props-class" },
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// Set global config
|
|
142
|
+
uiUtils.vuelessConfig.components = {
|
|
143
|
+
TestComponent: globalConfig,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Mock getCurrentInstance to return props config
|
|
147
|
+
vi.mocked(getCurrentInstance).mockReturnValue({
|
|
148
|
+
type: { __name: "TestComponent" },
|
|
149
|
+
props: { config: propsConfig, dataTest: "test" },
|
|
150
|
+
parent: null,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Call useUI to trigger the config merging
|
|
154
|
+
useUI(defaultConfig);
|
|
155
|
+
|
|
156
|
+
expect(uiUtils.getMergedConfig).toHaveBeenCalledWith({
|
|
157
|
+
defaultConfig,
|
|
158
|
+
globalConfig,
|
|
159
|
+
propsConfig,
|
|
160
|
+
unstyled: false,
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe("CVA Integration", () => {
|
|
166
|
+
it("should generate classes using CVA when config has variants", () => {
|
|
167
|
+
const defaultConfig = {
|
|
168
|
+
body: {
|
|
169
|
+
base: "base-class",
|
|
170
|
+
variants: {
|
|
171
|
+
variant: {
|
|
172
|
+
primary: "primary-class",
|
|
173
|
+
secondary: "secondary-class",
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// Call useUI to trigger CVA usage
|
|
180
|
+
useUI(defaultConfig);
|
|
181
|
+
|
|
182
|
+
expect(uiUtils.cva).toHaveBeenCalledWith(defaultConfig.body);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("should handle string-based config values", () => {
|
|
186
|
+
const defaultConfig = {
|
|
187
|
+
body: "simple-string-class",
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const result = useUI(defaultConfig);
|
|
191
|
+
const bodyAttrs = result.bodyAttrs;
|
|
192
|
+
|
|
193
|
+
expect(bodyAttrs.value.class).toContain("simple-string-class");
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
describe("Color Handling", () => {
|
|
198
|
+
it("should replace {color} placeholders in classes", () => {
|
|
199
|
+
// Mock getCurrentInstance to return color prop
|
|
200
|
+
vi.mocked(getCurrentInstance).mockReturnValue({
|
|
201
|
+
type: { __name: "TestComponent" },
|
|
202
|
+
props: { color: "blue", dataTest: "test" },
|
|
203
|
+
parent: null,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Test the setColor function directly
|
|
207
|
+
expect(uiUtils.setColor).toBeDefined();
|
|
208
|
+
|
|
209
|
+
// The setColor function should replace {color} placeholders
|
|
210
|
+
const testClasses = "text-{color} bg-{color}";
|
|
211
|
+
const coloredClasses = uiUtils.setColor(testClasses, "blue");
|
|
212
|
+
|
|
213
|
+
expect(coloredClasses).toBe("text-blue bg-blue");
|
|
214
|
+
|
|
215
|
+
// Test that useUI can be called with color-containing config
|
|
216
|
+
const defaultConfig = {
|
|
217
|
+
wrapper: {
|
|
218
|
+
base: "text-{color} bg-{color}",
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const result = useUI(defaultConfig);
|
|
223
|
+
|
|
224
|
+
expect(result).toHaveProperty("config");
|
|
225
|
+
expect(result).toHaveProperty("getDataTest");
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
describe("getDataTest Function", () => {
|
|
230
|
+
it("should return data-test value when dataTest prop is provided", () => {
|
|
231
|
+
const result = useUI({});
|
|
232
|
+
const dataTest = result.getDataTest();
|
|
233
|
+
|
|
234
|
+
expect(dataTest).toBe("test");
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it("should return data-test with suffix when suffix is provided", () => {
|
|
238
|
+
const result = useUI({});
|
|
239
|
+
const dataTest = result.getDataTest("button");
|
|
240
|
+
|
|
241
|
+
expect(dataTest).toBe("test-button");
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it("should return null when dataTest prop is not provided", () => {
|
|
245
|
+
// Mock getCurrentInstance to return no dataTest
|
|
246
|
+
vi.mocked(getCurrentInstance).mockReturnValue({
|
|
247
|
+
type: { __name: "TestComponent" },
|
|
248
|
+
props: {},
|
|
249
|
+
parent: null,
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
const result = useUI({});
|
|
253
|
+
const dataTest = result.getDataTest();
|
|
254
|
+
|
|
255
|
+
expect(dataTest).toBeNull();
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
describe("Nested Component Handling", () => {
|
|
260
|
+
it("should handle nested component references like {UIcon}", () => {
|
|
261
|
+
const defaultConfig = {
|
|
262
|
+
icon: "{UIcon}",
|
|
263
|
+
button: "btn {UIcon} end",
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const result = useUI(defaultConfig);
|
|
267
|
+
|
|
268
|
+
// The nested component pattern should be processed
|
|
269
|
+
expect(result).toHaveProperty("iconAttrs");
|
|
270
|
+
expect(result).toHaveProperty("buttonAttrs");
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
describe("Reactivity", () => {
|
|
275
|
+
it("should update config when props.config changes", async () => {
|
|
276
|
+
const component = mount(TestComponent);
|
|
277
|
+
|
|
278
|
+
// Initial state
|
|
279
|
+
expect(component.vm.config).toBeDefined();
|
|
280
|
+
|
|
281
|
+
// Change props
|
|
282
|
+
await component.setProps({
|
|
283
|
+
config: {
|
|
284
|
+
body: { base: "new-class" },
|
|
285
|
+
},
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
await nextTick();
|
|
289
|
+
|
|
290
|
+
// Config should be updated
|
|
291
|
+
expect(uiUtils.getMergedConfig).toHaveBeenCalled();
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
describe("Extends Pattern Handling", () => {
|
|
296
|
+
it("should handle extends pattern {>key} syntax", () => {
|
|
297
|
+
const defaultConfig = {
|
|
298
|
+
button: "base-class {>icon}",
|
|
299
|
+
icon: "icon-class",
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
const result = useUI(defaultConfig);
|
|
303
|
+
|
|
304
|
+
expect(result).toHaveProperty("buttonAttrs");
|
|
305
|
+
expect(result).toHaveProperty("iconAttrs");
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
describe("Mutated Props", () => {
|
|
310
|
+
it("should use mutated props for class generation", () => {
|
|
311
|
+
const defaultConfig = {
|
|
312
|
+
body: {
|
|
313
|
+
base: "base-class",
|
|
314
|
+
variants: {
|
|
315
|
+
hasIcon: {
|
|
316
|
+
true: "with-icon",
|
|
317
|
+
false: "without-icon",
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
const mutatedProps = computed(() => ({
|
|
324
|
+
hasIcon: true,
|
|
325
|
+
}));
|
|
326
|
+
|
|
327
|
+
const result = useUI(defaultConfig, mutatedProps);
|
|
328
|
+
|
|
329
|
+
expect(result).toHaveProperty("bodyAttrs");
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
describe("Component Name Detection", () => {
|
|
334
|
+
it("should detect component name from type.__name", () => {
|
|
335
|
+
vi.mocked(getCurrentInstance).mockReturnValue({
|
|
336
|
+
type: { __name: "UButton" },
|
|
337
|
+
props: { dataTest: "test" },
|
|
338
|
+
parent: null,
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
const result = useUI({});
|
|
342
|
+
|
|
343
|
+
expect(result).toBeDefined();
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it("should detect component name from parent when internal component", () => {
|
|
347
|
+
vi.mocked(getCurrentInstance).mockReturnValue({
|
|
348
|
+
type: { internal: true },
|
|
349
|
+
props: { dataTest: "test" },
|
|
350
|
+
parent: {
|
|
351
|
+
type: { __name: "UButton" },
|
|
352
|
+
},
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
const result = useUI({});
|
|
356
|
+
|
|
357
|
+
expect(result).toBeDefined();
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
describe("Attribute Generation", () => {
|
|
362
|
+
it("should generate proper attributes for each config key", () => {
|
|
363
|
+
const defaultConfig = {
|
|
364
|
+
wrapper: { base: "wrapper-class" },
|
|
365
|
+
content: { base: "content-class" },
|
|
366
|
+
footer: "footer-class",
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
const result = useUI(defaultConfig);
|
|
370
|
+
|
|
371
|
+
expect(result).toHaveProperty("wrapperAttrs");
|
|
372
|
+
expect(result).toHaveProperty("contentAttrs");
|
|
373
|
+
expect(result).toHaveProperty("footerAttrs");
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it("should include config in attributes for nested components", () => {
|
|
377
|
+
const defaultConfig = {
|
|
378
|
+
icon: {
|
|
379
|
+
base: "{UIcon}",
|
|
380
|
+
defaults: {
|
|
381
|
+
size: "sm",
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
const result = useUI(defaultConfig);
|
|
387
|
+
const iconAttrs = result.iconAttrs;
|
|
388
|
+
|
|
389
|
+
expect(iconAttrs.value).toHaveProperty("config");
|
|
390
|
+
});
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
describe("Edge Cases", () => {
|
|
394
|
+
it("should handle empty config", () => {
|
|
395
|
+
const result = useUI({});
|
|
396
|
+
|
|
397
|
+
expect(result.config).toBeDefined();
|
|
398
|
+
expect(result.getDataTest).toBeDefined();
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it("should handle null/undefined config values", () => {
|
|
402
|
+
const defaultConfig = {
|
|
403
|
+
body: "",
|
|
404
|
+
icon: undefined,
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
const result = useUI(defaultConfig);
|
|
408
|
+
|
|
409
|
+
expect(result).toHaveProperty("bodyAttrs");
|
|
410
|
+
expect(result).toHaveProperty("iconAttrs");
|
|
411
|
+
|
|
412
|
+
// Should not throw errors when accessing attributes
|
|
413
|
+
expect(() => result.bodyAttrs.value).not.toThrow();
|
|
414
|
+
expect(() => result.iconAttrs.value).not.toThrow();
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it("should handle unstyled mode", () => {
|
|
418
|
+
uiUtils.vuelessConfig.unstyled = true;
|
|
419
|
+
|
|
420
|
+
const defaultConfig = {
|
|
421
|
+
body: { base: "styled-class" },
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
useUI(defaultConfig);
|
|
425
|
+
|
|
426
|
+
expect(uiUtils.getMergedConfig).toHaveBeenCalledWith(
|
|
427
|
+
expect.objectContaining({
|
|
428
|
+
unstyled: true,
|
|
429
|
+
}),
|
|
430
|
+
);
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
it("should handle config with only defaults", () => {
|
|
434
|
+
const defaultConfig = {
|
|
435
|
+
defaults: {
|
|
436
|
+
variant: "primary",
|
|
437
|
+
size: "md",
|
|
438
|
+
},
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
const result = useUI(defaultConfig);
|
|
442
|
+
|
|
443
|
+
expect(result.config).toBeDefined();
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
it("should handle deep config changes", async () => {
|
|
447
|
+
const component = mount(TestComponent);
|
|
448
|
+
|
|
449
|
+
// Change nested config
|
|
450
|
+
await component.setProps({
|
|
451
|
+
config: {
|
|
452
|
+
body: {
|
|
453
|
+
base: "new-base",
|
|
454
|
+
variants: {
|
|
455
|
+
variant: {
|
|
456
|
+
custom: "custom-class",
|
|
457
|
+
},
|
|
458
|
+
},
|
|
459
|
+
},
|
|
460
|
+
},
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
await nextTick();
|
|
464
|
+
|
|
465
|
+
expect(uiUtils.getMergedConfig).toHaveBeenCalled();
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
describe("Integration Tests", () => {
|
|
470
|
+
it("should work with real component mounting", () => {
|
|
471
|
+
const component = mount(TestComponent);
|
|
472
|
+
|
|
473
|
+
expect(component.exists()).toBe(true);
|
|
474
|
+
expect(component.attributes("data-test")).toBe("test");
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
it("should handle prop changes in mounted component", async () => {
|
|
478
|
+
const component = mount(TestComponent);
|
|
479
|
+
|
|
480
|
+
// The component should render with the default dataTest from the mock
|
|
481
|
+
expect(component.exists()).toBe(true);
|
|
482
|
+
|
|
483
|
+
// Test that the component can handle config changes
|
|
484
|
+
await component.setProps({
|
|
485
|
+
config: {
|
|
486
|
+
body: { base: "new-config-class" },
|
|
487
|
+
},
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
// The component should still exist and function after prop changes
|
|
491
|
+
expect(component.exists()).toBe(true);
|
|
492
|
+
});
|
|
493
|
+
});
|
|
494
|
+
});
|