@kiva/kv-components 3.107.0 → 3.107.2
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 +22 -0
- package/dist/components/.storybook/main.js +85 -0
- package/dist/components/.storybook/package.json +3 -0
- package/dist/components/.storybook/preview.js +61 -0
- package/dist/components/.storybook/tailwind.css +5 -0
- package/dist/components/KvAccordionItem.vue +130 -0
- package/dist/components/KvActivityRow.vue +33 -0
- package/dist/components/KvBorrowerImage.vue +179 -0
- package/dist/components/KvButton.vue +287 -0
- package/dist/components/KvCarousel.vue +297 -0
- package/dist/components/KvCartModal.vue +365 -0
- package/dist/components/KvCheckbox.vue +203 -0
- package/dist/components/KvChip.vue +54 -0
- package/dist/components/KvClassicLoanCard.vue +527 -0
- package/dist/components/KvCommentsAdd.vue +135 -0
- package/dist/components/KvCommentsContainer.vue +84 -0
- package/dist/components/KvCommentsHeartButton.vue +70 -0
- package/dist/components/KvCommentsList.vue +68 -0
- package/dist/components/KvCommentsListItem.vue +241 -0
- package/dist/components/KvCommentsReplyButton.vue +52 -0
- package/dist/components/KvContentfulImg.vue +273 -0
- package/dist/components/KvCountdownTimer.vue +59 -0
- package/dist/components/KvExpandable.vue +84 -0
- package/dist/components/KvExpandableQuestion.vue +120 -0
- package/dist/components/KvFlag.vue +120 -0
- package/dist/components/KvGrid.vue +28 -0
- package/dist/components/KvImpactDashboardHeader.vue +40 -0
- package/dist/components/KvInlineActivityCard.vue +55 -0
- package/dist/components/KvInlineActivityFeed.vue +38 -0
- package/dist/components/KvIntroductionLoanCard.vue +446 -0
- package/dist/components/KvLendAmountButton.vue +65 -0
- package/dist/components/KvLendCta.vue +451 -0
- package/dist/components/KvLightbox.vue +334 -0
- package/dist/components/KvLineGraph.vue +128 -0
- package/dist/components/KvLoadingPlaceholder.vue +38 -0
- package/dist/components/KvLoadingSpinner.vue +81 -0
- package/dist/components/KvLoanActivities.vue +268 -0
- package/dist/components/KvLoanBookmark.vue +39 -0
- package/dist/components/KvLoanCallouts.vue +53 -0
- package/dist/components/KvLoanProgressGroup.vue +76 -0
- package/dist/components/KvLoanTag.vue +88 -0
- package/dist/components/KvLoanTeamPick.vue +44 -0
- package/dist/components/KvLoanUse.vue +92 -0
- package/dist/components/KvMap.vue +599 -0
- package/dist/components/KvMaterialIcon.vue +47 -0
- package/dist/components/KvPageContainer.vue +15 -0
- package/dist/components/KvPagination.vue +198 -0
- package/dist/components/KvPieChart.vue +257 -0
- package/dist/components/KvPopper.vue +178 -0
- package/dist/components/KvProgressBar.vue +149 -0
- package/dist/components/KvRadio.vue +198 -0
- package/dist/components/KvSelect.vue +114 -0
- package/dist/components/KvSideSheet.vue +134 -0
- package/dist/components/KvSwitch.vue +143 -0
- package/dist/components/KvTab.vue +90 -0
- package/dist/components/KvTabPanel.vue +64 -0
- package/dist/components/KvTabs.vue +182 -0
- package/dist/components/KvTextInput.vue +247 -0
- package/dist/components/KvTextLink.vue +138 -0
- package/dist/components/KvThemeProvider.vue +122 -0
- package/dist/components/KvToast.vue +221 -0
- package/dist/components/KvTooltip.vue +168 -0
- package/dist/components/KvTreeMapChart.vue +229 -0
- package/dist/components/KvUserAvatar.vue +132 -0
- package/dist/components/KvVerticalCarousel.vue +156 -0
- package/dist/components/KvVotingCard.vue +160 -0
- package/dist/components/KvVotingCardV2.vue +154 -0
- package/dist/components/KvWideLoanCard.vue +432 -0
- package/dist/components/stories/Forms.stories.js +62 -0
- package/dist/components/stories/KvAccordionItem.stories.js +24 -0
- package/dist/components/stories/KvActivityRow.stories.js +25 -0
- package/dist/components/stories/KvBorrowerImage.stories.js +68 -0
- package/dist/components/stories/KvButton.stories.js +144 -0
- package/dist/components/stories/KvCarousel.stories.js +426 -0
- package/dist/components/stories/KvCartModal.stories.js +54 -0
- package/dist/components/stories/KvCheckbox.stories.js +163 -0
- package/dist/components/stories/KvChip.stories.js +43 -0
- package/dist/components/stories/KvClassicLoanCard.stories.js +480 -0
- package/dist/components/stories/KvCommentsAdd.stories.js +32 -0
- package/dist/components/stories/KvCommentsContainer.stories.js +42 -0
- package/dist/components/stories/KvCommentsHeartButton.stories.js +25 -0
- package/dist/components/stories/KvCommentsList.stories.js +39 -0
- package/dist/components/stories/KvCommentsListItem.stories.js +45 -0
- package/dist/components/stories/KvCommentsReplyButton.stories.js +21 -0
- package/dist/components/stories/KvContentfulImg.stories.js +196 -0
- package/dist/components/stories/KvCountdownTimer.stories.js +30 -0
- package/dist/components/stories/KvExpandableQuestion.stories.js +129 -0
- package/dist/components/stories/KvFlag.stories.js +36 -0
- package/dist/components/stories/KvGrid.stories.js +97 -0
- package/dist/components/stories/KvImpactDashboardHeader.stories.js +22 -0
- package/dist/components/stories/KvInlineActivityCard.stories.js +69 -0
- package/dist/components/stories/KvInlineActivityFeed.stories.js +76 -0
- package/dist/components/stories/KvIntroductionLoanCard.stories.js +208 -0
- package/dist/components/stories/KvLendAmountButton.stories.js +31 -0
- package/dist/components/stories/KvLendCta.stories.js +177 -0
- package/dist/components/stories/KvLightbox.stories.js +304 -0
- package/dist/components/stories/KvLineGraph.stories.js +52 -0
- package/dist/components/stories/KvLoadingPlaceholder.stories.js +17 -0
- package/dist/components/stories/KvLoadingSpinner.stories.js +52 -0
- package/dist/components/stories/KvLoanActivities.stories.js +104 -0
- package/dist/components/stories/KvLoanBookmark.stories.js +22 -0
- package/dist/components/stories/KvLoanCallouts.stories.js +22 -0
- package/dist/components/stories/KvLoanProgressGroup.stories.js +29 -0
- package/dist/components/stories/KvLoanTag.stories.js +61 -0
- package/dist/components/stories/KvLoanTeamPick.stories.js +20 -0
- package/dist/components/stories/KvLoanUse.stories.js +60 -0
- package/dist/components/stories/KvMap.stories.js +121 -0
- package/dist/components/stories/KvMaterialIcon.stories.js +201 -0
- package/dist/components/stories/KvPageContainer.stories.js +50 -0
- package/dist/components/stories/KvPagination.stories.js +70 -0
- package/dist/components/stories/KvPieChart.stories.js +47 -0
- package/dist/components/stories/KvProgressBar.stories.js +53 -0
- package/dist/components/stories/KvRadio.stories.js +140 -0
- package/dist/components/stories/KvSelect.stories.js +125 -0
- package/dist/components/stories/KvSideSheet.stories.js +50 -0
- package/dist/components/stories/KvSwitch.stories.js +66 -0
- package/dist/components/stories/KvTabs.stories.js +106 -0
- package/dist/components/stories/KvTextInput.stories.js +194 -0
- package/dist/components/stories/KvTextLink.stories.js +55 -0
- package/dist/components/stories/KvThemeProvider.stories.js +178 -0
- package/dist/components/stories/KvToast.stories.js +117 -0
- package/dist/components/stories/KvTooltip.stories.js +26 -0
- package/dist/components/stories/KvTreeMapChart.stories.js +42 -0
- package/dist/components/stories/KvUserAvatar.stories.js +47 -0
- package/dist/components/stories/KvVerticalCarousel.stories.js +168 -0
- package/dist/components/stories/KvVotingCard.stories.js +33 -0
- package/dist/components/stories/KvVotingCardV2.stories.js +89 -0
- package/dist/components/stories/KvWideLoanCard.stories.js +292 -0
- package/dist/components/stories/StyleguidePrimitives.stories.js +499 -0
- package/dist/components/stories/StyleguideProse.stories.js +215 -0
- package/dist/data/countries-borders.json +1 -0
- package/dist/data/ne_110m_admin_0_countries.json +1 -0
- package/dist/utils/Alea.js +9 -0
- package/dist/utils/attrs.js +7 -0
- package/dist/utils/carousels.js +8 -0
- package/dist/{attrs.js → utils/chunk-3HK4G4NT.js} +1 -0
- package/dist/{loanCard.js → utils/chunk-55HF2ORX.js} +1 -0
- package/dist/{expander.js → utils/chunk-AY3PR5S4.js} +3 -2
- package/dist/{carousels.js → utils/chunk-AZPWOFD5.js} +1 -0
- package/dist/{printing.js → utils/chunk-B5J5WLAH.js} +1 -0
- package/dist/{Alea.js → utils/chunk-GPSH6OPA.js} +2 -1
- package/dist/{scrollLock.js → utils/chunk-HIY5IW65.js} +2 -1
- package/dist/{treemap.js → utils/chunk-MSMZIN54.js} +1 -0
- package/dist/{imageUtils.js → utils/chunk-OXJCCNNW.js} +1 -0
- package/dist/{touchEvents.js → utils/chunk-S3MABILA.js} +3 -2
- package/dist/{mapUtils.js → utils/chunk-VIGEMAKO.js} +5 -4
- package/dist/utils/chunk-YCNMJ4YV.js +37 -0
- package/dist/{loanUtils.js → utils/chunk-YFEC5ODJ.js} +7 -6
- package/dist/utils/expander.js +9 -0
- package/dist/utils/imageUtils.js +9 -0
- package/dist/utils/index.cjs +1118 -0
- package/dist/utils/index.js +166 -0
- package/dist/utils/loanCard.js +9 -0
- package/dist/utils/loanUtils.js +23 -0
- package/dist/utils/mapUtils.js +15 -0
- package/dist/utils/printing.js +9 -0
- package/dist/utils/scrollLock.js +13 -0
- package/dist/{throttle.js → utils/throttle.js} +1 -0
- package/dist/utils/touchEvents.js +11 -0
- package/dist/utils/treemap.js +7 -0
- package/package.json +11 -7
- package/utils/index.js +14 -0
- package/index.js +0 -3
- /package/dist/{Alea.cjs → utils/Alea.cjs} +0 -0
- /package/dist/{attrs.cjs → utils/attrs.cjs} +0 -0
- /package/dist/{carousels.cjs → utils/carousels.cjs} +0 -0
- /package/dist/{chunk-HV3AUBFT.js → utils/chunk-HV3AUBFT.js} +0 -0
- /package/dist/{expander.cjs → utils/expander.cjs} +0 -0
- /package/dist/{imageUtils.cjs → utils/imageUtils.cjs} +0 -0
- /package/dist/{loanCard.cjs → utils/loanCard.cjs} +0 -0
- /package/dist/{loanUtils.cjs → utils/loanUtils.cjs} +0 -0
- /package/dist/{mapUtils.cjs → utils/mapUtils.cjs} +0 -0
- /package/dist/{printing.cjs → utils/printing.cjs} +0 -0
- /package/dist/{scrollLock.cjs → utils/scrollLock.cjs} +0 -0
- /package/dist/{throttle.cjs → utils/throttle.cjs} +0 -0
- /package/dist/{touchEvents.cjs → utils/touchEvents.cjs} +0 -0
- /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>
|