@kiva/kv-components 3.105.2 → 3.106.0

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/CHANGELOG.md CHANGED
@@ -3,6 +3,25 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [3.106.0](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.105.3...@kiva/kv-components@3.106.0) (2024-11-01)
7
+
8
+
9
+ ### Features
10
+
11
+ * basic vertical carousel ([6a40563](https://github.com/kiva/kv-ui-elements/commit/6a405637ee4186d3cb5a7dbf71f87d8a04d46d86))
12
+
13
+
14
+
15
+
16
+
17
+ ## [3.105.3](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.105.2...@kiva/kv-components@3.105.3) (2024-10-28)
18
+
19
+ **Note:** Version bump only for package @kiva/kv-components
20
+
21
+
22
+
23
+
24
+
6
25
  ## [3.105.2](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.105.1...@kiva/kv-components@3.105.2) (2024-10-25)
7
26
 
8
27
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kiva/kv-components",
3
- "version": "3.105.2",
3
+ "version": "3.106.0",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -83,5 +83,5 @@
83
83
  "optional": true
84
84
  }
85
85
  },
86
- "gitHead": "1eb69b9a5626681003c8bf9569e64e3fc51801c4"
86
+ "gitHead": "c195fd4d6bf8055879846dc5821873e9bc336f1c"
87
87
  }
@@ -0,0 +1,190 @@
1
+ /* eslint-disable import/prefer-default-export */
2
+ import {
3
+ computed,
4
+ onMounted,
5
+ onUnmounted,
6
+ ref,
7
+ toRefs,
8
+ nextTick,
9
+ } from 'vue-demi';
10
+ import EmblaCarousel from 'embla-carousel';
11
+ import { throttle } from './throttle';
12
+
13
+ export function carouselUtil(props, { emit, slots }, extraEmblaOptions) {
14
+ const {
15
+ emblaOptions,
16
+ slidesToScroll,
17
+ } = toRefs(props);
18
+ const rootEl = ref(null);
19
+ const embla = ref(null);
20
+ const slides = ref([]);
21
+ const startIndex = emblaOptions.value?.startIndex ?? 0;
22
+ const currentIndex = ref(startIndex);
23
+ // The indicator count may differ from the slide count when multiple slides are in view
24
+ const slideIndicatorCount = ref(0);
25
+
26
+ const componentSlotKeys = computed(() => {
27
+ const keys = Object.keys(slots);
28
+ return keys;
29
+ });
30
+
31
+ const nextIndex = computed(() => {
32
+ const nextSlideIndex = currentIndex.value + 1;
33
+ if (nextSlideIndex < slides.value.length) {
34
+ return nextSlideIndex;
35
+ }
36
+ return 0;
37
+ });
38
+
39
+ const previousIndex = computed(() => {
40
+ const previousSlideIndex = currentIndex.value - 1;
41
+ if (previousSlideIndex >= 0) {
42
+ return previousSlideIndex;
43
+ }
44
+ return slides.value.length - 1;
45
+ });
46
+
47
+ /**
48
+ * Jump to a specific slide index
49
+ *
50
+ * @param {Number} num Index of slide to show
51
+ * @public This is a public method
52
+ */
53
+ const goToSlide = (index) => {
54
+ embla.value.scrollTo(index);
55
+ };
56
+ const handleUserInteraction = async (index, interactionType) => {
57
+ if (index !== null && typeof index !== 'undefined') {
58
+ await nextTick(); // wait for embla.
59
+ goToSlide(index);
60
+ }
61
+ /**
62
+ * Fires when the user interacts with the carousel.
63
+ * Contains the interaction type (swipe-left, click-left-arrow, etc.)
64
+ * @event interact-carousel
65
+ * @type {Event}
66
+ */
67
+ emit('interact-carousel', interactionType);
68
+ };
69
+
70
+ /**
71
+ * Returns number of slides in the carousel
72
+ *
73
+ * @returns {Number}
74
+ */
75
+ const slideIndicatorListLength = () => {
76
+ const indicator = embla.value ? embla.value.scrollSnapList().length : 0;
77
+ slideIndicatorCount.value = indicator;
78
+ return indicator;
79
+ };
80
+
81
+ /**
82
+ * Reinitialize the carousel.
83
+ * Used after adding slides dynamically.
84
+ *
85
+ * @public This is a public method
86
+ */
87
+ const reInitVisible = () => {
88
+ const slidesInView = embla.value.slidesInView(true).length;
89
+ if (slidesInView) {
90
+ embla.value.reInit({
91
+ slidesToScroll: slidesInView,
92
+ inViewThreshold: 0.9,
93
+ });
94
+ }
95
+ };
96
+ const reInit = () => {
97
+ embla.value.reInit();
98
+ if (slidesToScroll.value === 'visible') {
99
+ reInitVisible();
100
+ }
101
+ slides.value = embla.value.slideNodes();
102
+ slideIndicatorListLength();
103
+ };
104
+ const onCarouselContainerClick = (e) => {
105
+ // If we're dragging, block click handlers within slides
106
+ if (embla.value && !embla.value.clickAllowed()) {
107
+ e.preventDefault();
108
+ e.stopPropagation();
109
+ }
110
+ };
111
+ /**
112
+ * If the slide is not completely in view in the carousel
113
+ * it should be aria-hidden
114
+ *
115
+ * @param {Number} index The current index of the slide
116
+ * @returns {Boolean}
117
+ */
118
+ const isAriaHidden = (index) => {
119
+ if (embla.value) {
120
+ return !embla.value.slidesInView(true).includes(index);
121
+ }
122
+ return false;
123
+ };
124
+
125
+ onMounted(async () => {
126
+ embla.value = EmblaCarousel(rootEl.value, {
127
+ loop: true,
128
+ containScroll: 'trimSnaps',
129
+ inViewThreshold: 0.9,
130
+ align: 'start',
131
+ ...extraEmblaOptions,
132
+ ...emblaOptions.value,
133
+ });
134
+
135
+ if (slidesToScroll.value === 'visible') {
136
+ reInitVisible();
137
+
138
+ embla.value.on(
139
+ 'resize',
140
+ throttle(() => {
141
+ embla.value.reInit({
142
+ slidesToScroll: embla.value.slidesInView(true).length || 'auto',
143
+ inViewThreshold: 0.9,
144
+ });
145
+ slides.value = embla.value.slideNodes();
146
+ slideIndicatorListLength();
147
+ }, 250),
148
+ );
149
+ }
150
+
151
+ // get slide components
152
+ slides.value = embla.value.slideNodes();
153
+ slideIndicatorListLength();
154
+
155
+ embla?.value?.on('select', () => {
156
+ currentIndex.value = embla.value.selectedScrollSnap();
157
+ /**
158
+ * The index of the slide that the carousel has changed to
159
+ * @event change
160
+ * @type {Event}
161
+ */
162
+ nextTick(() => {
163
+ emit('change', currentIndex);
164
+ });
165
+ });
166
+ });
167
+
168
+ onUnmounted(async () => {
169
+ embla?.value?.off('select');
170
+ embla?.value?.destroy();
171
+ });
172
+
173
+ return {
174
+ rootEl,
175
+ embla,
176
+ slides,
177
+ currentIndex,
178
+ componentSlotKeys,
179
+ nextIndex,
180
+ previousIndex,
181
+ slideIndicatorCount,
182
+ handleUserInteraction,
183
+ goToSlide,
184
+ reInit,
185
+ reInitVisible,
186
+ onCarouselContainerClick,
187
+ isAriaHidden,
188
+ slideIndicatorListLength,
189
+ };
190
+ }
@@ -23,7 +23,7 @@
23
23
  :aria-current="currentIndex === index ? 'true' : 'false'"
24
24
  :aria-hidden="isAriaHidden(index)? 'true' : 'false'"
25
25
  :tab-index="isAriaHidden(index) ? '-1' : false"
26
- :class="{ 'tw-w-full': !multipleSlidesVisible || slideMaxWidth, 'cirle-slide': inCircle }"
26
+ :class="{ 'tw-w-full': !multipleSlidesVisible || slideMaxWidth, 'circle-slide': inCircle }"
27
27
  :style="slideMaxWidth ? `max-width:${slideMaxWidth}` :''"
28
28
  >
29
29
  <slot
@@ -146,22 +146,13 @@
146
146
  </template>
147
147
 
148
148
  <script>
149
- import {
150
- computed,
151
- onMounted,
152
- onUnmounted,
153
- ref,
154
- toRefs,
155
- nextTick,
156
- } from 'vue-demi';
157
- import EmblaCarousel from 'embla-carousel';
158
149
  import {
159
150
  mdiChevronLeft,
160
151
  mdiChevronRight,
161
152
  mdiArrowLeft,
162
153
  mdiArrowRight,
163
154
  } from '@mdi/js';
164
- import { throttle } from '../utils/throttle';
155
+ import { carouselUtil } from '../utils/carousels';
165
156
 
166
157
  import KvMaterialIcon from './KvMaterialIcon.vue';
167
158
 
@@ -236,183 +227,43 @@ export default {
236
227
  ],
237
228
  setup(props, { emit, slots }) {
238
229
  const {
239
- emblaOptions,
240
- slidesToScroll,
241
- } = toRefs(props);
242
- const rootEl = ref(null);
243
- const embla = ref(null);
244
- const slides = ref([]);
245
- const startIndex = emblaOptions.value?.startIndex ?? 0;
246
- const currentIndex = ref(startIndex);
247
- // The indicator count may differ from the slide count when multiple slides are in view
248
- const slideIndicatorCount = ref(0);
249
-
250
- const componentSlotKeys = computed(() => {
251
- const keys = Object.keys(slots);
252
- return keys;
253
- });
254
-
255
- const nextIndex = computed(() => {
256
- const nextSlideIndex = currentIndex.value + 1;
257
- if (nextSlideIndex < slides.value.length) {
258
- return nextSlideIndex;
259
- }
260
- return 0;
261
- });
262
-
263
- const previousIndex = computed(() => {
264
- const previousSlideIndex = currentIndex.value - 1;
265
- if (previousSlideIndex >= 0) {
266
- return previousSlideIndex;
267
- }
268
- return slides.value.length - 1;
269
- });
270
-
271
- /**
272
- * Jump to a specific slide index
273
- *
274
- * @param {Number} num Index of slide to show
275
- * @public This is a public method
276
- */
277
- const goToSlide = (index) => {
278
- embla.value.scrollTo(index);
279
- };
280
- const handleUserInteraction = async (index, interactionType) => {
281
- if (index !== null && typeof index !== 'undefined') {
282
- await nextTick(); // wait for embla.
283
- goToSlide(index);
284
- }
285
- /**
286
- * Fires when the user interacts with the carousel.
287
- * Contains the interaction type (swipe-left, click-left-arrow, etc.)
288
- * @event interact-carousel
289
- * @type {Event}
290
- */
291
- emit('interact-carousel', interactionType);
292
- };
293
-
294
- /**
295
- * Returns number of slides in the carousel
296
- *
297
- * @returns {Number}
298
- */
299
- const slideIndicatorListLength = () => {
300
- const indicator = embla.value ? embla.value.scrollSnapList().length : 0;
301
- slideIndicatorCount.value = indicator;
302
- return indicator;
303
- };
304
-
305
- /**
306
- * Reinitialize the carousel.
307
- * Used after adding slides dynamically.
308
- *
309
- * @public This is a public method
310
- */
311
- const reInitVisible = () => {
312
- const slidesInView = embla.value.slidesInView(true).length;
313
- if (slidesInView) {
314
- embla.value.reInit({
315
- slidesToScroll: slidesInView,
316
- inViewThreshold: 0.9,
317
- });
318
- }
319
- };
320
- const reInit = () => {
321
- embla.value.reInit();
322
- if (slidesToScroll.value === 'visible') {
323
- reInitVisible();
324
- }
325
- slides.value = embla.value.slideNodes();
326
- slideIndicatorListLength();
327
- };
328
- const onCarouselContainerClick = (e) => {
329
- // If we're dragging, block click handlers within slides
330
- if (embla.value && !embla.value.clickAllowed()) {
331
- e.preventDefault();
332
- e.stopPropagation();
333
- }
334
- };
335
- /**
336
- * If the slide is not completely in view in the carousel
337
- * it should be aria-hidden
338
- *
339
- * @param {Number} index The current index of the slide
340
- * @returns {Boolean}
341
- */
342
- const isAriaHidden = (index) => {
343
- if (embla.value) {
344
- return !embla.value.slidesInView(true).includes(index);
345
- }
346
- return false;
347
- };
348
-
349
- onMounted(async () => {
350
- embla.value = EmblaCarousel(rootEl.value, {
351
- loop: true,
352
- containScroll: 'trimSnaps',
353
- inViewThreshold: 0.9,
354
- align: 'start',
355
- ...emblaOptions.value,
356
- });
357
-
358
- if (slidesToScroll.value === 'visible') {
359
- reInitVisible();
360
-
361
- embla.value.on(
362
- 'resize',
363
- throttle(() => {
364
- embla.value.reInit({
365
- slidesToScroll: embla.value.slidesInView(true).length || 'auto',
366
- inViewThreshold: 0.9,
367
- });
368
- slides.value = embla.value.slideNodes();
369
- slideIndicatorListLength();
370
- }, 250),
371
- );
372
- }
373
-
374
- // get slide components
375
- slides.value = embla.value.slideNodes();
376
- slideIndicatorListLength();
377
-
378
- embla?.value?.on('select', () => {
379
- currentIndex.value = embla.value.selectedScrollSnap();
380
- /**
381
- * The index of the slide that the carousel has changed to
382
- * @event change
383
- * @type {Event}
384
- */
385
- nextTick(() => {
386
- emit('change', currentIndex);
387
- });
388
- });
389
- });
390
-
391
- onUnmounted(async () => {
392
- embla?.value?.off('select');
393
- embla?.value?.destroy();
394
- });
230
+ componentSlotKeys,
231
+ currentIndex,
232
+ embla,
233
+ goToSlide,
234
+ handleUserInteraction,
235
+ isAriaHidden,
236
+ nextIndex,
237
+ onCarouselContainerClick,
238
+ previousIndex,
239
+ reInit,
240
+ reInitVisible,
241
+ rootEl,
242
+ slideIndicatorCount,
243
+ slideIndicatorListLength,
244
+ slides,
245
+ } = carouselUtil(props, { emit, slots });
395
246
 
396
247
  return {
397
- rootEl,
398
- mdiChevronLeft,
399
- mdiChevronRight,
248
+ componentSlotKeys,
249
+ currentIndex,
250
+ embla,
251
+ goToSlide,
252
+ handleUserInteraction,
253
+ isAriaHidden,
400
254
  mdiArrowLeft,
401
255
  mdiArrowRight,
402
- embla,
403
- slides,
404
- currentIndex,
405
- componentSlotKeys,
256
+ mdiChevronLeft,
257
+ mdiChevronRight,
406
258
  nextIndex,
259
+ onCarouselContainerClick,
407
260
  previousIndex,
408
- slideIndicatorCount,
409
- handleUserInteraction,
410
- goToSlide,
411
261
  reInit,
412
262
  reInitVisible,
413
- onCarouselContainerClick,
414
- isAriaHidden,
263
+ rootEl,
264
+ slideIndicatorCount,
415
265
  slideIndicatorListLength,
266
+ slides,
416
267
  };
417
268
  },
418
269
  };
@@ -425,17 +276,17 @@ export default {
425
276
  }
426
277
  }
427
278
 
428
- .cirle-slide {
279
+ .circle-slide {
429
280
  width: auto;
430
281
  }
431
282
 
432
- .cirle-slide.is-selected {
283
+ .circle-slide.is-selected {
433
284
  opacity: 1;
434
285
  transform: scale(1.2);
435
286
  max-width: 300px;
436
287
  }
437
288
 
438
- .cirle-slide:not(.is-selected) {
289
+ .circle-slide:not(.is-selected) {
439
290
  opacity: 0.5;
440
291
  transform: scale(0.7);
441
292
  }
package/vue/KvMap.vue CHANGED
@@ -203,6 +203,8 @@ export default {
203
203
  },
204
204
  async mounted() {
205
205
  if (this.countriesData) {
206
+ // current source data is from https://geojson.xyz/ under "admin 0 countries"
207
+ // https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_110m_admin_0_countries.geojson
206
208
  this.countriesBorders = await import('../data/ne_110m_admin_0_countries.json');
207
209
  }
208
210
 
@@ -0,0 +1,156 @@
1
+ <template>
2
+ <div>
3
+ <section
4
+ ref="rootEl"
5
+ aria-label="carousel"
6
+ class="kv-carousel tw-overflow-hidden tw-relative"
7
+ >
8
+ <!-- Carousel Content -->
9
+ <div
10
+ class="tw-flex tw-flex-col tw-gap-y-1"
11
+ :style="`height: ${heightStyle}`"
12
+ @click.capture="onCarouselContainerClick"
13
+ >
14
+ <div
15
+ v-for="(slotName, index) in componentSlotKeys"
16
+ :key="index"
17
+ role="group"
18
+ :aria-label="`slide ${index + 1} of ${componentSlotKeys.length}`"
19
+ :aria-current="currentIndex === index ? 'true' : 'false'"
20
+ :aria-hidden="isAriaHidden(index)? 'true' : 'false'"
21
+ :tab-index="isAriaHidden(index) ? '-1' : false"
22
+ >
23
+ <slot
24
+ :name="slotName"
25
+ ></slot>
26
+ </div>
27
+ </div>
28
+ </section>
29
+ <!-- Carousel Controls -->
30
+ <div
31
+ class="kv-carousel__controls tw-flex
32
+ tw-justify-between md:tw-justify-center tw-items-center tw-gap-2
33
+ tw-mt-2 tw-w-full"
34
+ >
35
+ <button
36
+ class="tw-text-primary
37
+ tw-rounded-full
38
+ tw-border-2 tw-border-primary
39
+ tw-h-4 tw-w-4
40
+ tw-flex tw-items-center tw-justify-center
41
+ disabled:tw-opacity-low disabled:tw-cursor-default"
42
+ :disabled="embla && !embla.canScrollPrev()"
43
+ @click="handleUserInteraction(previousIndex, 'click-left-arrow')"
44
+ >
45
+ <kv-material-icon
46
+ class="tw-w-4"
47
+ :icon="mdiChevronUp"
48
+ />
49
+ <span class="tw-sr-only">Show previous slide</span>
50
+ </button>
51
+ <button
52
+ class="tw-text-primary
53
+ tw-rounded-full
54
+ tw-border-2 tw-border-primary
55
+ tw-h-4 tw-w-4
56
+ tw-flex tw-items-center tw-justify-center
57
+ disabled:tw-opacity-low disabled:tw-cursor-default"
58
+ :disabled="embla && !embla.canScrollNext()"
59
+ @click="handleUserInteraction(nextIndex, 'click-right-arrow')"
60
+ >
61
+ <kv-material-icon
62
+ class="tw-w-4"
63
+ :icon="mdiChevronDown"
64
+ />
65
+ <span class="tw-sr-only">Show next slide</span>
66
+ </button>
67
+ </div>
68
+ </div>
69
+ </template>
70
+
71
+ <script>
72
+ import {
73
+ mdiChevronUp,
74
+ mdiChevronDown,
75
+ } from '@mdi/js';
76
+ import { carouselUtil } from '../utils/carousels';
77
+ import KvMaterialIcon from './KvMaterialIcon.vue';
78
+
79
+ export default {
80
+ components: {
81
+ KvMaterialIcon,
82
+ },
83
+ props: {
84
+ /**
85
+ * Height style declaration of the vertical carousel.
86
+ * */
87
+ heightStyle: {
88
+ type: String,
89
+ default: '400px;',
90
+ },
91
+ /**
92
+ * Options for the embla carousel - // https://davidcetinkaya.github.io/embla-carousel/api#options
93
+ * */
94
+ emblaOptions: {
95
+ type: Object,
96
+ default() {
97
+ return {};
98
+ },
99
+ },
100
+ /**
101
+ * The type of logic to implement when deciding how many slides
102
+ * to scroll when pressing the next/prev button
103
+ * `visible, auto`
104
+ * */
105
+ slidesToScroll: {
106
+ type: String,
107
+ default: 'auto',
108
+ validator: (value) => ['visible', 'auto'].indexOf(value) !== -1,
109
+ },
110
+ },
111
+ emits: [
112
+ 'change',
113
+ 'interact-carousel',
114
+ ],
115
+ setup(props, { emit, slots }) {
116
+ const {
117
+ componentSlotKeys,
118
+ currentIndex,
119
+ embla,
120
+ goToSlide,
121
+ handleUserInteraction,
122
+ isAriaHidden,
123
+ nextIndex,
124
+ onCarouselContainerClick,
125
+ previousIndex,
126
+ reInit,
127
+ reInitVisible,
128
+ rootEl,
129
+ slideIndicatorCount,
130
+ slides,
131
+ } = carouselUtil(props, { emit, slots }, { axis: 'y' });
132
+
133
+ return {
134
+ componentSlotKeys,
135
+ currentIndex,
136
+ embla,
137
+ goToSlide,
138
+ handleUserInteraction,
139
+ isAriaHidden,
140
+ mdiChevronDown,
141
+ mdiChevronUp,
142
+ nextIndex,
143
+ onCarouselContainerClick,
144
+ previousIndex,
145
+ reInit,
146
+ reInitVisible,
147
+ rootEl,
148
+ slideIndicatorCount,
149
+ slides,
150
+ };
151
+ },
152
+ };
153
+ </script>
154
+
155
+ <style scoped>
156
+ </style>
@@ -0,0 +1,168 @@
1
+ import KvVerticalCarousel from '../KvVerticalCarousel.vue';
2
+ import KvButton from '../KvButton.vue';
3
+
4
+ const randomHexColor = (index) => {
5
+ const defaultColor = '96d4b3';
6
+ const colorArray = [
7
+ 'D5573B',
8
+ '885053',
9
+ '777DA7',
10
+ '94C9A9',
11
+ 'C6ECAE',
12
+ 'C490D1',
13
+ 'A0D2DB',
14
+ '7D8CC4',
15
+ '726DA8',
16
+ ];
17
+ return colorArray?.[index] || defaultColor;
18
+ };
19
+
20
+ // This is not an actual loan card template, just a vague
21
+ // approximation to make testing in the stories nicer
22
+ const generateLoanCardTemplate = (index) => {
23
+ const amounts = [
24
+ '100',
25
+ '2,255',
26
+ '50',
27
+ '41,900',
28
+ ];
29
+ const cardCopy = [
30
+ 'A loan of $5,450 helps a member to buy flour, eggs, lard, sugar, sweets and other...',
31
+ 'A loan of $1,125 helps to face the financial problem of covering tuition fees.',
32
+ 'A loan of $450 helps to purchase store goods for resale.',
33
+ ];
34
+
35
+ return `
36
+ <div style="width: 336px">
37
+ <img src="https://placehold.co/336x252/${randomHexColor(index)}/000000" class="tw-w-full tw-rounded tw-mb-2">
38
+ <h3>Card Title</h3>
39
+ <h4 class="tw-my-1">$${amounts?.[index] || amounts?.[1]} to go</h4>
40
+ <p class="tw-mt-1 tw-mb-9">${cardCopy?.[index] || cardCopy?.[1]}</p>
41
+ <kv-button
42
+ variant="primary"
43
+ >
44
+ Read more
45
+ </kv-button>
46
+ </div>`;
47
+ };
48
+
49
+ const defaultCarouselSlides = `
50
+ <template #slide1>
51
+ <img src="https://placehold.co/400x150/${randomHexColor(1)}/000000">
52
+ </template>
53
+ <template #slide2>
54
+ <img src="https://placehold.co/400x150/${randomHexColor(2)}/000000">
55
+ </template>
56
+ <template #slide3>
57
+ <img src="https://placehold.co/400x150/${randomHexColor(3)}/000000">
58
+ </template>
59
+ <template #slide4>
60
+ <img src="https://placehold.co/400x150/${randomHexColor(4)}/000000">
61
+ </template>
62
+ `;
63
+
64
+ export default {
65
+ title: 'KvVerticalCarousel',
66
+ component: KvVerticalCarousel,
67
+ };
68
+
69
+ export const Default = () => ({
70
+ components: {
71
+ KvVerticalCarousel,
72
+ },
73
+ template: `
74
+ <div style="width: 400px;">
75
+ <kv-vertical-carousel height-style="310px" class="tw-w-full">
76
+ ${defaultCarouselSlides}
77
+ </kv-vertical-carousel>
78
+ </div>
79
+ `,
80
+ });
81
+
82
+ export const LoopFalse = () => ({
83
+ components: {
84
+ KvVerticalCarousel,
85
+ },
86
+ template: `
87
+ <div style="width: 400px;">
88
+ <kv-vertical-carousel height-style="400px" class="tw-w-full">
89
+ ${defaultCarouselSlides}
90
+ </kv-vertical-carousel>
91
+ </div>
92
+ `,
93
+ });
94
+
95
+ export const MultipleLoanCards = () => ({
96
+ components: {
97
+ KvVerticalCarousel,
98
+ KvButton,
99
+ },
100
+ template: `
101
+ <kv-vertical-carousel
102
+ :embla-options="{ loop: false }"
103
+ :multiple-slides-visible="true"
104
+ style="max-width: 600px;"
105
+ height-style="510px"
106
+ class="tw-w-full"
107
+ >
108
+ <template #slide1>
109
+ ${generateLoanCardTemplate(1)}
110
+ </template>
111
+ <template #slide2>
112
+ ${generateLoanCardTemplate(2)}
113
+ </template>
114
+ <template #slide3>
115
+ ${generateLoanCardTemplate(3)}
116
+ </template>
117
+ <template #slide4>
118
+ ${generateLoanCardTemplate(4)}
119
+ </template>
120
+ <template #slide5>
121
+ ${generateLoanCardTemplate(5)}
122
+ </template>
123
+ </kv-vertical-carousel>
124
+ `,
125
+ });
126
+
127
+ export const CustomStartIndex = () => ({
128
+ components: {
129
+ KvVerticalCarousel,
130
+ KvButton,
131
+ },
132
+ template: `
133
+ <kv-vertical-carousel
134
+ :embla-options="{ loop: false, align: 'center', startIndex: 1 }"
135
+ :multiple-slides-visible="true"
136
+ slides-to-scroll="visible"
137
+ style="max-width: 1072px;"
138
+ >
139
+ <template #slide1>
140
+ ${generateLoanCardTemplate(1)}
141
+ </template>
142
+ <template #slide2>
143
+ ${generateLoanCardTemplate(2)}
144
+ </template>
145
+ <template #slide3>
146
+ ${generateLoanCardTemplate(3)}
147
+ </template>
148
+ <template #slide4>
149
+ ${generateLoanCardTemplate(4)}
150
+ </template>
151
+ <template #slide5>
152
+ ${generateLoanCardTemplate(5)}
153
+ </template>
154
+ <template #slide6>
155
+ ${generateLoanCardTemplate(6)}
156
+ </template>
157
+ <template #slide7>
158
+ ${generateLoanCardTemplate(7)}
159
+ </template>
160
+ <template #slide8>
161
+ ${generateLoanCardTemplate(8)}
162
+ </template>
163
+ <template #slide9>
164
+ ${generateLoanCardTemplate(9)}
165
+ </template>
166
+ </kv-vertical-carousel>
167
+ `,
168
+ });