srcdev-nuxt-components 9.1.37 → 9.1.39
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/.claude/settings.json +4 -1
- package/.claude/skills/components/carousel-flip.md +188 -0
- package/.claude/skills/components/data-grid.md +167 -0
- package/.claude/skills/index.md +4 -1
- package/.claude/skills/qa-panel.md +231 -0
- package/app/components/01.atoms/grids/data-grid/DataGrid.vue +39 -0
- package/app/components/01.atoms/grids/data-grid/stories/DataGrid.stories.ts +234 -0
- package/app/components/01.atoms/grids/data-grid/tests/DataGrid.spec.ts +140 -0
- package/app/components/01.atoms/grids/data-grid/tests/__snapshots__/DataGrid.spec.ts.snap +11 -0
- package/app/components/01.atoms/{grid-stack → grids/grid-stack}/stories/GridStack.stories.ts +1 -1
- package/app/components/02.molecules/qr-code/CaptureQrCode.vue +49 -49
- package/app/components/carousels/CarouselFlip.vue +211 -153
- package/app/components/carousels/stories/CarouselFlip.stories.ts +35 -0
- package/app/components/carousels/tests/CarouselFlip.spec.ts +38 -0
- package/app/pages/ui/carousel-flip.vue +222 -17
- package/app/pages/ui/simple-grid.vue +2 -2
- package/package.json +1 -1
- package/app/components/display-grid/DisplayGridCore.vue +0 -22
- /package/app/components/01.atoms/{scroll-reveal-frame → animations/scroll-reveal-frame}/ScrollRevealFrame.vue +0 -0
- /package/app/components/01.atoms/{scroll-reveal-frame → animations/scroll-reveal-frame}/stories/ScrollRevealFrame.stories.ts +0 -0
- /package/app/components/01.atoms/{scroll-reveal-frame → animations/scroll-reveal-frame}/tests/ScrollRevealFrame.spec.ts +0 -0
- /package/app/components/01.atoms/{scroll-reveal-frame → animations/scroll-reveal-frame}/tests/__snapshots__/ScrollRevealFrame.spec.ts.snap +0 -0
- /package/app/components/01.atoms/{scroll-reveal-image → animations/scroll-reveal-image}/ScrollRevealImage.vue +0 -0
- /package/app/components/01.atoms/{scroll-reveal-image → animations/scroll-reveal-image}/stories/ScrollRevealImage.stories.ts +0 -0
- /package/app/components/01.atoms/{scroll-reveal-image → animations/scroll-reveal-image}/tests/ScrollRevealImage.spec.ts +0 -0
- /package/app/components/01.atoms/{scroll-reveal-image → animations/scroll-reveal-image}/tests/__snapshots__/ScrollRevealImage.spec.ts.snap +0 -0
- /package/app/components/01.atoms/{grid-stack → grids/grid-stack}/GridStack.vue +0 -0
- /package/app/components/01.atoms/{grid-stack → grids/grid-stack}/tests/GridStack.spec.ts +0 -0
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
ref="carouselWrapperRef"
|
|
4
4
|
class="carousel-flip"
|
|
5
5
|
:class="[elementClasses]"
|
|
6
|
+
:data-button-layout="buttonLayout"
|
|
6
7
|
role="region"
|
|
7
8
|
aria-label="Image carousel"
|
|
8
9
|
>
|
|
@@ -10,84 +11,81 @@
|
|
|
10
11
|
Item {{ currentActiveIndex + 1 }} of {{ itemCount }}
|
|
11
12
|
</div>
|
|
12
13
|
|
|
13
|
-
<
|
|
14
|
+
<div
|
|
15
|
+
ref="carouselContainerRef"
|
|
16
|
+
tabindex="0"
|
|
17
|
+
class="item-container"
|
|
18
|
+
:class="{ 'allow-overflow': allowCarouselOverflow }"
|
|
19
|
+
role="group"
|
|
20
|
+
aria-label="Carousel items"
|
|
21
|
+
>
|
|
14
22
|
<div
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
v-for="(item, index) in carouselDataIds"
|
|
24
|
+
:key="index"
|
|
25
|
+
ref="carouselItems"
|
|
26
|
+
class="item"
|
|
27
|
+
:class="{ loaded: carouselInitComplete && userHasInteracted }"
|
|
28
|
+
:data-id="item"
|
|
29
|
+
:aria-current="currentActiveIndex === index ? 'true' : 'false'"
|
|
21
30
|
>
|
|
22
|
-
<
|
|
23
|
-
v-for="(item, index) in carouselDataIds"
|
|
24
|
-
:key="index"
|
|
25
|
-
ref="carouselItems"
|
|
26
|
-
class="item"
|
|
27
|
-
:class="{ loaded: carouselInitComplete && userHasInteracted }"
|
|
28
|
-
:data-id="item"
|
|
29
|
-
:aria-current="currentActiveIndex === index ? 'true' : 'false'"
|
|
30
|
-
>
|
|
31
|
-
<slot :name="item"></slot>
|
|
32
|
-
</div>
|
|
31
|
+
<slot :name="item"></slot>
|
|
33
32
|
</div>
|
|
34
|
-
</
|
|
35
|
-
|
|
36
|
-
<
|
|
37
|
-
<div
|
|
38
|
-
<
|
|
39
|
-
<
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
</ul>
|
|
49
|
-
</div>
|
|
50
|
-
<div class="buttons-container">
|
|
51
|
-
<button type="button" class="btn-action" aria-label="Go to previous item" @click.prevent="actionPrevious()">
|
|
52
|
-
<Icon name="ic:outline-keyboard-arrow-left" class="arrows-icon" />
|
|
53
|
-
</button>
|
|
54
|
-
<button type="button" class="btn-action" aria-label="Go to next item" @click.prevent="actionNext()">
|
|
55
|
-
<Icon name="ic:outline-keyboard-arrow-right" class="arrows-icon" />
|
|
56
|
-
</button>
|
|
57
|
-
</div>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div v-if="showControls" ref="controlsContainerRef" tabindex="0" class="controls-container">
|
|
36
|
+
<div class="markers-container">
|
|
37
|
+
<ul class="markers-list">
|
|
38
|
+
<li v-for="index in itemCount" :key="index" class="markers-item">
|
|
39
|
+
<button
|
|
40
|
+
class="btn-marker"
|
|
41
|
+
:class="[{ active: displayActiveIndex === index - 1 }]"
|
|
42
|
+
:aria-label="`Jump to item ${index}`"
|
|
43
|
+
@click.prevent="jumpToFrame(index - 1)"
|
|
44
|
+
></button>
|
|
45
|
+
</li>
|
|
46
|
+
</ul>
|
|
58
47
|
</div>
|
|
59
|
-
</
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<div class="buttons-container">
|
|
51
|
+
<button
|
|
52
|
+
type="button"
|
|
53
|
+
class="btn-action btn-prev"
|
|
54
|
+
aria-label="Go to previous item"
|
|
55
|
+
@click.prevent="actionPrevious()"
|
|
56
|
+
>
|
|
57
|
+
<Icon name="ic:outline-keyboard-arrow-left" class="arrows-icon" />
|
|
58
|
+
</button>
|
|
59
|
+
<button type="button" class="btn-action btn-next" aria-label="Go to next item" @click.prevent="actionNext()">
|
|
60
|
+
<Icon name="ic:outline-keyboard-arrow-right" class="arrows-icon" />
|
|
61
|
+
</button>
|
|
62
|
+
</div>
|
|
60
63
|
</section>
|
|
61
64
|
</template>
|
|
62
65
|
|
|
63
66
|
<script setup lang="ts">
|
|
64
67
|
import { useEventListener, useResizeObserver, useSwipe } from "@vueuse/core";
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
carouselDataIds
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
},
|
|
87
|
-
useSpringEffect: {
|
|
88
|
-
type: Boolean,
|
|
89
|
-
default: false,
|
|
90
|
-
},
|
|
69
|
+
interface Props {
|
|
70
|
+
carouselDataIds?: string[];
|
|
71
|
+
styleClassPassthrough?: string | string[];
|
|
72
|
+
transitionSpeed?: number;
|
|
73
|
+
allowCarouselOverflow?: boolean;
|
|
74
|
+
useFlipAnimation?: boolean;
|
|
75
|
+
useSpringEffect?: boolean;
|
|
76
|
+
buttonLayout?: "sides" | "controls-flanking" | "controls-grouped-right" | "overlay";
|
|
77
|
+
showControls?: boolean;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
81
|
+
carouselDataIds: () => [],
|
|
82
|
+
styleClassPassthrough: () => [],
|
|
83
|
+
transitionSpeed: 200,
|
|
84
|
+
allowCarouselOverflow: false,
|
|
85
|
+
useFlipAnimation: false,
|
|
86
|
+
useSpringEffect: false,
|
|
87
|
+
buttonLayout: "sides",
|
|
88
|
+
showControls: true,
|
|
91
89
|
});
|
|
92
90
|
|
|
93
91
|
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
|
|
@@ -417,93 +415,100 @@ onMounted(() => {
|
|
|
417
415
|
|
|
418
416
|
<style lang="css">
|
|
419
417
|
@layer components {
|
|
420
|
-
.carousel-flip {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
height: 1px;
|
|
436
|
-
padding: 0;
|
|
437
|
-
margin: -1px;
|
|
438
|
-
overflow: hidden;
|
|
439
|
-
clip: rect(0, 0, 0, 0);
|
|
440
|
-
white-space: nowrap;
|
|
441
|
-
border: 0;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
.item-container {
|
|
445
|
-
display: flex;
|
|
446
|
-
gap: var(--_carousel-item-track-gap);
|
|
447
|
-
overflow-x: hidden;
|
|
448
|
-
position: relative;
|
|
449
|
-
isolation: isolate;
|
|
450
|
-
|
|
451
|
-
max-inline-size: var(--_carousel-display-max-width);
|
|
452
|
-
margin-inline: auto;
|
|
418
|
+
.carousel-flip {
|
|
419
|
+
--_carousel-item-track-gap: 10px;
|
|
420
|
+
|
|
421
|
+
display: grid;
|
|
422
|
+
grid-template-columns: auto 1fr auto;
|
|
423
|
+
grid-template-rows: 1fr auto;
|
|
424
|
+
grid-template-areas:
|
|
425
|
+
"prev carousel next"
|
|
426
|
+
". controls . ";
|
|
427
|
+
gap: 10px;
|
|
428
|
+
opacity: 0;
|
|
429
|
+
|
|
430
|
+
&.mounted {
|
|
431
|
+
opacity: 1;
|
|
432
|
+
}
|
|
453
433
|
|
|
454
|
-
|
|
455
|
-
|
|
434
|
+
.sr-only {
|
|
435
|
+
position: absolute;
|
|
436
|
+
width: 1px;
|
|
437
|
+
height: 1px;
|
|
438
|
+
padding: 0;
|
|
439
|
+
margin: -1px;
|
|
440
|
+
overflow: hidden;
|
|
441
|
+
clip: rect(0, 0, 0, 0);
|
|
442
|
+
white-space: nowrap;
|
|
443
|
+
border: 0;
|
|
456
444
|
}
|
|
457
445
|
|
|
458
|
-
.item {
|
|
446
|
+
.item-container {
|
|
447
|
+
grid-area: carousel;
|
|
459
448
|
display: flex;
|
|
460
|
-
|
|
449
|
+
gap: var(--_carousel-item-track-gap);
|
|
450
|
+
overflow-x: hidden;
|
|
461
451
|
position: relative;
|
|
452
|
+
isolation: isolate;
|
|
462
453
|
|
|
454
|
+
max-inline-size: var(--_carousel-display-max-width);
|
|
463
455
|
margin-inline: auto;
|
|
464
456
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
457
|
+
&.allow-overflow {
|
|
458
|
+
overflow-x: initial;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
.item {
|
|
462
|
+
display: flex;
|
|
463
|
+
flex: 0 0 100%;
|
|
464
|
+
position: relative;
|
|
469
465
|
|
|
470
|
-
|
|
471
|
-
v-bind(itemWidthOffsetStr) - var(--_carousel-item-track-gap) + var(--_carousel-item-edge-preview-width)
|
|
472
|
-
)
|
|
473
|
-
0;
|
|
466
|
+
margin-inline: auto;
|
|
474
467
|
|
|
475
|
-
|
|
476
|
-
|
|
468
|
+
max-inline-size: calc(
|
|
469
|
+
var(--_carousel-container-max-inline-size) + var(--_carousel-item-track-gap) -
|
|
470
|
+
(2 * var(--_carousel-item-edge-preview-width))
|
|
471
|
+
);
|
|
472
|
+
|
|
473
|
+
translate: calc(
|
|
474
|
+
v-bind(itemWidthOffsetStr) - var(--_carousel-item-track-gap) + var(--_carousel-item-edge-preview-width)
|
|
475
|
+
)
|
|
476
|
+
0;
|
|
477
|
+
|
|
478
|
+
&.loaded {
|
|
479
|
+
transition: transform v-bind(transitionSpeedStr) ease;
|
|
480
|
+
}
|
|
477
481
|
}
|
|
478
482
|
}
|
|
479
|
-
}
|
|
480
483
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
484
|
+
.controls-container {
|
|
485
|
+
grid-area: controls;
|
|
486
|
+
display: flex;
|
|
487
|
+
align-items: center;
|
|
488
|
+
justify-content: center;
|
|
489
|
+
max-inline-size: var(--_carousel-display-max-width);
|
|
490
|
+
margin-inline: auto;
|
|
487
491
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
492
|
+
.markers-container {
|
|
493
|
+
.markers-list {
|
|
494
|
+
display: flex;
|
|
495
|
+
flex-direction: row;
|
|
496
|
+
gap: 10px;
|
|
497
|
+
list-style-type: none;
|
|
498
|
+
margin: unset;
|
|
499
|
+
padding: unset;
|
|
500
|
+
|
|
501
|
+
.markers-item {
|
|
502
|
+
.btn-marker {
|
|
503
|
+
border: 1px solid transparent;
|
|
504
|
+
outline: 1px solid transparent;
|
|
505
|
+
box-shadow: none;
|
|
506
|
+
cursor: pointer;
|
|
507
|
+
transition: background-color v-bind(transitionSpeedStr) linear;
|
|
508
|
+
|
|
509
|
+
&.active {
|
|
510
|
+
background-color: light-dark(var(--slate-10), var(--slate-00));
|
|
511
|
+
}
|
|
507
512
|
}
|
|
508
513
|
}
|
|
509
514
|
}
|
|
@@ -511,26 +516,79 @@ onMounted(() => {
|
|
|
511
516
|
}
|
|
512
517
|
|
|
513
518
|
.buttons-container {
|
|
519
|
+
display: contents;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
.btn-prev {
|
|
523
|
+
grid-area: prev;
|
|
524
|
+
align-self: center;
|
|
525
|
+
z-index: 1;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
.btn-next {
|
|
529
|
+
grid-area: next;
|
|
530
|
+
align-self: center;
|
|
531
|
+
z-index: 1;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.btn-action {
|
|
514
535
|
display: flex;
|
|
515
536
|
align-items: center;
|
|
516
|
-
justify-content:
|
|
517
|
-
|
|
537
|
+
justify-content: center;
|
|
538
|
+
cursor: pointer;
|
|
539
|
+
height: fit-content;
|
|
540
|
+
|
|
541
|
+
background-color: white;
|
|
542
|
+
border: 1px solid light-dark(hsl(0, 29%, 3%), hsl(0, 0%, 92%));
|
|
543
|
+
border-radius: 100vw;
|
|
544
|
+
padding: 8px;
|
|
545
|
+
|
|
546
|
+
.arrows-icon {
|
|
547
|
+
width: 24px;
|
|
548
|
+
height: 24px;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/* ── controls-flanking: buttons flank the controls row ─────── */
|
|
553
|
+
&[data-button-layout="controls-flanking"] {
|
|
554
|
+
.btn-prev {
|
|
555
|
+
grid-area: unset;
|
|
556
|
+
grid-column: 1;
|
|
557
|
+
grid-row: 2;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
.btn-next {
|
|
561
|
+
grid-area: unset;
|
|
562
|
+
grid-column: 3;
|
|
563
|
+
grid-row: 2;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/* ── controls-grouped-right: markers centred, buttons end ────── */
|
|
568
|
+
&[data-button-layout="controls-grouped-right"] {
|
|
569
|
+
grid-template-columns: 1fr;
|
|
570
|
+
grid-template-areas:
|
|
571
|
+
"carousel"
|
|
572
|
+
"controls";
|
|
518
573
|
|
|
519
|
-
.
|
|
574
|
+
.buttons-container {
|
|
520
575
|
display: flex;
|
|
521
576
|
align-items: center;
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
577
|
+
gap: 10px;
|
|
578
|
+
grid-area: controls;
|
|
579
|
+
justify-self: end;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
526
582
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
583
|
+
/* ── overlay: controls float at the bottom edge of the frame ── */
|
|
584
|
+
&[data-button-layout="overlay"] {
|
|
585
|
+
.controls-container {
|
|
586
|
+
grid-area: carousel;
|
|
587
|
+
align-self: end;
|
|
588
|
+
z-index: 1;
|
|
589
|
+
padding-block-end: 1rem;
|
|
531
590
|
}
|
|
532
591
|
}
|
|
533
592
|
}
|
|
534
593
|
}
|
|
535
|
-
}
|
|
536
594
|
</style>
|
|
@@ -16,6 +16,8 @@ interface CarouselFlipStoryArgs {
|
|
|
16
16
|
transitionSpeed: number;
|
|
17
17
|
useFlipAnimation: boolean;
|
|
18
18
|
useSpringEffect: boolean;
|
|
19
|
+
buttonLayout: "sides" | "controls-flanking" | "controls-grouped-right" | "overlay";
|
|
20
|
+
showControls: boolean;
|
|
19
21
|
styleClassPassthrough: string[];
|
|
20
22
|
// Mock data for stories
|
|
21
23
|
carouselData: CarouselItem[];
|
|
@@ -105,6 +107,21 @@ export default {
|
|
|
105
107
|
category: "Animation",
|
|
106
108
|
},
|
|
107
109
|
},
|
|
110
|
+
buttonLayout: {
|
|
111
|
+
control: { type: "select" },
|
|
112
|
+
options: ["sides", "controls-flanking", "controls-grouped-right", "overlay"],
|
|
113
|
+
description: "Placement of prev/next buttons relative to the carousel and controls bar",
|
|
114
|
+
table: {
|
|
115
|
+
category: "Layout",
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
showControls: {
|
|
119
|
+
control: { type: "boolean" },
|
|
120
|
+
description: "Show or hide the markers/controls bar",
|
|
121
|
+
table: {
|
|
122
|
+
category: "Layout",
|
|
123
|
+
},
|
|
124
|
+
},
|
|
108
125
|
styleClassPassthrough: {
|
|
109
126
|
control: { type: "object" },
|
|
110
127
|
description: "Additional CSS classes to pass through",
|
|
@@ -127,6 +144,8 @@ export default {
|
|
|
127
144
|
transitionSpeed: 1000,
|
|
128
145
|
useFlipAnimation: true,
|
|
129
146
|
useSpringEffect: false,
|
|
147
|
+
buttonLayout: "sides",
|
|
148
|
+
showControls: true,
|
|
130
149
|
styleClassPassthrough: ["carousel-flip-demo"],
|
|
131
150
|
carouselData: sampleCarouselItems,
|
|
132
151
|
},
|
|
@@ -289,6 +308,8 @@ const Template: StoryFn<CarouselFlipStoryArgs> = (args) => ({
|
|
|
289
308
|
:transition-speed="args.transitionSpeed"
|
|
290
309
|
:use-flip-animation="args.useFlipAnimation"
|
|
291
310
|
:use-spring-effect="args.useSpringEffect"
|
|
311
|
+
:button-layout="args.buttonLayout"
|
|
312
|
+
:show-controls="args.showControls"
|
|
292
313
|
:style-class-passthrough="args.styleClassPassthrough"
|
|
293
314
|
>
|
|
294
315
|
<template v-for="(item, index) in filteredCarouselData" #[item.id] :key="index">
|
|
@@ -350,6 +371,16 @@ NoOverflow.args = {
|
|
|
350
371
|
styleClassPassthrough: ["carousel-flip-demo", "no-overflow"],
|
|
351
372
|
};
|
|
352
373
|
|
|
374
|
+
export const NoControls = Template.bind({});
|
|
375
|
+
NoControls.args = {
|
|
376
|
+
carouselDataIds: [1, 2, 3, 4, 5],
|
|
377
|
+
transitionSpeed: 1000,
|
|
378
|
+
useFlipAnimation: true,
|
|
379
|
+
useSpringEffect: false,
|
|
380
|
+
allowCarouselOverflow: true,
|
|
381
|
+
showControls: false,
|
|
382
|
+
};
|
|
383
|
+
|
|
353
384
|
export const ManyItems = Template.bind({});
|
|
354
385
|
ManyItems.args = {
|
|
355
386
|
carouselDataIds: [1, 2, 3, 4, 5, 6, 7, 8],
|
|
@@ -452,6 +483,8 @@ const RichContentTemplate: StoryFn<CarouselFlipStoryArgs> = (args) => ({
|
|
|
452
483
|
:transition-speed="args.transitionSpeed"
|
|
453
484
|
:use-flip-animation="args.useFlipAnimation"
|
|
454
485
|
:use-spring-effect="args.useSpringEffect"
|
|
486
|
+
:button-layout="args.buttonLayout"
|
|
487
|
+
:show-controls="args.showControls"
|
|
455
488
|
:style-class-passthrough="args.styleClassPassthrough"
|
|
456
489
|
>
|
|
457
490
|
<template v-for="(item, index) in filteredCarouselData" #[item.id] :key="index">
|
|
@@ -592,6 +625,8 @@ const AnimationShowcaseTemplate: StoryFn<CarouselFlipStoryArgs> = (args) => ({
|
|
|
592
625
|
:transition-speed="args.transitionSpeed"
|
|
593
626
|
:use-flip-animation="args.useFlipAnimation"
|
|
594
627
|
:use-spring-effect="args.useSpringEffect"
|
|
628
|
+
:button-layout="args.buttonLayout"
|
|
629
|
+
:show-controls="args.showControls"
|
|
595
630
|
:style-class-passthrough="args.styleClassPassthrough"
|
|
596
631
|
>
|
|
597
632
|
<template v-for="(item, index) in filteredCarouselData" #[item.id] :key="index">
|
|
@@ -232,6 +232,44 @@ describe("CarouselFlip", () => {
|
|
|
232
232
|
expect(component).toBeDefined();
|
|
233
233
|
// Spring effect is applied during transitions
|
|
234
234
|
});
|
|
235
|
+
|
|
236
|
+
it("shows controls container by default", async () => {
|
|
237
|
+
await createWrapper();
|
|
238
|
+
|
|
239
|
+
expect(wrapper.find(".controls-container").exists()).toBe(true);
|
|
240
|
+
expect(wrapper.findAll(".btn-marker").length).toBe(6);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it("hides controls container when showControls is false", async () => {
|
|
244
|
+
await createWrapper({ showControls: false });
|
|
245
|
+
|
|
246
|
+
expect(wrapper.find(".controls-container").exists()).toBe(false);
|
|
247
|
+
expect(wrapper.findAll(".btn-marker").length).toBe(0);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it("still renders navigation buttons when showControls is false", async () => {
|
|
251
|
+
await createWrapper({ showControls: false });
|
|
252
|
+
|
|
253
|
+
expect(wrapper.find('[aria-label="Go to previous item"]').exists()).toBe(true);
|
|
254
|
+
expect(wrapper.find('[aria-label="Go to next item"]').exists()).toBe(true);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it("navigation still works when showControls is false", async () => {
|
|
258
|
+
await createWrapper({ showControls: false });
|
|
259
|
+
await nextTick();
|
|
260
|
+
|
|
261
|
+
const nextButton = wrapper.find('[aria-label="Go to next item"]');
|
|
262
|
+
await nextButton.trigger("click");
|
|
263
|
+
await nextTick();
|
|
264
|
+
|
|
265
|
+
expect(component.currentActiveIndex).toBe(1);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it("sets data-button-layout attribute from buttonLayout prop", async () => {
|
|
269
|
+
await createWrapper({ buttonLayout: "overlay" });
|
|
270
|
+
|
|
271
|
+
expect(wrapper.attributes("data-button-layout")).toBe("overlay");
|
|
272
|
+
});
|
|
235
273
|
});
|
|
236
274
|
|
|
237
275
|
describe("Initial Setup", () => {
|