@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/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-0f229e1b]{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%}}
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",
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: "Option 1",
22
- items: ["Option 1", "Option 2", "Option 3", "Option 4"],
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 options",
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
- {{ option }}
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<string | string[]>("modelValue", {
77
- default: [],
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<string>();
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<string>();
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: string[];
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: string) => {
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: string) => {
177
- if (typeof selectedValues.value === "object")
190
+ const updateMVSingle = (newValue: MucSelectItemTypes) => {
191
+ if (Array.isArray(selectedValues.value))
178
192
  selectedValues.value = selectedValues.value.join(" ");
179
193
 
180
- selectedValues.value = selectedValues.value === newValue ? "" : newValue;
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: string) => {
188
- if (typeof selectedValues.value === "string")
211
+ const updateMVMultiple = (newValue: MucSelectItemTypes) => {
212
+ if (!Array.isArray(selectedValues.value))
189
213
  selectedValues.value = [selectedValues.value];
190
214
 
191
- selectedValues.value = selectedValues.value.includes(newValue)
192
- ? selectedValues.value.filter((val: string) => val !== newValue)
193
- : [...selectedValues.value, newValue];
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") return selectedValues.value;
201
- return selectedValues.value.join(props.multiple ? ", " : " ");
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.filter((item) => item.includes(search));
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: string) =>
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: string) =>
248
- selectedValues.value.includes(value) ? "selected" : "";
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>
@@ -0,0 +1,8 @@
1
+ export interface ItemAsObject {
2
+ [key: string]: any;
3
+ }
4
+
5
+ /**
6
+ * Different possible types of items
7
+ */
8
+ export type MucSelectItemTypes = string | ItemAsObject;