vueless 1.0.2-beta.0 → 1.0.2-beta.2
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/icons/storybook/add.svg +1 -0
- package/icons/storybook/star.svg +1 -0
- package/icons/storybook/timer.svg +1 -0
- package/package.json +1 -1
- package/ui.button/tests/UButton.test.ts +1 -0
- package/ui.button-link/tests/ULink.test.ts +365 -0
- package/ui.button-toggle/UToggle.vue +3 -2
- package/ui.button-toggle/storybook/stories.ts +4 -18
- package/ui.button-toggle/tests/UToggle.test.ts +437 -0
- package/ui.image-icon/UIcon.vue +2 -0
- package/ui.other-chip/storybook/stories.ts +1 -1
- package/ui.other-chip/types.ts +1 -1
- package/ui.other-dot/config.ts +1 -0
- package/ui.other-dot/types.ts +1 -1
- package/ui.text-badge/tests/UBadge.test.ts +322 -0
- package/ui.text-block/tests/UText.test.ts +148 -0
- package/ui.text-empty/UEmpty.vue +23 -8
- package/ui.text-empty/config.ts +1 -1
- package/ui.text-empty/tests/UEmpty.test.ts +228 -0
- package/ui.text-empty/types.ts +5 -0
- package/ui.text-header/tests/UHeader.test.ts +144 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 -960 960 960"><path d="M445.93-445.93H194.02v-68.14h251.91v-252.15h68.14v252.15h252.15v68.14H514.07v251.91h-68.14v-251.91Z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 -960 960 960"><path d="m326.37-249.79 153.64-91.89 153.64 92.9-41.28-173.94L727.5-540.33l-178.17-15.52L480-720.02l-69.33 163.41-178.17 15.28 135.22 117.38-41.35 174.16ZM224.15-107.56l67.39-291.29L65.41-594.78l298.43-25.67L480-895.3l116.16 274.85 298.43 25.67-226.13 195.93 67.63 291.29L480-262.3 224.15-107.56ZM480-474.52Z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 -960 960 960"><path d="M354.5-860v-65.5h251v65.5h-251Zm92.87 452.02h65.26v-230.48h-65.26v230.48ZM479.94-70q-75.49 0-142.05-28.94-66.56-28.94-116.36-78.7-49.79-49.75-78.65-116.29-28.86-66.54-28.86-142.01 0-75.47 28.88-142.04 28.88-66.56 78.68-116.4 49.79-49.84 116.35-78.83Q404.5-802.2 480-802.2q67.48 0 127.08 22.5 59.59 22.5 105.83 62.74l53.16-53.15 46.3 46.07-53.15 53.15q36.24 40.48 61.62 97.96 25.38 57.47 25.38 136.95 0 75.52-28.96 142.11-28.95 66.59-78.78 116.31T622.04-98.92Q555.43-70 479.94-70Zm.02-68.37q124.32 0 211.11-86.62 86.78-86.62 86.78-210.95 0-124.32-86.74-211.1-86.75-86.79-211.07-86.79t-211.11 86.75q-86.78 86.74-86.78 211.06 0 124.32 86.74 210.99 86.75 86.66 211.07 86.66Zm.04-296.61Z"/></svg>
|
package/package.json
CHANGED
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import { mount } from "@vue/test-utils";
|
|
2
|
+
import { describe, it, expect } from "vitest";
|
|
3
|
+
import { createRouter, createWebHistory } from "vue-router";
|
|
4
|
+
|
|
5
|
+
import ULink from "../ULink.vue";
|
|
6
|
+
|
|
7
|
+
import type { Props } from "../types.ts";
|
|
8
|
+
|
|
9
|
+
// Create a mock router for testing router-link functionality
|
|
10
|
+
const router = createRouter({
|
|
11
|
+
history: createWebHistory(),
|
|
12
|
+
routes: [
|
|
13
|
+
{ path: "/", name: "home", component: { template: "<div>Home</div>" } },
|
|
14
|
+
{ path: "/about", name: "about", component: { template: "<div>About</div>" } },
|
|
15
|
+
],
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("ULink.vue", () => {
|
|
19
|
+
// Props tests
|
|
20
|
+
describe("Props", () => {
|
|
21
|
+
// Size prop
|
|
22
|
+
it("applies the correct size class", async () => {
|
|
23
|
+
const size = {
|
|
24
|
+
sm: "text-small",
|
|
25
|
+
md: "text-medium",
|
|
26
|
+
lg: "text-large",
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
Object.entries(size).forEach(([size, classes]) => {
|
|
30
|
+
const component = mount(ULink, {
|
|
31
|
+
props: {
|
|
32
|
+
size: size as Props["size"],
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
expect(component.attributes("class")).toContain(classes);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Color prop
|
|
41
|
+
it("applies the correct color class", async () => {
|
|
42
|
+
const colors = [
|
|
43
|
+
"primary",
|
|
44
|
+
"secondary",
|
|
45
|
+
"error",
|
|
46
|
+
"warning",
|
|
47
|
+
"success",
|
|
48
|
+
"info",
|
|
49
|
+
"notice",
|
|
50
|
+
"neutral",
|
|
51
|
+
"grayscale",
|
|
52
|
+
"inherit",
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
colors.forEach((color) => {
|
|
56
|
+
const component = mount(ULink, {
|
|
57
|
+
props: {
|
|
58
|
+
color: color as Props["color"],
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
expect(component.attributes("class")).toContain(color);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Label prop
|
|
67
|
+
it("renders the correct label text", () => {
|
|
68
|
+
const label = "Link Text";
|
|
69
|
+
|
|
70
|
+
const component = mount(ULink, {
|
|
71
|
+
props: {
|
|
72
|
+
label,
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
expect(component.text()).toBe(label);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Href prop
|
|
80
|
+
it("renders the correct href attribute", () => {
|
|
81
|
+
const href = "https://example.com";
|
|
82
|
+
|
|
83
|
+
const component = mount(ULink, {
|
|
84
|
+
props: {
|
|
85
|
+
href,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
expect(component.attributes("href")).toBe(href);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Type prop
|
|
93
|
+
it("applies the correct href prefix based on type", () => {
|
|
94
|
+
const types = {
|
|
95
|
+
phone: { href: "1234567890", expected: "tel:1234567890" },
|
|
96
|
+
email: { href: "test@example.com", expected: "mailto:test@example.com" },
|
|
97
|
+
link: { href: "https://example.com", expected: "https://example.com" },
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
Object.entries(types).forEach(([type, { href, expected }]) => {
|
|
101
|
+
const component = mount(ULink, {
|
|
102
|
+
props: {
|
|
103
|
+
type: type as Props["type"],
|
|
104
|
+
href,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
expect(component.attributes("href")).toBe(expected);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// To prop
|
|
113
|
+
it("renders as router-link when to prop is provided", async () => {
|
|
114
|
+
const to = "/about";
|
|
115
|
+
|
|
116
|
+
const component = mount(ULink, {
|
|
117
|
+
props: {
|
|
118
|
+
to,
|
|
119
|
+
},
|
|
120
|
+
global: {
|
|
121
|
+
plugins: [router],
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Check if it's a router-link by looking for the to attribute
|
|
126
|
+
expect(component.findComponent({ name: "RouterLink" }).exists()).toBe(true);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Target prop
|
|
130
|
+
it("applies the correct target attribute", () => {
|
|
131
|
+
const targets = ["_blank", "_self", "_parent", "_top"];
|
|
132
|
+
|
|
133
|
+
targets.forEach((target) => {
|
|
134
|
+
const component = mount(ULink, {
|
|
135
|
+
props: {
|
|
136
|
+
target: target as Props["target"],
|
|
137
|
+
href: "https://example.com",
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
expect(component.attributes("target")).toBe(target);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Rel prop
|
|
146
|
+
it("applies the correct rel attribute", () => {
|
|
147
|
+
const rel = "noopener noreferrer";
|
|
148
|
+
|
|
149
|
+
const component = mount(ULink, {
|
|
150
|
+
props: {
|
|
151
|
+
rel,
|
|
152
|
+
href: "https://example.com",
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
expect(component.attributes("rel")).toBe(rel);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Underlined prop
|
|
160
|
+
it("applies underlined class when underlined prop is true", () => {
|
|
161
|
+
const underlined = {
|
|
162
|
+
true: "underline",
|
|
163
|
+
false: "no-underline",
|
|
164
|
+
undefined: "hover:underline",
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
Object.entries(underlined).forEach(([value, expectedClass]) => {
|
|
168
|
+
const component = mount(ULink, {
|
|
169
|
+
props: {
|
|
170
|
+
underlined: value === "undefined" ? undefined : value === "true",
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
expect(component.attributes("class")).toContain(expectedClass);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Dashed prop
|
|
179
|
+
it("applies dashed class when dashed prop is true", () => {
|
|
180
|
+
const dashed = true;
|
|
181
|
+
const dashedClass = "decoration-dashed";
|
|
182
|
+
|
|
183
|
+
const component = mount(ULink, {
|
|
184
|
+
props: {
|
|
185
|
+
dashed,
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
expect(component.attributes("class")).toContain(dashedClass);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Dotted prop
|
|
193
|
+
it("applies dotted class when dotted prop is true", () => {
|
|
194
|
+
const dotted = true;
|
|
195
|
+
const dottedClass = "decoration-dotted";
|
|
196
|
+
|
|
197
|
+
const component = mount(ULink, {
|
|
198
|
+
props: {
|
|
199
|
+
dotted,
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
expect(component.attributes("class")).toContain(dottedClass);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Disabled prop
|
|
207
|
+
it("applies disabled class when disabled prop is true", () => {
|
|
208
|
+
const disabled = true;
|
|
209
|
+
|
|
210
|
+
const component = mount(ULink, {
|
|
211
|
+
props: {
|
|
212
|
+
disabled,
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
expect(component.attributes("class")).toContain("cursor-not-allowed");
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// Block prop
|
|
220
|
+
it("applies block class when block prop is true", () => {
|
|
221
|
+
const block = true;
|
|
222
|
+
const blockClass = "w-full";
|
|
223
|
+
|
|
224
|
+
const component = mount(ULink, {
|
|
225
|
+
props: {
|
|
226
|
+
block,
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
expect(component.attributes("class")).toContain(blockClass);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// DataTest prop
|
|
234
|
+
it("applies the correct data-test attribute", () => {
|
|
235
|
+
const dataTest = "test-link";
|
|
236
|
+
|
|
237
|
+
const component = mount(ULink, {
|
|
238
|
+
props: {
|
|
239
|
+
dataTest,
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
expect(component.attributes("data-test")).toBe(dataTest);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// Slots tests
|
|
248
|
+
describe("Slots", () => {
|
|
249
|
+
// Default slot
|
|
250
|
+
it("renders content from default slot", () => {
|
|
251
|
+
const slotContent = "Custom Content";
|
|
252
|
+
const label = "Link";
|
|
253
|
+
|
|
254
|
+
const component = mount(ULink, {
|
|
255
|
+
props: {
|
|
256
|
+
label,
|
|
257
|
+
},
|
|
258
|
+
slots: {
|
|
259
|
+
default: slotContent,
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
expect(component.text()).not.toContain(label);
|
|
264
|
+
expect(component.text()).toContain(slotContent);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Default slot with router-link
|
|
268
|
+
it("renders content from default slot with router-link", () => {
|
|
269
|
+
const slotContent = "Custom Content";
|
|
270
|
+
const label = "Link";
|
|
271
|
+
|
|
272
|
+
const component = mount(ULink, {
|
|
273
|
+
props: {
|
|
274
|
+
label,
|
|
275
|
+
to: "/about",
|
|
276
|
+
},
|
|
277
|
+
slots: {
|
|
278
|
+
default: slotContent,
|
|
279
|
+
},
|
|
280
|
+
global: {
|
|
281
|
+
plugins: [router],
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
expect(component.text()).not.toContain(label);
|
|
286
|
+
expect(component.text()).toContain(slotContent);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// Default slot with bindings
|
|
290
|
+
it("provides isActive and isExactActive bindings to default slot with router-link", () => {
|
|
291
|
+
const component = mount(ULink, {
|
|
292
|
+
props: {
|
|
293
|
+
to: "/about",
|
|
294
|
+
},
|
|
295
|
+
slots: {
|
|
296
|
+
default: `
|
|
297
|
+
<template #default="{ isActive, isExactActive }">
|
|
298
|
+
<span class="active-status">{{ isActive }}</span>
|
|
299
|
+
<span class="exact-active-status">{{ isExactActive }}</span>
|
|
300
|
+
</template>
|
|
301
|
+
`,
|
|
302
|
+
},
|
|
303
|
+
global: {
|
|
304
|
+
plugins: [router],
|
|
305
|
+
},
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
expect(component.find(".active-status").exists()).toBe(true);
|
|
309
|
+
expect(component.find(".exact-active-status").exists()).toBe(true);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// Events tests
|
|
314
|
+
describe("Events", () => {
|
|
315
|
+
// Click event
|
|
316
|
+
it("emits click event when clicked", async () => {
|
|
317
|
+
const component = mount(ULink, {});
|
|
318
|
+
|
|
319
|
+
await component.trigger("click");
|
|
320
|
+
expect(component.emitted("click")).toBeTruthy();
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// Mouseover event
|
|
324
|
+
it("emits mouseover event when hovered", async () => {
|
|
325
|
+
const component = mount(ULink, {});
|
|
326
|
+
|
|
327
|
+
await component.trigger("mouseover");
|
|
328
|
+
expect(component.emitted("mouseover")).toBeTruthy();
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
// Focus event
|
|
332
|
+
it("emits focus event when focused", async () => {
|
|
333
|
+
const component = mount(ULink, {});
|
|
334
|
+
|
|
335
|
+
await component.trigger("focus");
|
|
336
|
+
expect(component.emitted("focus")).toBeTruthy();
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
// Blur event
|
|
340
|
+
it("emits blur event when blurred", async () => {
|
|
341
|
+
const component = mount(ULink, {});
|
|
342
|
+
|
|
343
|
+
await component.trigger("blur");
|
|
344
|
+
expect(component.emitted("blur")).toBeTruthy();
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// Keydown event
|
|
348
|
+
it("emits keydown event when key is pressed", async () => {
|
|
349
|
+
const component = mount(ULink, {});
|
|
350
|
+
|
|
351
|
+
await component.trigger("keydown");
|
|
352
|
+
expect(component.emitted("keydown")).toBeTruthy();
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
// Exposed refs tests
|
|
357
|
+
describe("Exposed refs", () => {
|
|
358
|
+
// linkRef
|
|
359
|
+
it("exposes linkRef", () => {
|
|
360
|
+
const component = mount(ULink, {});
|
|
361
|
+
|
|
362
|
+
expect(component.vm.linkRef).toBeDefined();
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, ref, useTemplateRef } from "vue";
|
|
2
|
+
import { computed, ref, useId, useTemplateRef } from "vue";
|
|
3
3
|
|
|
4
4
|
import UButton from "../ui.button/UButton.vue";
|
|
5
5
|
|
|
@@ -27,6 +27,7 @@ const emit = defineEmits([
|
|
|
27
27
|
"update:modelValue",
|
|
28
28
|
]);
|
|
29
29
|
|
|
30
|
+
const elementId = props.id || useId();
|
|
30
31
|
const optionsRef = useTemplateRef<HTMLDivElement>("options");
|
|
31
32
|
|
|
32
33
|
const hoveredItem = ref();
|
|
@@ -106,7 +107,7 @@ const {
|
|
|
106
107
|
</script>
|
|
107
108
|
|
|
108
109
|
<template>
|
|
109
|
-
<div ref="options" v-bind="optionsAttrs">
|
|
110
|
+
<div :id="elementId" ref="options" v-bind="optionsAttrs" :data-test="getDataTest()">
|
|
110
111
|
<template v-for="(option, index) in options" :key="index">
|
|
111
112
|
<UButton
|
|
112
113
|
:label="option.label"
|
|
@@ -57,16 +57,7 @@ const DefaultTemplate: StoryFn<UToggleArgs> = (args: UToggleArgs) => ({
|
|
|
57
57
|
|
|
58
58
|
const EnumTemplate: StoryFn<UToggleArgs> = (args: UToggleArgs, { argTypes }) => ({
|
|
59
59
|
components: { UToggle, URow },
|
|
60
|
-
setup() {
|
|
61
|
-
const values = ref(argTypes.size?.options);
|
|
62
|
-
|
|
63
|
-
return {
|
|
64
|
-
args,
|
|
65
|
-
values,
|
|
66
|
-
argTypes,
|
|
67
|
-
getArgs,
|
|
68
|
-
};
|
|
69
|
-
},
|
|
60
|
+
setup: () => ({ args, argTypes, getArgs, values: ref(argTypes.size?.options) }),
|
|
70
61
|
template: `
|
|
71
62
|
<URow>
|
|
72
63
|
<UToggle
|
|
@@ -110,15 +101,10 @@ Square.args = {
|
|
|
110
101
|
name: "square",
|
|
111
102
|
square: true,
|
|
112
103
|
options: [
|
|
113
|
-
{ value: "11",
|
|
114
|
-
{ value: "12",
|
|
115
|
-
{ value: "13",
|
|
104
|
+
{ value: "11", icon: "star" },
|
|
105
|
+
{ value: "12", icon: "add" },
|
|
106
|
+
{ value: "13", icon: "timer" },
|
|
116
107
|
],
|
|
117
|
-
slotTemplate: `
|
|
118
|
-
<template #option="{ label, index }">
|
|
119
|
-
<UIcon :name="label" color="inherit" />
|
|
120
|
-
</template>
|
|
121
|
-
`,
|
|
122
108
|
};
|
|
123
109
|
|
|
124
110
|
export const Disabled = DefaultTemplate.bind({});
|