PluginProbe
The Innovative Form Builder – IvyForms / 0.2.1
The Innovative Form Builder – IvyForms v0.2.1
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
ivyforms / frontend / src / views / _components / input / IvySelectInput.vue

IvySelectInput.vue in The Innovative Form Builder – IvyForms 0.2.1, at frontend/src/views/_components/input/IvySelectInput.vue

288 lines 6.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <template>
2 <ElSelect
3 ref="elInputRef"
4 v-bind="{ ...$attrs, ...$props }"
5 v-model="model"
6 :placeholder="props.placeholder"
7 :disabled="props.disabled"
8 :multiple="props.multiple"
9 :collapse-tags="props.multiple"
10 :clearable="props.clearable"
11 :class="[
12 {
13 'is-clearable': props.clearable,
14 'is-filled': props.filled,
15 'is-secondary': isSecondary,
16 },
17 'ivyforms-form-item-select',
18 ]"
19 :max-collapse-tags="props.maxTags"
20 :aria-label="computedAriaLabel"
21 >
22 <template v-if="!!slots['prefix'] || iconStart" #prefix>
23 <slot name="prefix">
24 <IvyIcon
25 v-if="iconStart"
26 :name="iconStart"
27 :category="iconStartCategory"
28 :type="iconStartType"
29 class="ivyforms-input__icon-start"
30 size="l"
31 color="var(--map-base-dusk-symbol-2)"
32 />
33
34 <!-- TODO Add the avatar component-->
35 <IvyIcon v-if="props.avatar" class="ivyforms-input__avatar" name="user" size="l" />
36 <!-- <IvyAvatar-->
37 <!-- v-if="props.avatar"-->
38 <!-- class="ivyforms-input__avatar"-->
39 <!-- />-->
40 </slot>
41 </template>
42 <slot />
43 </ElSelect>
44 </template>
45
46 <script setup lang="ts">
47 import { useSlots, inject, computed } from 'vue'
48 import type { IconCategory } from '@/types/icons/icon-category'
49 import type { IconType } from '@/types/icons/icon-type'
50 import { useLabels } from '@/composables/useLabels'
51 const { getLabel } = useLabels()
52
53 interface Props {
54 modelValue: string | string[] | null | undefined
55 label?: string
56 placeholder?: string
57 iconStart?: string
58 iconEnd?: string
59 iconStartCategory?: IconCategory
60 iconEndCategory?: IconCategory
61 avatar?: string
62 iconStartType?: IconType
63 iconEndType?: IconType
64 filled?: boolean
65 prefix?: string
66 suffix?: string
67 clearable?: boolean
68 disabled?: boolean
69 multiple?: boolean
70 maxTags?: number
71 ariaLabel?: string
72 }
73
74 const props = withDefaults(defineProps<Props>(), {
75 placeholder: '',
76 iconStartCategory: 'global',
77 iconEndCategory: 'global',
78 iconStartType: 'outline',
79 iconEndType: 'outline',
80 label: '',
81 iconStart: '',
82 iconEnd: '',
83 avatar: '',
84 prefix: '',
85 suffix: '',
86 maxTags: 3,
87 ariaLabel: '',
88 })
89
90 const isSecondary = inject('isSecondary', false)
91
92 const slots = useSlots()
93
94 const emit = defineEmits(['update:modelValue'])
95
96 const model = computed({
97 get: () => props.modelValue,
98 set: (value) => emit('update:modelValue', value),
99 })
100
101 const computedAriaLabel = computed(() => props.ariaLabel || getLabel('select'))
102 </script>
103
104 <style lang="scss">
105 .ivyforms-form-item-select {
106 .el-select__wrapper {
107 border: 1px solid var(--map-base-dusk-stroke--2);
108 background: var(--map-base-dusk-o05);
109 border-radius: var(--Radius-radius-md, 8px);
110 display: flex;
111 align-items: center;
112 gap: var(--Spacing-sm, 8px);
113 padding: var(--Spacing-sm, 8px) var(--Spacing-lg, 12px);
114 height: 40px;
115 box-shadow: none !important;
116
117 &:hover,
118 &.is-hovering:not(.is-focused) {
119 border: 1px solid var(--map-base-dusk-stroke-0);
120 }
121
122 &:focus,
123 &:active,
124 &.is-active,
125 &.is-focused {
126 border: 1px solid var(--map-base-brand-stroke-0);
127
128 .el-tag {
129 background: var(--map-base-brand-o10);
130 color: var(--map-base-brand-symbol-0);
131
132 .el-tag__close svg {
133 color: var(--map-base-brand-symbol-0);
134 width: 14px;
135 height: 14px;
136 }
137 }
138 }
139
140 .el-select__selection {
141 padding: 0;
142 font-size: 16px;
143 font-weight: 400;
144 line-height: 22px;
145 color: var(--map-base-text-0);
146 background-color: transparent;
147 display: flex;
148 align-items: center;
149 gap: 4px;
150 flex: 1 0 0;
151 }
152
153 .el-select__suffix .el-icon.el-select__caret.el-select__icon {
154 background: url('../../../assets/icons/arrows/line/chevron-down.svg') no-repeat center;
155 background-size: contain;
156 width: 16px;
157 height: 16px;
158 cursor: pointer;
159 opacity: 1 !important;
160
161 &.el-select__clear {
162 background: url('../../../assets/icons/global/fill-duo/close-circle.svg') no-repeat center;
163 }
164 }
165 }
166
167 &.is-secondary .el-select__wrapper {
168 &:active,
169 &:focus,
170 &.is-focused,
171 &.is-active {
172 border: 1px solid var(--map-base-purple-stroke-0);
173
174 .el-tag {
175 background: var(--map-base-purple-o10);
176 color: var(--map-base-purple-symbol-0);
177
178 .el-tag__close svg {
179 color: var(--map-base-purple-symbol-0);
180 width: 14px;
181 height: 14px;
182 }
183 }
184 }
185
186 .el-select__wrapper {
187 // Active & Focus
188 &:active,
189 &:focus,
190 &.is-focused,
191 &.is-active {
192 border: 1px solid var(--map-base-purple-stroke-0);
193 }
194 }
195 }
196
197 // Filled
198 &.is-filled {
199 .el-select__wrapper {
200 border: 1px solid var(--map-base-dusk-stroke--2);
201 background: var(--map-base-dusk-o05);
202
203 &:hover,
204 &.is-hovering {
205 border: 1px solid var(--map-base-dusk-stroke-0);
206 }
207
208 &:active,
209 &.is-active,
210 &:focus,
211 &.is-focused {
212 border: 1px solid var(--map-base-brand-stroke-0);
213
214 .el-tag {
215 background: var(--map-base-brand-o10);
216 color: var(--map-base-brand-symbol-0);
217
218 .el-tag__close svg {
219 color: var(--map-base-brand-symbol-0);
220 width: 14px;
221 height: 14px;
222 }
223 }
224 }
225
226 .el-tag {
227 background: var(--map-base-dusk-o20);
228 color: var(--map-base-text-0);
229
230 .el-tag__close svg {
231 color: var(--map-base-text-0);
232 width: 14px;
233 height: 14px;
234 }
235 }
236 }
237
238 &.is-error .el-select__wrapper {
239 border: 1px solid var(--map-status-error-symbol-0);
240 }
241
242 &.is-warning .el-select__wrapper {
243 border: 1px solid var(--map-status-warning-stroke-0);
244 }
245
246 .el-tag {
247 font-size: 14px;
248 font-weight: 400;
249 line-height: 20px;
250 display: flex;
251 padding: 2px 4px 2px 8px;
252 align-items: center;
253 gap: 4px;
254 cursor: pointer;
255 background: var(--map-base-dusk-o20);
256 color: var(--map-base-text-0);
257
258 .el-tag__close {
259 background: url('../../../assets/icons/global/outline/close.svg') no-repeat center;
260 background-size: contain;
261 width: 16px;
262 height: 16px;
263 cursor: pointer;
264 margin: 0;
265
266 svg {
267 color: var(--map-base-text-0);
268 width: 14px;
269 height: 14px;
270 }
271
272 &:hover {
273 background: url('../../../assets/icons/global/outline/close.svg') no-repeat center;
274 width: 16px;
275 height: 16px;
276 }
277 }
278 }
279 }
280 }
281
282 .el-select__popper {
283 .el-scrollbar {
284 background-color: transparent;
285 }
286 }
287 </style>
288