@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.
Files changed (177) hide show
  1. package/CHANGELOG.md +22 -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 +11 -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,149 @@
1
+ <template>
2
+ <div
3
+ class="
4
+ tw-h-1 tw-w-full tw-rounded-full tw-overflow-hidden tw-relative
5
+ "
6
+ :class="backgroundVariant"
7
+ role="progressbar"
8
+ :aria-label="ariaLabel"
9
+ :aria-valuemin="min"
10
+ :aria-valuemax="max"
11
+ :aria-valuenow="value"
12
+ >
13
+ <div
14
+ class="
15
+ tw-h-1 tw-w-full tw-absolute tw--left-full tw-rounded-full
16
+ tw-transition-all tw-duration-1000 tw-origin-left tw-ease-out
17
+ "
18
+ :class="variantClass"
19
+ :style="{transform: loaded ? `translateX(${percent}%)` : 'translateX(0)' }"
20
+ >
21
+ </div>
22
+ </div>
23
+ </template>
24
+
25
+ <script>
26
+ /**
27
+ * Horizontal progress bar which communicates to the user the progress of a particular process
28
+ */
29
+ import {
30
+ ref,
31
+ toRefs,
32
+ computed,
33
+ onMounted,
34
+ nextTick,
35
+ } from 'vue-demi';
36
+
37
+ export default {
38
+ props: {
39
+ /**
40
+ * The words to announce to screenreaders describing what this progress represents
41
+ * e.g., "Percent the loan has funded"
42
+ * */
43
+ ariaLabel: {
44
+ type: String,
45
+ required: true,
46
+ },
47
+ /**
48
+ * The min value of the progress bar
49
+ * */
50
+ min: {
51
+ type: Number,
52
+ default: 0,
53
+ },
54
+ /**
55
+ * The max value of the progress bar
56
+ * */
57
+ max: {
58
+ type: Number,
59
+ default: 100,
60
+ },
61
+ /**
62
+ * The current value to display
63
+ * */
64
+ value: {
65
+ type: Number,
66
+ default: 0,
67
+ required: true,
68
+ },
69
+ /**
70
+ * Appearance of the progress bar
71
+ * `primary (default), ghost, danger, caution
72
+ * */
73
+ variant: {
74
+ type: String,
75
+ default: 'primary',
76
+ validator(value) {
77
+ return ['primary', 'ghost', 'danger', 'caution'].includes(value);
78
+ },
79
+ },
80
+ /**
81
+ * Appearance of the progress bar background
82
+ * `secondary (default), tertiary
83
+ * */
84
+ bgVariant: {
85
+ type: String,
86
+ default: 'secondary',
87
+ validator(value) {
88
+ return ['secondary', 'tertiary'].includes(value);
89
+ },
90
+ },
91
+ },
92
+ setup(props) {
93
+ const {
94
+ min,
95
+ max,
96
+ value,
97
+ variant,
98
+ bgVariant,
99
+ } = toRefs(props);
100
+ const loaded = ref(false);
101
+
102
+ const percent = computed(() => {
103
+ const percentValue = ((value.value - min.value) / (max.value - min.value)) * 100;
104
+ const rounded = Math.round(percentValue * 10) / 10; // Keep percents to 1 decimal places 12.3%
105
+ const clamped = Math.min(Math.max(rounded, 0), 100); // Always between 0 and 100%
106
+ return clamped;
107
+ });
108
+
109
+ const variantClass = computed(() => {
110
+ switch (variant.value) {
111
+ case 'ghost':
112
+ return 'tw-bg-tertiary';
113
+ case 'danger':
114
+ return 'tw-bg-danger';
115
+ case 'caution':
116
+ return 'tw-bg-caution';
117
+ default:
118
+ return 'tw-bg-brand';
119
+ }
120
+ });
121
+
122
+ const backgroundVariant = computed(() => {
123
+ switch (bgVariant.value) {
124
+ case 'tertiary':
125
+ return 'tw-bg-tertiary';
126
+ default:
127
+ return 'tw-bg-secondary';
128
+ }
129
+ });
130
+
131
+ const animateProgressBar = () => {
132
+ loaded.value = true;
133
+ };
134
+
135
+ onMounted(async () => {
136
+ await nextTick();
137
+ animateProgressBar();
138
+ });
139
+
140
+ return {
141
+ loaded,
142
+ percent,
143
+ animateProgressBar,
144
+ variantClass,
145
+ backgroundVariant,
146
+ };
147
+ },
148
+ };
149
+ </script>
@@ -0,0 +1,198 @@
1
+ <template>
2
+ <div
3
+ :class="classes"
4
+ :style="styles"
5
+ >
6
+ <label
7
+ class="tw-inline-flex tw-items-center tw-align-middle"
8
+ :class="{ 'tw-opacity-low': disabled }"
9
+ :for="uuid"
10
+ >
11
+ <input
12
+ v-bind="inputAttrs"
13
+ :id="uuid"
14
+ ref="radioRef"
15
+ class="tw-peer tw-appearance-none tw-w-max"
16
+ type="radio"
17
+ :checked="isChecked"
18
+ :name="name"
19
+ :value="value"
20
+ :disabled="disabled"
21
+ v-on="inputListeners"
22
+ @change.prevent="onChange"
23
+ >
24
+ <div
25
+ class="
26
+ tw-w-3 tw-h-3 tw-mr-2
27
+ tw-rounded-full
28
+ tw-border
29
+ tw-flex-shrink-0
30
+ tw-overflow-hidden
31
+ tw-flex tw-justify-center tw-items-center
32
+ tw-transition-all tw-duration-100
33
+ peer-focus-visible:tw-ring-2 peer-focus-visible:tw-ring-action
34
+ "
35
+ :class="{
36
+ 'tw-border-secondary' : !isChecked,
37
+ 'tw-border-action' : isChecked
38
+ }"
39
+ >
40
+ <div
41
+ v-if="isChecked"
42
+ class="tw-rounded-full tw-bg-action"
43
+ style="width: 0.75rem; height: 0.75rem;"
44
+ ></div>
45
+ </div>
46
+
47
+ <div class="tw-flex-1 peer-focus-visible:tw-ring-2 peer-focus-visible:tw-ring-action">
48
+ <slot></slot>
49
+ </div>
50
+ </label>
51
+ </div>
52
+ </template>
53
+
54
+ <script>
55
+ import { nanoid } from 'nanoid';
56
+ import {
57
+ computed,
58
+ onMounted,
59
+ ref,
60
+ toRefs,
61
+ } from 'vue-demi';
62
+ import { useAttrs } from '../utils/attrs';
63
+
64
+ const emits = [
65
+ 'change',
66
+ 'update:modelValue',
67
+ ];
68
+
69
+ /* eslint-disable max-len */
70
+
71
+ /**
72
+ * Use as you would an `<input type="radio" />`. Ensure you're using a fieldset and legend for a11y.
73
+ *
74
+ * @usage
75
+ * ```
76
+ * <fieldset>
77
+ * <legend>Choose an item</legend>
78
+ * <KvRadio value="foo" v-model="someDataValue">Label for foo</KvRadio>
79
+ * <KvRadio value="bar" v-model="someDataValue">Label for bar</KvRadio>
80
+ * <KvRadio value="baz" v-model="someDataValue">Label for baz</KvRadio>
81
+ * </fieldset>
82
+ *
83
+ * or
84
+ *
85
+ * <fieldset>
86
+ * <legend>Choose an item</legend>
87
+ * <KvRadio value="foo" name="myGroupName" @change="(val) => someDataValue = val" :checked="someDataValue === 'foo'" />Label for foo</KvRadio>
88
+ * <KvRadio value="bar" name="myGroupName" @change="(val) => someDataValue = val" :checked="someDataValue === 'bar'" />Label for bar</KvRadio>
89
+ * <KvRadio value="baz" name="myGroupName" @change="(val) => someDataValue = val" :checked="someDataValue === 'baz'" />Label for baz</KvRadio>
90
+ * </fieldset>
91
+ * ```
92
+ */
93
+ /* eslint-enable max-len */
94
+
95
+ export default {
96
+ inheritAttrs: false,
97
+ model: {
98
+ prop: 'modelValue',
99
+ event: 'update:modelValue',
100
+ },
101
+ props: {
102
+ /**
103
+ * Value of the input
104
+ * */
105
+ value: {
106
+ type: [String, Number, Boolean],
107
+ required: true,
108
+ },
109
+ /**
110
+ * Prevents the radio from being toggled or focused
111
+ * */
112
+ disabled: {
113
+ type: Boolean,
114
+ default: false,
115
+ },
116
+ /**
117
+ * Native name attribute. Used to group radios if you're not using v-model. E.g.,
118
+ * ```
119
+ * <KvRadio name="cats">Tabby</KvRadio>
120
+ * <KvRadio name="cats">Siamese</KvRadio>
121
+ * <KvRadio name="dogs">Husky</KvRadio>
122
+ * <KvRadio name="dogs">Boxer</KvRadio>
123
+ * ```
124
+ * */
125
+ name: {
126
+ type: String,
127
+ default: '',
128
+ },
129
+ /**
130
+ * Native checked attribute. Used to select the radio if you're not using v-model E.g.,
131
+ * ```
132
+ * <KvRadio value="foo" :checked="myModel === foo">Foo</KvRadio>
133
+ * <KvRadio value="bar" :checked="myModel === bar">Bar</KvRadio>
134
+ * ```
135
+ * */
136
+ checked: {
137
+ type: [String, Number, Boolean],
138
+ default: false,
139
+ },
140
+ modelValue: {
141
+ type: [String, Number, Boolean],
142
+ default: false,
143
+ },
144
+ },
145
+ emits,
146
+ setup(props, context) {
147
+ const { emit } = context;
148
+ const {
149
+ value,
150
+ checked,
151
+ modelValue,
152
+ } = toRefs(props);
153
+
154
+ const uuid = ref(`kvr-${nanoid(10)}`);
155
+ const radioRef = ref(null);
156
+
157
+ const {
158
+ classes,
159
+ styles,
160
+ inputAttrs,
161
+ inputListeners,
162
+ } = useAttrs(context, emits);
163
+
164
+ const isChecked = computed(() => {
165
+ if (typeof modelValue.value === typeof value.value) {
166
+ return modelValue.value === value.value;
167
+ }
168
+ return Boolean(checked.value);
169
+ });
170
+
171
+ onMounted(() => {
172
+ uuid.value = `kvr-${nanoid(10)}`;
173
+ });
174
+
175
+ const onChange = (event) => {
176
+ emit('change', event.target.value);
177
+ emit('update:modelValue', event.target.value);
178
+ };
179
+
180
+ const focus = () => radioRef.focus();
181
+
182
+ const blur = () => radioRef.blur();
183
+
184
+ return {
185
+ uuid,
186
+ isChecked,
187
+ radioRef,
188
+ onChange,
189
+ focus,
190
+ blur,
191
+ classes,
192
+ styles,
193
+ inputAttrs,
194
+ inputListeners,
195
+ };
196
+ },
197
+ };
198
+ </script>
@@ -0,0 +1,114 @@
1
+ <template>
2
+ <div
3
+ class="tw-inline-flex"
4
+ :class="classes"
5
+ :style="styles"
6
+ >
7
+ <div class="tw-relative tw-w-full">
8
+ <!-- eslint-disable max-len -->
9
+ <select
10
+ :id="id"
11
+ v-bind="inputAttrs"
12
+ v-model="inputValue"
13
+ :disabled="disabled"
14
+ class="tw-text-base tw-bg-primary tw-h-6 tw-pr-4 tw-pl-2 tw-border tw-border-tertiary tw-rounded-sm tw-appearance-none tw-w-full tw-ring-inset focus:tw-outline-none focus:tw-ring-2 focus:tw-ring-action focus:tw-border-transparent"
15
+ :class="{ 'tw-opacity-low': disabled }"
16
+ @change="onChange"
17
+ >
18
+ <!-- eslint-enable max-len -->
19
+ <slot></slot>
20
+ </select>
21
+ <kv-material-icon
22
+ :icon="mdiChevronDown"
23
+ class="tw-w-4 tw-absolute tw-top-0 tw-right-0 tw-pt-1.5 tw-pr-1 tw-pointer-events-none"
24
+ :class="{ 'tw-opacity-low': disabled }"
25
+ />
26
+ </div>
27
+ </div>
28
+ </template>
29
+
30
+ <script>
31
+ import { ref, watch } from 'vue-demi';
32
+ import { mdiChevronDown } from '@mdi/js';
33
+ import KvMaterialIcon from './KvMaterialIcon.vue';
34
+ import { useAttrs } from '../utils/attrs';
35
+
36
+ const emits = [
37
+ 'change',
38
+ 'update:modelValue',
39
+ ];
40
+
41
+ export default {
42
+ components: {
43
+ KvMaterialIcon,
44
+ },
45
+ // v-model will change when select value updates
46
+ model: {
47
+ prop: 'modelValue',
48
+ event: 'update:modelValue',
49
+ },
50
+ props: {
51
+ /**
52
+ * Unique id to connect label and select
53
+ * */
54
+ id: {
55
+ type: String,
56
+ required: true,
57
+ default: '',
58
+ },
59
+ /**
60
+ * Use if select is disabled
61
+ * */
62
+ disabled: {
63
+ type: Boolean,
64
+ default: false,
65
+ },
66
+ /**
67
+ * modelValue prop
68
+ * */
69
+ modelValue: {
70
+ type: [Number, String],
71
+ default: 0,
72
+ },
73
+ },
74
+ emits,
75
+ setup(props, context) {
76
+ const { emit } = context;
77
+
78
+ const {
79
+ classes,
80
+ styles,
81
+ inputAttrs,
82
+ inputListeners,
83
+ } = useAttrs(context, emits);
84
+
85
+ const inputValue = ref(props.modelValue);
86
+
87
+ watch(() => props.modelValue, (newValue) => {
88
+ if (newValue !== inputValue.value) {
89
+ inputValue.value = newValue;
90
+ }
91
+ });
92
+
93
+ const onChange = (event) => {
94
+ /**
95
+ * The value that the select has changed to
96
+ * @event change
97
+ * @type {Event}
98
+ */
99
+ emit('change', event.target.value);
100
+ emit('update:modelValue', event.target.value);
101
+ };
102
+
103
+ return {
104
+ mdiChevronDown,
105
+ onChange,
106
+ classes,
107
+ styles,
108
+ inputAttrs,
109
+ inputListeners,
110
+ inputValue,
111
+ };
112
+ },
113
+ };
114
+ </script>
@@ -0,0 +1,134 @@
1
+ <template>
2
+ <div
3
+ v-if="visible"
4
+ class="tw-hidden lg:tw-block tw-fixed tw-inset-0
5
+ tw-bg-black tw-transition-all tw-duration-150 tw-z-modal tw-mt-8"
6
+ :class="{
7
+ 'tw-bg-opacity-0 tw-delay-300': !open,
8
+ 'tw-bg-opacity-low': open,
9
+ }"
10
+ @click.self="closeSideSheet"
11
+ >
12
+ <div
13
+ class="tw-absolute tw-right-0 tw-h-full tw-transition-all tw-duration-300 tw-bg-white"
14
+ :class="{
15
+ 'tw-w-0 tw-p-0 tw-delay-200': !open,
16
+ 'tw-w-1/2 tw-p-2': open,
17
+ }"
18
+ >
19
+ <div class="tw-flex tw-justify-between">
20
+ <button
21
+ class="hover:tw-text-action-highlight"
22
+ @click="closeSideSheet"
23
+ >
24
+ <kv-material-icon
25
+ class="tw-w-3 tw-h-3"
26
+ :icon="mdiClose"
27
+ />
28
+ </button>
29
+
30
+ <button
31
+ v-if="showGoToLink"
32
+ class="hover:tw-text-action-highlight"
33
+ @click="goToLink"
34
+ >
35
+ <kv-material-icon
36
+ class="tw-w-3 tw-h-3"
37
+ :icon="mdiLaunch"
38
+ />
39
+ </button>
40
+ </div>
41
+ <div
42
+ class="tw-p-4 tw-overflow-y-auto tw-transition-opacity tw-duration-500 tw-delay-200"
43
+ :class="{
44
+ 'tw-opacity-0': !open,
45
+ 'tw-opacity-full': open,
46
+ }"
47
+ >
48
+ <slot></slot>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </template>
53
+
54
+ <script>
55
+ import { ref, toRefs, watch } from 'vue-demi';
56
+ import { mdiClose, mdiLaunch } from '@mdi/js';
57
+ import KvMaterialIcon from './KvMaterialIcon.vue';
58
+
59
+ export default {
60
+ components: {
61
+ KvMaterialIcon,
62
+ },
63
+ props: {
64
+ /**
65
+ * Whether the side sheet is open or not
66
+ * */
67
+ visible: {
68
+ type: Boolean,
69
+ default: false,
70
+ },
71
+ /**
72
+ * Show the go to link button
73
+ * */
74
+ showGoToLink: {
75
+ type: Boolean,
76
+ default: false,
77
+ },
78
+ /**
79
+ * Tracking event function
80
+ * */
81
+ kvTrackFunction: {
82
+ type: Function,
83
+ default: () => ({}),
84
+ },
85
+ /**
86
+ * Tracking event category
87
+ * */
88
+ trackEventCategory: {
89
+ type: String,
90
+ default: '',
91
+ },
92
+ },
93
+ emits: [
94
+ 'side-sheet-closed',
95
+ ],
96
+ setup(props, { emit }) {
97
+ const {
98
+ visible,
99
+ kvTrackFunction,
100
+ trackEventCategory,
101
+ } = toRefs(props);
102
+
103
+ const open = ref(false);
104
+
105
+ const closeSideSheet = () => {
106
+ open.value = false;
107
+ kvTrackFunction.value(trackEventCategory.value, 'click', 'side-sheet-closed');
108
+ setTimeout(() => {
109
+ emit('side-sheet-closed');
110
+ }, '700');
111
+ };
112
+
113
+ const goToLink = () => {
114
+ emit('go-to-link');
115
+ };
116
+
117
+ watch(visible, () => {
118
+ if (visible.value) {
119
+ setTimeout(() => {
120
+ open.value = true;
121
+ }, '300');
122
+ }
123
+ });
124
+
125
+ return {
126
+ mdiClose,
127
+ mdiLaunch,
128
+ open,
129
+ closeSideSheet,
130
+ goToLink,
131
+ };
132
+ },
133
+ };
134
+ </script>