@kiva/kv-components 3.84.0 → 3.86.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 +31 -0
- package/package.json +2 -2
- package/vue/KvCarousel.vue +2 -2
- package/vue/KvCartModal.vue +357 -0
- package/vue/stories/KvCartModal.stories.js +52 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,37 @@
|
|
|
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.86.0](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.85.0...@kiva/kv-components@3.86.0) (2024-07-12)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* adding tracking info ([a666513](https://github.com/kiva/kv-ui-elements/commit/a6665130d65f350d119c5e5669b6dd45a7e0ddef))
|
|
12
|
+
* lint ([a197c47](https://github.com/kiva/kv-ui-elements/commit/a197c47ea65c2927d4b60bb9f2533622dbae6f85))
|
|
13
|
+
* missing js docs ([1370e81](https://github.com/kiva/kv-ui-elements/commit/1370e81d8baecf49e6b40b84cad527ea68779763))
|
|
14
|
+
* remove unnecesary important in loan img ([014b48d](https://github.com/kiva/kv-ui-elements/commit/014b48d5506782fdcb6aa102ec3fc4d68f042012))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* add secondary btn ([579c61a](https://github.com/kiva/kv-ui-elements/commit/579c61ad6d7c0b25cb0a6f7e01fb2da5c58c9c86))
|
|
20
|
+
* create new cart modal component ([3719d2b](https://github.com/kiva/kv-ui-elements/commit/3719d2b3aaa47cb2f9b856c577aa1230619aab11))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# [3.85.0](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.84.0...@kiva/kv-components@3.85.0) (2024-07-10)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Features
|
|
30
|
+
|
|
31
|
+
* carousel controls arrow added for aside version ([#423](https://github.com/kiva/kv-ui-elements/issues/423)) ([f1f8fb3](https://github.com/kiva/kv-ui-elements/commit/f1f8fb337b4a8ffb343e8341ce7a8d932805df1f))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
6
37
|
# [3.84.0](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.83.2...@kiva/kv-components@3.84.0) (2024-07-08)
|
|
7
38
|
|
|
8
39
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kiva/kv-components",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.86.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -75,5 +75,5 @@
|
|
|
75
75
|
"optional": true
|
|
76
76
|
}
|
|
77
77
|
},
|
|
78
|
-
"gitHead": "
|
|
78
|
+
"gitHead": "f5afa172fdace504add5543a4a312742cfddda61"
|
|
79
79
|
}
|
package/vue/KvCarousel.vue
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
>
|
|
49
49
|
<kv-material-icon
|
|
50
50
|
class="tw-w-4"
|
|
51
|
-
:icon="mdiChevronLeft"
|
|
51
|
+
:icon="asideControls? mdiArrowLeft : mdiChevronLeft"
|
|
52
52
|
/>
|
|
53
53
|
<span class="tw-sr-only">Show previous slide</span>
|
|
54
54
|
</button>
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
>
|
|
71
71
|
<kv-material-icon
|
|
72
72
|
class="tw-w-4"
|
|
73
|
-
:icon="mdiChevronRight"
|
|
73
|
+
:icon="asideControls ? mdiArrowRight : mdiChevronRight"
|
|
74
74
|
/>
|
|
75
75
|
<span class="tw-sr-only">Show next slide</span>
|
|
76
76
|
</button>
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<transition
|
|
3
|
+
enter-active-class="tw-transition-opacity tw-duration-300"
|
|
4
|
+
leave-active-class="tw-transition-opacity tw-duration-300"
|
|
5
|
+
enter-class="tw-opacity-0"
|
|
6
|
+
enter-to-class="tw-opacity-full"
|
|
7
|
+
leave-class="tw-opacity-full"
|
|
8
|
+
leave-to-class="tw-opacity-0"
|
|
9
|
+
>
|
|
10
|
+
<!-- the screen -->
|
|
11
|
+
<div
|
|
12
|
+
v-show="visible"
|
|
13
|
+
class="screen"
|
|
14
|
+
@click.stop.prevent="onScreenClick"
|
|
15
|
+
>
|
|
16
|
+
<div>
|
|
17
|
+
<div
|
|
18
|
+
class="
|
|
19
|
+
tw-absolute
|
|
20
|
+
tw-inset-0
|
|
21
|
+
md:tw-px-2
|
|
22
|
+
"
|
|
23
|
+
>
|
|
24
|
+
<div
|
|
25
|
+
ref="kvCartModal"
|
|
26
|
+
tabindex="-1"
|
|
27
|
+
data-test="kv-cart-modal"
|
|
28
|
+
class="modal"
|
|
29
|
+
aria-modal="true"
|
|
30
|
+
aria-label="Added to basket"
|
|
31
|
+
@click.stop
|
|
32
|
+
>
|
|
33
|
+
<!-- header -->
|
|
34
|
+
<div
|
|
35
|
+
class="
|
|
36
|
+
tw-flex
|
|
37
|
+
tw-p-2.5 md:tw-px-4 md:tw-pt-4 md:tw-pb-3.5
|
|
38
|
+
"
|
|
39
|
+
>
|
|
40
|
+
<div class="tw-flex tw-flex-grow tw-gap-1 tw-items-center">
|
|
41
|
+
<!-- header -->
|
|
42
|
+
<slot name="header">
|
|
43
|
+
<kv-material-icon
|
|
44
|
+
class="tw-w-4 tw-h-4 tw-text-brand"
|
|
45
|
+
:icon="mdiCheckCircle"
|
|
46
|
+
/>
|
|
47
|
+
<h3 class="tw-text-h3 tw-flex-1">
|
|
48
|
+
Added to Basket
|
|
49
|
+
</h3>
|
|
50
|
+
</slot>
|
|
51
|
+
<button
|
|
52
|
+
v-if="!preventClose"
|
|
53
|
+
class="
|
|
54
|
+
tw-grid tw-content-center tw-justify-center
|
|
55
|
+
tw-ml-auto
|
|
56
|
+
tw-w-6 tw-h-6 tw--m-2
|
|
57
|
+
hover:tw-text-action-highlight
|
|
58
|
+
"
|
|
59
|
+
@click.stop="hide('x-button')"
|
|
60
|
+
>
|
|
61
|
+
<kv-material-icon
|
|
62
|
+
class="tw-w-3 tw-h-3"
|
|
63
|
+
:icon="mdiClose"
|
|
64
|
+
/>
|
|
65
|
+
<span class="tw-sr-only">Close</span>
|
|
66
|
+
</button>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<!-- body -->
|
|
71
|
+
<div
|
|
72
|
+
id="kvCartModalBody"
|
|
73
|
+
ref="kvCartModalBody"
|
|
74
|
+
class="modal__body"
|
|
75
|
+
>
|
|
76
|
+
<div>
|
|
77
|
+
<kv-borrower-image
|
|
78
|
+
class="tw-rounded loan-image"
|
|
79
|
+
:alt="borrowerImage.alt"
|
|
80
|
+
:aspect-ratio="borrowerImage.aspectRatio"
|
|
81
|
+
:default-image="borrowerImage.defaultImage"
|
|
82
|
+
:hash="borrowerImage.hash"
|
|
83
|
+
:images="borrowerImage.images"
|
|
84
|
+
:photo-path="photoPath"
|
|
85
|
+
/>
|
|
86
|
+
</div>
|
|
87
|
+
<div class="tw-flex tw-items-center tw-justify-between tw-w-full">
|
|
88
|
+
<div class="tw-flex tw-flex-col tw-h-full tw-justify-between">
|
|
89
|
+
<p>{{ borrowerName }}</p>
|
|
90
|
+
<p class="tw-p-1 tw-text-center tw-rounded tw-bg-secondary tw-text-h5">
|
|
91
|
+
{{ borrowerCountry }}
|
|
92
|
+
</p>
|
|
93
|
+
</div>
|
|
94
|
+
<p> ${{ amount }}</p>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<!-- controls -->
|
|
99
|
+
<div
|
|
100
|
+
ref="controlsRef"
|
|
101
|
+
class="
|
|
102
|
+
tw-flex-shrink-0 tw-flex tw-justify-end tw-gap-x-2.5
|
|
103
|
+
tw-p-2.5 md:tw-px-4 md:tw-pb-4 tw-flex-col tw-gap-1
|
|
104
|
+
"
|
|
105
|
+
>
|
|
106
|
+
<kv-button
|
|
107
|
+
class="tw-w-full"
|
|
108
|
+
@click="handleClick('view-basket')"
|
|
109
|
+
>
|
|
110
|
+
View basket ({{ basketCount }})
|
|
111
|
+
</kv-button>
|
|
112
|
+
<kv-button
|
|
113
|
+
class="tw-w-full"
|
|
114
|
+
variant="secondary"
|
|
115
|
+
@click="handleClick('help-another-person')"
|
|
116
|
+
>
|
|
117
|
+
Help another person
|
|
118
|
+
</kv-button>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
</transition>
|
|
125
|
+
</template>
|
|
126
|
+
|
|
127
|
+
<script>
|
|
128
|
+
import {
|
|
129
|
+
ref,
|
|
130
|
+
toRefs,
|
|
131
|
+
computed,
|
|
132
|
+
nextTick,
|
|
133
|
+
watch,
|
|
134
|
+
onBeforeUnmount,
|
|
135
|
+
onMounted,
|
|
136
|
+
} from 'vue-demi';
|
|
137
|
+
import { mdiClose, mdiCheckCircle } from '@mdi/js';
|
|
138
|
+
import { useFocusTrap } from '@vueuse/integrations/useFocusTrap';
|
|
139
|
+
import { hideOthers as makePageInert } from 'aria-hidden';
|
|
140
|
+
import { lockScroll, unlockScroll } from '../utils/scrollLock';
|
|
141
|
+
import { lockPrintSingleEl, unlockPrintSingleEl } from '../utils/printing';
|
|
142
|
+
import KvButton from './KvButton.vue';
|
|
143
|
+
import KvMaterialIcon from './KvMaterialIcon.vue';
|
|
144
|
+
import KvBorrowerImage from './KvBorrowerImage.vue';
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Based on KvLightbox functionality
|
|
148
|
+
* */
|
|
149
|
+
|
|
150
|
+
export default {
|
|
151
|
+
components: {
|
|
152
|
+
KvMaterialIcon,
|
|
153
|
+
KvButton,
|
|
154
|
+
KvBorrowerImage,
|
|
155
|
+
},
|
|
156
|
+
props: {
|
|
157
|
+
/**
|
|
158
|
+
* Whether the dialog is open or not
|
|
159
|
+
* */
|
|
160
|
+
visible: {
|
|
161
|
+
type: Boolean,
|
|
162
|
+
default: false,
|
|
163
|
+
},
|
|
164
|
+
/**
|
|
165
|
+
* The dialog has no close X button, clicking the screen does not close,
|
|
166
|
+
* pressing ESC does not close.
|
|
167
|
+
* */
|
|
168
|
+
preventClose: {
|
|
169
|
+
type: Boolean,
|
|
170
|
+
default: false,
|
|
171
|
+
},
|
|
172
|
+
/**
|
|
173
|
+
* The number of loans in the basket
|
|
174
|
+
* */
|
|
175
|
+
basketCount: {
|
|
176
|
+
type: Number,
|
|
177
|
+
default: 0,
|
|
178
|
+
},
|
|
179
|
+
/**
|
|
180
|
+
* The loan added to the basket
|
|
181
|
+
* */
|
|
182
|
+
addedLoan: {
|
|
183
|
+
type: Object,
|
|
184
|
+
default: () => ({}),
|
|
185
|
+
},
|
|
186
|
+
/**
|
|
187
|
+
* The photo path for the borrower image
|
|
188
|
+
* */
|
|
189
|
+
photoPath: {
|
|
190
|
+
type: String,
|
|
191
|
+
default: '',
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
emits: [
|
|
195
|
+
'cart-modal-closed',
|
|
196
|
+
],
|
|
197
|
+
setup(props, { emit }) {
|
|
198
|
+
const {
|
|
199
|
+
visible,
|
|
200
|
+
preventClose,
|
|
201
|
+
addedLoan,
|
|
202
|
+
} = toRefs(props);
|
|
203
|
+
|
|
204
|
+
const kvCartModal = ref(null);
|
|
205
|
+
const kvCartModalBody = ref(null);
|
|
206
|
+
const controlsRef = ref(null);
|
|
207
|
+
|
|
208
|
+
const trapElements = computed(() => [
|
|
209
|
+
kvCartModal.value, // This cart modal
|
|
210
|
+
]);
|
|
211
|
+
const {
|
|
212
|
+
activate: activateFocusTrap,
|
|
213
|
+
deactivate: deactivateFocusTrap,
|
|
214
|
+
} = useFocusTrap(trapElements, {
|
|
215
|
+
allowOutsideClick: true, // allow clicking outside the cart modal to close it
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
let makePageInertCallback = null;
|
|
219
|
+
let onKeyUp = null;
|
|
220
|
+
|
|
221
|
+
const hide = (closedBy = '') => {
|
|
222
|
+
// scroll any content inside the cart modal back to top
|
|
223
|
+
if (kvCartModal.value && kvCartModalBody.value) {
|
|
224
|
+
deactivateFocusTrap();
|
|
225
|
+
kvCartModalBody.value.scrollTop = 0;
|
|
226
|
+
unlockPrintSingleEl(kvCartModalBody.value);
|
|
227
|
+
}
|
|
228
|
+
unlockScroll();
|
|
229
|
+
if (makePageInertCallback) {
|
|
230
|
+
makePageInertCallback();
|
|
231
|
+
makePageInertCallback = null;
|
|
232
|
+
}
|
|
233
|
+
document.removeEventListener('keyup', onKeyUp);
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Triggered when the cart modal is closed
|
|
237
|
+
* @event cart-modal-closed
|
|
238
|
+
* @type {Event}
|
|
239
|
+
*/
|
|
240
|
+
emit('cart-modal-closed', { type: closedBy });
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
onKeyUp = (e) => {
|
|
244
|
+
if (!!e && e.key === 'Escape' && !preventClose.value) {
|
|
245
|
+
hide();
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
const onScreenClick = () => {
|
|
250
|
+
if (!preventClose.value) {
|
|
251
|
+
hide('background');
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const show = () => {
|
|
256
|
+
if (visible.value) {
|
|
257
|
+
document.addEventListener('keyup', onKeyUp);
|
|
258
|
+
|
|
259
|
+
nextTick(() => {
|
|
260
|
+
if (kvCartModal.value && kvCartModalBody.value) {
|
|
261
|
+
activateFocusTrap();
|
|
262
|
+
makePageInertCallback = makePageInert(kvCartModal.value);
|
|
263
|
+
lockPrintSingleEl(kvCartModalBody.value);
|
|
264
|
+
}
|
|
265
|
+
lockScroll();
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
const borrowerName = computed(() => {
|
|
271
|
+
return addedLoan.value?.name ?? '';
|
|
272
|
+
});
|
|
273
|
+
const borrowerImage = computed(() => {
|
|
274
|
+
return {
|
|
275
|
+
alt: `Photo of ${borrowerName.value}`,
|
|
276
|
+
aspectRatio: 1,
|
|
277
|
+
defaultImage: { width: 300 },
|
|
278
|
+
hash: addedLoan.value.imageHash,
|
|
279
|
+
images: [
|
|
280
|
+
{
|
|
281
|
+
width: 300,
|
|
282
|
+
},
|
|
283
|
+
],
|
|
284
|
+
};
|
|
285
|
+
});
|
|
286
|
+
const borrowerCountry = computed(() => {
|
|
287
|
+
return addedLoan.value.country ?? '';
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
const amount = computed(() => {
|
|
291
|
+
return addedLoan.value.amount ?? '';
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
const handleClick = (cta) => {
|
|
295
|
+
hide(cta);
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
watch(visible, () => {
|
|
299
|
+
if (visible.value) {
|
|
300
|
+
show();
|
|
301
|
+
} else {
|
|
302
|
+
hide();
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
onMounted(() => {
|
|
307
|
+
if (visible.value) {
|
|
308
|
+
show();
|
|
309
|
+
setTimeout(() => {
|
|
310
|
+
// Automatically close the cart modal after 10 seconds
|
|
311
|
+
emit('cart-modal-closed', { type: 'time' });
|
|
312
|
+
}, 10000);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
onBeforeUnmount(() => hide());
|
|
317
|
+
|
|
318
|
+
return {
|
|
319
|
+
mdiClose,
|
|
320
|
+
mdiCheckCircle,
|
|
321
|
+
onKeyUp,
|
|
322
|
+
onScreenClick,
|
|
323
|
+
hide,
|
|
324
|
+
show,
|
|
325
|
+
controlsRef,
|
|
326
|
+
|
|
327
|
+
handleClick,
|
|
328
|
+
borrowerName,
|
|
329
|
+
borrowerImage,
|
|
330
|
+
borrowerCountry,
|
|
331
|
+
amount,
|
|
332
|
+
};
|
|
333
|
+
},
|
|
334
|
+
};
|
|
335
|
+
</script>
|
|
336
|
+
|
|
337
|
+
<style lang="postcss" scoped>
|
|
338
|
+
.screen {
|
|
339
|
+
@apply tw-z-modal tw-absolute tw-inset-0;
|
|
340
|
+
background-color: rgb(0, 0, 0, 0.2);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.modal {
|
|
344
|
+
@apply tw-bg-primary md:tw-absolute md:tw-right-0 tw-w-full md:tw-w-auto tw-rounded-b;
|
|
345
|
+
max-width: 30rem;
|
|
346
|
+
max-height: 90%;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.modal__body {
|
|
350
|
+
@apply tw-flex tw-gap-2 tw-px-2.5 md:tw-px-4;
|
|
351
|
+
height: 3.75rem;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.loan-image {
|
|
355
|
+
width: 3.75rem;
|
|
356
|
+
}
|
|
357
|
+
</style>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import KvCartModal from '../KvCartModal.vue';
|
|
2
|
+
import KvButton from '../KvButton.vue';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'KvCartModal',
|
|
6
|
+
component: KvCartModal,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'fullscreen',
|
|
9
|
+
},
|
|
10
|
+
args: {
|
|
11
|
+
visible: true,
|
|
12
|
+
title: '',
|
|
13
|
+
preventClose: false,
|
|
14
|
+
addedLoan: {
|
|
15
|
+
name: 'Test Loan',
|
|
16
|
+
amount: 100,
|
|
17
|
+
country: 'Kenya',
|
|
18
|
+
imageHash: '9673d0722a7675b9b8d11f90849d9b44',
|
|
19
|
+
},
|
|
20
|
+
photoPath: 'https://www-kiva-org.freetls.fastly.net/img/',
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const DefaultTemplate = (args, { argTypes }) => ({
|
|
25
|
+
props: Object.keys(argTypes),
|
|
26
|
+
components: { KvCartModal, KvButton },
|
|
27
|
+
template: `
|
|
28
|
+
<div>
|
|
29
|
+
<kv-button @click="isVisible = true;">Show cart modal</kv-button>
|
|
30
|
+
<p>The lightbox is visible: {{isVisible}}</p>
|
|
31
|
+
|
|
32
|
+
<kv-cart-modal
|
|
33
|
+
:visible="isVisible"
|
|
34
|
+
:prevent-close="preventClose"
|
|
35
|
+
:added-loan="addedLoan"
|
|
36
|
+
:photo-path="photoPath"
|
|
37
|
+
@cart-modal-closed="isVisible = false"
|
|
38
|
+
>
|
|
39
|
+
</kv-cart-modal>
|
|
40
|
+
</div>
|
|
41
|
+
`,
|
|
42
|
+
data() {
|
|
43
|
+
return {
|
|
44
|
+
isVisible: args.visible,
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
export const Lightbox = DefaultTemplate.bind({});
|
|
50
|
+
Lightbox.args = {
|
|
51
|
+
title: 'Added to Basket',
|
|
52
|
+
};
|