srcdev-nuxt-components 6.0.0 → 6.0.1
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/README.md +2 -2
- package/app/assets/styles/extends-layer/srcdev-components/components/_display-prompt-core.css +72 -0
- package/app/assets/styles/extends-layer/srcdev-components/components/index.css +1 -0
- package/app/assets/styles/extends-layer/srcdev-components/index.css +2 -0
- package/app/assets/styles/extends-layer/srcdev-components/setup/index.css +1 -0
- package/app/assets/styles/extends-layer/srcdev-components/setup/themes/_error.css +15 -0
- package/app/assets/styles/extends-layer/srcdev-components/setup/themes/_info.css +15 -0
- package/app/assets/styles/extends-layer/srcdev-components/setup/themes/_secondary.css +15 -0
- package/app/assets/styles/extends-layer/srcdev-components/setup/themes/_success.css +15 -0
- package/app/assets/styles/extends-layer/srcdev-components/setup/themes/_warning.css +15 -0
- package/app/assets/styles/extends-layer/srcdev-components/setup/themes/index.css +5 -0
- package/app/assets/styles/main.css +2 -0
- package/app/assets/styles/setup/_head.css +36 -0
- package/app/assets/styles/setup/a11y/_utils.css +20 -0
- package/app/assets/styles/setup/a11y/_variables.css +8 -0
- package/app/assets/styles/setup/a11y/index.css +2 -0
- package/app/assets/styles/setup/index.css +5 -0
- package/app/assets/styles/setup/typography/index.css +2 -0
- package/app/assets/styles/setup/typography/utility-classes/_generic-font-classes.css +217 -0
- package/app/assets/styles/setup/typography/utility-classes/_generic-font-variation-settings.css +29 -0
- package/app/assets/styles/setup/typography/utility-classes/_generic-font-weights.css +39 -0
- package/app/assets/styles/setup/typography/utility-classes/index.css +3 -0
- package/app/assets/styles/setup/typography/vars/_colors.css +14 -0
- package/app/assets/styles/setup/typography/vars/_reponsive-font-sizes.css +12 -0
- package/app/assets/styles/setup/typography/vars/index.css +2 -0
- package/app/assets/styles/setup/utility-classes/_fluid-spacing.css +13 -0
- package/app/assets/styles/setup/utility-classes/animations/_auto-rotate.css +13 -0
- package/app/assets/styles/setup/utility-classes/animations/_entry-exit-blur.css +16 -0
- package/app/assets/styles/setup/utility-classes/animations/_entry-slide-in.css +15 -0
- package/app/assets/styles/setup/utility-classes/animations/_entry-zoom-reveal.css +15 -0
- package/app/assets/styles/setup/utility-classes/animations/index.css +4 -0
- package/app/assets/styles/setup/utility-classes/index.css +2 -0
- package/app/assets/styles/setup/variables/colors/_blue.css +15 -0
- package/app/assets/styles/setup/variables/colors/_gray.css +16 -0
- package/app/assets/styles/setup/variables/colors/_green.css +15 -0
- package/app/assets/styles/setup/variables/colors/_orange.css +15 -0
- package/app/assets/styles/setup/variables/colors/_red.css +15 -0
- package/app/assets/styles/setup/variables/colors/_yellow.css +15 -0
- package/app/assets/styles/setup/variables/colors/index.css +6 -0
- package/app/assets/styles/setup/variables/index.css +1 -0
- package/app/components/accordian/AccordianCore.vue +46 -0
- package/app/components/animated-svg-text/AnimatedSvgText.vue +87 -0
- package/app/components/canvas-switcher/CanvasSwitcher.vue +77 -0
- package/app/components/carousel-basic/CarouselBasic.vue +291 -0
- package/app/components/carousel-basic/CarouselFlip.vue +461 -0
- package/app/components/carousel-basic/CarouselInfinite.vue +325 -0
- package/app/components/clip-element/ClipElement.vue +73 -0
- package/app/components/clipped-panels/ClippedPanel.vue +73 -0
- package/app/components/container-glow/ContainerGlowCore.vue +211 -0
- package/app/components/content-grid/ContentGrid.vue +85 -0
- package/app/components/deep-expanding-menu/DeepExpandingMenu.vue +214 -0
- package/app/components/deep-expanding-menu/DeepExpandingMenuOld.vue +218 -0
- package/app/components/display-banner/DisplayBanner.vue +63 -0
- package/app/components/display-details/DisplayDetailsCore.vue +301 -0
- package/app/components/display-dialog/DisplayDialogCore.vue +255 -0
- package/app/components/display-dialog/variants/DisplayDialogConfirm.vue +45 -0
- package/app/components/display-dialog/variants/DisplayDialogScrollableContent.vue +49 -0
- package/app/components/display-grid/DisplayGridCore.vue +22 -0
- package/app/components/display-prompt/DisplayPromptCore.vue +187 -0
- package/app/components/display-prompt/variants/DisplayPromptError.vue +53 -0
- package/app/components/expanding-panel/ExpandingPanel.vue +124 -0
- package/app/components/image-galleries/SliderGallery.vue +784 -0
- package/app/components/layout-grids/LayoutGridA.vue +103 -0
- package/app/components/layout-grids/LayoutGridB.vue +132 -0
- package/app/components/layout-row/LayoutRow.vue +165 -0
- package/app/components/masonry-grid/MasonryGrid.vue +62 -0
- package/app/components/masonry-grid-ordered/MasonryGridOrdered.vue +158 -0
- package/app/components/masonry-grid-sorted/MasonryGridSorted.vue +115 -0
- package/app/components/pop-over/PopOver.vue +88 -0
- package/app/components/responsive-header/NavigationItems.vue +169 -0
- package/app/components/responsive-header/ResponsiveHeader.vue +686 -0
- package/app/components/rotating-carousel/RotatingCarouselImage.vue +200 -0
- package/app/components/skip-links/SkipLinks.vue +92 -0
- package/app/components/tabs/TabsCore.vue +277 -0
- package/app/composables/useDialogControls.ts +44 -0
- package/app/composables/useStyleClassPassthrough.ts +35 -0
- package/app/composables/useTabs.ts +201 -0
- package/app/types/gallery-data.ts +13 -0
- package/app/types/responsiveHeader.ts +38 -0
- package/app/types/types.carousel-basic.ts +19 -0
- package/package.json +3 -6
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<section class="carousel-flip" :class="[elementClasses]" ref="carouselWrapperRef" role="region" aria-label="Image carousel">
|
|
3
|
+
<div aria-live="polite" aria-atomic="true" class="sr-only">Item {{ currentActiveIndex + 1 }} of {{ itemCount }}</div>
|
|
4
|
+
|
|
5
|
+
<LayoutRow tag="div" variant="full-width" :style-class-passthrough="['mbe-20']">
|
|
6
|
+
<div tabindex="0" class="item-container" :class="{ 'allow-overflow': allowCarouselOverflow }" ref="carouselContainerRef" role="group" aria-label="Carousel items">
|
|
7
|
+
<div
|
|
8
|
+
v-for="(item, index) in carouselDataIds"
|
|
9
|
+
:key="index"
|
|
10
|
+
class="item"
|
|
11
|
+
:class="{ loaded: carouselInitComplete && userHasInteracted }"
|
|
12
|
+
ref="carouselItems"
|
|
13
|
+
:data-id="item"
|
|
14
|
+
:aria-current="currentActiveIndex === index ? 'true' : 'false'"
|
|
15
|
+
>
|
|
16
|
+
<slot :name="item"></slot>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</LayoutRow>
|
|
20
|
+
|
|
21
|
+
<LayoutRow tag="div" variant="full-width" :style-class-passthrough="['mbe-20']">
|
|
22
|
+
<div tabindex="0" class="controls-container" ref="controlsContainerRef">
|
|
23
|
+
<div class="markers-container">
|
|
24
|
+
<ul class="markers-list">
|
|
25
|
+
<li v-for="index in itemCount" :key="index" class="markers-item">
|
|
26
|
+
<button
|
|
27
|
+
@click.prevent="jumpToFrame(index - 1)"
|
|
28
|
+
class="btn-marker"
|
|
29
|
+
:class="[{ active: currentActiveIndex === getOffsetIndex(index - 1, circularOffsetBase, itemCount) }]"
|
|
30
|
+
:aria-label="`Jump to item ${Math.floor(index + 1)}`"
|
|
31
|
+
></button>
|
|
32
|
+
</li>
|
|
33
|
+
</ul>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="buttons-container">
|
|
36
|
+
<button type="button" @click.prevent="actionPrevious()" class="btn-action" aria-label="Go to previous item">
|
|
37
|
+
<Icon name="ic:outline-keyboard-arrow-left" class="arrows-icon" />
|
|
38
|
+
</button>
|
|
39
|
+
<button type="button" @click.prevent="actionNext()" class="btn-action" aria-label="Go to next item">
|
|
40
|
+
<Icon name="ic:outline-keyboard-arrow-right" class="arrows-icon" />
|
|
41
|
+
</button>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</LayoutRow>
|
|
45
|
+
</section>
|
|
46
|
+
</template>
|
|
47
|
+
|
|
48
|
+
<script setup lang="ts">
|
|
49
|
+
import { useEventListener, useResizeObserver, useSwipe } from '@vueuse/core';
|
|
50
|
+
|
|
51
|
+
const props = defineProps({
|
|
52
|
+
carouselDataIds: {
|
|
53
|
+
type: Array as PropType<string[]>,
|
|
54
|
+
default: () => [],
|
|
55
|
+
},
|
|
56
|
+
styleClassPassthrough: {
|
|
57
|
+
type: Array as PropType<string[]>,
|
|
58
|
+
default: () => [],
|
|
59
|
+
},
|
|
60
|
+
transitionSpeed: {
|
|
61
|
+
type: Number,
|
|
62
|
+
default: 200,
|
|
63
|
+
},
|
|
64
|
+
allowCarouselOverflow: {
|
|
65
|
+
type: Boolean,
|
|
66
|
+
default: false,
|
|
67
|
+
},
|
|
68
|
+
useFlipAnimation: {
|
|
69
|
+
type: Boolean,
|
|
70
|
+
default: true,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
|
|
75
|
+
|
|
76
|
+
const carouselWrapperRef = ref<HTMLDivElement | null>(null);
|
|
77
|
+
const carouselContainerRef = ref<HTMLDivElement | null>(null);
|
|
78
|
+
const carouselItemsRef = useTemplateRef<HTMLDivElement[]>('carouselItems');
|
|
79
|
+
const controlsContainerRef = ref<HTMLDivElement | null>(null);
|
|
80
|
+
const carouselInitComplete = ref(false);
|
|
81
|
+
const userHasInteracted = ref(false);
|
|
82
|
+
|
|
83
|
+
const initialItemOffset = computed(() => {
|
|
84
|
+
return props.useFlipAnimation ? 1 : 2;
|
|
85
|
+
});
|
|
86
|
+
const circularOffsetBase = computed(() => {
|
|
87
|
+
return props.useFlipAnimation ? 1 : Math.floor(2 * initialItemOffset.value);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
function getOffsetIndex(index: number, offset: number, itemCount: number): number {
|
|
91
|
+
return (index + offset) % itemCount;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const currentIndex = ref(0);
|
|
95
|
+
const itemCount = ref(props.carouselDataIds.length);
|
|
96
|
+
const transitionSpeedStr = props.transitionSpeed + 'ms';
|
|
97
|
+
|
|
98
|
+
const itemWidth = ref(0);
|
|
99
|
+
const itemWidthOffsetStr = computed(() => {
|
|
100
|
+
if (props.allowCarouselOverflow) {
|
|
101
|
+
if (props.useFlipAnimation) {
|
|
102
|
+
return `calc(-${initialItemOffset.value} * ${itemWidth.value}px - var(--_carousel-item-track-gap))`; // Good
|
|
103
|
+
} else {
|
|
104
|
+
return `calc(-${initialItemOffset.value} * ${itemWidth.value}px - (2 * var(--_carousel-item-track-gap)))`; // Good
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
if (props.useFlipAnimation) {
|
|
108
|
+
return `calc(-${initialItemOffset.value} * ${itemWidth.value}px - var(--_carousel-item-track-gap))`; // Goof
|
|
109
|
+
} else {
|
|
110
|
+
return `calc(-${initialItemOffset.value} * ${itemWidth.value}px - (2 * var(--_carousel-item-track-gap)))`; // Good
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
const currentActiveIndex = ref(0);
|
|
115
|
+
|
|
116
|
+
const updateItemOrder = (index: number, order: number, zIndex: number = 2) => {
|
|
117
|
+
if (carouselItemsRef?.value && carouselItemsRef.value[index]) {
|
|
118
|
+
carouselItemsRef.value[index].style.order = order.toString();
|
|
119
|
+
carouselItemsRef.value[index].style.zIndex = zIndex.toString();
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
function analyzeOffsets(offsets: number[]) {
|
|
124
|
+
const counts = new Map<number, number>();
|
|
125
|
+
|
|
126
|
+
offsets.forEach((val) => {
|
|
127
|
+
counts.set(val, (counts.get(val) || 0) + 1);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const sorted = [...counts.entries()].sort((a, b) => b[1] - a[1]);
|
|
131
|
+
|
|
132
|
+
const majorityValue = sorted[0][0];
|
|
133
|
+
const minorityValue = sorted[sorted.length - 1][0];
|
|
134
|
+
const minorityIndex = offsets.findIndex((val) => val === minorityValue);
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
majorityValue,
|
|
138
|
+
minorityValue,
|
|
139
|
+
minorityIndex,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const reorderItems = (direction: 'next' | 'previous' | 'jump' = 'jump', skipAnimation: boolean = false) => {
|
|
144
|
+
if (!carouselItemsRef?.value) return;
|
|
145
|
+
|
|
146
|
+
// Capture positions before reordering (only if we're going to animate)
|
|
147
|
+
const beforeRects = skipAnimation ? [] : carouselItemsRef.value.map((item) => item.getBoundingClientRect());
|
|
148
|
+
|
|
149
|
+
// Apply new order and z-index based on direction
|
|
150
|
+
let order = 1;
|
|
151
|
+
|
|
152
|
+
// For items from currentActiveIndex to end
|
|
153
|
+
for (let i = currentActiveIndex.value; i < itemCount.value; i++) {
|
|
154
|
+
let zIndex = 2; // default normal z-index
|
|
155
|
+
|
|
156
|
+
if (i === currentActiveIndex.value) {
|
|
157
|
+
// The item becoming visible
|
|
158
|
+
if (direction === 'previous') {
|
|
159
|
+
// When going previous, the item moving to first position should go behind
|
|
160
|
+
zIndex = 1;
|
|
161
|
+
} else {
|
|
162
|
+
// Normal case - visible item gets highest z-index
|
|
163
|
+
zIndex = 3;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
updateItemOrder(i, order++, zIndex);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// For items from 0 to currentActiveIndex
|
|
171
|
+
for (let i = 0; i < currentActiveIndex.value; i++) {
|
|
172
|
+
// Items that wrap around get lower z-index to slide behind
|
|
173
|
+
const zIndex = 1;
|
|
174
|
+
updateItemOrder(i, order++, zIndex);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Skip animation if requested (for initial setup)
|
|
178
|
+
if (skipAnimation) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Animate using FLIP technique
|
|
183
|
+
requestAnimationFrame(() => {
|
|
184
|
+
const afterRects = carouselItemsRef.value!.map((item) => item.getBoundingClientRect());
|
|
185
|
+
|
|
186
|
+
// Calculate offset values
|
|
187
|
+
const offsetValues = beforeRects.map((beforeRect, index) => {
|
|
188
|
+
const afterRect = afterRects[index];
|
|
189
|
+
return beforeRect.left - afterRect.left;
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const leftValues = analyzeOffsets(offsetValues);
|
|
193
|
+
|
|
194
|
+
carouselItemsRef.value!.forEach((item, index) => {
|
|
195
|
+
const deltaX = beforeRects[index].left - afterRects[index].left;
|
|
196
|
+
|
|
197
|
+
if (deltaX !== 0) {
|
|
198
|
+
item.style.transition = 'none';
|
|
199
|
+
item.style.transform = `translateX(${deltaX}px)`;
|
|
200
|
+
|
|
201
|
+
requestAnimationFrame(() => {
|
|
202
|
+
const shouldTransition = carouselInitComplete.value && userHasInteracted.value;
|
|
203
|
+
let transitionProperties = 'none';
|
|
204
|
+
|
|
205
|
+
if (shouldTransition) {
|
|
206
|
+
if (props.allowCarouselOverflow) {
|
|
207
|
+
if (props.useFlipAnimation) {
|
|
208
|
+
transitionProperties = `transform ${transitionSpeedStr} ease`;
|
|
209
|
+
} else {
|
|
210
|
+
if (leftValues.minorityIndex !== index) {
|
|
211
|
+
transitionProperties = `transform ${transitionSpeedStr} ease`;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
if (props.useFlipAnimation) {
|
|
216
|
+
transitionProperties = `transform ${transitionSpeedStr} ease`;
|
|
217
|
+
} else {
|
|
218
|
+
if (leftValues.minorityIndex !== index) {
|
|
219
|
+
transitionProperties = `transform ${transitionSpeedStr} ease`;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
item.style.transition = transitionProperties;
|
|
226
|
+
item.style.transform = 'translateX(0)';
|
|
227
|
+
|
|
228
|
+
// After animation completes, normalize z-index values
|
|
229
|
+
const handleTransitionEnd = (event: TransitionEvent) => {
|
|
230
|
+
if (event.propertyName === 'transform') {
|
|
231
|
+
// Set final z-index: current item gets highest, others get normal
|
|
232
|
+
const isCurrentlyVisible = index === currentActiveIndex.value;
|
|
233
|
+
item.style.zIndex = isCurrentlyVisible ? '3' : '2';
|
|
234
|
+
item.removeEventListener('transitionend', handleTransitionEnd);
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
if (shouldTransition) {
|
|
239
|
+
item.addEventListener('transitionend', handleTransitionEnd);
|
|
240
|
+
} else {
|
|
241
|
+
// If no transition, immediately normalize z-index
|
|
242
|
+
const isCurrentlyVisible = index === currentActiveIndex.value;
|
|
243
|
+
item.style.zIndex = isCurrentlyVisible ? '3' : '2';
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const actionPrevious = () => {
|
|
252
|
+
if (!carouselInitComplete.value || !carouselItemsRef?.value) return;
|
|
253
|
+
|
|
254
|
+
userHasInteracted.value = true;
|
|
255
|
+
|
|
256
|
+
if (currentActiveIndex.value === 0) {
|
|
257
|
+
currentActiveIndex.value = itemCount.value - 1;
|
|
258
|
+
} else {
|
|
259
|
+
currentActiveIndex.value = currentActiveIndex.value === 0 ? itemCount.value - 1 : currentActiveIndex.value - 1;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
reorderItems('previous');
|
|
263
|
+
currentIndex.value = currentActiveIndex.value;
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const actionNext = () => {
|
|
267
|
+
if (!carouselInitComplete.value || !carouselItemsRef?.value) return;
|
|
268
|
+
|
|
269
|
+
userHasInteracted.value = true;
|
|
270
|
+
|
|
271
|
+
if (currentActiveIndex.value === itemCount.value - 1) {
|
|
272
|
+
currentActiveIndex.value = 0;
|
|
273
|
+
} else {
|
|
274
|
+
currentActiveIndex.value = currentActiveIndex.value === itemCount.value - 1 ? 0 : currentActiveIndex.value + 1;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
reorderItems('next');
|
|
278
|
+
currentIndex.value = currentActiveIndex.value;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
const jumpToFrame = (index: number) => {
|
|
282
|
+
if (index >= 0 && index < itemCount.value) {
|
|
283
|
+
// Only mark as user interaction if carousel is already initialized
|
|
284
|
+
if (carouselInitComplete.value) {
|
|
285
|
+
userHasInteracted.value = true;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
currentActiveIndex.value = getOffsetIndex(index, circularOffsetBase.value, itemCount.value);
|
|
289
|
+
|
|
290
|
+
// currentActiveIndex.value = index;
|
|
291
|
+
reorderItems('jump');
|
|
292
|
+
currentIndex.value = currentActiveIndex.value;
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const checkAndMoveLastItem = () => {
|
|
297
|
+
if (props.allowCarouselOverflow || !props.useFlipAnimation) {
|
|
298
|
+
currentActiveIndex.value = itemCount.value - initialItemOffset.value;
|
|
299
|
+
reorderItems('jump', true); // Skip animation during initial setup
|
|
300
|
+
currentIndex.value = currentActiveIndex.value;
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
const initialSetup = () => {
|
|
305
|
+
if (carouselItemsRef?.value && carouselItemsRef.value.length > 0 && carouselItemsRef.value[0]) {
|
|
306
|
+
itemWidth.value = carouselItemsRef.value[0].offsetWidth;
|
|
307
|
+
|
|
308
|
+
// Set initial order and z-index for all items
|
|
309
|
+
carouselItemsRef.value.forEach((item, index) => {
|
|
310
|
+
item.style.order = String(index + 1);
|
|
311
|
+
item.dataset.order = String(index + 1);
|
|
312
|
+
// First item gets higher z-index, others get normal z-index
|
|
313
|
+
item.style.zIndex = index === 0 ? '3' : '2';
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
carouselInitComplete.value = true;
|
|
318
|
+
checkAndMoveLastItem();
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const { direction } = useSwipe(carouselContainerRef, {
|
|
322
|
+
passive: false,
|
|
323
|
+
onSwipeEnd() {
|
|
324
|
+
if (direction.value === 'left') {
|
|
325
|
+
actionNext();
|
|
326
|
+
} else if (direction.value === 'right') {
|
|
327
|
+
actionPrevious();
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
useEventListener(carouselContainerRef, 'keydown', (event: KeyboardEvent) => {
|
|
333
|
+
if (event.key === 'ArrowLeft') {
|
|
334
|
+
actionPrevious();
|
|
335
|
+
} else if (event.key === 'ArrowRight') {
|
|
336
|
+
actionNext();
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
useEventListener(controlsContainerRef, 'keydown', (event: KeyboardEvent) => {
|
|
341
|
+
if (event.key === 'ArrowLeft') {
|
|
342
|
+
actionPrevious();
|
|
343
|
+
} else if (event.key === 'ArrowRight') {
|
|
344
|
+
actionNext();
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
useResizeObserver(carouselWrapperRef, async () => {
|
|
349
|
+
initialSetup();
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
onMounted(() => {
|
|
353
|
+
initialSetup();
|
|
354
|
+
});
|
|
355
|
+
</script>
|
|
356
|
+
|
|
357
|
+
<style lang="css">
|
|
358
|
+
.carousel-flip {
|
|
359
|
+
--_carousel-item-track-gap: 10px;
|
|
360
|
+
|
|
361
|
+
display: grid;
|
|
362
|
+
grid-template-columns: 1fr;
|
|
363
|
+
gap: 10px;
|
|
364
|
+
|
|
365
|
+
.sr-only {
|
|
366
|
+
position: absolute;
|
|
367
|
+
width: 1px;
|
|
368
|
+
height: 1px;
|
|
369
|
+
padding: 0;
|
|
370
|
+
margin: -1px;
|
|
371
|
+
overflow: hidden;
|
|
372
|
+
clip: rect(0, 0, 0, 0);
|
|
373
|
+
white-space: nowrap;
|
|
374
|
+
border: 0;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.item-container {
|
|
378
|
+
display: flex;
|
|
379
|
+
gap: var(--_carousel-item-track-gap);
|
|
380
|
+
overflow-x: hidden;
|
|
381
|
+
position: relative;
|
|
382
|
+
|
|
383
|
+
max-inline-size: var(--_carousel-display-max-width);
|
|
384
|
+
margin-inline: auto;
|
|
385
|
+
|
|
386
|
+
&.allow-overflow {
|
|
387
|
+
overflow-x: initial;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.item {
|
|
391
|
+
display: flex;
|
|
392
|
+
flex: 0 0 100%;
|
|
393
|
+
position: relative;
|
|
394
|
+
|
|
395
|
+
margin-inline: auto;
|
|
396
|
+
|
|
397
|
+
max-inline-size: calc(var(--_carousel-container-max-inline-size) + var(--_carousel-item-track-gap) - (2 * var(--_carousel-item-edge-preview-width)));
|
|
398
|
+
|
|
399
|
+
translate: calc(v-bind(itemWidthOffsetStr) - var(--_carousel-item-track-gap) + var(--_carousel-item-edge-preview-width)) 0;
|
|
400
|
+
|
|
401
|
+
&.loaded {
|
|
402
|
+
transition: transform v-bind(transitionSpeedStr) ease;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.controls-container {
|
|
408
|
+
display: flex;
|
|
409
|
+
align-items: center;
|
|
410
|
+
justify-content: flex-end;
|
|
411
|
+
max-inline-size: var(--_carousel-display-max-width);
|
|
412
|
+
margin-inline: auto;
|
|
413
|
+
|
|
414
|
+
.markers-container {
|
|
415
|
+
.markers-list {
|
|
416
|
+
display: flex;
|
|
417
|
+
flex-direction: row;
|
|
418
|
+
gap: 10px;
|
|
419
|
+
list-style-type: none;
|
|
420
|
+
margin: unset;
|
|
421
|
+
padding: unset;
|
|
422
|
+
|
|
423
|
+
.markers-item {
|
|
424
|
+
.btn-marker {
|
|
425
|
+
border: 1px solid transparent;
|
|
426
|
+
outline: 1px solid transparent;
|
|
427
|
+
box-shadow: none;
|
|
428
|
+
cursor: pointer;
|
|
429
|
+
transition: background-color v-bind(transitionSpeedStr) linear;
|
|
430
|
+
|
|
431
|
+
&.active {
|
|
432
|
+
background-color: light-dark(var(--gray-12), var(--gray-00));
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.buttons-container {
|
|
440
|
+
display: flex;
|
|
441
|
+
align-items: center;
|
|
442
|
+
justify-content: end;
|
|
443
|
+
gap: 20px;
|
|
444
|
+
|
|
445
|
+
.btn-action {
|
|
446
|
+
display: flex;
|
|
447
|
+
align-items: center;
|
|
448
|
+
justify-content: center;
|
|
449
|
+
|
|
450
|
+
cursor: pointer;
|
|
451
|
+
height: fit-content;
|
|
452
|
+
|
|
453
|
+
.arrows-icon {
|
|
454
|
+
width: 24px;
|
|
455
|
+
height: 24px;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
</style>
|