vueless 1.0.2-beta.8 → 1.0.2-beta.9
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/package.json +4 -4
- package/ui.form-select/USelect.vue +1 -1
- package/ui.text-file/UFile.vue +1 -1
- package/ui.text-file/tests/UFile.test.ts +257 -0
- package/ui.text-files/UFiles.vue +20 -21
- package/ui.text-files/storybook/stories.ts +2 -2
- package/ui.text-files/tests/UFiles.test.ts +325 -0
- package/ui.text-number/tests/UNumber.test.ts +351 -0
- package/utils/node/helper.js +4 -1
- package/utils/node/loaderIcon.js +1 -1
- package/utils/node/vuelessConfig.js +4 -1
- package/utils/storybook.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vueless",
|
|
3
|
-
"version": "1.0.2-beta.
|
|
3
|
+
"version": "1.0.2-beta.9",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Vue Styleless UI Component Library, powered by Tailwind CSS.",
|
|
6
6
|
"keywords": [
|
|
@@ -30,13 +30,13 @@
|
|
|
30
30
|
"scripts": {
|
|
31
31
|
"pre:start": "npx node .scripts/icons",
|
|
32
32
|
"dev:docs": "storybook dev -p 6006 --docs --no-open",
|
|
33
|
-
"dev": "
|
|
33
|
+
"dev": "storybook dev -p 6006 --no-open",
|
|
34
34
|
"build": "storybook build --docs",
|
|
35
35
|
"preview": "vite preview --host --outDir=storybook-static",
|
|
36
36
|
"ts:check": "vue-tsc --build --force",
|
|
37
37
|
"release:prepare": "npm run pre:start && rm -rf dist && mkdir -p dist && cp -r src/. package.json LICENSE README.md dist/ && npx node .scripts/writeLocales",
|
|
38
38
|
"release:beta": "release-it --ci --npm.publish --preRelease=beta --increment=prerelease",
|
|
39
|
-
"release:patch": "release-it patch --ci --npm.publish",
|
|
39
|
+
"release:patch": "release-it patch --ci --npm.publish --git.tag --github.release",
|
|
40
40
|
"release:minor": "release-it minor --ci --npm.publish --git.tag --github.release",
|
|
41
41
|
"release:major": "release-it major --ci --npm.publish --git.tag --github.release",
|
|
42
42
|
"lint": "eslint --no-fix src/ .storybook/",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"@vue/eslint-config-typescript": "^14.5.0",
|
|
76
76
|
"@vue/test-utils": "^2.4.6",
|
|
77
77
|
"@vue/tsconfig": "^0.7.0",
|
|
78
|
-
"@vueless/storybook": "^1.0.
|
|
78
|
+
"@vueless/storybook": "^1.0.1-beta.1",
|
|
79
79
|
"eslint": "^9.27.0",
|
|
80
80
|
"eslint-plugin-storybook": "^0.12.0",
|
|
81
81
|
"eslint-plugin-vue": "^10.1.0",
|
package/ui.text-file/UFile.vue
CHANGED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { mount } from "@vue/test-utils";
|
|
2
|
+
import { describe, it, expect } from "vitest";
|
|
3
|
+
|
|
4
|
+
import UFile from "../UFile.vue";
|
|
5
|
+
import ULink from "../../ui.button-link/ULink.vue";
|
|
6
|
+
import UIcon from "../../ui.image-icon/UIcon.vue";
|
|
7
|
+
|
|
8
|
+
import type { ComponentPublicInstance } from "vue";
|
|
9
|
+
import type { Props } from "../types.ts";
|
|
10
|
+
|
|
11
|
+
describe("UFile.vue", () => {
|
|
12
|
+
// Props tests
|
|
13
|
+
describe("Props", () => {
|
|
14
|
+
// URL prop
|
|
15
|
+
it("passes the correct url to ULink", () => {
|
|
16
|
+
const url = "https://example.com/file.pdf";
|
|
17
|
+
|
|
18
|
+
const component = mount(UFile, {
|
|
19
|
+
props: {
|
|
20
|
+
url,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const linkComponent = component.findComponent(ULink);
|
|
25
|
+
|
|
26
|
+
expect(linkComponent.props("href")).toBe(url);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// ImageUrl prop
|
|
30
|
+
it("renders image when imageUrl prop is provided", () => {
|
|
31
|
+
const imageUrl = "https://example.com/image.jpg";
|
|
32
|
+
|
|
33
|
+
const component = mount(UFile, {
|
|
34
|
+
props: {
|
|
35
|
+
imageUrl,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const image = component.find("img");
|
|
40
|
+
|
|
41
|
+
expect(image.exists()).toBe(true);
|
|
42
|
+
expect(image.attributes("src")).toBe(imageUrl);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Label prop
|
|
46
|
+
it("renders the correct label text", () => {
|
|
47
|
+
const label = "Example File";
|
|
48
|
+
|
|
49
|
+
const component = mount(UFile, {
|
|
50
|
+
props: {
|
|
51
|
+
label,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const linkComponent = component.findComponent(ULink);
|
|
56
|
+
|
|
57
|
+
expect(linkComponent.text()).toContain(label);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Size prop
|
|
61
|
+
it("applies the correct size class", async () => {
|
|
62
|
+
const sizeClasses = {
|
|
63
|
+
sm: "gap-0.5",
|
|
64
|
+
md: "gap-1",
|
|
65
|
+
lg: "gap-1.5",
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
Object.entries(sizeClasses).forEach(([size, classes]) => {
|
|
69
|
+
const component = mount(UFile, {
|
|
70
|
+
props: {
|
|
71
|
+
size: size as Props["size"],
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
expect(component.attributes("class")).toContain(classes);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// ID prop
|
|
80
|
+
it("uses provided id", () => {
|
|
81
|
+
const id = "test-file-id";
|
|
82
|
+
const removable = true;
|
|
83
|
+
|
|
84
|
+
const component = mount(UFile, {
|
|
85
|
+
props: {
|
|
86
|
+
id,
|
|
87
|
+
removable, // Need to set removable to true to show the remove button
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Directly call the onRemove method
|
|
92
|
+
(component.vm as ComponentPublicInstance & { onRemove: () => void }).onRemove();
|
|
93
|
+
|
|
94
|
+
expect(component.emitted("remove")?.[0][0]).toBe(id);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Removable prop
|
|
98
|
+
it("shows remove button when removable prop is true", () => {
|
|
99
|
+
const removable = true;
|
|
100
|
+
const dataTest = "test-file";
|
|
101
|
+
const removeIconDataTest = "test-file-remove-item";
|
|
102
|
+
|
|
103
|
+
const component = mount(UFile, {
|
|
104
|
+
props: {
|
|
105
|
+
removable,
|
|
106
|
+
dataTest,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Get the remove button directly using the same approach as in the event test
|
|
111
|
+
const removeIcon = component.findAllComponents(UIcon).find((component) => {
|
|
112
|
+
return component.props("dataTest") === removeIconDataTest;
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
expect(removeIcon).toBeDefined();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// DataTest prop
|
|
119
|
+
it("applies the correct data-test attribute", () => {
|
|
120
|
+
const dataTest = "test-file";
|
|
121
|
+
|
|
122
|
+
const component = mount(UFile, {
|
|
123
|
+
props: {
|
|
124
|
+
dataTest,
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
expect(component.attributes("data-test")).toBe(dataTest);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Slots tests
|
|
133
|
+
describe("Slots", () => {
|
|
134
|
+
// Default slot
|
|
135
|
+
it("renders content from default slot", () => {
|
|
136
|
+
const slotContent = "Custom Content";
|
|
137
|
+
|
|
138
|
+
const component = mount(UFile, {
|
|
139
|
+
slots: {
|
|
140
|
+
default: slotContent,
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
expect(component.text()).toContain(slotContent);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Default slot with bindings
|
|
148
|
+
it("provides correct bindings to default slot", () => {
|
|
149
|
+
const id = "test-id";
|
|
150
|
+
const label = "Test File";
|
|
151
|
+
const url = "https://example.com/file.pdf";
|
|
152
|
+
const imageUrl = "https://example.com/image.jpg";
|
|
153
|
+
|
|
154
|
+
// Define class names as constants instead of hardcoding them
|
|
155
|
+
const idClass = "file-id";
|
|
156
|
+
const labelClass = "file-label";
|
|
157
|
+
const urlClass = "file-url";
|
|
158
|
+
const imageUrlClass = "file-image-url";
|
|
159
|
+
|
|
160
|
+
const component = mount(UFile, {
|
|
161
|
+
props: {
|
|
162
|
+
id,
|
|
163
|
+
label,
|
|
164
|
+
url,
|
|
165
|
+
imageUrl,
|
|
166
|
+
},
|
|
167
|
+
slots: {
|
|
168
|
+
default: `
|
|
169
|
+
<template #default="{ id, label, url, imageUrl }">
|
|
170
|
+
<div class="${idClass}">{{ id }}</div>
|
|
171
|
+
<div class="${labelClass}">{{ label }}</div>
|
|
172
|
+
<div class="${urlClass}">{{ url }}</div>
|
|
173
|
+
<div class="${imageUrlClass}">{{ imageUrl }}</div>
|
|
174
|
+
</template>
|
|
175
|
+
`,
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
expect(component.find(`.${idClass}`).text()).toBe(id);
|
|
180
|
+
expect(component.find(`.${labelClass}`).text()).toBe(label);
|
|
181
|
+
expect(component.find(`.${urlClass}`).text()).toBe(url);
|
|
182
|
+
expect(component.find(`.${imageUrlClass}`).text()).toBe(imageUrl);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Left slot
|
|
186
|
+
it("renders content from left slot", () => {
|
|
187
|
+
const slotText = "Left";
|
|
188
|
+
const slotClass = "left-content";
|
|
189
|
+
|
|
190
|
+
const component = mount(UFile, {
|
|
191
|
+
slots: {
|
|
192
|
+
left: `<span class='${slotClass}'>${slotText}</span>`,
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(true);
|
|
197
|
+
expect(component.find(`.${slotClass}`).text()).toBe(slotText);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Right slot
|
|
201
|
+
it("renders content from right slot", () => {
|
|
202
|
+
const slotText = "Right";
|
|
203
|
+
const slotClass = "right-content";
|
|
204
|
+
|
|
205
|
+
const component = mount(UFile, {
|
|
206
|
+
slots: {
|
|
207
|
+
right: `<span class='${slotClass}'>${slotText}</span>`,
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(true);
|
|
212
|
+
expect(component.find(`.${slotClass}`).text()).toBe(slotText);
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Events tests
|
|
217
|
+
describe("Events", () => {
|
|
218
|
+
// Remove event
|
|
219
|
+
it("emits remove event when remove button is clicked", async () => {
|
|
220
|
+
const id = "test-file-id";
|
|
221
|
+
const removable = true;
|
|
222
|
+
const dataTest = "test-file";
|
|
223
|
+
const removeIconDataTest = "test-file-remove-item";
|
|
224
|
+
|
|
225
|
+
const component = mount(UFile, {
|
|
226
|
+
props: {
|
|
227
|
+
id,
|
|
228
|
+
removable,
|
|
229
|
+
dataTest,
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
const removeIcon = component.findAllComponents(UIcon).find((component) => {
|
|
234
|
+
return component.props("dataTest") === removeIconDataTest;
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
expect(removeIcon).toBeDefined();
|
|
238
|
+
|
|
239
|
+
// Directly call the onRemove method
|
|
240
|
+
(component.vm as ComponentPublicInstance & { onRemove: () => void }).onRemove();
|
|
241
|
+
|
|
242
|
+
// Check if the remove event was emitted with the correct value
|
|
243
|
+
expect(component.emitted("remove")).toBeTruthy();
|
|
244
|
+
expect(component.emitted("remove")?.[0][0]).toBe(id);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// Exposed refs tests
|
|
249
|
+
describe("Exposed refs", () => {
|
|
250
|
+
// link ref
|
|
251
|
+
it("exposes link ref", () => {
|
|
252
|
+
const component = mount(UFile, {});
|
|
253
|
+
|
|
254
|
+
expect(component.vm.link).toBeDefined();
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
});
|
package/ui.text-files/UFiles.vue
CHANGED
|
@@ -98,36 +98,35 @@ const { getDataTest, filesLabelAttrs, itemsAttrs, itemAttrs } = useUI<Config>(de
|
|
|
98
98
|
>
|
|
99
99
|
<template #left>
|
|
100
100
|
<!--
|
|
101
|
-
@slot Use it to add something
|
|
101
|
+
@slot Use it to add something before the file content.
|
|
102
102
|
@binding {number} index
|
|
103
103
|
-->
|
|
104
|
-
<slot name="
|
|
104
|
+
<slot name="before-file" :index="index" />
|
|
105
105
|
</template>
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
</template>
|
|
107
|
+
<!--
|
|
108
|
+
@slot Use it to add a file directly.
|
|
109
|
+
@binding {string | number} id
|
|
110
|
+
@binding {string} label
|
|
111
|
+
@binding {string} url
|
|
112
|
+
@binding {string} image-url
|
|
113
|
+
@binding {number} index
|
|
114
|
+
-->
|
|
115
|
+
<slot
|
|
116
|
+
:id="file?.id"
|
|
117
|
+
name="file"
|
|
118
|
+
:label="file?.label"
|
|
119
|
+
:url="file?.url"
|
|
120
|
+
:image-url="file?.imageUrl"
|
|
121
|
+
:index="index"
|
|
122
|
+
/>
|
|
124
123
|
|
|
125
124
|
<template #right>
|
|
126
125
|
<!--
|
|
127
|
-
@slot Use it to add something
|
|
126
|
+
@slot Use it to add something after the file content.
|
|
128
127
|
@binding {number} index
|
|
129
128
|
-->
|
|
130
|
-
<slot name="
|
|
129
|
+
<slot name="after-file" :index="index" />
|
|
131
130
|
</template>
|
|
132
131
|
</UFile>
|
|
133
132
|
</slot>
|
|
@@ -92,10 +92,10 @@ export const Slots: StoryFn<UFilesArgs> = (args) => ({
|
|
|
92
92
|
},
|
|
93
93
|
template: `
|
|
94
94
|
<UFiles v-bind="args">
|
|
95
|
-
<template #
|
|
95
|
+
<template #before-file="{ index }">
|
|
96
96
|
<UIcon v-if="index === 0" name="info" color="warning" size="xs" />
|
|
97
97
|
</template>
|
|
98
|
-
<template #
|
|
98
|
+
<template #after-file="{ index }">
|
|
99
99
|
<UIcon v-if="index === 1" name="check_circle" color="success" size="xs" />
|
|
100
100
|
</template>
|
|
101
101
|
</UFiles>
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import { mount } from "@vue/test-utils";
|
|
2
|
+
import { describe, it, expect, beforeAll, afterAll, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
import UFiles from "../UFiles.vue";
|
|
5
|
+
import UFile from "../../ui.text-file/UFile.vue";
|
|
6
|
+
import ULabel from "../../ui.form-label/ULabel.vue";
|
|
7
|
+
|
|
8
|
+
import type { Props } from "../types.ts";
|
|
9
|
+
|
|
10
|
+
// Mock URL.createObjectURL
|
|
11
|
+
const originalCreateObjectURL = URL.createObjectURL;
|
|
12
|
+
const mockCreateObjectURL = vi.fn().mockImplementation((file) => `mock-url-for-${file.name}`);
|
|
13
|
+
|
|
14
|
+
describe("UFiles.vue", () => {
|
|
15
|
+
const fileList = [createMockFile("file1.pdf"), createMockFile("file2.pdf")];
|
|
16
|
+
|
|
17
|
+
// Create a mock File object
|
|
18
|
+
function createMockFile(name: string, type: string = "application/pdf") {
|
|
19
|
+
return new File(["dummy content"], name, { type });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Setup and teardown for URL.createObjectURL mock
|
|
23
|
+
beforeAll(() => {
|
|
24
|
+
// Mock URL.createObjectURL before tests
|
|
25
|
+
URL.createObjectURL = mockCreateObjectURL;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
afterAll(() => {
|
|
29
|
+
// Restore original URL.createObjectURL after tests
|
|
30
|
+
URL.createObjectURL = originalCreateObjectURL;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Props tests
|
|
34
|
+
describe("Props", () => {
|
|
35
|
+
// FileList prop
|
|
36
|
+
it("renders the correct number of files", () => {
|
|
37
|
+
const component = mount(UFiles, {
|
|
38
|
+
props: {
|
|
39
|
+
fileList,
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const fileComponents = component.findAllComponents(UFile);
|
|
44
|
+
|
|
45
|
+
expect(fileComponents.length).toBe(fileList.length);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Label prop
|
|
49
|
+
it("renders the correct label text", () => {
|
|
50
|
+
const label = "File List";
|
|
51
|
+
|
|
52
|
+
const component = mount(UFiles, {
|
|
53
|
+
props: {
|
|
54
|
+
fileList: [],
|
|
55
|
+
label,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const labelComponent = component.findComponent(ULabel);
|
|
60
|
+
|
|
61
|
+
expect(labelComponent.props("label")).toBe(label);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// LabelAlign prop
|
|
65
|
+
it("passes the correct labelAlign to ULabel", () => {
|
|
66
|
+
const labelAligns = ["top", "topWithDesc"];
|
|
67
|
+
|
|
68
|
+
labelAligns.forEach((labelAlign) => {
|
|
69
|
+
const component = mount(UFiles, {
|
|
70
|
+
props: {
|
|
71
|
+
fileList,
|
|
72
|
+
labelAlign: labelAlign as Props["labelAlign"],
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const labelComponent = component.findComponent(ULabel);
|
|
77
|
+
|
|
78
|
+
expect(labelComponent.props("align")).toBe(labelAlign);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Description prop
|
|
83
|
+
it("passes the correct description to ULabel", () => {
|
|
84
|
+
const description = "List of files";
|
|
85
|
+
|
|
86
|
+
const component = mount(UFiles, {
|
|
87
|
+
props: {
|
|
88
|
+
fileList,
|
|
89
|
+
description,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const labelComponent = component.findComponent(ULabel);
|
|
94
|
+
|
|
95
|
+
expect(labelComponent.props("description")).toBe(description);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Size prop
|
|
99
|
+
it("passes the correct size prop to ULabel", () => {
|
|
100
|
+
const sizes = ["sm", "md", "lg"];
|
|
101
|
+
|
|
102
|
+
sizes.forEach((size) => {
|
|
103
|
+
const component = mount(UFiles, {
|
|
104
|
+
props: {
|
|
105
|
+
fileList,
|
|
106
|
+
size: size as Props["size"],
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const labelComponent = component.findComponent(ULabel);
|
|
111
|
+
|
|
112
|
+
expect(labelComponent.props("size")).toBe(size);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Removable prop
|
|
117
|
+
it("passes removable prop to UFile components", () => {
|
|
118
|
+
const removable = true;
|
|
119
|
+
const fileList = [createMockFile("file1.pdf")];
|
|
120
|
+
|
|
121
|
+
const component = mount(UFiles, {
|
|
122
|
+
props: {
|
|
123
|
+
fileList,
|
|
124
|
+
removable,
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const fileComponent = component.findComponent(UFile);
|
|
129
|
+
|
|
130
|
+
expect(fileComponent.props("removable")).toBe(removable);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// DataTest prop
|
|
134
|
+
it("applies the correct data-test attribute to file items", () => {
|
|
135
|
+
const dataTest = "test-files";
|
|
136
|
+
const fileList = [createMockFile("file1.pdf")];
|
|
137
|
+
|
|
138
|
+
const component = mount(UFiles, {
|
|
139
|
+
props: {
|
|
140
|
+
fileList,
|
|
141
|
+
dataTest,
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const fileComponent = component.findComponent(UFile);
|
|
146
|
+
|
|
147
|
+
expect(fileComponent.attributes("data-test")).toBe(`${dataTest}-item-0`);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Image file detection
|
|
151
|
+
it("detects image files and sets imageUrl prop", () => {
|
|
152
|
+
const imageFile = createMockFile("image.jpg", "image/jpeg");
|
|
153
|
+
const fileList = [imageFile];
|
|
154
|
+
|
|
155
|
+
const component = mount(UFiles, {
|
|
156
|
+
props: {
|
|
157
|
+
fileList,
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const fileComponent = component.findComponent(UFile);
|
|
162
|
+
|
|
163
|
+
expect(fileComponent.props("imageUrl")).toBeDefined();
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Slots tests
|
|
168
|
+
describe("Slots", () => {
|
|
169
|
+
// Default slot
|
|
170
|
+
it("renders content from default slot", () => {
|
|
171
|
+
const slotContent = "Custom Content";
|
|
172
|
+
|
|
173
|
+
const component = mount(UFiles, {
|
|
174
|
+
props: {
|
|
175
|
+
fileList: [],
|
|
176
|
+
},
|
|
177
|
+
slots: {
|
|
178
|
+
default: slotContent,
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
expect(component.text()).toContain(slotContent);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Label slot
|
|
186
|
+
it("renders content from label slot", () => {
|
|
187
|
+
const label = "File List";
|
|
188
|
+
const slotText = "Custom Label";
|
|
189
|
+
const slotClass = "label-content";
|
|
190
|
+
|
|
191
|
+
const component = mount(UFiles, {
|
|
192
|
+
props: {
|
|
193
|
+
fileList: [],
|
|
194
|
+
label,
|
|
195
|
+
},
|
|
196
|
+
slots: {
|
|
197
|
+
label: `<span class='${slotClass}'>${slotText}</span>`,
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(true);
|
|
202
|
+
expect(component.find(`.${slotClass}`).text()).toBe(slotText);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Before-file slot
|
|
206
|
+
it("renders content from before-file slot", () => {
|
|
207
|
+
const slotText = "Before";
|
|
208
|
+
const slotClass = "before-content";
|
|
209
|
+
|
|
210
|
+
const component = mount(UFiles, {
|
|
211
|
+
props: {
|
|
212
|
+
fileList,
|
|
213
|
+
},
|
|
214
|
+
slots: {
|
|
215
|
+
"before-file": `
|
|
216
|
+
<template #before-file="{ index }">
|
|
217
|
+
<span class='${slotClass}'>${slotText}{{ index }}</span>
|
|
218
|
+
</template>
|
|
219
|
+
`,
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(true);
|
|
224
|
+
expect(component.find(`.${slotClass}`).text()).toBe(`${slotText}0`);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// After-file slot
|
|
228
|
+
it("renders content from after-file slot", () => {
|
|
229
|
+
const slotText = "After";
|
|
230
|
+
const slotClass = "after-content";
|
|
231
|
+
|
|
232
|
+
const component = mount(UFiles, {
|
|
233
|
+
props: {
|
|
234
|
+
fileList,
|
|
235
|
+
},
|
|
236
|
+
slots: {
|
|
237
|
+
"after-file": `
|
|
238
|
+
<template #after-file="{ index }">
|
|
239
|
+
<span class='${slotClass}'>${slotText}{{ index }}</span>
|
|
240
|
+
</template>
|
|
241
|
+
`,
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(true);
|
|
246
|
+
expect(component.find(`.${slotClass}`).text()).toBe(`${slotText}0`);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// File slot with bindings
|
|
250
|
+
it("provides correct bindings to file slot", () => {
|
|
251
|
+
const fileName = "file1.pdf";
|
|
252
|
+
const fileIndex = "0";
|
|
253
|
+
const fileList = [createMockFile(fileName)];
|
|
254
|
+
|
|
255
|
+
// Define class names as constants instead of hardcoding them
|
|
256
|
+
const idClass = "file-id";
|
|
257
|
+
const labelClass = "file-label";
|
|
258
|
+
const urlClass = "file-url";
|
|
259
|
+
const imageUrlClass = "file-image-url";
|
|
260
|
+
const indexClass = "file-index";
|
|
261
|
+
|
|
262
|
+
const component = mount(UFiles, {
|
|
263
|
+
props: {
|
|
264
|
+
fileList,
|
|
265
|
+
},
|
|
266
|
+
slots: {
|
|
267
|
+
file: `
|
|
268
|
+
<template #file="{ id, label, url, imageUrl, index }">
|
|
269
|
+
<div v-if="id" class="${idClass}">{{ id }}</div>
|
|
270
|
+
<div v-if="label" class="${labelClass}">{{ label }}</div>
|
|
271
|
+
<div v-if="url" class="${urlClass}">{{ url }}</div>
|
|
272
|
+
<div v-if="imageUrl" class="${imageUrlClass}">{{ imageUrl }}</div>
|
|
273
|
+
<div v-if="index >= 0" class="${indexClass}">{{ index }}</div>
|
|
274
|
+
</template>
|
|
275
|
+
`,
|
|
276
|
+
},
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
expect(component.find(`.${idClass}`).exists()).toBe(true);
|
|
280
|
+
expect(component.find(`.${labelClass}`).text()).toBe(fileName);
|
|
281
|
+
expect(component.find(`.${urlClass}`).exists()).toBe(true);
|
|
282
|
+
expect(component.find(`.${imageUrlClass}`).exists()).toBe(false);
|
|
283
|
+
expect(component.find(`.${indexClass}`).text()).toBe(fileIndex);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Events tests
|
|
288
|
+
describe("Events", () => {
|
|
289
|
+
// Remove event
|
|
290
|
+
it("emits remove event when file is removed", async () => {
|
|
291
|
+
const fileList = [createMockFile("file1.pdf")];
|
|
292
|
+
const fileId = "test-id";
|
|
293
|
+
const removable = true;
|
|
294
|
+
|
|
295
|
+
const component = mount(UFiles, {
|
|
296
|
+
props: {
|
|
297
|
+
fileList,
|
|
298
|
+
removable,
|
|
299
|
+
},
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// Find the UFile component and trigger its remove event
|
|
303
|
+
const fileComponent = component.findComponent(UFile);
|
|
304
|
+
|
|
305
|
+
await fileComponent.vm.$emit("remove", fileId);
|
|
306
|
+
|
|
307
|
+
expect(component.emitted("remove")).toBeTruthy();
|
|
308
|
+
expect(component.emitted("remove")?.[0][0]).toBe(fileId);
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// Exposed refs tests
|
|
313
|
+
describe("Exposed refs", () => {
|
|
314
|
+
// itemsRef
|
|
315
|
+
it("exposes itemsRef", () => {
|
|
316
|
+
const component = mount(UFiles, {
|
|
317
|
+
props: {
|
|
318
|
+
fileList: [],
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
expect(component.vm.itemsRef).toBeDefined();
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
});
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { mount } from "@vue/test-utils";
|
|
2
|
+
import { describe, it, expect, beforeAll } from "vitest";
|
|
3
|
+
|
|
4
|
+
import UNumber from "../UNumber.vue";
|
|
5
|
+
import { MATH_SIGN, MATH_SIGN_TYPE } from "../utilNumber.ts";
|
|
6
|
+
|
|
7
|
+
import type { Props } from "../types.ts";
|
|
8
|
+
|
|
9
|
+
describe("UNumber.vue", () => {
|
|
10
|
+
let value: number;
|
|
11
|
+
|
|
12
|
+
beforeAll(() => {
|
|
13
|
+
value = 1234.56;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// Props tests
|
|
17
|
+
describe("Props", () => {
|
|
18
|
+
// Size prop
|
|
19
|
+
it("applies the correct size class", async () => {
|
|
20
|
+
const sizeClasses = {
|
|
21
|
+
xs: "text-tiny",
|
|
22
|
+
sm: "text-small",
|
|
23
|
+
md: "text-medium",
|
|
24
|
+
lg: "text-large",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
Object.entries(sizeClasses).forEach(([size, classes]) => {
|
|
28
|
+
const component = mount(UNumber, {
|
|
29
|
+
props: {
|
|
30
|
+
size: size as Props["size"],
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
expect(component.attributes("class")).toContain(classes);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Color prop
|
|
39
|
+
it("applies the correct color class", async () => {
|
|
40
|
+
const colors = [
|
|
41
|
+
"primary",
|
|
42
|
+
"secondary",
|
|
43
|
+
"error",
|
|
44
|
+
"warning",
|
|
45
|
+
"success",
|
|
46
|
+
"info",
|
|
47
|
+
"notice",
|
|
48
|
+
"neutral",
|
|
49
|
+
"grayscale",
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
colors.forEach((color) => {
|
|
53
|
+
const component = mount(UNumber, {
|
|
54
|
+
props: {
|
|
55
|
+
color: color as Props["color"],
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
expect(component.attributes("class")).toContain(color);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Value prop
|
|
64
|
+
it("renders the correct number value", () => {
|
|
65
|
+
const expectedFormattedNumber = "1 234,56";
|
|
66
|
+
|
|
67
|
+
const component = mount(UNumber, {
|
|
68
|
+
props: {
|
|
69
|
+
value,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
expect(component.text()).toContain(expectedFormattedNumber);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Sign prop
|
|
77
|
+
it("renders the correct sign based on sign prop", () => {
|
|
78
|
+
const testNegativeValue = -123;
|
|
79
|
+
|
|
80
|
+
// Auto sign (negative value)
|
|
81
|
+
// Should show minus sign for negative values
|
|
82
|
+
const autoComponent = mount(UNumber, {
|
|
83
|
+
props: {
|
|
84
|
+
value: testNegativeValue,
|
|
85
|
+
sign: MATH_SIGN_TYPE.auto as Props["sign"],
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
expect(autoComponent.text()).toContain(MATH_SIGN.MINUS);
|
|
90
|
+
|
|
91
|
+
// Auto sign (positive value)
|
|
92
|
+
// Should not show any sign for positive values
|
|
93
|
+
const autoPositiveComponent = mount(UNumber, {
|
|
94
|
+
props: {
|
|
95
|
+
value,
|
|
96
|
+
sign: MATH_SIGN_TYPE.auto as Props["sign"],
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
expect(autoPositiveComponent.text()).not.toContain(MATH_SIGN.MINUS);
|
|
101
|
+
expect(autoPositiveComponent.text()).not.toContain(MATH_SIGN.PLUS);
|
|
102
|
+
|
|
103
|
+
// Positive sign
|
|
104
|
+
// Should show plus sign regardless of value
|
|
105
|
+
const positiveComponent = mount(UNumber, {
|
|
106
|
+
props: {
|
|
107
|
+
value,
|
|
108
|
+
sign: MATH_SIGN_TYPE.positive as Props["sign"],
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
expect(positiveComponent.text()).toContain(MATH_SIGN.PLUS);
|
|
113
|
+
|
|
114
|
+
// Negative sign
|
|
115
|
+
// Should show minus sign regardless of value
|
|
116
|
+
const negativeComponent = mount(UNumber, {
|
|
117
|
+
props: {
|
|
118
|
+
value,
|
|
119
|
+
sign: MATH_SIGN_TYPE.negative as Props["sign"],
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
expect(negativeComponent.text()).toContain(MATH_SIGN.MINUS);
|
|
124
|
+
|
|
125
|
+
// Unsigned
|
|
126
|
+
// Should not show any sign regardless of value
|
|
127
|
+
const unsignedComponent = mount(UNumber, {
|
|
128
|
+
props: {
|
|
129
|
+
value: testNegativeValue,
|
|
130
|
+
sign: MATH_SIGN_TYPE.unsigned as Props["sign"],
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
expect(unsignedComponent.text()).not.toContain(MATH_SIGN.MINUS);
|
|
135
|
+
expect(unsignedComponent.text()).not.toContain(MATH_SIGN.PLUS);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Currency prop
|
|
139
|
+
it("renders the currency symbol", () => {
|
|
140
|
+
const currency = "$";
|
|
141
|
+
|
|
142
|
+
const component = mount(UNumber, {
|
|
143
|
+
props: {
|
|
144
|
+
value,
|
|
145
|
+
currency,
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
expect(component.text()).toContain(currency);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// CurrencyAlign prop
|
|
153
|
+
it("aligns currency correctly based on currencyAlign prop", () => {
|
|
154
|
+
const currency = "$";
|
|
155
|
+
|
|
156
|
+
const alignTests = [
|
|
157
|
+
{ align: "left", expectation: (text: string) => text.startsWith(currency) },
|
|
158
|
+
{ align: "right", expectation: (text: string) => text.endsWith(currency) },
|
|
159
|
+
];
|
|
160
|
+
|
|
161
|
+
alignTests.forEach(({ align, expectation }) => {
|
|
162
|
+
const component = mount(UNumber, {
|
|
163
|
+
props: {
|
|
164
|
+
value,
|
|
165
|
+
currency,
|
|
166
|
+
currencyAlign: align as Props["currencyAlign"],
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
expect(expectation(component.text())).toBe(true);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// CurrencySpace prop
|
|
175
|
+
it("adds space between currency and number when currencySpace is true", () => {
|
|
176
|
+
const currency = "$";
|
|
177
|
+
|
|
178
|
+
const spaceTests = [
|
|
179
|
+
{ space: true, align: "left" },
|
|
180
|
+
{ space: false, align: "left" },
|
|
181
|
+
{ space: true, align: "right" },
|
|
182
|
+
{ space: false, align: "right" },
|
|
183
|
+
];
|
|
184
|
+
|
|
185
|
+
spaceTests.forEach(({ space, align }) => {
|
|
186
|
+
const component = mount(UNumber, {
|
|
187
|
+
props: {
|
|
188
|
+
value,
|
|
189
|
+
currency,
|
|
190
|
+
currencySpace: space,
|
|
191
|
+
currencyAlign: align as Props["currencyAlign"],
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
expect(component.html()).toContain(currency);
|
|
196
|
+
// Visual inspection of spacing would be done in a real browser
|
|
197
|
+
// Here we just verify the component renders with the given props
|
|
198
|
+
expect(component.props().currencySpace).toBe(space);
|
|
199
|
+
expect(component.props().currencyAlign).toBe(align);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// MinFractionDigits prop
|
|
204
|
+
it("adds zeros to meet the minimum fraction digits requirement", () => {
|
|
205
|
+
const value = 123;
|
|
206
|
+
const minFractionDigits = 2;
|
|
207
|
+
const expectedMinFractionResult = "123,00";
|
|
208
|
+
|
|
209
|
+
const component = mount(UNumber, {
|
|
210
|
+
props: {
|
|
211
|
+
value,
|
|
212
|
+
minFractionDigits,
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
expect(component.text()).toContain(expectedMinFractionResult);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// MaxFractionDigits prop
|
|
220
|
+
it("rounds the fraction to the maximum number of digits", () => {
|
|
221
|
+
const value = 123.456789;
|
|
222
|
+
const maxFractionDigits = 2;
|
|
223
|
+
const expectedMaxFractionResult = "123,46"; // Rounded from .456789 to 2 digits
|
|
224
|
+
|
|
225
|
+
const component = mount(UNumber, {
|
|
226
|
+
props: {
|
|
227
|
+
value,
|
|
228
|
+
maxFractionDigits,
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
expect(component.text()).toContain(expectedMaxFractionResult);
|
|
233
|
+
// Original decimal part should not be present
|
|
234
|
+
const originalDecimalPart = value.toString().split(".")[1];
|
|
235
|
+
|
|
236
|
+
expect(component.text()).not.toContain(originalDecimalPart);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// DecimalSeparator prop
|
|
240
|
+
it("uses the correct decimal separator", () => {
|
|
241
|
+
const value = 123.45;
|
|
242
|
+
const decimalSeparator = ",";
|
|
243
|
+
const expectedFormattedNumber = "123,45";
|
|
244
|
+
|
|
245
|
+
const component = mount(UNumber, {
|
|
246
|
+
props: {
|
|
247
|
+
value,
|
|
248
|
+
decimalSeparator,
|
|
249
|
+
},
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
expect(component.text()).toContain(expectedFormattedNumber);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// ThousandsSeparator prop
|
|
256
|
+
it("uses the correct thousands separator", () => {
|
|
257
|
+
const value = 1234567.89;
|
|
258
|
+
const thousandsSeparator = " ";
|
|
259
|
+
const expectedFormattedInteger = "1 234 567";
|
|
260
|
+
|
|
261
|
+
const component = mount(UNumber, {
|
|
262
|
+
props: {
|
|
263
|
+
value,
|
|
264
|
+
thousandsSeparator,
|
|
265
|
+
},
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
expect(component.text()).toContain(expectedFormattedInteger);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// Align prop
|
|
272
|
+
it("applies the correct align class", () => {
|
|
273
|
+
const alignClasses = {
|
|
274
|
+
left: "justify-start",
|
|
275
|
+
right: "justify-end",
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
Object.entries(alignClasses).forEach(([align, classes]) => {
|
|
279
|
+
const component = mount(UNumber, {
|
|
280
|
+
props: {
|
|
281
|
+
align: align as Props["align"],
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
expect(component.attributes("class")).toContain(classes);
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// DataTest prop
|
|
290
|
+
it("applies the correct data-test attribute", () => {
|
|
291
|
+
const testDataTest = "test-number";
|
|
292
|
+
|
|
293
|
+
const component = mount(UNumber, {
|
|
294
|
+
props: {
|
|
295
|
+
dataTest: testDataTest,
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
expect(component.find("[data-test]").attributes("data-test")).toBe(testDataTest);
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Slots tests
|
|
304
|
+
describe("Slots", () => {
|
|
305
|
+
// Left slot
|
|
306
|
+
it("renders content from left slot", () => {
|
|
307
|
+
const slotText = "Left";
|
|
308
|
+
const slotClass = "left-content";
|
|
309
|
+
|
|
310
|
+
const component = mount(UNumber, {
|
|
311
|
+
props: {
|
|
312
|
+
value,
|
|
313
|
+
},
|
|
314
|
+
slots: {
|
|
315
|
+
left: `<span class='${slotClass}'>${slotText}</span>`,
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(true);
|
|
320
|
+
expect(component.find(`.${slotClass}`).text()).toBe(slotText);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// Right slot
|
|
324
|
+
it("renders content from right slot", () => {
|
|
325
|
+
const slotText = "Right";
|
|
326
|
+
const slotClass = "right-content";
|
|
327
|
+
|
|
328
|
+
const component = mount(UNumber, {
|
|
329
|
+
props: {
|
|
330
|
+
value,
|
|
331
|
+
},
|
|
332
|
+
slots: {
|
|
333
|
+
right: `<span class='${slotClass}'>${slotText}</span>`,
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(true);
|
|
338
|
+
expect(component.find(`.${slotClass}`).text()).toBe(slotText);
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
// Exposed refs tests
|
|
343
|
+
describe("Exposed refs", () => {
|
|
344
|
+
// wrapperRef
|
|
345
|
+
it("exposes wrapperRef", () => {
|
|
346
|
+
const component = mount(UNumber, {});
|
|
347
|
+
|
|
348
|
+
expect(component.vm.wrapperRef).toBeDefined();
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
});
|
package/utils/node/helper.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import esbuild from "esbuild";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { cwd } from "node:process";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
4
5
|
import { existsSync, statSync } from "node:fs";
|
|
5
6
|
import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
|
|
6
7
|
|
|
@@ -100,7 +101,9 @@ export async function getDefaultComponentConfig(name, configDir) {
|
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
if (existsSync(configOutPath)) {
|
|
103
|
-
|
|
104
|
+
const module = await import(pathToFileURL(configOutPath));
|
|
105
|
+
|
|
106
|
+
config = module.default;
|
|
104
107
|
}
|
|
105
108
|
|
|
106
109
|
return config;
|
package/utils/node/loaderIcon.js
CHANGED
|
@@ -125,7 +125,7 @@ export function generateIconExports() {
|
|
|
125
125
|
const entries = files
|
|
126
126
|
.map((relativePath) => {
|
|
127
127
|
const fullImportPath = path.resolve(cachePath, relativePath).replace(/\\/g, "/");
|
|
128
|
-
const virtualPath = path.join(cwd(), ICONS_CACHED_DIR, relativePath);
|
|
128
|
+
const virtualPath = path.join(cwd(), ICONS_CACHED_DIR, relativePath).replace(/\\/g, "/");
|
|
129
129
|
|
|
130
130
|
return ` ["${virtualPath}", import("${fullImportPath}?component")]`;
|
|
131
131
|
})
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { cwd } from "node:process";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
4
5
|
import { defineConfig } from "cva";
|
|
5
6
|
import { createGetMergedConfig } from "./mergeConfigs.js";
|
|
6
7
|
import { merge } from "lodash-es";
|
|
@@ -35,7 +36,9 @@ export let vuelessConfig = {};
|
|
|
35
36
|
fs.existsSync(configPathTs) && (await buildTSFile(configPathTs, configOutPath));
|
|
36
37
|
|
|
37
38
|
if (fs.existsSync(configOutPath)) {
|
|
38
|
-
|
|
39
|
+
const module = await import(pathToFileURL(configOutPath));
|
|
40
|
+
|
|
41
|
+
vuelessConfig = module.default;
|
|
39
42
|
}
|
|
40
43
|
})();
|
|
41
44
|
|
package/utils/storybook.ts
CHANGED
|
@@ -304,7 +304,7 @@ export function getArgTypes(componentName: string | undefined) {
|
|
|
304
304
|
description: event.description,
|
|
305
305
|
};
|
|
306
306
|
|
|
307
|
-
if (import.meta.env.
|
|
307
|
+
if (import.meta.env.DEV) {
|
|
308
308
|
const eventName = "on" + event.name.charAt(0).toUpperCase() + event.name.slice(1);
|
|
309
309
|
|
|
310
310
|
types[eventName] = {
|