vueless 1.3.2-beta.1 → 1.3.2-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/ui.container-drawer/UDrawer.vue +34 -2
- package/ui.container-drawer/config.ts +10 -5
- package/ui.container-drawer/storybook/stories.ts +3 -0
- package/ui.container-drawer/tests/UDrawer.test.ts +50 -11
- package/ui.container-drawer/types.ts +5 -0
- package/ui.form-date-picker/UDatePicker.vue +1 -1
- package/ui.form-date-picker-range/UDatePickerRange.vue +1 -1
- package/ui.form-input/UInput.vue +15 -7
- package/ui.form-input-number/storybook/stories.ts +3 -3
- package/ui.form-input-password/storybook/stories.ts +2 -2
- package/ui.form-input-search/storybook/stories.ts +3 -3
- package/ui.loader-overlay/storybook/stories.ts +2 -2
package/package.json
CHANGED
|
@@ -6,6 +6,8 @@ import { getDefaults } from "../utils/ui";
|
|
|
6
6
|
import { hasSlotContent } from "../utils/helper";
|
|
7
7
|
|
|
8
8
|
import UHeader from "../ui.text-header/UHeader.vue";
|
|
9
|
+
import UButton from "../ui.button/UButton.vue";
|
|
10
|
+
import UIcon from "../ui.image-icon/UIcon.vue";
|
|
9
11
|
|
|
10
12
|
import defaultConfig from "./config";
|
|
11
13
|
import { COMPONENT_NAME } from "./constants";
|
|
@@ -38,8 +40,10 @@ const slots = useSlots();
|
|
|
38
40
|
|
|
39
41
|
const wrapperRef = useTemplateRef<HTMLDivElement>("wrapper");
|
|
40
42
|
const drawerRef = useTemplateRef<HTMLDivElement>("drawer");
|
|
43
|
+
const handleWrapperRef = useTemplateRef<HTMLDivElement>("handleWrapper");
|
|
41
44
|
|
|
42
45
|
const isDragging = ref(false);
|
|
46
|
+
const isDraggingFromHandle = ref(false);
|
|
43
47
|
const dragStartPosition = ref({ x: 0, y: 0 });
|
|
44
48
|
const dragCurrentPosition = ref({ x: 0, y: 0 });
|
|
45
49
|
const minDragDistance = 10;
|
|
@@ -201,6 +205,12 @@ function onDragStart(e: MouseEvent | TouchEvent) {
|
|
|
201
205
|
dragStartPosition.value = { x: clientX, y: clientY };
|
|
202
206
|
dragCurrentPosition.value = { x: clientX, y: clientY };
|
|
203
207
|
|
|
208
|
+
const targetNode = e.target as Node;
|
|
209
|
+
|
|
210
|
+
isDraggingFromHandle.value = !!handleWrapperRef.value?.contains(targetNode);
|
|
211
|
+
|
|
212
|
+
if (!props.handle || !isDraggingFromHandle.value) return;
|
|
213
|
+
|
|
204
214
|
document.addEventListener("mousemove", onDragMove);
|
|
205
215
|
document.addEventListener("mouseup", onDragEnd);
|
|
206
216
|
document.addEventListener("touchmove", onDragMove, { passive: false });
|
|
@@ -282,6 +292,8 @@ const {
|
|
|
282
292
|
footerRightAttrs,
|
|
283
293
|
beforeTitleAttrs,
|
|
284
294
|
titleFallbackAttrs,
|
|
295
|
+
closeButtonAttrs,
|
|
296
|
+
closeIconAttrs,
|
|
285
297
|
} = useUI<Config>(defaultConfig);
|
|
286
298
|
</script>
|
|
287
299
|
|
|
@@ -329,9 +341,29 @@ const {
|
|
|
329
341
|
|
|
330
342
|
<!--
|
|
331
343
|
@slot Use it to add something instead of the close button.
|
|
344
|
+
@binding {string} icon-name
|
|
332
345
|
@binding {function} close
|
|
333
346
|
-->
|
|
334
|
-
<slot name="actions" :close="closeDrawer"
|
|
347
|
+
<slot name="actions" :icon-name="config.defaults.closeIcon" :close="closeDrawer">
|
|
348
|
+
<UButton
|
|
349
|
+
v-if="closeOnCross"
|
|
350
|
+
size="2xs"
|
|
351
|
+
square
|
|
352
|
+
color="grayscale"
|
|
353
|
+
variant="ghost"
|
|
354
|
+
v-bind="closeButtonAttrs"
|
|
355
|
+
@click="closeDrawer"
|
|
356
|
+
>
|
|
357
|
+
<UIcon
|
|
358
|
+
interactive
|
|
359
|
+
size="sm"
|
|
360
|
+
color="grayscale"
|
|
361
|
+
:name="config.defaults.closeIcon"
|
|
362
|
+
v-bind="closeIconAttrs"
|
|
363
|
+
:data-test="getDataTest('close')"
|
|
364
|
+
/>
|
|
365
|
+
</UButton>
|
|
366
|
+
</slot>
|
|
335
367
|
</div>
|
|
336
368
|
|
|
337
369
|
<div v-bind="bodyAttrs">
|
|
@@ -352,7 +384,7 @@ const {
|
|
|
352
384
|
</div>
|
|
353
385
|
</div>
|
|
354
386
|
|
|
355
|
-
<div v-if="handle" v-bind="handleWrapperAttrs">
|
|
387
|
+
<div v-if="handle" v-bind="handleWrapperAttrs" ref="handleWrapper">
|
|
356
388
|
<!-- @slot Use it to add something instead of the default handle. -->
|
|
357
389
|
<slot name="handle">
|
|
358
390
|
<div v-bind="handleAttrs" />
|
|
@@ -42,7 +42,7 @@ export default /*tw*/ {
|
|
|
42
42
|
leaveToClass: "opacity-0",
|
|
43
43
|
},
|
|
44
44
|
innerWrapper: {
|
|
45
|
-
base: "h-full relative",
|
|
45
|
+
base: "h-full relative",
|
|
46
46
|
variants: {
|
|
47
47
|
inset: {
|
|
48
48
|
true: "m-4 h-[calc(100%-2rem)]",
|
|
@@ -60,6 +60,8 @@ export default /*tw*/ {
|
|
|
60
60
|
beforeTitle: "flex items-center gap-3",
|
|
61
61
|
titleFallback: "flex flex-col",
|
|
62
62
|
title: "{UHeader}",
|
|
63
|
+
closeIcon: "{UIcon}",
|
|
64
|
+
closeButton: "{UButton} h-fit",
|
|
63
65
|
description: "mt-1.5 text-medium font-normal text-lifted",
|
|
64
66
|
body: {
|
|
65
67
|
base: "px-6 pb-6 text-medium",
|
|
@@ -79,7 +81,7 @@ export default /*tw*/ {
|
|
|
79
81
|
footerLeft: "flex flex-col md:flex-row gap-4 w-full",
|
|
80
82
|
footerRight: "flex flex-col md:flex-row gap-4 w-full justify-end",
|
|
81
83
|
drawerWrapper: {
|
|
82
|
-
base: "flex border absolute select-none
|
|
84
|
+
base: "flex border absolute select-none overflow-x-hidden",
|
|
83
85
|
variants: {
|
|
84
86
|
variant: {
|
|
85
87
|
solid: "bg-default border-transparent",
|
|
@@ -99,9 +101,9 @@ export default /*tw*/ {
|
|
|
99
101
|
},
|
|
100
102
|
},
|
|
101
103
|
},
|
|
102
|
-
drawer: "",
|
|
104
|
+
drawer: "overflow-y-auto",
|
|
103
105
|
handleWrapper: {
|
|
104
|
-
base: "flex items-center justify-center bg-inherit",
|
|
106
|
+
base: "flex items-center justify-center bg-inherit cursor-grab active:cursor-grabbing",
|
|
105
107
|
variants: {
|
|
106
108
|
position: {
|
|
107
109
|
top: "w-full h-11",
|
|
@@ -112,7 +114,7 @@ export default /*tw*/ {
|
|
|
112
114
|
},
|
|
113
115
|
},
|
|
114
116
|
handle: {
|
|
115
|
-
base: "rounded-large cursor-
|
|
117
|
+
base: "rounded-large cursor-grab active:cursor-grabbing bg-lifted hover:bg-accented transition",
|
|
116
118
|
compoundVariants: [
|
|
117
119
|
{ position: ["top", "bottom"], class: "w-11 h-1.5" },
|
|
118
120
|
{ position: ["left", "right"], class: "w-1.5 h-11" },
|
|
@@ -124,6 +126,9 @@ export default /*tw*/ {
|
|
|
124
126
|
inset: false,
|
|
125
127
|
handle: true,
|
|
126
128
|
closeOnEsc: true,
|
|
129
|
+
closeOnCross: true,
|
|
127
130
|
closeOnOverlay: true,
|
|
131
|
+
/* icons */
|
|
132
|
+
closeIcon: "close",
|
|
128
133
|
},
|
|
129
134
|
};
|
|
@@ -156,6 +156,9 @@ NoCloseOnEscAndOverlay.args = {
|
|
|
156
156
|
closeOnOverlay: false,
|
|
157
157
|
};
|
|
158
158
|
|
|
159
|
+
export const NoCloseOnCross = DefaultTemplate.bind({});
|
|
160
|
+
NoCloseOnCross.args = { closeOnCross: false };
|
|
161
|
+
|
|
159
162
|
export const Position = EnumTemplate.bind({});
|
|
160
163
|
Position.args = { enum: "position", modelValues: {} };
|
|
161
164
|
|
|
@@ -210,6 +210,40 @@ describe("UDrawer", () => {
|
|
|
210
210
|
|
|
211
211
|
expect(drawerWrapper.attributes("data-test")).toBe(dataTest);
|
|
212
212
|
});
|
|
213
|
+
|
|
214
|
+
it("CloseOnCross – shows cross by default and closes on click when true", async () => {
|
|
215
|
+
const component = mount(UDrawer, {
|
|
216
|
+
props: {
|
|
217
|
+
modelValue: true,
|
|
218
|
+
title: "Drawer Title",
|
|
219
|
+
closeOnCross: true,
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const closeButton = component.find('[vl-key="closeButton"]');
|
|
224
|
+
|
|
225
|
+
expect(closeButton.exists()).toBe(true);
|
|
226
|
+
|
|
227
|
+
await closeButton.trigger("click");
|
|
228
|
+
|
|
229
|
+
expect(component.emitted("update:modelValue")).toBeTruthy();
|
|
230
|
+
expect(component.emitted("update:modelValue")?.[0]).toEqual([false]);
|
|
231
|
+
expect(component.emitted("close")).toBeTruthy();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("CloseOnCross – hides cross when false", () => {
|
|
235
|
+
const component = mount(UDrawer, {
|
|
236
|
+
props: {
|
|
237
|
+
modelValue: true,
|
|
238
|
+
title: "Drawer Title",
|
|
239
|
+
closeOnCross: false,
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
const closeButton = component.find('[vl-key="closeButton"]');
|
|
244
|
+
|
|
245
|
+
expect(closeButton.exists()).toBe(false);
|
|
246
|
+
});
|
|
213
247
|
});
|
|
214
248
|
|
|
215
249
|
// Slots tests
|
|
@@ -545,26 +579,29 @@ describe("UDrawer", () => {
|
|
|
545
579
|
|
|
546
580
|
// Drag functionality tests
|
|
547
581
|
describe("Drag Functionality", () => {
|
|
548
|
-
it("Cursor – applies drag cursor classes when
|
|
582
|
+
it("Cursor – applies drag cursor classes when handle is enabled", () => {
|
|
549
583
|
const component = mount(UDrawer, {
|
|
550
584
|
props: {
|
|
551
585
|
modelValue: true,
|
|
586
|
+
handle: true,
|
|
552
587
|
},
|
|
553
588
|
});
|
|
554
589
|
|
|
555
|
-
const
|
|
590
|
+
const handleWrapper = component.find("[vl-key='handleWrapper']");
|
|
556
591
|
|
|
557
|
-
expect(
|
|
592
|
+
expect(handleWrapper.attributes("class")).toContain("cursor-grab");
|
|
558
593
|
});
|
|
559
594
|
|
|
560
|
-
it("Mouse Drag – handles drag start", async () => {
|
|
595
|
+
it("Mouse Drag – handles drag start from handle", async () => {
|
|
561
596
|
const component = mount(UDrawer, {
|
|
562
597
|
props: {
|
|
563
598
|
modelValue: true,
|
|
599
|
+
handle: true,
|
|
564
600
|
},
|
|
565
601
|
});
|
|
566
602
|
|
|
567
603
|
const drawer = component.find("[vl-key='drawerWrapper']");
|
|
604
|
+
const handleWrapper = component.find("[vl-key='handleWrapper']");
|
|
568
605
|
|
|
569
606
|
// Mock getBoundingClientRect
|
|
570
607
|
const mockRect = {
|
|
@@ -578,23 +615,25 @@ describe("UDrawer", () => {
|
|
|
578
615
|
|
|
579
616
|
vi.spyOn(drawer.element, "getBoundingClientRect").mockReturnValue(mockRect as DOMRect);
|
|
580
617
|
|
|
581
|
-
await
|
|
618
|
+
await handleWrapper.trigger("mousedown", {
|
|
582
619
|
clientX: 100,
|
|
583
620
|
clientY: 100,
|
|
584
621
|
});
|
|
585
622
|
|
|
586
|
-
// Check if
|
|
587
|
-
expect(
|
|
623
|
+
// Check if handle has drag cursor class
|
|
624
|
+
expect(handleWrapper.attributes("class")).toContain("cursor-grab");
|
|
588
625
|
});
|
|
589
626
|
|
|
590
|
-
it("Touch Drag – handles drag start", async () => {
|
|
627
|
+
it("Touch Drag – handles drag start from handle", async () => {
|
|
591
628
|
const component = mount(UDrawer, {
|
|
592
629
|
props: {
|
|
593
630
|
modelValue: true,
|
|
631
|
+
handle: true,
|
|
594
632
|
},
|
|
595
633
|
});
|
|
596
634
|
|
|
597
635
|
const drawer = component.find("[vl-key='drawerWrapper']");
|
|
636
|
+
const handleWrapper = component.find("[vl-key='handleWrapper']");
|
|
598
637
|
|
|
599
638
|
// Mock getBoundingClientRect
|
|
600
639
|
const mockRect = {
|
|
@@ -608,12 +647,12 @@ describe("UDrawer", () => {
|
|
|
608
647
|
|
|
609
648
|
vi.spyOn(drawer.element, "getBoundingClientRect").mockReturnValue(mockRect as DOMRect);
|
|
610
649
|
|
|
611
|
-
await
|
|
650
|
+
await handleWrapper.trigger("touchstart", {
|
|
612
651
|
touches: [{ clientX: 100, clientY: 100 }],
|
|
613
652
|
});
|
|
614
653
|
|
|
615
|
-
// Check if
|
|
616
|
-
expect(
|
|
654
|
+
// Check if handle has drag cursor class
|
|
655
|
+
expect(handleWrapper.attributes("class")).toContain("cursor-grab");
|
|
617
656
|
});
|
|
618
657
|
|
|
619
658
|
it("Transform – applies drag transform styles during drag", async () => {
|
|
@@ -318,7 +318,7 @@ watchEffect(() => {
|
|
|
318
318
|
@binding {string} icon-name
|
|
319
319
|
-->
|
|
320
320
|
<slot name="right" :icon-name="iconName">
|
|
321
|
-
<UIcon :name="iconName" color="neutral" v-bind="rightIconAttrs" />
|
|
321
|
+
<UIcon :name="iconName" color="neutral" v-bind="rightIconAttrs" @click="activate" />
|
|
322
322
|
</slot>
|
|
323
323
|
</template>
|
|
324
324
|
</UInput>
|
|
@@ -653,7 +653,7 @@ watchEffect(() => {
|
|
|
653
653
|
@binding {string} icon-name
|
|
654
654
|
-->
|
|
655
655
|
<slot name="right" :icon-name="iconName">
|
|
656
|
-
<UIcon :name="iconName" color="neutral" v-bind="rightIconAttrs" />
|
|
656
|
+
<UIcon :name="iconName" color="neutral" v-bind="rightIconAttrs" @click="activate" />
|
|
657
657
|
</slot>
|
|
658
658
|
</template>
|
|
659
659
|
</UInput>
|
package/ui.form-input/UInput.vue
CHANGED
|
@@ -176,9 +176,7 @@ function onKeydown(event: KeyboardEvent) {
|
|
|
176
176
|
emit("keydown", event);
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
function
|
|
180
|
-
if (event.target !== event.currentTarget) return;
|
|
181
|
-
|
|
179
|
+
function onClickIcon() {
|
|
182
180
|
inputRef.value?.focus();
|
|
183
181
|
}
|
|
184
182
|
|
|
@@ -297,14 +295,19 @@ const {
|
|
|
297
295
|
v-if="hasSlotContent($slots['left'], { iconName: leftIcon }) || leftIcon"
|
|
298
296
|
v-bind="leftSlotAttrs"
|
|
299
297
|
ref="leftSlotWrapper"
|
|
300
|
-
@click="onSlotClick"
|
|
301
298
|
>
|
|
302
299
|
<!--
|
|
303
300
|
@slot Use it to add something before the text.
|
|
304
301
|
@binding {string} icon-name
|
|
305
302
|
-->
|
|
306
303
|
<slot name="left" :icon-name="leftIcon">
|
|
307
|
-
<UIcon
|
|
304
|
+
<UIcon
|
|
305
|
+
v-if="leftIcon"
|
|
306
|
+
color="neutral"
|
|
307
|
+
:name="leftIcon"
|
|
308
|
+
v-bind="leftIconAttrs"
|
|
309
|
+
@click="onClickIcon"
|
|
310
|
+
/>
|
|
308
311
|
</slot>
|
|
309
312
|
</span>
|
|
310
313
|
|
|
@@ -335,14 +338,19 @@ const {
|
|
|
335
338
|
<span
|
|
336
339
|
v-if="hasSlotContent($slots['right'], { iconName: rightIcon }) || rightIcon"
|
|
337
340
|
v-bind="rightSlotAttrs"
|
|
338
|
-
@click="onSlotClick"
|
|
339
341
|
>
|
|
340
342
|
<!--
|
|
341
343
|
@slot Use it to add something after the text.
|
|
342
344
|
@binding {string} icon-name
|
|
343
345
|
-->
|
|
344
346
|
<slot name="right" :icon-name="rightIcon">
|
|
345
|
-
<UIcon
|
|
347
|
+
<UIcon
|
|
348
|
+
v-if="rightIcon"
|
|
349
|
+
color="neutral"
|
|
350
|
+
:name="rightIcon"
|
|
351
|
+
v-bind="rightIconAttrs"
|
|
352
|
+
@click="onClickIcon"
|
|
353
|
+
/>
|
|
346
354
|
</slot>
|
|
347
355
|
</span>
|
|
348
356
|
</div>
|
|
@@ -203,9 +203,9 @@ export const Slots: StoryFn<UInputNumberArgs> = (args) => ({
|
|
|
203
203
|
components: { UInputNumber, URow, UButton, UDropdownButton, UText },
|
|
204
204
|
setup() {
|
|
205
205
|
const currencies = [
|
|
206
|
-
{ label: "USD",
|
|
207
|
-
{ label: "EUR",
|
|
208
|
-
{ label: "UAH",
|
|
206
|
+
{ label: "USD", value: "usd" },
|
|
207
|
+
{ label: "EUR", value: "eur" },
|
|
208
|
+
{ label: "UAH", value: "uah" },
|
|
209
209
|
];
|
|
210
210
|
|
|
211
211
|
const currency = ref("usd");
|
|
@@ -142,8 +142,8 @@ export const Slots: StoryFn<UInputPasswordArgs> = (args) => ({
|
|
|
142
142
|
components: { UInputPassword, URow, UButton, UDropdownButton },
|
|
143
143
|
setup() {
|
|
144
144
|
const wifiTypes = [
|
|
145
|
-
{ label: "WPA2",
|
|
146
|
-
{ label: "WPA3",
|
|
145
|
+
{ label: "WPA2", value: "wpa2" },
|
|
146
|
+
{ label: "WPA3", value: "wpa3" },
|
|
147
147
|
];
|
|
148
148
|
|
|
149
149
|
return { args, wifiTypes };
|
|
@@ -155,9 +155,9 @@ export const Slots: StoryFn<UInputSearchArgs> = (args) => ({
|
|
|
155
155
|
components: { UInputSearch, UCol, URow, UIcon, UDropdownButton, UText },
|
|
156
156
|
setup() {
|
|
157
157
|
const aiVersions = [
|
|
158
|
-
{ label: "GPT-4o",
|
|
159
|
-
{ label: "GPT-4o-mini",
|
|
160
|
-
{ label: "GPT-4",
|
|
158
|
+
{ label: "GPT-4o", value: "gpt-4o" },
|
|
159
|
+
{ label: "GPT-4o-mini", value: "gpt-4o-mini" },
|
|
160
|
+
{ label: "GPT-4", value: "gpt-4" },
|
|
161
161
|
];
|
|
162
162
|
|
|
163
163
|
return { args, aiVersions };
|
|
@@ -51,11 +51,11 @@ const EnumTemplate: StoryFn<ULoaderOverlayArgs> = (args: ULoaderOverlayArgs, { a
|
|
|
51
51
|
const selectModel = ref(null);
|
|
52
52
|
|
|
53
53
|
const options = computed(() => {
|
|
54
|
-
return argTypes?.[args.enum]?.options?.map((label,
|
|
54
|
+
return argTypes?.[args.enum]?.options?.map((label, value) => ({ label, value }));
|
|
55
55
|
});
|
|
56
56
|
|
|
57
57
|
const selectedValue = computed(() => {
|
|
58
|
-
return options.value?.find((option) => option.
|
|
58
|
+
return options.value?.find((option) => option.value === selectModel.value)?.label;
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
return {
|