@kiva/kv-components 3.107.0 → 3.107.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 (177) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/components/.storybook/main.js +85 -0
  3. package/dist/components/.storybook/package.json +3 -0
  4. package/dist/components/.storybook/preview.js +61 -0
  5. package/dist/components/.storybook/tailwind.css +5 -0
  6. package/dist/components/KvAccordionItem.vue +130 -0
  7. package/dist/components/KvActivityRow.vue +33 -0
  8. package/dist/components/KvBorrowerImage.vue +179 -0
  9. package/dist/components/KvButton.vue +287 -0
  10. package/dist/components/KvCarousel.vue +297 -0
  11. package/dist/components/KvCartModal.vue +365 -0
  12. package/dist/components/KvCheckbox.vue +203 -0
  13. package/dist/components/KvChip.vue +54 -0
  14. package/dist/components/KvClassicLoanCard.vue +527 -0
  15. package/dist/components/KvCommentsAdd.vue +135 -0
  16. package/dist/components/KvCommentsContainer.vue +84 -0
  17. package/dist/components/KvCommentsHeartButton.vue +70 -0
  18. package/dist/components/KvCommentsList.vue +68 -0
  19. package/dist/components/KvCommentsListItem.vue +241 -0
  20. package/dist/components/KvCommentsReplyButton.vue +52 -0
  21. package/dist/components/KvContentfulImg.vue +273 -0
  22. package/dist/components/KvCountdownTimer.vue +59 -0
  23. package/dist/components/KvExpandable.vue +84 -0
  24. package/dist/components/KvExpandableQuestion.vue +120 -0
  25. package/dist/components/KvFlag.vue +120 -0
  26. package/dist/components/KvGrid.vue +28 -0
  27. package/dist/components/KvImpactDashboardHeader.vue +40 -0
  28. package/dist/components/KvInlineActivityCard.vue +55 -0
  29. package/dist/components/KvInlineActivityFeed.vue +38 -0
  30. package/dist/components/KvIntroductionLoanCard.vue +446 -0
  31. package/dist/components/KvLendAmountButton.vue +65 -0
  32. package/dist/components/KvLendCta.vue +451 -0
  33. package/dist/components/KvLightbox.vue +334 -0
  34. package/dist/components/KvLineGraph.vue +128 -0
  35. package/dist/components/KvLoadingPlaceholder.vue +38 -0
  36. package/dist/components/KvLoadingSpinner.vue +81 -0
  37. package/dist/components/KvLoanActivities.vue +268 -0
  38. package/dist/components/KvLoanBookmark.vue +39 -0
  39. package/dist/components/KvLoanCallouts.vue +53 -0
  40. package/dist/components/KvLoanProgressGroup.vue +76 -0
  41. package/dist/components/KvLoanTag.vue +88 -0
  42. package/dist/components/KvLoanTeamPick.vue +44 -0
  43. package/dist/components/KvLoanUse.vue +92 -0
  44. package/dist/components/KvMap.vue +599 -0
  45. package/dist/components/KvMaterialIcon.vue +47 -0
  46. package/dist/components/KvPageContainer.vue +15 -0
  47. package/dist/components/KvPagination.vue +198 -0
  48. package/dist/components/KvPieChart.vue +257 -0
  49. package/dist/components/KvPopper.vue +178 -0
  50. package/dist/components/KvProgressBar.vue +149 -0
  51. package/dist/components/KvRadio.vue +198 -0
  52. package/dist/components/KvSelect.vue +114 -0
  53. package/dist/components/KvSideSheet.vue +134 -0
  54. package/dist/components/KvSwitch.vue +143 -0
  55. package/dist/components/KvTab.vue +90 -0
  56. package/dist/components/KvTabPanel.vue +64 -0
  57. package/dist/components/KvTabs.vue +182 -0
  58. package/dist/components/KvTextInput.vue +247 -0
  59. package/dist/components/KvTextLink.vue +138 -0
  60. package/dist/components/KvThemeProvider.vue +122 -0
  61. package/dist/components/KvToast.vue +221 -0
  62. package/dist/components/KvTooltip.vue +168 -0
  63. package/dist/components/KvTreeMapChart.vue +229 -0
  64. package/dist/components/KvUserAvatar.vue +132 -0
  65. package/dist/components/KvVerticalCarousel.vue +156 -0
  66. package/dist/components/KvVotingCard.vue +160 -0
  67. package/dist/components/KvVotingCardV2.vue +154 -0
  68. package/dist/components/KvWideLoanCard.vue +432 -0
  69. package/dist/components/stories/Forms.stories.js +62 -0
  70. package/dist/components/stories/KvAccordionItem.stories.js +24 -0
  71. package/dist/components/stories/KvActivityRow.stories.js +25 -0
  72. package/dist/components/stories/KvBorrowerImage.stories.js +68 -0
  73. package/dist/components/stories/KvButton.stories.js +144 -0
  74. package/dist/components/stories/KvCarousel.stories.js +426 -0
  75. package/dist/components/stories/KvCartModal.stories.js +54 -0
  76. package/dist/components/stories/KvCheckbox.stories.js +163 -0
  77. package/dist/components/stories/KvChip.stories.js +43 -0
  78. package/dist/components/stories/KvClassicLoanCard.stories.js +480 -0
  79. package/dist/components/stories/KvCommentsAdd.stories.js +32 -0
  80. package/dist/components/stories/KvCommentsContainer.stories.js +42 -0
  81. package/dist/components/stories/KvCommentsHeartButton.stories.js +25 -0
  82. package/dist/components/stories/KvCommentsList.stories.js +39 -0
  83. package/dist/components/stories/KvCommentsListItem.stories.js +45 -0
  84. package/dist/components/stories/KvCommentsReplyButton.stories.js +21 -0
  85. package/dist/components/stories/KvContentfulImg.stories.js +196 -0
  86. package/dist/components/stories/KvCountdownTimer.stories.js +30 -0
  87. package/dist/components/stories/KvExpandableQuestion.stories.js +129 -0
  88. package/dist/components/stories/KvFlag.stories.js +36 -0
  89. package/dist/components/stories/KvGrid.stories.js +97 -0
  90. package/dist/components/stories/KvImpactDashboardHeader.stories.js +22 -0
  91. package/dist/components/stories/KvInlineActivityCard.stories.js +69 -0
  92. package/dist/components/stories/KvInlineActivityFeed.stories.js +76 -0
  93. package/dist/components/stories/KvIntroductionLoanCard.stories.js +208 -0
  94. package/dist/components/stories/KvLendAmountButton.stories.js +31 -0
  95. package/dist/components/stories/KvLendCta.stories.js +177 -0
  96. package/dist/components/stories/KvLightbox.stories.js +304 -0
  97. package/dist/components/stories/KvLineGraph.stories.js +52 -0
  98. package/dist/components/stories/KvLoadingPlaceholder.stories.js +17 -0
  99. package/dist/components/stories/KvLoadingSpinner.stories.js +52 -0
  100. package/dist/components/stories/KvLoanActivities.stories.js +104 -0
  101. package/dist/components/stories/KvLoanBookmark.stories.js +22 -0
  102. package/dist/components/stories/KvLoanCallouts.stories.js +22 -0
  103. package/dist/components/stories/KvLoanProgressGroup.stories.js +29 -0
  104. package/dist/components/stories/KvLoanTag.stories.js +61 -0
  105. package/dist/components/stories/KvLoanTeamPick.stories.js +20 -0
  106. package/dist/components/stories/KvLoanUse.stories.js +60 -0
  107. package/dist/components/stories/KvMap.stories.js +121 -0
  108. package/dist/components/stories/KvMaterialIcon.stories.js +201 -0
  109. package/dist/components/stories/KvPageContainer.stories.js +50 -0
  110. package/dist/components/stories/KvPagination.stories.js +70 -0
  111. package/dist/components/stories/KvPieChart.stories.js +47 -0
  112. package/dist/components/stories/KvProgressBar.stories.js +53 -0
  113. package/dist/components/stories/KvRadio.stories.js +140 -0
  114. package/dist/components/stories/KvSelect.stories.js +125 -0
  115. package/dist/components/stories/KvSideSheet.stories.js +50 -0
  116. package/dist/components/stories/KvSwitch.stories.js +66 -0
  117. package/dist/components/stories/KvTabs.stories.js +106 -0
  118. package/dist/components/stories/KvTextInput.stories.js +194 -0
  119. package/dist/components/stories/KvTextLink.stories.js +55 -0
  120. package/dist/components/stories/KvThemeProvider.stories.js +178 -0
  121. package/dist/components/stories/KvToast.stories.js +117 -0
  122. package/dist/components/stories/KvTooltip.stories.js +26 -0
  123. package/dist/components/stories/KvTreeMapChart.stories.js +42 -0
  124. package/dist/components/stories/KvUserAvatar.stories.js +47 -0
  125. package/dist/components/stories/KvVerticalCarousel.stories.js +168 -0
  126. package/dist/components/stories/KvVotingCard.stories.js +33 -0
  127. package/dist/components/stories/KvVotingCardV2.stories.js +89 -0
  128. package/dist/components/stories/KvWideLoanCard.stories.js +292 -0
  129. package/dist/components/stories/StyleguidePrimitives.stories.js +499 -0
  130. package/dist/components/stories/StyleguideProse.stories.js +215 -0
  131. package/dist/data/countries-borders.json +1 -0
  132. package/dist/data/ne_110m_admin_0_countries.json +1 -0
  133. package/dist/utils/Alea.js +9 -0
  134. package/dist/utils/attrs.js +7 -0
  135. package/dist/utils/carousels.js +8 -0
  136. package/dist/{attrs.js → utils/chunk-3HK4G4NT.js} +1 -0
  137. package/dist/{loanCard.js → utils/chunk-55HF2ORX.js} +1 -0
  138. package/dist/{expander.js → utils/chunk-AY3PR5S4.js} +3 -2
  139. package/dist/{carousels.js → utils/chunk-AZPWOFD5.js} +1 -0
  140. package/dist/{printing.js → utils/chunk-B5J5WLAH.js} +1 -0
  141. package/dist/{Alea.js → utils/chunk-GPSH6OPA.js} +2 -1
  142. package/dist/{scrollLock.js → utils/chunk-HIY5IW65.js} +2 -1
  143. package/dist/{treemap.js → utils/chunk-MSMZIN54.js} +1 -0
  144. package/dist/{imageUtils.js → utils/chunk-OXJCCNNW.js} +1 -0
  145. package/dist/{touchEvents.js → utils/chunk-S3MABILA.js} +3 -2
  146. package/dist/{mapUtils.js → utils/chunk-VIGEMAKO.js} +5 -4
  147. package/dist/utils/chunk-YCNMJ4YV.js +37 -0
  148. package/dist/{loanUtils.js → utils/chunk-YFEC5ODJ.js} +7 -6
  149. package/dist/utils/expander.js +9 -0
  150. package/dist/utils/imageUtils.js +9 -0
  151. package/dist/utils/index.cjs +1118 -0
  152. package/dist/utils/index.js +166 -0
  153. package/dist/utils/loanCard.js +9 -0
  154. package/dist/utils/loanUtils.js +23 -0
  155. package/dist/utils/mapUtils.js +15 -0
  156. package/dist/utils/printing.js +9 -0
  157. package/dist/utils/scrollLock.js +13 -0
  158. package/dist/{throttle.js → utils/throttle.js} +1 -0
  159. package/dist/utils/touchEvents.js +11 -0
  160. package/dist/utils/treemap.js +7 -0
  161. package/package.json +7 -7
  162. package/utils/index.js +14 -0
  163. package/index.js +0 -3
  164. /package/dist/{Alea.cjs → utils/Alea.cjs} +0 -0
  165. /package/dist/{attrs.cjs → utils/attrs.cjs} +0 -0
  166. /package/dist/{carousels.cjs → utils/carousels.cjs} +0 -0
  167. /package/dist/{chunk-HV3AUBFT.js → utils/chunk-HV3AUBFT.js} +0 -0
  168. /package/dist/{expander.cjs → utils/expander.cjs} +0 -0
  169. /package/dist/{imageUtils.cjs → utils/imageUtils.cjs} +0 -0
  170. /package/dist/{loanCard.cjs → utils/loanCard.cjs} +0 -0
  171. /package/dist/{loanUtils.cjs → utils/loanUtils.cjs} +0 -0
  172. /package/dist/{mapUtils.cjs → utils/mapUtils.cjs} +0 -0
  173. /package/dist/{printing.cjs → utils/printing.cjs} +0 -0
  174. /package/dist/{scrollLock.cjs → utils/scrollLock.cjs} +0 -0
  175. /package/dist/{throttle.cjs → utils/throttle.cjs} +0 -0
  176. /package/dist/{touchEvents.cjs → utils/touchEvents.cjs} +0 -0
  177. /package/dist/{treemap.cjs → utils/treemap.cjs} +0 -0
@@ -0,0 +1,138 @@
1
+ <template>
2
+ <component
3
+ :is="tag"
4
+ ref="buttonRef"
5
+ :to="to"
6
+ :disabled="state === 'disabled'"
7
+ class="tw-text-h4 tw-text-link"
8
+ :class="{
9
+ 'tw-opacity-low tw-pointer-events-none': state === 'disabled',
10
+ 'tw-group tw-inline-flex tw-items-center tw-gap-x-0.5': icon
11
+ }"
12
+ @click="onClick"
13
+ >
14
+ <slot></slot>
15
+ <kv-material-icon
16
+ v-if="icon"
17
+ :icon="icon"
18
+ class="
19
+ tw-w-1.5 tw-h-1.5 md:tw-w-2 md:tw-h-2
20
+ tw-transition-transform tw-ease-in-out tw-duration-200
21
+ group-hover:tw-translate-x-[0.125rem] group-focus:tw-translate-x-[0.125rem]
22
+ "
23
+ />
24
+ </component>
25
+ </template>
26
+
27
+ <script>
28
+ import {
29
+ computed,
30
+ onMounted,
31
+ ref,
32
+ toRefs,
33
+ watch,
34
+ } from 'vue-demi';
35
+ import KvMaterialIcon from './KvMaterialIcon.vue';
36
+
37
+ /**
38
+ * A component for displaying a stylized button or link with or without an icon
39
+ */
40
+ export default {
41
+ components: {
42
+ KvMaterialIcon,
43
+ },
44
+ props: {
45
+ /**
46
+ * Use if linking to a Vue route
47
+ * */
48
+ to: {
49
+ type: [String, Object],
50
+ default: null,
51
+ },
52
+ /**
53
+ * Use if linking to an external link or old-stack page
54
+ * */
55
+ href: {
56
+ type: String,
57
+ default: null,
58
+ },
59
+ /**
60
+ * SVG path data passed in from an imported @mdi/js module.
61
+ * ```
62
+ * import { mdiArrowRight } from '@mdi/js';
63
+ * data() { return { mdiArrowRight } };
64
+ * <kv-text-link :icon="mdiArrowRight" />`
65
+ * ```
66
+ * */
67
+ icon: {
68
+ type: String,
69
+ default: '',
70
+ },
71
+ /**
72
+ * State of the button
73
+ * @values '', disabled
74
+ * */
75
+ state: {
76
+ type: String,
77
+ default: '',
78
+ validator(value) {
79
+ return ['', 'disabled'].includes(value);
80
+ },
81
+ },
82
+ },
83
+ emits: [
84
+ 'click',
85
+ ],
86
+ setup(props, { emit }) {
87
+ const {
88
+ to,
89
+ href,
90
+ } = toRefs(props);
91
+
92
+ const buttonRef = ref(null);
93
+
94
+ const tag = computed(() => {
95
+ if (to.value) {
96
+ return 'router-link';
97
+ }
98
+ if (href.value) {
99
+ return 'a';
100
+ }
101
+ return 'button';
102
+ });
103
+
104
+ const onClick = (event) => {
105
+ // emit a vue event and prevent native event
106
+ // so we don't have to write @click.native in our templates
107
+ if (tag.value === 'button') {
108
+ event.preventDefault();
109
+ /**
110
+ * Fired when the button is clicked
111
+ *
112
+ * @event click
113
+ * @param {Event}
114
+ */
115
+ emit('click', event);
116
+ }
117
+ };
118
+
119
+ const setHref = () => {
120
+ // if the component is a router-link, router-link will set the href
121
+ // if the href is passed as a prop, use that instead
122
+ if (href.value) {
123
+ buttonRef.value.href = href.value;
124
+ }
125
+ };
126
+
127
+ watch(href, () => setHref());
128
+ onMounted(() => setHref());
129
+
130
+ return {
131
+ tag,
132
+ onClick,
133
+ buttonRef,
134
+ setHref,
135
+ };
136
+ },
137
+ };
138
+ </script>
@@ -0,0 +1,122 @@
1
+ <template>
2
+ <div
3
+ :style="{
4
+ ...theme,
5
+ color: 'rgb(var(--text-primary))',
6
+ }"
7
+ >
8
+ <slot></slot>
9
+ </div>
10
+ </template>
11
+
12
+ <script>
13
+ /**
14
+ * A wrapper component that sets CSS custom properties to theme its children.
15
+ * Most of the time you'll be importing a predefined theme from kv-tokens.
16
+ *
17
+ * @usage
18
+ * ```
19
+ * import {
20
+ * darkTheme,
21
+ * darkGreenTheme,
22
+ * mintTheme,
23
+ * defaultTheme
24
+ * } from '@kiva/kv-tokens/configs/kivaColors.cjs';
25
+ * ...
26
+ * data() { return { darkTheme }; }
27
+ * ...
28
+ * <kv-theme-provider :theme="darkTheme">...</kv-theme-provider>
29
+ * ```
30
+ *
31
+ * */
32
+ export default {
33
+ props: {
34
+ /**
35
+ * An object containing CSS custom properties set to RGB values.
36
+ *
37
+ * For custom theming, see all available custom properties set to white in RGB, below
38
+ * @usage
39
+ * ```
40
+ * {
41
+ * --text-primary: '255, 255, 255',
42
+ * --text-primary-inverse: '255, 255, 255',
43
+ * --text-secondary: '255, 255, 255',
44
+ * --text-tertiary: '255, 255, 255',
45
+ * --text-action: '255, 255, 255',
46
+ * --text-action-highlight: '255, 255, 255',
47
+ * --text-danger: '255, 255, 255',
48
+ * --text-danger-highlight: '255, 255, 255',
49
+ *
50
+ * --bg-primary: '255, 255, 255',
51
+ * --bg-primary-inverse: '255, 255, 255',
52
+ * --bg-secondary: '255, 255, 255',
53
+ * --bg-tertiary: '255, 255, 255',
54
+ * --bg-action: '255, 255, 255',
55
+ * --bg-action-highlight: '255, 255, 255',
56
+ * --bg-danger: '255, 255, 255',
57
+ * --bg-danger-highlight: '255, 255, 255',
58
+ * --bg-caution: '255, 255, 255',
59
+ *
60
+ * --border-primary: '255, 255, 255',
61
+ * --border-primary-inverse: '255, 255, 255',
62
+ * --border-secondary: '255, 255, 255',
63
+ * --border-tertiary: '255, 255, 255',
64
+ * --border-action: '255, 255, 255',
65
+ * --border-action-highlight: '255, 255, 255',
66
+ * --border-danger: '255, 255, 255',
67
+ * --border-danger-highlight: '255, 255, 255',
68
+ *
69
+ * --heading-underline-primary: url('/heading-underline.svg#FFFFFF'),
70
+ * }
71
+ * ```
72
+ *
73
+ * */
74
+ theme: {
75
+ type: Object,
76
+ default: null,
77
+ },
78
+ },
79
+ };
80
+ </script>
81
+
82
+ <style lang="postcss">
83
+ /* heading underline styling, intentionally not scoped */
84
+ .tw-text-jumbo u,
85
+ .tw-text-h1 u,
86
+ .tw-text-h2 u,
87
+ .tw-text-h3 u,
88
+ h1 u,
89
+ h2 u,
90
+ h3 u {
91
+ text-decoration: none;
92
+ box-decoration-break: clone;
93
+ background-image: var(--heading-underline-primary);
94
+ background-repeat: no-repeat;
95
+ background-position: left bottom;
96
+ }
97
+ .tw-text-jumbo u {
98
+ background-size: 100% 0.75rem;
99
+ padding-bottom: 0.375rem;
100
+ }
101
+ .tw-text-h1 u,
102
+ h1 u {
103
+ background-size: 100% 0.75rem;
104
+ padding-bottom: 0.375rem;
105
+ }
106
+ .tw-text-h2 u,
107
+ h2 u {
108
+ background-size: 100% 0.375rem;
109
+ padding-bottom: 0.125rem;
110
+ }
111
+ .tw-text-h3 u,
112
+ h3 u {
113
+ background-size: 100% 0.375rem;
114
+ padding-bottom: 0.2rem;
115
+ }
116
+ @screen lg {
117
+ .tw-text-jumbo u {
118
+ background-size: 100% 1rem;
119
+ padding-bottom: 0.375rem;
120
+ }
121
+ }
122
+ </style>
@@ -0,0 +1,221 @@
1
+ <template>
2
+ <div
3
+ role="alert"
4
+ aria-live="polite"
5
+ >
6
+ <transition
7
+ enter-active-class="tw-transition-opacity tw-duration-300"
8
+ leave-active-class="tw-transition-opacity tw-duration-300"
9
+ enter-class="tw-opacity-0"
10
+ enter-to-class="tw-opacity-full"
11
+ leave-class="tw-opacity-full"
12
+ leave-to-class="tw-opacity-0"
13
+ >
14
+ <div
15
+ v-if="isVisible"
16
+ data-test="tip-message"
17
+ class="tw-mx-2.5"
18
+ >
19
+ <kv-page-container>
20
+ <div
21
+ class="
22
+ tw-rounded tw-overflow-hidden
23
+ tw-flex
24
+ tw-bg-secondary
25
+ tw-mx-auto
26
+ tw-w-full md:tw-w-max md:tw-max-w-full md:tw-min-w-1/2
27
+ tw-shadow
28
+ "
29
+ >
30
+ <div
31
+ class="
32
+ tw-w-5
33
+ tw-flex-shrink-0
34
+ tw-flex
35
+ tw-items-center tw-justify-center
36
+ "
37
+ :class="{
38
+ 'tw-bg-brand tw-text-white' : (
39
+ messageType === '' || messageType === 'confirmation' ||
40
+ messageType === 'kiva-logo'
41
+ ),
42
+ 'tw-bg-danger tw-text-primary-inverse' : messageType === 'error',
43
+ 'tw-bg-caution tw-text-primary' : messageType === 'warning',
44
+ }"
45
+ >
46
+ <!-- Kiva Icon SVG -->
47
+ <!-- eslint-disable max-len -->
48
+ <svg
49
+ v-if="messageType === 'kiva-logo'"
50
+ width="16"
51
+ height="24"
52
+ viewBox="0 0 16 24"
53
+ fill="none"
54
+ xmlns="http://www.w3.org/2000/svg"
55
+ >
56
+ <path
57
+ d="M4.78202 0H0V23.141H4.78202V0ZM6.00533 14.6274C13.6788 14.6274 15.4582 8.05649 15.4582 6.91372H14.7909C7.11743 6.91372 5.33807 13.4846 5.33807 14.6274H6.00533ZM5.33807 15.1988C5.33807 16.3987 6.67259 23.0838 14.9021 23.0838H15.5694C15.5694 21.8839 14.2349 15.1988 6.00533 15.1988H5.33807Z"
58
+ fill="white"
59
+ />
60
+ </svg>
61
+ <kv-material-icon
62
+ v-else
63
+ class="tw-w-2.5 tw-h-2.5"
64
+ :icon="icon"
65
+ />
66
+ </div>
67
+ <div
68
+ ref="messageRef"
69
+ class="
70
+ tw-flex-1
71
+ tw-px-1 tw-py-2
72
+ tw-flex
73
+ "
74
+ >
75
+ <slot
76
+ v-if="hasToastContentSlot"
77
+ name="toastContent"
78
+ ></slot>
79
+ <!-- eslint-disable vue/no-v-html -->
80
+ <p
81
+ v-else
82
+ class="tw-inline-block tw-m-auto"
83
+ v-html="message"
84
+ >
85
+ </p>
86
+ <!--eslint-enable-->
87
+ </div>
88
+
89
+ <button
90
+ class="
91
+ tw-w-5
92
+ tw-flex-shrink-0
93
+ tw-flex
94
+ tw-items-center tw-justify-center
95
+ tw-bg-secondary
96
+ hover:tw-text-action-highlight
97
+ "
98
+ @click="close"
99
+ >
100
+ <kv-material-icon
101
+ class="tw-w-2.5 tw-h-2.5"
102
+ :icon="mdiClose"
103
+ />
104
+ <span class="tw-sr-only">Close notification</span>
105
+ </button>
106
+ </div>
107
+ </kv-page-container>
108
+ </div>
109
+ </transition>
110
+ </div>
111
+ </template>
112
+
113
+ <script>
114
+ import {
115
+ ref,
116
+ computed,
117
+ } from 'vue-demi';
118
+ import {
119
+ mdiClose, mdiAlertCircle, mdiAlert, mdiCheckCircle,
120
+ } from '@mdi/js';
121
+ import KvMaterialIcon from './KvMaterialIcon.vue';
122
+ import KvPageContainer from './KvPageContainer.vue';
123
+
124
+ /**
125
+ * A component which displays a temporary notice to the user.
126
+ * Toasts remain visible for 100ms * message character count, with a minumum of 5 seconds.
127
+ * Queuing toasts is not included in this component and should be handled by your application.
128
+ *
129
+ * Usage:
130
+ *
131
+ * ```
132
+ * <kv-toast ref="myToastRef" />
133
+ *
134
+ * this.$refs.myToastRef.show(
135
+ * message: String,
136
+ * messageType: 'error' | 'info' | 'confirmation',
137
+ * persist: Boolean
138
+ * );
139
+ * this.$refs.myToastRef.close();
140
+ * ```
141
+ */
142
+ export default {
143
+ components: {
144
+ KvMaterialIcon,
145
+ KvPageContainer,
146
+ },
147
+ emits: [
148
+ 'close',
149
+ ],
150
+ setup(props, { emit, slots }) {
151
+ const isVisible = ref(false);
152
+ const message = ref('');
153
+ const messageType = ref('confirmation'); // 'error', 'info', 'confirmation'
154
+ const persist = ref(false);
155
+ const timeout = ref(null);
156
+
157
+ const icon = computed(() => {
158
+ if (messageType.value === 'warning') {
159
+ return mdiAlert;
160
+ }
161
+ if (messageType.value === 'error') {
162
+ return mdiAlertCircle;
163
+ }
164
+ return mdiCheckCircle;
165
+ });
166
+
167
+ const msToDisplayToast = computed(() => {
168
+ const MINIMUM_MS = 5000;
169
+ const MS_PER_CHARACTER = 100;
170
+
171
+ // create an empty span to get the character count without HTML
172
+ const span = document.createElement('span');
173
+ span.innerHTML = message.value;
174
+ const characterCount = span.innerText.length;
175
+
176
+ const characterMs = MS_PER_CHARACTER * characterCount;
177
+ return Math.max(characterMs, MINIMUM_MS);
178
+ });
179
+
180
+ const hasToastContentSlot = computed(() => !!slots?.toastContent ?? false);
181
+
182
+ const close = () => {
183
+ isVisible.value = false;
184
+ clearTimeout(timeout.value);
185
+
186
+ /**
187
+ * Indicates the toast has closed by a user or after timeout
188
+ * @event close
189
+ */
190
+ emit('close');
191
+ };
192
+
193
+ const show = (messageInput, type, persistInput, hideDelay) => {
194
+ isVisible.value = true;
195
+ message.value = typeof messageInput === 'string' ? messageInput : '';
196
+ messageType.value = typeof type === 'string' ? type : '';
197
+ persist.value = Boolean(persistInput);
198
+
199
+ if (!persist.value) {
200
+ timeout.value = setTimeout(() => {
201
+ close();
202
+ }, hideDelay ?? msToDisplayToast.value);
203
+ }
204
+ };
205
+
206
+ return {
207
+ mdiClose,
208
+ isVisible,
209
+ message,
210
+ messageType,
211
+ persist,
212
+ timeout,
213
+ icon,
214
+ msToDisplayToast,
215
+ close,
216
+ show,
217
+ hasToastContentSlot,
218
+ };
219
+ },
220
+ };
221
+ </script>
@@ -0,0 +1,168 @@
1
+ <template>
2
+ <kv-theme-provider
3
+ :theme="themeStyle"
4
+ class="kv-tailwind"
5
+ >
6
+ <kv-popper
7
+ :controller="controller"
8
+ :popper-modifiers="popperModifiers"
9
+ popper-placement="top"
10
+ transition-type="kvfastfade"
11
+ class="tooltip-pane tw-absolute tw-bg-primary tw-rounded tw-z-popover"
12
+ >
13
+ <div
14
+ class="tw-p-2.5"
15
+ style="max-width: 250px;"
16
+ >
17
+ <div
18
+ v-if="$slots.title"
19
+ class="tw-text-primary tw-font-medium tw-mb-1.5"
20
+ >
21
+ <slot name="title"></slot>
22
+ </div>
23
+ <div class="tw-text-primary">
24
+ <slot></slot>
25
+ </div>
26
+ </div>
27
+ <div
28
+ class="tooltip-arrow tw-absolute tw-w-0 tw-h-0 tw-border-solid"
29
+ x-arrow=""
30
+ ></div>
31
+ </kv-popper>
32
+ </kv-theme-provider>
33
+ </template>
34
+
35
+ <script>
36
+ import { ref, toRefs, computed } from 'vue-demi';
37
+ import {
38
+ darkTheme,
39
+ mintTheme,
40
+ } from '@kiva/kv-tokens/configs/kivaColors.cjs';
41
+ import KvPopper from './KvPopper.vue';
42
+ import KvThemeProvider from './KvThemeProvider.vue';
43
+
44
+ export default {
45
+ name: 'KvTooltip',
46
+ components: {
47
+ KvPopper,
48
+ KvThemeProvider,
49
+ },
50
+ // TODO: Add prop for tooltip placement, Currently defaults to 'top' but will flip to bottom when constrained
51
+ props: {
52
+ controller: {
53
+ validator(value) {
54
+ if (typeof value === 'string') return true;
55
+ if (typeof window !== 'undefined'
56
+ && 'HTMLElement' in window
57
+ && value instanceof HTMLElement) return true;
58
+ return false;
59
+ },
60
+ required: true,
61
+ },
62
+ theme: {
63
+ type: String,
64
+ default: 'default',
65
+ validator(value) {
66
+ // The value must match one of these strings
67
+ return ['default', 'mint', 'dark'].indexOf(value) !== -1;
68
+ },
69
+ },
70
+ },
71
+ setup(props) {
72
+ const {
73
+ theme,
74
+ } = toRefs(props);
75
+
76
+ const popperModifiers = ref({
77
+ preventOverflow: {
78
+ padding: 10,
79
+ },
80
+ });
81
+
82
+ const themeStyle = computed(() => {
83
+ const themeMapper = {
84
+ mint: mintTheme,
85
+ dark: darkTheme,
86
+ };
87
+ return themeMapper[theme.value];
88
+ });
89
+
90
+ return {
91
+ darkTheme,
92
+ mintTheme,
93
+ popperModifiers,
94
+ themeStyle,
95
+ };
96
+ },
97
+ };
98
+ </script>
99
+
100
+ <style lang="postcss" scoped>
101
+ .tooltip-pane,
102
+ .tooltip-arrow {
103
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
104
+ }
105
+
106
+ .tooltip-arrow {
107
+ @apply tw-m-1;
108
+ @apply tw-border-white;
109
+ }
110
+
111
+ /* Top Tooltip Arrow appears on Bottom */
112
+ .tooltip-pane[x-placement^="top"] {
113
+ @apply tw-mb-1;
114
+ }
115
+
116
+ .tooltip-pane[x-placement^="top"] .tooltip-arrow {
117
+ border-width: 8px 8px 0 8px;
118
+ border-left-color: transparent;
119
+ border-right-color: transparent;
120
+ border-bottom-color: transparent;
121
+ left: calc(50% - 8px);
122
+ @apply -tw-bottom-1 tw-mt-0 tw-mb-0;
123
+ }
124
+
125
+ /* Bottom Tooltip Arrow appears on Top */
126
+ .tooltip-pane[x-placement^="bottom"] {
127
+ @apply tw-mt-1;
128
+ }
129
+
130
+ .tooltip-pane[x-placement^="bottom"] .tooltip-arrow {
131
+ border-width: 0 8px 8px 8px;
132
+ border-left-color: transparent;
133
+ border-right-color: transparent;
134
+ border-top-color: transparent;
135
+ left: calc(50% - 8px);
136
+ @apply -tw-top-1 tw-mb-0 tw-mt-0;
137
+ }
138
+
139
+ /* TODO: TWEAK Inner Arrow Styles for Left + Right Orientations */
140
+
141
+ /* Right Side Tooltip, Arrow appears on Left */
142
+ .tooltip-pane[x-placement^="right"] {
143
+ @apply tw-ml-1;
144
+ }
145
+
146
+ .tooltip-pane[x-placement^="right"] .tooltip-arrow {
147
+ border-width: 8px 8px 8px 0;
148
+ border-left-color: transparent;
149
+ border-top-color: transparent;
150
+ border-bottom-color: transparent;
151
+ top: calc(50% - 8px);
152
+ @apply -tw-left-1 tw-ml-0 tw-mr-0;
153
+ }
154
+
155
+ /* Left Side Tooltip, Arrow appears on Right */
156
+ .tooltip-pane[x-placement^="left"] {
157
+ @apply tw-mr-1;
158
+ }
159
+
160
+ .tooltip-pane[x-placement^="left"] .tooltip-arrow {
161
+ border-width: 8px 0 8px 8px;
162
+ border-top-color: transparent;
163
+ border-right-color: transparent;
164
+ border-bottom-color: transparent;
165
+ top: calc(50% - 8px);
166
+ @apply -tw-right-1 tw-ml-0 tw-mr-0;
167
+ }
168
+ </style>