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.
Files changed (81) hide show
  1. package/README.md +2 -2
  2. package/app/assets/styles/extends-layer/srcdev-components/components/_display-prompt-core.css +72 -0
  3. package/app/assets/styles/extends-layer/srcdev-components/components/index.css +1 -0
  4. package/app/assets/styles/extends-layer/srcdev-components/index.css +2 -0
  5. package/app/assets/styles/extends-layer/srcdev-components/setup/index.css +1 -0
  6. package/app/assets/styles/extends-layer/srcdev-components/setup/themes/_error.css +15 -0
  7. package/app/assets/styles/extends-layer/srcdev-components/setup/themes/_info.css +15 -0
  8. package/app/assets/styles/extends-layer/srcdev-components/setup/themes/_secondary.css +15 -0
  9. package/app/assets/styles/extends-layer/srcdev-components/setup/themes/_success.css +15 -0
  10. package/app/assets/styles/extends-layer/srcdev-components/setup/themes/_warning.css +15 -0
  11. package/app/assets/styles/extends-layer/srcdev-components/setup/themes/index.css +5 -0
  12. package/app/assets/styles/main.css +2 -0
  13. package/app/assets/styles/setup/_head.css +36 -0
  14. package/app/assets/styles/setup/a11y/_utils.css +20 -0
  15. package/app/assets/styles/setup/a11y/_variables.css +8 -0
  16. package/app/assets/styles/setup/a11y/index.css +2 -0
  17. package/app/assets/styles/setup/index.css +5 -0
  18. package/app/assets/styles/setup/typography/index.css +2 -0
  19. package/app/assets/styles/setup/typography/utility-classes/_generic-font-classes.css +217 -0
  20. package/app/assets/styles/setup/typography/utility-classes/_generic-font-variation-settings.css +29 -0
  21. package/app/assets/styles/setup/typography/utility-classes/_generic-font-weights.css +39 -0
  22. package/app/assets/styles/setup/typography/utility-classes/index.css +3 -0
  23. package/app/assets/styles/setup/typography/vars/_colors.css +14 -0
  24. package/app/assets/styles/setup/typography/vars/_reponsive-font-sizes.css +12 -0
  25. package/app/assets/styles/setup/typography/vars/index.css +2 -0
  26. package/app/assets/styles/setup/utility-classes/_fluid-spacing.css +13 -0
  27. package/app/assets/styles/setup/utility-classes/animations/_auto-rotate.css +13 -0
  28. package/app/assets/styles/setup/utility-classes/animations/_entry-exit-blur.css +16 -0
  29. package/app/assets/styles/setup/utility-classes/animations/_entry-slide-in.css +15 -0
  30. package/app/assets/styles/setup/utility-classes/animations/_entry-zoom-reveal.css +15 -0
  31. package/app/assets/styles/setup/utility-classes/animations/index.css +4 -0
  32. package/app/assets/styles/setup/utility-classes/index.css +2 -0
  33. package/app/assets/styles/setup/variables/colors/_blue.css +15 -0
  34. package/app/assets/styles/setup/variables/colors/_gray.css +16 -0
  35. package/app/assets/styles/setup/variables/colors/_green.css +15 -0
  36. package/app/assets/styles/setup/variables/colors/_orange.css +15 -0
  37. package/app/assets/styles/setup/variables/colors/_red.css +15 -0
  38. package/app/assets/styles/setup/variables/colors/_yellow.css +15 -0
  39. package/app/assets/styles/setup/variables/colors/index.css +6 -0
  40. package/app/assets/styles/setup/variables/index.css +1 -0
  41. package/app/components/accordian/AccordianCore.vue +46 -0
  42. package/app/components/animated-svg-text/AnimatedSvgText.vue +87 -0
  43. package/app/components/canvas-switcher/CanvasSwitcher.vue +77 -0
  44. package/app/components/carousel-basic/CarouselBasic.vue +291 -0
  45. package/app/components/carousel-basic/CarouselFlip.vue +461 -0
  46. package/app/components/carousel-basic/CarouselInfinite.vue +325 -0
  47. package/app/components/clip-element/ClipElement.vue +73 -0
  48. package/app/components/clipped-panels/ClippedPanel.vue +73 -0
  49. package/app/components/container-glow/ContainerGlowCore.vue +211 -0
  50. package/app/components/content-grid/ContentGrid.vue +85 -0
  51. package/app/components/deep-expanding-menu/DeepExpandingMenu.vue +214 -0
  52. package/app/components/deep-expanding-menu/DeepExpandingMenuOld.vue +218 -0
  53. package/app/components/display-banner/DisplayBanner.vue +63 -0
  54. package/app/components/display-details/DisplayDetailsCore.vue +301 -0
  55. package/app/components/display-dialog/DisplayDialogCore.vue +255 -0
  56. package/app/components/display-dialog/variants/DisplayDialogConfirm.vue +45 -0
  57. package/app/components/display-dialog/variants/DisplayDialogScrollableContent.vue +49 -0
  58. package/app/components/display-grid/DisplayGridCore.vue +22 -0
  59. package/app/components/display-prompt/DisplayPromptCore.vue +187 -0
  60. package/app/components/display-prompt/variants/DisplayPromptError.vue +53 -0
  61. package/app/components/expanding-panel/ExpandingPanel.vue +124 -0
  62. package/app/components/image-galleries/SliderGallery.vue +784 -0
  63. package/app/components/layout-grids/LayoutGridA.vue +103 -0
  64. package/app/components/layout-grids/LayoutGridB.vue +132 -0
  65. package/app/components/layout-row/LayoutRow.vue +165 -0
  66. package/app/components/masonry-grid/MasonryGrid.vue +62 -0
  67. package/app/components/masonry-grid-ordered/MasonryGridOrdered.vue +158 -0
  68. package/app/components/masonry-grid-sorted/MasonryGridSorted.vue +115 -0
  69. package/app/components/pop-over/PopOver.vue +88 -0
  70. package/app/components/responsive-header/NavigationItems.vue +169 -0
  71. package/app/components/responsive-header/ResponsiveHeader.vue +686 -0
  72. package/app/components/rotating-carousel/RotatingCarouselImage.vue +200 -0
  73. package/app/components/skip-links/SkipLinks.vue +92 -0
  74. package/app/components/tabs/TabsCore.vue +277 -0
  75. package/app/composables/useDialogControls.ts +44 -0
  76. package/app/composables/useStyleClassPassthrough.ts +35 -0
  77. package/app/composables/useTabs.ts +201 -0
  78. package/app/types/gallery-data.ts +13 -0
  79. package/app/types/responsiveHeader.ts +38 -0
  80. package/app/types/types.carousel-basic.ts +19 -0
  81. 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>