@muenchen/muc-patternlab-vue 1.11.0-beta.2 → 1.11.0-beta.3
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/README.md +1 -4
- package/dist/components/Form/MucCheckbox.stories.d.ts +34 -0
- package/dist/components/Form/MucCheckbox.vue.d.ts +18 -0
- package/dist/components/Form/MucCheckboxGroup.stories.d.ts +223 -0
- package/dist/components/Form/MucCheckboxGroup.vue.d.ts +46 -0
- package/dist/components/Form/MucErrorList.stories.d.ts +41 -0
- package/dist/components/Form/MucErrorList.vue.d.ts +17 -0
- package/dist/components/Form/MucInput.stories.d.ts +225 -0
- package/dist/components/Form/MucInput.vue.d.ts +86 -0
- package/dist/components/Form/MucRadioButton.stories.d.ts +154 -0
- package/dist/components/Form/MucRadioButton.vue.d.ts +59 -0
- package/dist/components/Form/MucRadioButtonGroup.vue.d.ts +37 -0
- package/dist/components/Form/MucSelect.stories.d.ts +64 -0
- package/dist/components/Form/MucSelect.vue.d.ts +36 -0
- package/dist/components/Form/MucTextArea.stories.d.ts +86 -0
- package/dist/components/Form/MucTextArea.vue.d.ts +49 -0
- package/dist/components/Form/RadioButtonTypes.d.ts +30 -0
- package/dist/components/Form/index.d.ts +10 -0
- package/dist/components/index.d.ts +2 -1
- package/dist/muc-patternlab-vue.es.js +311 -240
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/Banner/MucBanner.vue +6 -6
- package/src/components/BuisnessHours/MucBusinessHours.vue +7 -11
- package/src/components/Button/MucButton.vue +5 -5
- package/src/components/Callout/MucCallout.vue +3 -6
- package/src/components/Comment/MucComment.vue +7 -21
- package/src/components/Form/MucCheckbox.stories.ts +25 -0
- package/src/components/Form/MucCheckbox.vue +47 -0
- package/src/components/Form/MucCheckboxGroup.stories.ts +43 -0
- package/src/components/Form/MucCheckboxGroup.vue +80 -0
- package/src/components/Form/MucErrorList.stories.ts +31 -0
- package/src/components/Form/MucErrorList.vue +34 -0
- package/src/components/Form/MucInput.stories.ts +90 -0
- package/src/components/Form/MucInput.vue +198 -0
- package/src/components/Form/MucRadioButton.stories.ts +32 -0
- package/src/components/Form/MucRadioButton.vue +81 -0
- package/src/components/Form/MucRadioButtonGroup.vue +62 -0
- package/src/components/Form/MucSelect.stories.ts +34 -0
- package/src/components/Form/MucSelect.vue +201 -0
- package/src/components/Form/MucTextArea.stories.ts +47 -0
- package/src/components/Form/MucTextArea.vue +80 -0
- package/src/components/Form/RadioButtonTypes.ts +41 -0
- package/src/components/Form/index.ts +23 -0
- package/src/components/Icon/MucIcon.vue +7 -1
- package/src/components/Intro/MucIntro.vue +2 -2
- package/src/components/index.ts +2 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="m-form-group"
|
|
4
|
+
:class="isErrorClass"
|
|
5
|
+
>
|
|
6
|
+
<label
|
|
7
|
+
for="search-input"
|
|
8
|
+
class="m-label"
|
|
9
|
+
>
|
|
10
|
+
{{ label }}
|
|
11
|
+
<span
|
|
12
|
+
v-if="required"
|
|
13
|
+
aria-hidden="true"
|
|
14
|
+
class="mandatory"
|
|
15
|
+
>
|
|
16
|
+
*
|
|
17
|
+
<span class="visually-hidden">(erforderlich)</span>
|
|
18
|
+
</span>
|
|
19
|
+
</label>
|
|
20
|
+
<p
|
|
21
|
+
id="text-input-error"
|
|
22
|
+
class="m-error-message"
|
|
23
|
+
>
|
|
24
|
+
{{ errorMsg }}
|
|
25
|
+
</p>
|
|
26
|
+
<div class="m-input-wrapper m-autocomplete">
|
|
27
|
+
<div
|
|
28
|
+
v-if="!!slots.prefix"
|
|
29
|
+
class="m-input__prefix"
|
|
30
|
+
>
|
|
31
|
+
<span>
|
|
32
|
+
<slot name="prefix" />
|
|
33
|
+
</span>
|
|
34
|
+
</div>
|
|
35
|
+
<input
|
|
36
|
+
class="m-input autocomplete-input"
|
|
37
|
+
:type="type"
|
|
38
|
+
v-model="modelValue"
|
|
39
|
+
:aria-describedby="type + '-input'"
|
|
40
|
+
:placeholder="placeholder"
|
|
41
|
+
:required="required"
|
|
42
|
+
/>
|
|
43
|
+
<ul
|
|
44
|
+
v-if="isSearch && currentAvalOptions.length !== 0"
|
|
45
|
+
class="autocomplete-result-list autocomplete-result-list--location"
|
|
46
|
+
>
|
|
47
|
+
<li
|
|
48
|
+
class="autocomplete-result"
|
|
49
|
+
v-for="option in currentAvalOptions"
|
|
50
|
+
:key="option"
|
|
51
|
+
@click="handleOptionSelection(option)"
|
|
52
|
+
>
|
|
53
|
+
{{ option }}
|
|
54
|
+
</li>
|
|
55
|
+
</ul>
|
|
56
|
+
<button
|
|
57
|
+
v-if="suffixIcon"
|
|
58
|
+
class="m-input__suffix"
|
|
59
|
+
@click="handleSuffixClick"
|
|
60
|
+
>
|
|
61
|
+
<svg
|
|
62
|
+
aria-hidden="true"
|
|
63
|
+
class="icon"
|
|
64
|
+
>
|
|
65
|
+
<use :xlink:href="'#icon-' + suffixIcon"></use>
|
|
66
|
+
</svg>
|
|
67
|
+
<span class="visually-hidden">Suchen</span>
|
|
68
|
+
</button>
|
|
69
|
+
</div>
|
|
70
|
+
<p
|
|
71
|
+
class="m-hint"
|
|
72
|
+
id="text-input-hint"
|
|
73
|
+
>
|
|
74
|
+
{{ hint }}
|
|
75
|
+
</p>
|
|
76
|
+
</div>
|
|
77
|
+
</template>
|
|
78
|
+
<script setup lang="ts">
|
|
79
|
+
import { computed } from "vue";
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Type includes all possible input types possible.
|
|
83
|
+
*/
|
|
84
|
+
type inputType =
|
|
85
|
+
| "text"
|
|
86
|
+
| "password"
|
|
87
|
+
| "color"
|
|
88
|
+
| "search"
|
|
89
|
+
| "date"
|
|
90
|
+
| "datetime-local";
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Input value from the input component.
|
|
94
|
+
*/
|
|
95
|
+
const modelValue = defineModel<string>({ default: "" });
|
|
96
|
+
|
|
97
|
+
const props = withDefaults(
|
|
98
|
+
defineProps<{
|
|
99
|
+
/**
|
|
100
|
+
* Displays error message and highlights the input form with a red border.
|
|
101
|
+
*/
|
|
102
|
+
errorMsg?: string;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Placeholder for empty input form.
|
|
106
|
+
*/
|
|
107
|
+
placeholder?: string;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Sets this input form as required. Default is wrong.
|
|
111
|
+
*/
|
|
112
|
+
required?: boolean;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Displays a label above the form component.
|
|
116
|
+
*/
|
|
117
|
+
label?: string;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Displays a hint beneath the form component.
|
|
121
|
+
*/
|
|
122
|
+
hint?: string;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Sets the type of this form component. This can be text, password, color, date or datetime-local.
|
|
126
|
+
*/
|
|
127
|
+
type?: inputType;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Options for the form component. Type must set to 'search'.
|
|
131
|
+
*/
|
|
132
|
+
datalist?: string[];
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Icon to be displayed as a suffix at the end of the input.
|
|
136
|
+
*/
|
|
137
|
+
suffixIcon?: string;
|
|
138
|
+
}>(),
|
|
139
|
+
{
|
|
140
|
+
required: false,
|
|
141
|
+
type: "text",
|
|
142
|
+
dataList: [],
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
const slots = defineSlots<{
|
|
147
|
+
/**
|
|
148
|
+
* Slot in front of the user input with divider.
|
|
149
|
+
*/
|
|
150
|
+
prefix(): any;
|
|
151
|
+
}>();
|
|
152
|
+
|
|
153
|
+
const emits = defineEmits<{
|
|
154
|
+
/**
|
|
155
|
+
* Triggered when suffix-button is clicked.
|
|
156
|
+
* @param e Click-Event
|
|
157
|
+
*/
|
|
158
|
+
(e: "suffixClick"): void;
|
|
159
|
+
}>();
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Computes a CSS class based on the presence of an error message.
|
|
163
|
+
* @returns {string} Returns "has-error" if there is an error message, otherwise an empty string.
|
|
164
|
+
*/
|
|
165
|
+
const isErrorClass = computed(() => (!props.errorMsg ? "" : "has-error"));
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Computes whether the current type is "search".
|
|
169
|
+
* @returns {boolean} Returns true if the type is "search", otherwise false.
|
|
170
|
+
*/
|
|
171
|
+
const isSearch = computed(() => props.type === "search");
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Computes the list of available options based on the current search value.
|
|
175
|
+
* Filters the options from the datalist based on whether they start with the search value.
|
|
176
|
+
* @returns {string[]} Returns an array of matching options.
|
|
177
|
+
*/
|
|
178
|
+
const currentAvalOptions = computed(() => {
|
|
179
|
+
if (modelValue.value === "") return [];
|
|
180
|
+
|
|
181
|
+
const searchValue = modelValue.value.toLowerCase();
|
|
182
|
+
return props.datalist!.filter(
|
|
183
|
+
(option) =>
|
|
184
|
+
option.toLowerCase().startsWith(searchValue) &&
|
|
185
|
+
option.toLowerCase() !== searchValue
|
|
186
|
+
);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Handles the selection of an option.
|
|
191
|
+
* Sets the model value to the selected option.
|
|
192
|
+
* @param {string} option - The selected option.
|
|
193
|
+
*/
|
|
194
|
+
const handleOptionSelection = (option: string) => (modelValue.value = option);
|
|
195
|
+
|
|
196
|
+
const handleSuffixClick = () => emits("suffixClick");
|
|
197
|
+
</script>
|
|
198
|
+
<style scoped></style>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import MucRadioButton from "./MucRadioButton.vue";
|
|
2
|
+
import MucRadioButtonGroup from "./MucRadioButtonGroup.vue";
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
component: MucRadioButton,
|
|
6
|
+
title: "Forms/RadioButton",
|
|
7
|
+
tags: ["autodocs"],
|
|
8
|
+
parameters: {
|
|
9
|
+
docs: {
|
|
10
|
+
description: {
|
|
11
|
+
component: `
|
|
12
|
+
Offers simple functionality of a radio-button.
|
|
13
|
+
You need to use the radio-button within the radio-button-group - combined you can provide grouping functionality to allow users to select from a predefined set of options.
|
|
14
|
+
|
|
15
|
+
[🔗 Patternlab-Docs](https://patternlab.muenchen.space/?p=elements-radios)
|
|
16
|
+
`,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const Default = () => ({
|
|
23
|
+
components: { MucRadioButton, MucRadioButtonGroup },
|
|
24
|
+
template: `
|
|
25
|
+
<MucRadioButtonGroup heading="Checkbox group" model-value="">
|
|
26
|
+
<template v-slot:default>
|
|
27
|
+
<MucRadioButton value="first" label="first option" hint="This is a hint for this radiobutton"/>
|
|
28
|
+
<MucRadioButton v-for="index in 3" :key="index" :label="'other option-' + index" :value="'val-' + index"/>
|
|
29
|
+
</template>
|
|
30
|
+
</MucRadioButtonGroup>
|
|
31
|
+
`,
|
|
32
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="m-radios__item"
|
|
4
|
+
v-if="isInRadioButtonGroup"
|
|
5
|
+
>
|
|
6
|
+
<input
|
|
7
|
+
class="m-radios__input"
|
|
8
|
+
type="radio"
|
|
9
|
+
:checked="isChecked"
|
|
10
|
+
:disabled="isDisabled"
|
|
11
|
+
@click.stop="clicked"
|
|
12
|
+
/>
|
|
13
|
+
<label
|
|
14
|
+
class="m-label m-radios__label"
|
|
15
|
+
@click="clicked"
|
|
16
|
+
>
|
|
17
|
+
{{ label }}
|
|
18
|
+
<span class="m-hint">
|
|
19
|
+
{{ hint }}
|
|
20
|
+
</span>
|
|
21
|
+
</label>
|
|
22
|
+
</div>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script setup lang="ts">
|
|
26
|
+
import { computed, inject } from "vue";
|
|
27
|
+
|
|
28
|
+
import { RadioButtonGroupKey } from "./RadioButtonTypes";
|
|
29
|
+
|
|
30
|
+
const props = withDefaults(
|
|
31
|
+
defineProps<{
|
|
32
|
+
/**
|
|
33
|
+
* value for this radiobutton
|
|
34
|
+
*/
|
|
35
|
+
value: string;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Optional label shown behind the radiobutton
|
|
39
|
+
*/
|
|
40
|
+
label?: string;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Optional hint shown beneath the radiobutton
|
|
44
|
+
*/
|
|
45
|
+
hint?: string;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Optionally disable this specific radiobutton
|
|
49
|
+
*/
|
|
50
|
+
disabled?: boolean;
|
|
51
|
+
}>(),
|
|
52
|
+
{
|
|
53
|
+
disabled: false,
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Data provided by the radio-button-group
|
|
59
|
+
*/
|
|
60
|
+
const parentData = inject(RadioButtonGroupKey);
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Function called upon clicking this radiobutton
|
|
64
|
+
*/
|
|
65
|
+
const clicked = () => parentData?.set(props.value);
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Computed property if this radiobutton is checked or not
|
|
69
|
+
*/
|
|
70
|
+
const isChecked = computed(() => parentData?.modelValue.value === props.value);
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Computed property if this radiobutton should be disabled
|
|
74
|
+
*/
|
|
75
|
+
const isDisabled = computed(() => props.disabled || parentData?.disabled.value);
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Determines if this radiobutton is used inside a radiobutton-group
|
|
79
|
+
*/
|
|
80
|
+
const isInRadioButtonGroup = computed(() => !!parentData?.disabled ?? false);
|
|
81
|
+
</script>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="m-form-group">
|
|
3
|
+
<fieldset class="m-radio-group">
|
|
4
|
+
<legend class="m-radio-group__legend">
|
|
5
|
+
<h3 class="m-radio-group__heading">
|
|
6
|
+
{{ heading }}
|
|
7
|
+
</h3>
|
|
8
|
+
</legend>
|
|
9
|
+
<div class="m-radios">
|
|
10
|
+
<slot name="default" />
|
|
11
|
+
</div>
|
|
12
|
+
</fieldset>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script setup lang="ts">
|
|
17
|
+
import { provide, readonly, toRef } from "vue";
|
|
18
|
+
|
|
19
|
+
import { RadioButtonGroupKey, RadioButtonValueTypes } from "./RadioButtonTypes";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* exposed two-way binding of the currently selected radiobuttons-value
|
|
23
|
+
*/
|
|
24
|
+
const selectedButton = defineModel<RadioButtonValueTypes>("modelValue");
|
|
25
|
+
|
|
26
|
+
const props = withDefaults(
|
|
27
|
+
defineProps<{
|
|
28
|
+
/**
|
|
29
|
+
* Optional heading above all radiobuttons as a group heading
|
|
30
|
+
*/
|
|
31
|
+
heading?: string;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Optionally disable all child radiobuttons - defaults to 'false'
|
|
35
|
+
*/
|
|
36
|
+
disabled?: boolean;
|
|
37
|
+
}>(),
|
|
38
|
+
{
|
|
39
|
+
disabled: false,
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const emit = defineEmits<{
|
|
44
|
+
/**
|
|
45
|
+
* Triggered when a different radiobutton is selected.
|
|
46
|
+
* @param value RadioButtonValueTypes the value of the newly selected radiobutton
|
|
47
|
+
*/
|
|
48
|
+
change: [value: RadioButtonValueTypes];
|
|
49
|
+
}>();
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Providing necessary data to all child radiobuttons.
|
|
53
|
+
*/
|
|
54
|
+
provide(RadioButtonGroupKey, {
|
|
55
|
+
set: (value: RadioButtonValueTypes) => {
|
|
56
|
+
emit("change", value);
|
|
57
|
+
selectedButton.value = value;
|
|
58
|
+
},
|
|
59
|
+
modelValue: selectedButton,
|
|
60
|
+
disabled: readonly(toRef(props.disabled)),
|
|
61
|
+
});
|
|
62
|
+
</script>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import MucSelect from "./MucSelect.vue";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
component: MucSelect,
|
|
5
|
+
title: "Forms/MucSelect",
|
|
6
|
+
tags: ["autodocs"],
|
|
7
|
+
parameters: {
|
|
8
|
+
docs: {
|
|
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.
|
|
11
|
+
|
|
12
|
+
[🔗 Patternlab-Docs](https://patternlab.muenchen.space/?p=elements-combobox)
|
|
13
|
+
`,
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const Default = {
|
|
20
|
+
args: {
|
|
21
|
+
modelValue: "Option 1",
|
|
22
|
+
items: ["Option 1", "Option 2", "Option 3", "Option 4"],
|
|
23
|
+
label: "This is a label",
|
|
24
|
+
hint: "This is a hint",
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const MultiSelect = {
|
|
29
|
+
args: {
|
|
30
|
+
...Default.args,
|
|
31
|
+
label: "Select multiple options",
|
|
32
|
+
multiple: true,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="m-form-group">
|
|
3
|
+
<label class="m-label">
|
|
4
|
+
{{ label }}
|
|
5
|
+
</label>
|
|
6
|
+
<div
|
|
7
|
+
class="m-input-wrapper"
|
|
8
|
+
:class="selectType"
|
|
9
|
+
>
|
|
10
|
+
<input
|
|
11
|
+
type="text"
|
|
12
|
+
class="m-input m-combobox m-combobox--single"
|
|
13
|
+
:value="outputTransformed"
|
|
14
|
+
@click="toggleItemList"
|
|
15
|
+
readonly
|
|
16
|
+
/>
|
|
17
|
+
<span
|
|
18
|
+
class="m-input__trigger"
|
|
19
|
+
@click="toggleItemList"
|
|
20
|
+
>
|
|
21
|
+
<svg
|
|
22
|
+
aria-hidden="true"
|
|
23
|
+
class="icon"
|
|
24
|
+
>
|
|
25
|
+
<use xlink:href="#icon-chevron-down"></use>
|
|
26
|
+
</svg>
|
|
27
|
+
<span class="visually-hidden">Auswahlliste öffnen</span>
|
|
28
|
+
</span>
|
|
29
|
+
<ul
|
|
30
|
+
class="listbox"
|
|
31
|
+
:class="displayOptions"
|
|
32
|
+
@mouseleave="emptyActiveItem"
|
|
33
|
+
>
|
|
34
|
+
<li
|
|
35
|
+
v-for="(option, index) in props.items"
|
|
36
|
+
:key="index"
|
|
37
|
+
class="option"
|
|
38
|
+
@mouseenter="activeItem = option"
|
|
39
|
+
:class="[isActiveClass(option), isSelectedClass(option)]"
|
|
40
|
+
@click="clicked(option)"
|
|
41
|
+
>
|
|
42
|
+
{{ option }}
|
|
43
|
+
</li>
|
|
44
|
+
</ul>
|
|
45
|
+
</div>
|
|
46
|
+
<p
|
|
47
|
+
v-if="!!hint"
|
|
48
|
+
class="m-hint"
|
|
49
|
+
>
|
|
50
|
+
{{ hint }}
|
|
51
|
+
</p>
|
|
52
|
+
</div>
|
|
53
|
+
</template>
|
|
54
|
+
|
|
55
|
+
<script setup lang="ts">
|
|
56
|
+
import { computed, ref } from "vue";
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Exposed selected value / values
|
|
60
|
+
*/
|
|
61
|
+
const selectedValues = defineModel<string | string[]>("modelValue", {
|
|
62
|
+
default: [],
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* If list of items is shown
|
|
67
|
+
*/
|
|
68
|
+
const showItems = ref<boolean>(false);
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Last interacted item - selected or deselected
|
|
72
|
+
*/
|
|
73
|
+
const lastClickedItem = ref<string>();
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Index of currently actively hovered item or selected item
|
|
77
|
+
*/
|
|
78
|
+
const activeItem = ref<string>();
|
|
79
|
+
|
|
80
|
+
const props = withDefaults(
|
|
81
|
+
defineProps<{
|
|
82
|
+
/**
|
|
83
|
+
* List of items to be available
|
|
84
|
+
*/
|
|
85
|
+
items: string[];
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Optional label shown above the input
|
|
89
|
+
*/
|
|
90
|
+
label?: string;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Optional hint shown below the input
|
|
94
|
+
*/
|
|
95
|
+
hint?: string;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Allow multiple selectable items
|
|
99
|
+
*/
|
|
100
|
+
multiple?: boolean;
|
|
101
|
+
}>(),
|
|
102
|
+
{
|
|
103
|
+
multiple: false,
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Toggles the list of items and sets the previously selected item as active
|
|
109
|
+
*/
|
|
110
|
+
const toggleItemList = () => {
|
|
111
|
+
showItems.value = !showItems.value;
|
|
112
|
+
activeItem.value = lastClickedItem.value;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Actions upon clicking an item
|
|
117
|
+
* @param clickedValue clicked item value
|
|
118
|
+
*/
|
|
119
|
+
const clicked = (clickedValue: string) => {
|
|
120
|
+
lastClickedItem.value = clickedValue;
|
|
121
|
+
|
|
122
|
+
props.multiple
|
|
123
|
+
? updateMVMultiple(clickedValue)
|
|
124
|
+
: updateMVSingle(clickedValue);
|
|
125
|
+
|
|
126
|
+
if (!props.multiple) showItems.value = false;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Update the modelValue with the given. Performs conversion to string if necessary.
|
|
131
|
+
* @param newValue the new value
|
|
132
|
+
*/
|
|
133
|
+
const updateMVSingle = (newValue: string) => {
|
|
134
|
+
if (typeof selectedValues.value === "object")
|
|
135
|
+
selectedValues.value = selectedValues.value.join(" ");
|
|
136
|
+
|
|
137
|
+
selectedValues.value = selectedValues.value === newValue ? "" : newValue;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Update the modelValue with the given. Performs conversion to array if necessary.
|
|
142
|
+
* @param newValue the new value
|
|
143
|
+
*/
|
|
144
|
+
const updateMVMultiple = (newValue: string) => {
|
|
145
|
+
if (typeof selectedValues.value === "string")
|
|
146
|
+
selectedValues.value = [selectedValues.value];
|
|
147
|
+
|
|
148
|
+
selectedValues.value = selectedValues.value.includes(newValue)
|
|
149
|
+
? selectedValues.value.filter((val: string) => val !== newValue)
|
|
150
|
+
: [...selectedValues.value, newValue];
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Converts the displayed text depending on the selection mode
|
|
155
|
+
*/
|
|
156
|
+
const outputTransformed = computed(() => {
|
|
157
|
+
if (typeof selectedValues.value === "string") return selectedValues.value;
|
|
158
|
+
return selectedValues.value.join(props.multiple ? ", " : " ");
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Apply active class to hovered item
|
|
163
|
+
* @param value of item
|
|
164
|
+
*/
|
|
165
|
+
const isActiveClass = (value: string) =>
|
|
166
|
+
value === activeItem.value ? "active" : "";
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Apply selected class to selected items
|
|
170
|
+
* @param value of item
|
|
171
|
+
*/
|
|
172
|
+
const isSelectedClass = (value: string) =>
|
|
173
|
+
selectedValues.value.includes(value) ? "selected" : "";
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Resets the currently activeItem
|
|
177
|
+
*/
|
|
178
|
+
const emptyActiveItem = () => (activeItem.value = "");
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Display the list of item by changing the css-display property
|
|
182
|
+
*/
|
|
183
|
+
const displayOptions = computed(() =>
|
|
184
|
+
showItems.value ? "display-listbox" : ""
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Switches between the selection modes according to multiple. Checkboxes are shown on the multiple select
|
|
189
|
+
*/
|
|
190
|
+
const selectType = computed(() =>
|
|
191
|
+
props.multiple
|
|
192
|
+
? "m-input-wrapper--multiselect multiselect"
|
|
193
|
+
: "m-input-wrapper--select"
|
|
194
|
+
);
|
|
195
|
+
</script>
|
|
196
|
+
|
|
197
|
+
<style scoped>
|
|
198
|
+
.display-listbox {
|
|
199
|
+
display: block !important;
|
|
200
|
+
}
|
|
201
|
+
</style>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import MucTextArea from "./MucTextArea.vue";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
component: MucTextArea,
|
|
5
|
+
title: "Forms/MucTextArea",
|
|
6
|
+
tags: ["autodocs"],
|
|
7
|
+
parameters: {
|
|
8
|
+
docs: {
|
|
9
|
+
description: {
|
|
10
|
+
component: `The muc-text-area component allows bigger text based inputs then the regular input. The size is adjustable.
|
|
11
|
+
|
|
12
|
+
[🔗 Patternlab-Docs](https://patternlab.muenchen.space/?p=elements-textarea)
|
|
13
|
+
`,
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const Default = {
|
|
20
|
+
args: {
|
|
21
|
+
placeholder: "Write some very long text here",
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const Error = {
|
|
26
|
+
args: {
|
|
27
|
+
...Default.args,
|
|
28
|
+
errorMsg: "An error occured",
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const Required = {
|
|
33
|
+
args: {
|
|
34
|
+
label: "Required textarea",
|
|
35
|
+
...Default.args,
|
|
36
|
+
required: true,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const BigTextArea = {
|
|
41
|
+
args: {
|
|
42
|
+
...Default.args,
|
|
43
|
+
rows: 7,
|
|
44
|
+
label: "Big textarea",
|
|
45
|
+
hint: "Write a lot of text",
|
|
46
|
+
},
|
|
47
|
+
};
|