@kiva/kv-components 3.105.3 → 3.107.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.
@@ -0,0 +1,109 @@
1
+ // utils/treemap.js
2
+ var getMaximum = (array) => Math.max(...array);
3
+ var getMinimum = (array) => Math.min(...array);
4
+ var sumReducer = (acc, cur) => acc + cur;
5
+ var roundValue = (number) => Math.max(Math.round(number * 100) / 100, 0);
6
+ var validateArguments = ({ data, width, height }) => {
7
+ if (!width || typeof width !== "number" || width < 0) {
8
+ throw new Error("You need to specify the width of your treemap");
9
+ }
10
+ if (!height || typeof height !== "number" || height < 0) {
11
+ throw new Error("You need to specify the height of your treemap");
12
+ }
13
+ if (!data || !Array.isArray(data) || data.length === 0 || !data.every((dataPoint) => Object.prototype.hasOwnProperty.call(dataPoint, "value") && typeof dataPoint.value === "number" && dataPoint.value >= 0 && !Number.isNaN(dataPoint.value))) {
14
+ throw new Error("You data must be in this format [{ value: 1 }, { value: 2 }], 'value' being a positive number");
15
+ }
16
+ };
17
+ function getTreemap({ data, width, height }) {
18
+ let Rectangle = {};
19
+ let initialData = [];
20
+ function worstRatio(row, width2) {
21
+ const sum = row.reduce(sumReducer, 0);
22
+ const rowMax = getMaximum(row);
23
+ const rowMin = getMinimum(row);
24
+ return Math.max(width2 ** 2 * rowMax / sum ** 2, sum ** 2 / (width2 ** 2 * rowMin));
25
+ }
26
+ const getMinWidth = () => {
27
+ if (Rectangle.totalHeight ** 2 > Rectangle.totalWidth ** 2) {
28
+ return { value: Rectangle.totalWidth, vertical: false };
29
+ }
30
+ return { value: Rectangle.totalHeight, vertical: true };
31
+ };
32
+ const layoutRow = (row, width2, vertical) => {
33
+ const rowHeight = row.reduce(sumReducer, 0) / width2;
34
+ row.forEach((rowItem) => {
35
+ const rowWidth = rowItem / rowHeight;
36
+ const { xBeginning } = Rectangle;
37
+ const { yBeginning } = Rectangle;
38
+ let data2;
39
+ if (vertical) {
40
+ data2 = {
41
+ x: xBeginning,
42
+ y: yBeginning,
43
+ width: rowHeight,
44
+ height: rowWidth,
45
+ data: initialData[Rectangle.data.length]
46
+ };
47
+ Rectangle.yBeginning += rowWidth;
48
+ } else {
49
+ data2 = {
50
+ x: xBeginning,
51
+ y: yBeginning,
52
+ width: rowWidth,
53
+ height: rowHeight,
54
+ data: initialData[Rectangle.data.length]
55
+ };
56
+ Rectangle.xBeginning += rowWidth;
57
+ }
58
+ Rectangle.data.push(data2);
59
+ });
60
+ if (vertical) {
61
+ Rectangle.xBeginning += rowHeight;
62
+ Rectangle.yBeginning -= width2;
63
+ Rectangle.totalWidth -= rowHeight;
64
+ } else {
65
+ Rectangle.xBeginning -= width2;
66
+ Rectangle.yBeginning += rowHeight;
67
+ Rectangle.totalHeight -= rowHeight;
68
+ }
69
+ };
70
+ const layoutLastRow = (rows, children, width2) => {
71
+ const { vertical } = getMinWidth();
72
+ layoutRow(rows, width2, vertical);
73
+ layoutRow(children, width2, vertical);
74
+ };
75
+ const squarify = (children, row, width2) => {
76
+ if (children.length === 1) {
77
+ return layoutLastRow(row, children, width2);
78
+ }
79
+ const rowWithChild = [...row, children[0]];
80
+ if (row.length === 0 || worstRatio(row, width2) >= worstRatio(rowWithChild, width2)) {
81
+ children.shift();
82
+ return squarify(children, rowWithChild, width2);
83
+ }
84
+ layoutRow(row, width2, getMinWidth().vertical);
85
+ return squarify(children, [], getMinWidth().value);
86
+ };
87
+ validateArguments({ data, width, height });
88
+ Rectangle = {
89
+ data: [],
90
+ xBeginning: 0,
91
+ yBeginning: 0,
92
+ totalWidth: width,
93
+ totalHeight: height
94
+ };
95
+ initialData = data;
96
+ const totalValue = data.map((dataPoint) => dataPoint.value).reduce(sumReducer, 0);
97
+ const dataScaled = data.map((dataPoint) => dataPoint.value * height * width / totalValue);
98
+ squarify(dataScaled, [], getMinWidth().value);
99
+ return Rectangle.data.map((dataPoint) => ({
100
+ ...dataPoint,
101
+ x: roundValue(dataPoint.x),
102
+ y: roundValue(dataPoint.y),
103
+ width: roundValue(dataPoint.width),
104
+ height: roundValue(dataPoint.height)
105
+ }));
106
+ }
107
+ export {
108
+ getTreemap
109
+ };
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@kiva/kv-components",
3
- "version": "3.105.3",
3
+ "version": "3.107.0",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
- "main": "index.js",
8
+ "main": "dist/index.cjs",
9
+ "module": "dist/index.js",
9
10
  "devDependencies": {
10
11
  "@babel/core": "^7.14.8",
11
12
  "@babel/eslint-parser": "^7.13.14",
@@ -46,6 +47,7 @@
46
47
  "storybook": "7.6.20",
47
48
  "style-loader": "^3.3.4",
48
49
  "tailwindcss": "^3.4.3",
50
+ "tsup": "^6.7.0",
49
51
  "vue": "2.6.14",
50
52
  "vue-loader": "^15.9.6",
51
53
  "vue-router": "^3.5.2",
@@ -56,7 +58,7 @@
56
58
  "build-storybook": "vue-demi-switch 2 && storybook build -c vue/.storybook",
57
59
  "lint": "eslint --ext .js,.vue ./",
58
60
  "test": "npm run lint",
59
- "build": "echo No build needed for @kiva/kv-components."
61
+ "build": "tsup utils/*.js --format cjs,esm --clean"
60
62
  },
61
63
  "dependencies": {
62
64
  "@kiva/kv-tokens": "^2.13.0",
@@ -74,6 +76,12 @@
74
76
  "popper.js": "^1.16.1",
75
77
  "vue-demi": "^0.14.7"
76
78
  },
79
+ "exports": {
80
+ ".": {
81
+ "require": "./dist/index.cjs",
82
+ "import": "./dist/index.js"
83
+ }
84
+ },
77
85
  "peerDependencies": {
78
86
  "@vue/composition-api": "^1.0.0-rc.1",
79
87
  "vue": "^2.6.0 || >=3.0.0"
@@ -83,5 +91,5 @@
83
91
  "optional": true
84
92
  }
85
93
  },
86
- "gitHead": "eed7b2a41aa41399178b8ca95a26f9333a797ac0"
94
+ "gitHead": "6efc99e83efc05ac8d3ee259bc24a22012dc22ef"
87
95
  }
@@ -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
  }