vueless 1.1.1-beta.2 → 1.1.1-beta.20
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/adapter.locale/vue-i18n.ts +3 -2
- package/adapter.locale/vueless.ts +2 -23
- package/composables/tests/useUI.test.ts +28 -13
- package/composables/useComponentLocaleMassages.ts +6 -3
- package/composables/useLocale.ts +2 -2
- package/constants.js +2 -5
- package/directives/tooltip/storybook/docs.mdx +37 -0
- package/directives/tooltip/storybook/stories.ts +11 -8
- package/directives/tooltip/vTooltip.ts +1 -2
- package/icons/storybook/contact_mail.svg +1 -0
- package/icons/storybook/vpn_key.svg +1 -0
- package/icons/storybook/web_traffic.svg +1 -0
- package/index.d.ts +2 -1
- package/index.ts +2 -1
- package/package.json +2 -3
- package/plugin-vite.js +1 -8
- package/tailwind.css +25 -0
- package/types.ts +21 -1
- package/ui.boilerplate/tests/UBoilerplate.test.ts +2 -24
- package/ui.container-accordion/UAccordion.vue +15 -2
- package/ui.container-accordion/config.ts +1 -0
- package/ui.container-accordion/storybook/stories.ts +28 -1
- package/ui.container-accordion/tests/UAccordion.test.ts +46 -0
- package/ui.data-list/UDataList.vue +2 -0
- package/ui.data-table/UTable.vue +19 -13
- package/ui.data-table/storybook/stories.ts +11 -0
- package/ui.data-table/tests/UTable.test.ts +18 -0
- package/ui.dropdown-button/UDropdownButton.vue +1 -0
- package/ui.dropdown-button/config.ts +9 -1
- package/ui.dropdown-button/storybook/stories.ts +1 -1
- package/ui.dropdown-button/tests/UDropdownButton.test.ts +17 -1
- package/ui.dropdown-button/types.ts +5 -0
- package/ui.form-calendar/UCalendar.vue +9 -7
- package/ui.form-input/tests/UInput.test.ts +1 -1
- package/ui.form-input-counter/tests/UInputCounter.test.ts +1 -1
- package/ui.form-input-file/tests/UInputFile.test.ts +1 -1
- package/ui.form-input-password/tests/UInputPassword.test.ts +3 -3
- package/ui.form-input-rating/tests/UInputRating.test.ts +2 -2
- package/ui.form-input-search/tests/UInputSearch.test.ts +2 -2
- package/ui.form-listbox/UListbox.vue +1 -1
- package/ui.form-listbox/storybook/stories.ts +5 -5
- package/ui.form-select/config.ts +1 -1
- package/ui.form-select/storybook/stories.ts +5 -5
- package/ui.image-icon/tests/UIcon.test.ts +2 -2
- package/ui.navigation-pagination/UPagination.vue +2 -7
- package/ui.navigation-pagination/config.ts +1 -0
- package/ui.navigation-pagination/tests/UPagination.test.ts +1 -1
- package/ui.navigation-pagination/types.ts +1 -1
- package/ui.text-notify/tests/UNotify.test.ts +1 -1
- package/utils/node/dynamicProps.js +17 -8
- package/utils/node/helper.js +11 -1
- package/utils/node/storybook.js +52 -0
- package/utils/node/vuelessConfig.js +18 -8
- package/utils/theme.ts +13 -11
- package/utils/node/dynamicStories.js +0 -62
|
@@ -82,10 +82,12 @@ describe("UAccordion", () => {
|
|
|
82
82
|
// ID prop
|
|
83
83
|
it("uses provided id prop", () => {
|
|
84
84
|
const id = "custom-id";
|
|
85
|
+
const description = "some text";
|
|
85
86
|
|
|
86
87
|
const component = mount(UAccordion, {
|
|
87
88
|
props: {
|
|
88
89
|
id,
|
|
90
|
+
description,
|
|
89
91
|
},
|
|
90
92
|
});
|
|
91
93
|
|
|
@@ -173,6 +175,50 @@ describe("UAccordion", () => {
|
|
|
173
175
|
|
|
174
176
|
expect(toggleElement.attributes("data-opened")).toBe("true");
|
|
175
177
|
});
|
|
178
|
+
|
|
179
|
+
// Default slot
|
|
180
|
+
it("renders default slot content when accordion is opened", async () => {
|
|
181
|
+
const slotContent = "Custom accordion content";
|
|
182
|
+
const slotClass = "custom-content";
|
|
183
|
+
|
|
184
|
+
const component = mount(UAccordion, {
|
|
185
|
+
slots: {
|
|
186
|
+
default: `<div class="${slotClass}">${slotContent}</div>`,
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(false);
|
|
191
|
+
|
|
192
|
+
await component.trigger("click");
|
|
193
|
+
|
|
194
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(true);
|
|
195
|
+
expect(component.find(`.${slotClass}`).text()).toBe(slotContent);
|
|
196
|
+
|
|
197
|
+
await component.trigger("click");
|
|
198
|
+
|
|
199
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(false);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("does not render default slot content when accordion is closed", () => {
|
|
203
|
+
const slotContent = "Custom accordion content";
|
|
204
|
+
const slotClass = "custom-content";
|
|
205
|
+
|
|
206
|
+
const component = mount(UAccordion, {
|
|
207
|
+
slots: {
|
|
208
|
+
default: `<div class="${slotClass}">${slotContent}</div>`,
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
expect(component.find(`.${slotClass}`).exists()).toBe(false);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("does not render content wrapper when default slot is empty", async () => {
|
|
216
|
+
const component = mount(UAccordion);
|
|
217
|
+
|
|
218
|
+
await component.trigger("click");
|
|
219
|
+
|
|
220
|
+
expect(component.find("[vl-key='content']").exists()).toBe(false);
|
|
221
|
+
});
|
|
176
222
|
});
|
|
177
223
|
|
|
178
224
|
// Events
|
|
@@ -186,6 +186,7 @@ const {
|
|
|
186
186
|
:data-test="getDataTest('table')"
|
|
187
187
|
@drag-sort="onDragEnd"
|
|
188
188
|
>
|
|
189
|
+
<!-- @vue-ignore -->
|
|
189
190
|
<template #label="slotProps: { item: DataListItem; crossed: boolean }">
|
|
190
191
|
<!--
|
|
191
192
|
@slot Use it to modify label.
|
|
@@ -200,6 +201,7 @@ const {
|
|
|
200
201
|
</slot>
|
|
201
202
|
</template>
|
|
202
203
|
|
|
204
|
+
<!-- @vue-ignore -->
|
|
203
205
|
<template #actions="slotProps: { item: DataListItem }">
|
|
204
206
|
<!--
|
|
205
207
|
@slot Use it to add custom actions.
|
package/ui.data-table/UTable.vue
CHANGED
|
@@ -378,9 +378,7 @@ function onChangeLocalSelectedRows(selectedRows: Row[]) {
|
|
|
378
378
|
|
|
379
379
|
selectAll.value = !!selectedRows.length;
|
|
380
380
|
|
|
381
|
-
|
|
382
|
-
emit("update:selectedRows", localSelectedRows.value);
|
|
383
|
-
}
|
|
381
|
+
emit("update:selectedRows", localSelectedRows.value);
|
|
384
382
|
}
|
|
385
383
|
|
|
386
384
|
function clearSelectedItems() {
|
|
@@ -533,11 +531,15 @@ const {
|
|
|
533
531
|
:data-test="getDataTest('select-all')"
|
|
534
532
|
/>
|
|
535
533
|
|
|
536
|
-
<div
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
534
|
+
<div v-if="localSelectedRows.length" v-bind="stickyHeaderCounterAttrs">
|
|
535
|
+
<!--
|
|
536
|
+
@slot Use it to customize header counter.
|
|
537
|
+
@binding {number} total
|
|
538
|
+
-->
|
|
539
|
+
<slot name="header-counter" :total="localSelectedRows.length">
|
|
540
|
+
{{ localSelectedRows.length }}
|
|
541
|
+
</slot>
|
|
542
|
+
</div>
|
|
541
543
|
</div>
|
|
542
544
|
|
|
543
545
|
<!-- TODO: Remove any when key attrs are typed-->
|
|
@@ -659,11 +661,15 @@ const {
|
|
|
659
661
|
:data-test="getDataTest('select-all')"
|
|
660
662
|
/>
|
|
661
663
|
|
|
662
|
-
<div
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
664
|
+
<div v-if="localSelectedRows.length" v-bind="headerCounterAttrs">
|
|
665
|
+
<!--
|
|
666
|
+
@slot Use it to customize header counter.
|
|
667
|
+
@binding {number} total
|
|
668
|
+
-->
|
|
669
|
+
<slot name="header-counter" :total="localSelectedRows.length">
|
|
670
|
+
{{ localSelectedRows.length }}
|
|
671
|
+
</slot>
|
|
672
|
+
</div>
|
|
667
673
|
</th>
|
|
668
674
|
|
|
669
675
|
<th
|
|
@@ -474,6 +474,17 @@ DateDividerCustomLabel.parameters = {
|
|
|
474
474
|
},
|
|
475
475
|
};
|
|
476
476
|
|
|
477
|
+
export const HeaderCounterSlot = DefaultTemplate.bind({});
|
|
478
|
+
HeaderCounterSlot.args = {
|
|
479
|
+
selectable: true,
|
|
480
|
+
config: { headerCellCheckbox: "w-20" },
|
|
481
|
+
slotTemplate: `
|
|
482
|
+
<template #header-counter="{ total }">
|
|
483
|
+
Total: {{ total }}
|
|
484
|
+
</template>
|
|
485
|
+
`,
|
|
486
|
+
};
|
|
487
|
+
|
|
477
488
|
export const HeaderKeySlot = DefaultTemplate.bind({});
|
|
478
489
|
HeaderKeySlot.args = {
|
|
479
490
|
slotTemplate: `
|
|
@@ -294,6 +294,24 @@ describe("UTable.vue", () => {
|
|
|
294
294
|
});
|
|
295
295
|
|
|
296
296
|
describe("Slots", () => {
|
|
297
|
+
it("Header Counter Slot – renders custom header counter content", () => {
|
|
298
|
+
const customHeaderCounterContent = "Custom Header Counter";
|
|
299
|
+
|
|
300
|
+
const component = mountUTable(
|
|
301
|
+
getDefaultProps({
|
|
302
|
+
selectable: true,
|
|
303
|
+
selectedRows: [defaultRows[0]],
|
|
304
|
+
}),
|
|
305
|
+
{
|
|
306
|
+
slots: {
|
|
307
|
+
"header-counter": customHeaderCounterContent,
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
expect(component.text()).toContain(customHeaderCounterContent);
|
|
313
|
+
});
|
|
314
|
+
|
|
297
315
|
it("Header Slot – renders custom header content", () => {
|
|
298
316
|
const customHeaderContent = "Custom Name Header";
|
|
299
317
|
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
export default /*tw*/ {
|
|
2
|
-
wrapper:
|
|
2
|
+
wrapper: {
|
|
3
|
+
base: "relative inline-block h-max",
|
|
4
|
+
variants: {
|
|
5
|
+
block: {
|
|
6
|
+
true: "w-full",
|
|
7
|
+
},
|
|
8
|
+
},
|
|
9
|
+
},
|
|
3
10
|
dropdownButton: "{UButton} justify-between",
|
|
4
11
|
toggleIcon: {
|
|
5
12
|
base: "{UIcon} transition duration-300 -mr-1",
|
|
@@ -48,6 +55,7 @@ export default /*tw*/ {
|
|
|
48
55
|
xPosition: "left",
|
|
49
56
|
searchable: false,
|
|
50
57
|
round: false,
|
|
58
|
+
block: false,
|
|
51
59
|
square: false,
|
|
52
60
|
disabled: false,
|
|
53
61
|
multiple: false,
|
|
@@ -207,6 +207,22 @@ describe("UDropdownButton.vue", () => {
|
|
|
207
207
|
expect(component.findComponent(UButton).props("disabled")).toBe(disabled);
|
|
208
208
|
});
|
|
209
209
|
|
|
210
|
+
// Block prop
|
|
211
|
+
it("applies class when prop is true", () => {
|
|
212
|
+
const block = true;
|
|
213
|
+
const expectedClass = "w-full";
|
|
214
|
+
|
|
215
|
+
const component = mount(UDropdownButton, {
|
|
216
|
+
props: {
|
|
217
|
+
block,
|
|
218
|
+
options: defaultOptions,
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
expect(component.attributes("class")).toContain(expectedClass);
|
|
223
|
+
expect(component.findComponent(UButton).attributes("class")).toContain(expectedClass);
|
|
224
|
+
});
|
|
225
|
+
|
|
210
226
|
// ToggleIcon prop (boolean: true)
|
|
211
227
|
it("shows default toggle icon when toggleIcon is true", () => {
|
|
212
228
|
const toggleIcon = true;
|
|
@@ -225,7 +241,7 @@ describe("UDropdownButton.vue", () => {
|
|
|
225
241
|
});
|
|
226
242
|
|
|
227
243
|
// ToggleIcon prop (boolean: false)
|
|
228
|
-
it("shows default toggle icon when toggleIcon is
|
|
244
|
+
it("shows default toggle icon when toggleIcon is false", () => {
|
|
229
245
|
const toggleIcon = false;
|
|
230
246
|
|
|
231
247
|
const component = mount(UDropdownButton, {
|
|
@@ -232,13 +232,15 @@ const localValue = computed({
|
|
|
232
232
|
parsedDate.setSeconds(Number(secondsRef.value?.value));
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
-
const isOutOfRange =
|
|
236
|
-
parsedDate
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
235
|
+
const isOutOfRange =
|
|
236
|
+
parsedDate !== null &&
|
|
237
|
+
dateIsOutOfRange(
|
|
238
|
+
parsedDate,
|
|
239
|
+
props.minDate,
|
|
240
|
+
props.maxDate,
|
|
241
|
+
locale.value,
|
|
242
|
+
actualDateFormat.value,
|
|
243
|
+
);
|
|
242
244
|
|
|
243
245
|
if (isOutOfRange) {
|
|
244
246
|
return;
|
|
@@ -291,7 +291,7 @@ describe("UInput.vue", () => {
|
|
|
291
291
|
expect(component.get("input").attributes("id")).toBe(idValue);
|
|
292
292
|
});
|
|
293
293
|
|
|
294
|
-
it("
|
|
294
|
+
it("Data Test – sets data-test attribute on input", () => {
|
|
295
295
|
const dataTestValue = "test-input";
|
|
296
296
|
|
|
297
297
|
const component = mount(UInput, {
|
|
@@ -172,7 +172,7 @@ describe("UInputPassword.vue", () => {
|
|
|
172
172
|
|
|
173
173
|
await flushPromises();
|
|
174
174
|
|
|
175
|
-
component.get(`[data-test='${dataTest}-password-icon']`);
|
|
175
|
+
expect(component.get(`[data-test='${dataTest}-password-icon']`)).toBeTruthy();
|
|
176
176
|
});
|
|
177
177
|
});
|
|
178
178
|
|
|
@@ -215,7 +215,7 @@ describe("UInputPassword.vue", () => {
|
|
|
215
215
|
},
|
|
216
216
|
});
|
|
217
217
|
|
|
218
|
-
component.get(`.${testClass}`);
|
|
218
|
+
expect(component.get(`.${testClass}`)).toBeTruthy();
|
|
219
219
|
});
|
|
220
220
|
|
|
221
221
|
it("Left – exposes leftIcon prop", () => {
|
|
@@ -242,7 +242,7 @@ describe("UInputPassword.vue", () => {
|
|
|
242
242
|
},
|
|
243
243
|
});
|
|
244
244
|
|
|
245
|
-
component.get(`.${testClass}`);
|
|
245
|
+
expect(component.get(`.${testClass}`)).toBeTruthy();
|
|
246
246
|
});
|
|
247
247
|
|
|
248
248
|
it("Right – exposes password visibility state", async () => {
|
|
@@ -18,8 +18,8 @@ describe("UInputRating.vue", () => {
|
|
|
18
18
|
|
|
19
19
|
const icons = component.findAllComponents(UIcon);
|
|
20
20
|
|
|
21
|
-
expect(icons[2].props("name")).
|
|
22
|
-
expect(icons[3].props("name")).
|
|
21
|
+
expect(icons[2].props("name")).toContain("star-fill");
|
|
22
|
+
expect(icons[3].props("name")).toContain("star");
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
it("Model Value – updates value on click", async () => {
|
|
@@ -227,7 +227,7 @@ describe("UInputSearch.vue", () => {
|
|
|
227
227
|
expect(component.get("input").attributes("disabled")).toBeDefined();
|
|
228
228
|
});
|
|
229
229
|
|
|
230
|
-
it("Data Test – applies the correct data-test attribute",
|
|
230
|
+
it("Data Test – applies the correct data-test attribute", () => {
|
|
231
231
|
const testCases = [
|
|
232
232
|
{ testCase: "search-icon" },
|
|
233
233
|
{ testCase: "clear" },
|
|
@@ -248,7 +248,7 @@ describe("UInputSearch.vue", () => {
|
|
|
248
248
|
|
|
249
249
|
await flushPromises();
|
|
250
250
|
|
|
251
|
-
component.get(`[data-test='${resolvedDataTest}']`);
|
|
251
|
+
expect(component.get(`[data-test='${resolvedDataTest}']`)).toBeTruthy();
|
|
252
252
|
});
|
|
253
253
|
});
|
|
254
254
|
});
|
|
@@ -26,11 +26,11 @@ export default {
|
|
|
26
26
|
component: UListbox,
|
|
27
27
|
args: {
|
|
28
28
|
options: [
|
|
29
|
-
{ label: "New York", id:
|
|
30
|
-
{ label: "Los Angeles", id:
|
|
31
|
-
{ label: "Chicago", id:
|
|
32
|
-
{ label: "Houston", id:
|
|
33
|
-
{ label: "San Francisco", id:
|
|
29
|
+
{ label: "New York", id: 1 },
|
|
30
|
+
{ label: "Los Angeles", id: 2 },
|
|
31
|
+
{ label: "Chicago", id: 3 },
|
|
32
|
+
{ label: "Houston", id: 4 },
|
|
33
|
+
{ label: "San Francisco", id: 5 },
|
|
34
34
|
],
|
|
35
35
|
},
|
|
36
36
|
argTypes: {
|
package/ui.form-select/config.ts
CHANGED
|
@@ -118,7 +118,7 @@ export default /*tw*/ {
|
|
|
118
118
|
clear: "{>toggle}",
|
|
119
119
|
clearIcon: "{UIcon} {>selectIcon}",
|
|
120
120
|
placeholder: {
|
|
121
|
-
base: "flex items-center text-muted !leading-none",
|
|
121
|
+
base: "flex items-center text-muted !leading-none shrink-0",
|
|
122
122
|
variants: {
|
|
123
123
|
size: {
|
|
124
124
|
sm: "text-small",
|
|
@@ -38,11 +38,11 @@ export default {
|
|
|
38
38
|
label: "Choose a city",
|
|
39
39
|
modelValue: null,
|
|
40
40
|
options: [
|
|
41
|
-
{ label: "New York", id:
|
|
42
|
-
{ label: "Los Angeles", id:
|
|
43
|
-
{ label: "Chicago", id:
|
|
44
|
-
{ label: "Houston", id:
|
|
45
|
-
{ label: "San Francisco", id:
|
|
41
|
+
{ label: "New York", id: 1 },
|
|
42
|
+
{ label: "Los Angeles", id: 2 },
|
|
43
|
+
{ label: "Chicago", id: 3 },
|
|
44
|
+
{ label: "Houston", id: 4 },
|
|
45
|
+
{ label: "San Francisco", id: 5 },
|
|
46
46
|
],
|
|
47
47
|
},
|
|
48
48
|
argTypes: {
|
|
@@ -20,7 +20,7 @@ describe("UIcon.vue", () => {
|
|
|
20
20
|
|
|
21
21
|
await flushPromises();
|
|
22
22
|
|
|
23
|
-
component.get("[vl-key='icon']");
|
|
23
|
+
expect(component.get("[vl-key='icon']")).toBeTruthy();
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
it("Src – renders icon based on provided src", async () => {
|
|
@@ -32,7 +32,7 @@ describe("UIcon.vue", () => {
|
|
|
32
32
|
|
|
33
33
|
await flushPromises();
|
|
34
34
|
|
|
35
|
-
component.get("[vl-key='icon']");
|
|
35
|
+
expect(component.get("[vl-key='icon']")).toBeTruthy();
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
it("Color – applies correct color classes", () => {
|
|
@@ -124,6 +124,7 @@ const {
|
|
|
124
124
|
nextButtonAttrs,
|
|
125
125
|
activeButtonAttrs,
|
|
126
126
|
inactiveButtonAttrs,
|
|
127
|
+
ellipsisAttrs,
|
|
127
128
|
lastIconAttrs,
|
|
128
129
|
firstIconAttrs,
|
|
129
130
|
prevIconAttrs,
|
|
@@ -181,13 +182,7 @@ const {
|
|
|
181
182
|
</UButton>
|
|
182
183
|
|
|
183
184
|
<template v-for="page in pageButtons" :key="page">
|
|
184
|
-
<UButton
|
|
185
|
-
v-if="!isFinite(page.number)"
|
|
186
|
-
square
|
|
187
|
-
disabled
|
|
188
|
-
variant="ghost"
|
|
189
|
-
v-bind="inactiveButtonAttrs"
|
|
190
|
-
>
|
|
185
|
+
<UButton v-if="!isFinite(page.number)" square disabled variant="ghost" v-bind="ellipsisAttrs">
|
|
191
186
|
<!-- @slot Use it to add something instead of the ellipsis. -->
|
|
192
187
|
<slot name="ellipsis">…</slot>
|
|
193
188
|
</UButton>
|
|
@@ -12,7 +12,7 @@ describe("UPagination.vue", () => {
|
|
|
12
12
|
describe("Props", () => {
|
|
13
13
|
// Variant prop
|
|
14
14
|
it("applies the correct variant to buttons", async () => {
|
|
15
|
-
const variants = ["solid", "outlined", "soft", "ghost"];
|
|
15
|
+
const variants = ["solid", "outlined", "subtle", "soft", "ghost"];
|
|
16
16
|
|
|
17
17
|
variants.forEach((variant) => {
|
|
18
18
|
const component = mount(UPagination, {
|
|
@@ -6,7 +6,7 @@ import UIcon from "../../ui.image-icon/UIcon.vue";
|
|
|
6
6
|
|
|
7
7
|
import { NotificationType } from "../constants.ts";
|
|
8
8
|
import { LocaleSymbol } from "../../composables/useLocale.ts";
|
|
9
|
-
import createVuelessAdapter from "../../adapter.locale/vueless.ts";
|
|
9
|
+
import { createVuelessAdapter } from "../../adapter.locale/vueless.ts";
|
|
10
10
|
|
|
11
11
|
import type { Props, Notification } from "../types.ts";
|
|
12
12
|
|
|
@@ -2,9 +2,11 @@ import fs from "node:fs/promises";
|
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
|
|
5
|
+
import { removeFolderIfEmpty } from "./helper.js";
|
|
5
6
|
import { vuelessConfig } from "./vuelessConfig.js";
|
|
6
7
|
|
|
7
8
|
import {
|
|
9
|
+
CACHE_DIR,
|
|
8
10
|
COMPONENTS,
|
|
9
11
|
GRAYSCALE_COLOR,
|
|
10
12
|
INHERIT_COLOR,
|
|
@@ -74,9 +76,8 @@ export async function setCustomPropTypes(srcDir) {
|
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
const isCustomProps = componentGlobalConfig && componentGlobalConfig.props;
|
|
77
|
-
const isHiddenStories = componentGlobalConfig && componentGlobalConfig.storybook === false;
|
|
78
79
|
|
|
79
|
-
if (isCustomProps
|
|
80
|
+
if (isCustomProps) {
|
|
80
81
|
await cacheComponentTypes(path.join(srcDir, componentDir));
|
|
81
82
|
await modifyComponentTypes(path.join(srcDir, componentDir), componentGlobalConfig.props);
|
|
82
83
|
}
|
|
@@ -91,26 +92,34 @@ export async function removeCustomPropTypes(srcDir) {
|
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
async function cacheComponentTypes(filePath) {
|
|
94
|
-
const cacheDir = path.join(filePath,
|
|
95
|
+
const cacheDir = path.join(filePath, CACHE_DIR);
|
|
95
96
|
const sourceFile = path.join(filePath, "types.ts");
|
|
96
97
|
const destFile = path.join(cacheDir, "types.ts");
|
|
97
98
|
|
|
98
|
-
if (existsSync(
|
|
99
|
+
if (existsSync(destFile) || !existsSync(sourceFile)) {
|
|
99
100
|
return;
|
|
100
101
|
}
|
|
101
102
|
|
|
102
|
-
if (existsSync(
|
|
103
|
+
if (!existsSync(cacheDir)) {
|
|
103
104
|
await fs.mkdir(cacheDir);
|
|
104
|
-
await fs.cp(sourceFile, destFile);
|
|
105
105
|
}
|
|
106
|
+
|
|
107
|
+
await fs.cp(sourceFile, destFile);
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
async function clearComponentTypesCache(filePath) {
|
|
109
|
-
|
|
111
|
+
const cacheDir = path.join(filePath, CACHE_DIR);
|
|
112
|
+
const sourceFile = path.join(cacheDir, "types.ts");
|
|
113
|
+
|
|
114
|
+
if (existsSync(sourceFile)) {
|
|
115
|
+
await fs.rm(sourceFile, { force: true });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
await removeFolderIfEmpty(cacheDir);
|
|
110
119
|
}
|
|
111
120
|
|
|
112
121
|
async function restoreComponentTypes(filePath) {
|
|
113
|
-
const cacheDir = path.join(filePath,
|
|
122
|
+
const cacheDir = path.join(filePath, CACHE_DIR);
|
|
114
123
|
const sourceFile = path.join(cacheDir, "types.ts");
|
|
115
124
|
const destFile = path.join(filePath, "types.ts");
|
|
116
125
|
|
package/utils/node/helper.js
CHANGED
|
@@ -3,7 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { cwd } from "node:process";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
5
|
import { existsSync, statSync } from "node:fs";
|
|
6
|
-
import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
|
|
6
|
+
import { mkdir, readdir, rmdir, readFile, writeFile } from "node:fs/promises";
|
|
7
7
|
|
|
8
8
|
import { vuelessConfig, getMergedConfig } from "./vuelessConfig.js";
|
|
9
9
|
|
|
@@ -157,6 +157,16 @@ export async function buildTSFile(entryPath, configOutFile) {
|
|
|
157
157
|
});
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
export async function removeFolderIfEmpty(dirPath) {
|
|
161
|
+
if (existsSync(dirPath)) {
|
|
162
|
+
const files = await readdir(dirPath);
|
|
163
|
+
|
|
164
|
+
if (!files.length) {
|
|
165
|
+
await rmdir(dirPath);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
160
170
|
export async function autoImportUserConfigs() {
|
|
161
171
|
const vuelessConfigDir = path.join(cwd(), ".vueless");
|
|
162
172
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { getVuelessConfig } from "./vuelessConfig.js";
|
|
2
|
+
import {
|
|
3
|
+
COMPONENTS,
|
|
4
|
+
INTERNAL_ENV,
|
|
5
|
+
VUELESS_LOCAL_DIR,
|
|
6
|
+
VUELESS_PACKAGE_DIR,
|
|
7
|
+
} from "../../constants.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Defines the config for Storybook.
|
|
11
|
+
*
|
|
12
|
+
* @param {Object} config - The config object.
|
|
13
|
+
* @return {Promise<Object>} A promise that resolves to the modified config object.
|
|
14
|
+
*/
|
|
15
|
+
export function defineConfigWithVueless(config) {
|
|
16
|
+
return (async () => ({
|
|
17
|
+
...config,
|
|
18
|
+
stories: [...config.stories, ...(await getVuelessStoriesGlob(config?.vuelessEnv))],
|
|
19
|
+
}))();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Retrieves the glob pattern for Vueless stories based on the provided Vueless environment.
|
|
24
|
+
*
|
|
25
|
+
* @param {string} vuelessEnv - The Vueless environment.
|
|
26
|
+
* @return {Promise<string[]>} A promise that resolves to an array of glob patterns for Vueless stories.
|
|
27
|
+
*/
|
|
28
|
+
export async function getVuelessStoriesGlob(vuelessEnv) {
|
|
29
|
+
const vuelessSrcDir = vuelessEnv === INTERNAL_ENV ? VUELESS_LOCAL_DIR : VUELESS_PACKAGE_DIR;
|
|
30
|
+
|
|
31
|
+
const storiesGlob = [
|
|
32
|
+
`../${vuelessSrcDir}/directives/**/stories.{js,jsx,ts,tsx}`,
|
|
33
|
+
`../${vuelessSrcDir}/directives/**/docs.mdx`,
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
const vuelessConfig = await getVuelessConfig();
|
|
37
|
+
|
|
38
|
+
for (const [componentName, componentDir] of Object.entries(COMPONENTS)) {
|
|
39
|
+
const componentGlobalConfig = vuelessConfig.components?.[componentName];
|
|
40
|
+
const isHiddenStoriesByComponent = componentGlobalConfig === false;
|
|
41
|
+
const isHiddenStoriesByKey = componentGlobalConfig?.storybook === false;
|
|
42
|
+
|
|
43
|
+
if (isHiddenStoriesByComponent || isHiddenStoriesByKey) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
storiesGlob.push(`../${vuelessSrcDir}/${componentDir}/storybook/stories.{js,jsx,ts,tsx}`);
|
|
48
|
+
storiesGlob.push(`../${vuelessSrcDir}/${componentDir}/storybook/docs.mdx`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return storiesGlob;
|
|
52
|
+
}
|