@muenchen/muc-patternlab-vue 1.13.0-beta.6 → 1.13.0-beta.7
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/dist/components/Form/MucSelect.stories.d.ts +43 -8
- package/dist/components/Form/MucSelect.vue.d.ts +12 -4
- package/dist/components/Form/MucSelectItem.vue.d.ts +18 -0
- package/dist/components/Form/MucSelectTypes.d.ts +7 -0
- package/dist/muc-patternlab-vue.es.js +375 -339
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/Form/MucSelect.stories.ts +39 -4
- package/src/components/Form/MucSelect.vue +98 -22
- package/src/components/Form/MucSelectItem.vue +25 -0
- package/src/components/Form/MucSelectTypes.ts +8 -0
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.m-banner--success[data-v-53bc7eca]{background-color:#f1f6f3;border-bottom:1px solid #3a7f53}.m-callout--success[data-v-e6cf4104]{background-color:#f1f6f3;border-color:#95b9a2}.m-callout--success .m-callout__icon[data-v-e6cf4104]{background-color:#3a7f53;box-shadow:0 .3125rem .625rem #005a9f33}.m-callout--error[data-v-e6cf4104]{background-color:#f8f2f2;border-color:#c79a9b}.m-callout--error .m-callout__icon[data-v-e6cf4104]{background-color:#984447;box-shadow:0 .3125rem .625rem #005a9f33}.card[data-v-acf0a1dd]{cursor:pointer;border:solid 1px var(--color-neutrals-blue);border-bottom:solid 5px var(--color-brand-main-blue);transition:background-color ease-in .15s}.card[data-v-acf0a1dd]:hover{background-color:#f1f1f1}.card-content[data-v-acf0a1dd]{padding:32px 24px}.card-header[data-v-acf0a1dd]{display:flex}.card-tagline[data-v-acf0a1dd]{font-size:16px;font-family:Open Sans,sans-serif;color:#005a9f;font-weight:700;line-height:24px;word-wrap:break-word;padding-bottom:4px}.muc-divider[data-v-acf0a1dd]{margin-top:16px;margin-bottom:16px}@media all and (min-width: 992px){.card-container[data-v-6740df8f]{padding-left:0;padding-right:0;display:grid;grid-template-columns:repeat(auto-fit,384px);grid-column-gap:32px;grid-row-gap:32px}}@media all and (max-width: 992px){.card-container[data-v-6740df8f]{padding-left:0;padding-right:0;display:inline-grid;grid-template-columns:1fr;grid-row-gap:32px}}.divider-border[data-v-a2b37f5b]{border-bottom:1px solid var(--color-neutrals-blue)}.wrapper[data-v-a20e4a10]{display:flex}.wrapper[data-v-a20e4a10]>*{margin:0 8px}.centered-text[data-v-a20e4a10]{display:flex;justify-content:center;align-items:center;height:100%}.display-listbox[data-v-
|
|
1
|
+
.m-banner--success[data-v-53bc7eca]{background-color:#f1f6f3;border-bottom:1px solid #3a7f53}.m-callout--success[data-v-e6cf4104]{background-color:#f1f6f3;border-color:#95b9a2}.m-callout--success .m-callout__icon[data-v-e6cf4104]{background-color:#3a7f53;box-shadow:0 .3125rem .625rem #005a9f33}.m-callout--error[data-v-e6cf4104]{background-color:#f8f2f2;border-color:#c79a9b}.m-callout--error .m-callout__icon[data-v-e6cf4104]{background-color:#984447;box-shadow:0 .3125rem .625rem #005a9f33}.card[data-v-acf0a1dd]{cursor:pointer;border:solid 1px var(--color-neutrals-blue);border-bottom:solid 5px var(--color-brand-main-blue);transition:background-color ease-in .15s}.card[data-v-acf0a1dd]:hover{background-color:#f1f1f1}.card-content[data-v-acf0a1dd]{padding:32px 24px}.card-header[data-v-acf0a1dd]{display:flex}.card-tagline[data-v-acf0a1dd]{font-size:16px;font-family:Open Sans,sans-serif;color:#005a9f;font-weight:700;line-height:24px;word-wrap:break-word;padding-bottom:4px}.muc-divider[data-v-acf0a1dd]{margin-top:16px;margin-bottom:16px}@media all and (min-width: 992px){.card-container[data-v-6740df8f]{padding-left:0;padding-right:0;display:grid;grid-template-columns:repeat(auto-fit,384px);grid-column-gap:32px;grid-row-gap:32px}}@media all and (max-width: 992px){.card-container[data-v-6740df8f]{padding-left:0;padding-right:0;display:inline-grid;grid-template-columns:1fr;grid-row-gap:32px}}.divider-border[data-v-a2b37f5b]{border-bottom:1px solid var(--color-neutrals-blue)}.wrapper[data-v-a20e4a10]{display:flex}.wrapper[data-v-a20e4a10]>*{margin:0 8px}.centered-text[data-v-a20e4a10]{display:flex;justify-content:center;align-items:center;height:100%}.display-listbox[data-v-e39e3aae]{display:block!important}.muc-divider[data-v-5c768acc]{margin-top:8px;margin-bottom:16px}@media screen and (width >992px){.muc-intro-content[data-v-5c768acc]{width:66.6%}}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"author": "FabianWilms",
|
|
4
4
|
"description": "A vue component library of some of the components available from https://patternlab.muenchen.space",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "1.13.0-beta.
|
|
6
|
+
"version": "1.13.0-beta.7",
|
|
7
7
|
"private": false,
|
|
8
8
|
"module": "./dist/muc-patternlab-vue.es.js",
|
|
9
9
|
"types": "./dist/types/index.d.ts",
|
|
@@ -7,7 +7,7 @@ export default {
|
|
|
7
7
|
parameters: {
|
|
8
8
|
docs: {
|
|
9
9
|
description: {
|
|
10
|
-
component: `Choose from an option from a given list - multiple can also be allowed. The design is similar to the text input with autocompletion.
|
|
10
|
+
component: `Choose from an option from a given list of objects or strings - multiple can also be allowed. The design is similar to the text input with autocompletion.
|
|
11
11
|
|
|
12
12
|
[🔗 Patternlab-Docs](https://patternlab.muenchen.space/?p=elements-combobox)
|
|
13
13
|
`,
|
|
@@ -18,17 +18,52 @@ export default {
|
|
|
18
18
|
|
|
19
19
|
export const Default = {
|
|
20
20
|
args: {
|
|
21
|
-
modelValue:
|
|
22
|
-
|
|
21
|
+
modelValue: {
|
|
22
|
+
id: "1",
|
|
23
|
+
name: "Object 1",
|
|
24
|
+
quantity: 1,
|
|
25
|
+
},
|
|
26
|
+
items: [
|
|
27
|
+
{
|
|
28
|
+
id: "1",
|
|
29
|
+
name: "Object 1",
|
|
30
|
+
quantity: 1,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "2",
|
|
34
|
+
name: "Object 2",
|
|
35
|
+
quantity: 2,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "3",
|
|
39
|
+
name: "Object 3",
|
|
40
|
+
quantity: 3,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: "4",
|
|
44
|
+
name: "Object 4",
|
|
45
|
+
quantity: 4,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
23
48
|
label: "This is a label",
|
|
24
49
|
hint: "This is a hint",
|
|
50
|
+
itemTitle: "name",
|
|
25
51
|
},
|
|
26
52
|
};
|
|
27
53
|
|
|
28
54
|
export const MultiSelect = {
|
|
29
55
|
args: {
|
|
30
56
|
...Default.args,
|
|
31
|
-
label: "Select multiple
|
|
57
|
+
label: "Select multiple objects",
|
|
32
58
|
multiple: true,
|
|
33
59
|
},
|
|
34
60
|
};
|
|
61
|
+
|
|
62
|
+
export const StringSelect = {
|
|
63
|
+
args: {
|
|
64
|
+
modelValue: "String 1",
|
|
65
|
+
items: ["String 1", "String 2", "String 3", "String 4"],
|
|
66
|
+
label: "Select strings",
|
|
67
|
+
hint: "This is a hint",
|
|
68
|
+
},
|
|
69
|
+
};
|
|
@@ -41,7 +41,10 @@
|
|
|
41
41
|
:class="[isActiveClass(option), isSelectedClass(option)]"
|
|
42
42
|
@click="clicked(option)"
|
|
43
43
|
>
|
|
44
|
-
|
|
44
|
+
<MucSelectItem
|
|
45
|
+
:item="option"
|
|
46
|
+
:item-label="itemTitle"
|
|
47
|
+
/>
|
|
45
48
|
</li>
|
|
46
49
|
<li
|
|
47
50
|
v-if="noItemsFound"
|
|
@@ -64,6 +67,8 @@
|
|
|
64
67
|
import { computed, ref, watch } from "vue";
|
|
65
68
|
|
|
66
69
|
import useOnClickOutside from "../../composables/useOnClickOutside";
|
|
70
|
+
import MucSelectItem from "./MucSelectItem.vue";
|
|
71
|
+
import { ItemAsObject, MucSelectItemTypes } from "./MucSelectTypes";
|
|
67
72
|
|
|
68
73
|
/**
|
|
69
74
|
* Ref ot the component
|
|
@@ -73,9 +78,12 @@ const selectComponentRef = ref();
|
|
|
73
78
|
/**
|
|
74
79
|
* Exposed selected value / values
|
|
75
80
|
*/
|
|
76
|
-
const selectedValues = defineModel<
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
const selectedValues = defineModel<MucSelectItemTypes | MucSelectItemTypes[]>(
|
|
82
|
+
"modelValue",
|
|
83
|
+
{
|
|
84
|
+
default: [],
|
|
85
|
+
}
|
|
86
|
+
);
|
|
79
87
|
|
|
80
88
|
/**
|
|
81
89
|
* If list of items is shown
|
|
@@ -85,7 +93,7 @@ const showItems = ref<boolean>(false);
|
|
|
85
93
|
/**
|
|
86
94
|
* Last interacted item - selected or deselected
|
|
87
95
|
*/
|
|
88
|
-
const lastClickedItem = ref<
|
|
96
|
+
const lastClickedItem = ref<MucSelectItemTypes>();
|
|
89
97
|
|
|
90
98
|
/**
|
|
91
99
|
* If no items found after filtering
|
|
@@ -95,14 +103,14 @@ const noItemsFound = ref<boolean>(false);
|
|
|
95
103
|
/**
|
|
96
104
|
* Index of currently actively hovered item or selected item
|
|
97
105
|
*/
|
|
98
|
-
const activeItem = ref<
|
|
106
|
+
const activeItem = ref<MucSelectItemTypes>();
|
|
99
107
|
|
|
100
108
|
const props = withDefaults(
|
|
101
109
|
defineProps<{
|
|
102
110
|
/**
|
|
103
111
|
* List of items to be available
|
|
104
112
|
*/
|
|
105
|
-
items:
|
|
113
|
+
items: MucSelectItemTypes[];
|
|
106
114
|
|
|
107
115
|
/**
|
|
108
116
|
* Optional label shown above the input
|
|
@@ -123,10 +131,16 @@ const props = withDefaults(
|
|
|
123
131
|
* Optional message shown no item is found after filtering
|
|
124
132
|
*/
|
|
125
133
|
noItemFoundMessage?: string;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Property that contains the value to be displayed in the list when a list of objects is used
|
|
137
|
+
*/
|
|
138
|
+
itemTitle?: string;
|
|
126
139
|
}>(),
|
|
127
140
|
{
|
|
128
141
|
multiple: false,
|
|
129
142
|
noItemFoundMessage: "No items found.",
|
|
143
|
+
itemTitle: "title",
|
|
130
144
|
}
|
|
131
145
|
);
|
|
132
146
|
|
|
@@ -159,7 +173,7 @@ useOnClickOutside(selectComponentRef, () => {
|
|
|
159
173
|
* Actions upon clicking an item
|
|
160
174
|
* @param clickedValue clicked item value
|
|
161
175
|
*/
|
|
162
|
-
const clicked = (clickedValue:
|
|
176
|
+
const clicked = (clickedValue: MucSelectItemTypes) => {
|
|
163
177
|
lastClickedItem.value = clickedValue;
|
|
164
178
|
|
|
165
179
|
props.multiple
|
|
@@ -173,32 +187,68 @@ const clicked = (clickedValue: string) => {
|
|
|
173
187
|
* Update the modelValue with the given. Performs conversion to string if necessary.
|
|
174
188
|
* @param newValue the new value
|
|
175
189
|
*/
|
|
176
|
-
const updateMVSingle = (newValue:
|
|
177
|
-
if (
|
|
190
|
+
const updateMVSingle = (newValue: MucSelectItemTypes) => {
|
|
191
|
+
if (Array.isArray(selectedValues.value))
|
|
178
192
|
selectedValues.value = selectedValues.value.join(" ");
|
|
179
193
|
|
|
180
|
-
|
|
194
|
+
if (
|
|
195
|
+
typeof selectedValues.value !== "string" &&
|
|
196
|
+
typeof newValue !== "string"
|
|
197
|
+
) {
|
|
198
|
+
selectedValues.value =
|
|
199
|
+
selectedValues.value[props.itemTitle] === newValue[props.itemTitle]
|
|
200
|
+
? ""
|
|
201
|
+
: newValue;
|
|
202
|
+
} else {
|
|
203
|
+
selectedValues.value = selectedValues.value === newValue ? "" : newValue;
|
|
204
|
+
}
|
|
181
205
|
};
|
|
182
206
|
|
|
183
207
|
/**
|
|
184
208
|
* Update the modelValue with the given. Performs conversion to array if necessary.
|
|
185
209
|
* @param newValue the new value
|
|
186
210
|
*/
|
|
187
|
-
const updateMVMultiple = (newValue:
|
|
188
|
-
if (
|
|
211
|
+
const updateMVMultiple = (newValue: MucSelectItemTypes) => {
|
|
212
|
+
if (!Array.isArray(selectedValues.value))
|
|
189
213
|
selectedValues.value = [selectedValues.value];
|
|
190
214
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
215
|
+
if (Array.isArray(selectedValues.value)) {
|
|
216
|
+
if (typeof newValue === "string") {
|
|
217
|
+
selectedValues.value = selectedValues.value
|
|
218
|
+
.map((item: string) => item)
|
|
219
|
+
.includes(newValue)
|
|
220
|
+
? selectedValues.value.filter((val: string) => val !== newValue)
|
|
221
|
+
: [...selectedValues.value, newValue];
|
|
222
|
+
} else {
|
|
223
|
+
selectedValues.value = selectedValues.value
|
|
224
|
+
.map((item: ItemAsObject) => item[props.itemTitle])
|
|
225
|
+
.includes(newValue[props.itemTitle])
|
|
226
|
+
? selectedValues.value.filter(
|
|
227
|
+
(val: ItemAsObject) =>
|
|
228
|
+
val[props.itemTitle] !== newValue[props.itemTitle]
|
|
229
|
+
)
|
|
230
|
+
: [...selectedValues.value, newValue];
|
|
231
|
+
}
|
|
232
|
+
}
|
|
194
233
|
};
|
|
195
234
|
|
|
196
235
|
/**
|
|
197
236
|
* Converts the displayed text depending on the selection mode
|
|
198
237
|
*/
|
|
199
238
|
const outputTransformed = computed(() => {
|
|
200
|
-
if (typeof selectedValues.value === "string")
|
|
201
|
-
|
|
239
|
+
if (typeof selectedValues.value === "string") {
|
|
240
|
+
return selectedValues.value;
|
|
241
|
+
} else if (!Array.isArray(selectedValues.value)) {
|
|
242
|
+
return selectedValues.value[props.itemTitle].toString();
|
|
243
|
+
} else if (
|
|
244
|
+
selectedValues.value.every((item: any) => typeof item === "string")
|
|
245
|
+
) {
|
|
246
|
+
return selectedValues.value.join(props.multiple ? ", " : " ");
|
|
247
|
+
} else {
|
|
248
|
+
return selectedValues.value
|
|
249
|
+
.map((item) => item[props.itemTitle].toString())
|
|
250
|
+
.join(props.multiple ? ", " : " ");
|
|
251
|
+
}
|
|
202
252
|
});
|
|
203
253
|
|
|
204
254
|
watch(outputTransformed, (newOutput) => {
|
|
@@ -226,7 +276,18 @@ const displayedItems = computed(() =>
|
|
|
226
276
|
*/
|
|
227
277
|
const updateDisplayedItems = (search: string) => {
|
|
228
278
|
noItemsFound.value = false;
|
|
229
|
-
const filteredItems = props.items.
|
|
279
|
+
const filteredItems = props.items.every(
|
|
280
|
+
(item: any) => typeof item === "string"
|
|
281
|
+
)
|
|
282
|
+
? props.items.filter((item) =>
|
|
283
|
+
item.toLowerCase().includes(search.toLowerCase())
|
|
284
|
+
)
|
|
285
|
+
: props.items.filter((item: any) =>
|
|
286
|
+
item[props.itemTitle]
|
|
287
|
+
.toString()
|
|
288
|
+
.toLowerCase()
|
|
289
|
+
.includes(search.toLowerCase())
|
|
290
|
+
);
|
|
230
291
|
if (filteredItems.length === 0) {
|
|
231
292
|
noItemsFound.value = true;
|
|
232
293
|
}
|
|
@@ -237,15 +298,30 @@ const updateDisplayedItems = (search: string) => {
|
|
|
237
298
|
* Apply active class to hovered item
|
|
238
299
|
* @param value of item
|
|
239
300
|
*/
|
|
240
|
-
const isActiveClass = (value:
|
|
301
|
+
const isActiveClass = (value: MucSelectItemTypes) =>
|
|
241
302
|
value === activeItem.value ? "active" : "";
|
|
242
303
|
|
|
243
304
|
/**
|
|
244
305
|
* Apply selected class to selected items
|
|
245
306
|
* @param value of item
|
|
246
307
|
*/
|
|
247
|
-
const isSelectedClass = (value:
|
|
248
|
-
|
|
308
|
+
const isSelectedClass = (value: MucSelectItemTypes) => {
|
|
309
|
+
if (typeof value === "string")
|
|
310
|
+
return selectedValues.value.includes(value) ? "selected" : "";
|
|
311
|
+
|
|
312
|
+
if (Array.isArray(selectedValues.value)) {
|
|
313
|
+
return selectedValues.value
|
|
314
|
+
.map((item) => item[props.itemTitle])
|
|
315
|
+
.includes(value[props.itemTitle])
|
|
316
|
+
? "selected"
|
|
317
|
+
: "";
|
|
318
|
+
}
|
|
319
|
+
if (typeof selectedValues.value !== "string") {
|
|
320
|
+
return selectedValues.value[props.itemTitle] === value[props.itemTitle]
|
|
321
|
+
? "selected"
|
|
322
|
+
: "";
|
|
323
|
+
}
|
|
324
|
+
};
|
|
249
325
|
|
|
250
326
|
/**
|
|
251
327
|
* Resets the currently activeItem
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<span>
|
|
3
|
+
{{ itemText }}
|
|
4
|
+
</span>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup lang="ts">
|
|
8
|
+
import { computed } from "vue";
|
|
9
|
+
|
|
10
|
+
import { MucSelectItemTypes } from "./MucSelectTypes";
|
|
11
|
+
|
|
12
|
+
const props = defineProps<{
|
|
13
|
+
item: MucSelectItemTypes;
|
|
14
|
+
itemLabel: string;
|
|
15
|
+
}>();
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Defines the displayed value
|
|
19
|
+
*/
|
|
20
|
+
const itemText = computed(() =>
|
|
21
|
+
typeof props.item === "string"
|
|
22
|
+
? props.item
|
|
23
|
+
: props.item[props.itemLabel].toString()
|
|
24
|
+
);
|
|
25
|
+
</script>
|