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