vueless 1.3.2-beta.2 → 1.3.2-beta.4

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vueless",
3
- "version": "1.3.2-beta.2",
3
+ "version": "1.3.2-beta.4",
4
4
  "description": "Vue Styleless UI Component Library, powered by Tailwind CSS.",
5
5
  "author": "Johnny Grid <hello@vueless.com> (https://vueless.com)",
6
6
  "homepage": "https://vueless.com",
@@ -27,7 +27,6 @@ export default {
27
27
  title: "Containers / Accordion Item",
28
28
  component: UAccordionItem,
29
29
  args: {
30
- opened: true,
31
30
  title: "Committed to Quality and Performance",
32
31
  description: trimText(
33
32
  `We take pride in delivering high-quality solutions tailored to your needs.
@@ -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", // add overflow-y
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 cursor-grab active:cursor-grabbing overflow-x-hidden overflow-y-auto",
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-pointer bg-lifted hover:bg-accented transition",
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 drawer is draggable", () => {
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 drawer = component.find("[vl-key='drawerWrapper']");
590
+ const handleWrapper = component.find("[vl-key='handleWrapper']");
556
591
 
557
- expect(drawer.attributes("class")).toContain("cursor-grab");
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 drawer.trigger("mousedown", {
618
+ await handleWrapper.trigger("mousedown", {
582
619
  clientX: 100,
583
620
  clientY: 100,
584
621
  });
585
622
 
586
- // Check if drag state is initialized (drag should not start until minimum distance)
587
- expect(drawer.attributes("class")).toContain("cursor-grab");
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 drawer.trigger("touchstart", {
650
+ await handleWrapper.trigger("touchstart", {
612
651
  touches: [{ clientX: 100, clientY: 100 }],
613
652
  });
614
653
 
615
- // Check if drag state is initialized (drag should not start until minimum distance)
616
- expect(drawer.attributes("class")).toContain("cursor-grab");
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 () => {
@@ -50,6 +50,11 @@ export interface Props {
50
50
  */
51
51
  closeOnEsc?: boolean;
52
52
 
53
+ /**
54
+ * Allow closing drawer by clicking on close cross.
55
+ */
56
+ closeOnCross?: boolean;
57
+
53
58
  /**
54
59
  * Unique element id.
55
60
  */