@madgex/design-system-ce 5.1.2 → 5.2.0
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/CHANGELOG.md +22 -0
- package/components/internals/MdsIcon.vue +29 -0
- package/components/text-editor/TextEditor.ce.vue +68 -0
- package/components/text-editor/TextEditorButton.vue +60 -0
- package/components/text-editor/TextEditorContent.vue +69 -0
- package/components/text-editor/TextEditorToolbar.vue +149 -0
- package/custom-elements/mds-combobox.js +13 -0
- package/custom-elements/mds-text-editor.js +12 -0
- package/dist/custom-elements/mds-combobox.js +1 -0
- package/dist/custom-elements/mds-text-editor.js +92 -0
- package/dist/index.js +1 -2
- package/dist/manifest.json +25 -11
- package/dist/plugin-vue_export-helper.js +2 -0
- package/index.js +8 -11
- package/package.json +4 -2
- package/vite.config.js +7 -15
- package/dist/assets/polyfills-legacy.bfe7dd4c.js +0 -1
- package/dist/index-legacy.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,28 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [5.2.0](https://github.com/projects/MDS/repos/mds-branding/compare/diff?targetBranch=refs/tags/@madgex/design-system-ce@5.1.2&sourceBranch=refs/tags/@madgex/design-system-ce@5.2.0) (2022-08-18)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* add text editor (wip) ([1d424b3](https://github.com/projects/MDS/repos/mds-branding/commits/1d424b399f1ce71a1db99b644dc72aa650eee1f0))
|
|
12
|
+
* add text editor (wip) ([804cabe](https://github.com/projects/MDS/repos/mds-branding/commits/804cabee541b65e8943a3e29b9c6108313a3400a))
|
|
13
|
+
* manage tabindex in toolbar, add examples and documentation ([74e1442](https://github.com/projects/MDS/repos/mds-branding/commits/74e1442437e9f27580b9f3f56d2c37a3874e98f6))
|
|
14
|
+
* refactoring toolbar, adding keyboard interaction and fixing icons ([b4c5121](https://github.com/projects/MDS/repos/mds-branding/commits/b4c5121ddfd1d1323ac3fb3d87ca52b85470768a))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* adding reusable icon vue component + svgs for editor menu ([f8bfaae](https://github.com/projects/MDS/repos/mds-branding/commits/f8bfaae311d607ce1ef15cf65f857b442d1fcbc5))
|
|
20
|
+
* export each custom element separately ([da9f94d](https://github.com/projects/MDS/repos/mds-branding/commits/da9f94de94c6612c8a645855f9e32a6abeee9194))
|
|
21
|
+
* move aria-pressed to toolbar instead of button ([5114f9d](https://github.com/projects/MDS/repos/mds-branding/commits/5114f9dd829ca10a5dbfd88a5784163575c2ac12))
|
|
22
|
+
* removed the disabled attribute to only aria-disabled to avoid focus issue ([2076227](https://github.com/projects/MDS/repos/mds-branding/commits/2076227c8a98c5eb359320271ccf5dc6e6a5bded))
|
|
23
|
+
* trying to separate the text editor from the main js ([db089b8](https://github.com/projects/MDS/repos/mds-branding/commits/db089b8779bbbf0d4a7c1bfbb2de6c9fc20d947d))
|
|
24
|
+
* update filenames ([7ad354f](https://github.com/projects/MDS/repos/mds-branding/commits/7ad354fb77629e738ca55a00f71dc87f365382ae))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
## [5.1.2](https://github.com/projects/MDS/repos/mds-branding/compare/diff?targetBranch=refs/tags/@madgex/design-system-ce@5.1.1&sourceBranch=refs/tags/@madgex/design-system-ce@5.1.2) (2022-07-12)
|
|
7
29
|
|
|
8
30
|
**Note:** Version bump only for package @madgex/design-system-ce
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<span>
|
|
3
|
+
<svg aria-hidden="true" focusable="false" class="mds-icon" :class="`mds-icon--${iconName} ${classes}`">
|
|
4
|
+
<use :href="`${iconPath}#icon-${iconName}`" />
|
|
5
|
+
</svg>
|
|
6
|
+
<span v-if="visuallyHiddenLabel" class="mds-visually-hidden">{{ visuallyHiddenLabel }}</span>
|
|
7
|
+
</span>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script>
|
|
11
|
+
export default {
|
|
12
|
+
name: 'MdsIcon',
|
|
13
|
+
props: {
|
|
14
|
+
iconName: {
|
|
15
|
+
type: String,
|
|
16
|
+
default: '',
|
|
17
|
+
},
|
|
18
|
+
classes: {
|
|
19
|
+
type: String,
|
|
20
|
+
default: '',
|
|
21
|
+
},
|
|
22
|
+
visuallyHiddenLabel: {
|
|
23
|
+
type: String,
|
|
24
|
+
default: '',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
inject: ['iconPath'],
|
|
28
|
+
};
|
|
29
|
+
</script>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<TextEditorContent v-model="content" />
|
|
4
|
+
<input type="hidden" :name="editorid" :value="content" />
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script>
|
|
9
|
+
import TextEditorContent from './TextEditorContent.vue';
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
name: 'TextEditor',
|
|
13
|
+
components: {
|
|
14
|
+
TextEditorContent,
|
|
15
|
+
},
|
|
16
|
+
props: {
|
|
17
|
+
editorid: {
|
|
18
|
+
type: String,
|
|
19
|
+
required: true,
|
|
20
|
+
},
|
|
21
|
+
iconpath: {
|
|
22
|
+
type: String,
|
|
23
|
+
default: '/assets/icons.svg',
|
|
24
|
+
},
|
|
25
|
+
menuButtons: {
|
|
26
|
+
type: String,
|
|
27
|
+
default: '',
|
|
28
|
+
},
|
|
29
|
+
i18n: {
|
|
30
|
+
type: String,
|
|
31
|
+
default: '',
|
|
32
|
+
},
|
|
33
|
+
value: {
|
|
34
|
+
type: String,
|
|
35
|
+
default: '',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
data() {
|
|
39
|
+
return {
|
|
40
|
+
content: this.value,
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
computed: {
|
|
44
|
+
customMenuButtons() {
|
|
45
|
+
return this.menuButtons ? JSON.parse(this.menuButtons) : null;
|
|
46
|
+
},
|
|
47
|
+
i18nText() {
|
|
48
|
+
return this.i18n
|
|
49
|
+
? JSON.parse(this.i18n)
|
|
50
|
+
: {
|
|
51
|
+
toolbarLabel: 'Text formatting',
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
provide() {
|
|
56
|
+
return {
|
|
57
|
+
iconPath: this.iconpath,
|
|
58
|
+
id: this.editorid,
|
|
59
|
+
customMenuButtons: this.customMenuButtons,
|
|
60
|
+
i18nText: this.i18nText,
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
mounted() {
|
|
64
|
+
const fallback = document.querySelector(`#text-editor-fallback-${this.editorid}`);
|
|
65
|
+
if (fallback) fallback.remove();
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
</script>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<button
|
|
3
|
+
type="button"
|
|
4
|
+
:title="label"
|
|
5
|
+
:aria-label="label"
|
|
6
|
+
class="mds-text-editor__button"
|
|
7
|
+
:class="{ 'mds-text-editor__button--active': isActive }"
|
|
8
|
+
:tabindex="tabindex"
|
|
9
|
+
:aria-disabled="disabled"
|
|
10
|
+
:aria-pressed="ariaPressed"
|
|
11
|
+
@focus="$emit('updateTabIndex', id)"
|
|
12
|
+
>
|
|
13
|
+
<MdsIcon :icon-name="iconName" />
|
|
14
|
+
</button>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script>
|
|
18
|
+
import MdsIcon from '../internals/MdsIcon.vue';
|
|
19
|
+
export default {
|
|
20
|
+
name: 'TextEditorButton',
|
|
21
|
+
components: {
|
|
22
|
+
MdsIcon,
|
|
23
|
+
},
|
|
24
|
+
emits: ['updateTabIndex'],
|
|
25
|
+
props: {
|
|
26
|
+
id: {
|
|
27
|
+
type: String,
|
|
28
|
+
required: true,
|
|
29
|
+
},
|
|
30
|
+
label: {
|
|
31
|
+
type: String,
|
|
32
|
+
default: '',
|
|
33
|
+
},
|
|
34
|
+
iconName: {
|
|
35
|
+
type: String,
|
|
36
|
+
default: '',
|
|
37
|
+
},
|
|
38
|
+
isActive: {
|
|
39
|
+
type: Boolean,
|
|
40
|
+
default: false,
|
|
41
|
+
},
|
|
42
|
+
initialTabindex: {
|
|
43
|
+
type: Number,
|
|
44
|
+
default: -1,
|
|
45
|
+
},
|
|
46
|
+
ariaPressed: {
|
|
47
|
+
type: Boolean,
|
|
48
|
+
default: false,
|
|
49
|
+
},
|
|
50
|
+
disabled: {
|
|
51
|
+
type: Boolean,
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
data() {
|
|
55
|
+
return {
|
|
56
|
+
tabindex: this.initialTabindex,
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
</script>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="mds-text-editor" v-if="editor">
|
|
3
|
+
<TextEditorToolbar :editor="editor" />
|
|
4
|
+
<EditorContent :editor="editor" />
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script>
|
|
9
|
+
import StarterKit from '@tiptap/starter-kit';
|
|
10
|
+
import { Editor, EditorContent } from '@tiptap/vue-3';
|
|
11
|
+
import TextEditorToolbar from './TextEditorToolbar.vue';
|
|
12
|
+
|
|
13
|
+
export default {
|
|
14
|
+
name: 'TextEditorContent',
|
|
15
|
+
components: {
|
|
16
|
+
EditorContent,
|
|
17
|
+
TextEditorToolbar,
|
|
18
|
+
},
|
|
19
|
+
props: {
|
|
20
|
+
modelValue: {
|
|
21
|
+
type: String,
|
|
22
|
+
default: '',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
inject: ['id'],
|
|
26
|
+
|
|
27
|
+
emits: ['update:modelValue'],
|
|
28
|
+
|
|
29
|
+
data() {
|
|
30
|
+
return {
|
|
31
|
+
editor: null,
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
watch: {
|
|
36
|
+
modelValue(value) {
|
|
37
|
+
const isSame = this.editor.getHTML() === value;
|
|
38
|
+
|
|
39
|
+
if (isSame) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
this.editor.commands.setContent(value, false);
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
mounted() {
|
|
48
|
+
this.editor = new Editor({
|
|
49
|
+
extensions: [StarterKit],
|
|
50
|
+
editorProps: {
|
|
51
|
+
attributes: {
|
|
52
|
+
class: 'mds-text-editor__content mds-edited-text',
|
|
53
|
+
id: this.id,
|
|
54
|
+
role: 'textbox',
|
|
55
|
+
[`aria-labelledby`]: `text-editor-label-${this.id}`,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
content: this.modelValue,
|
|
59
|
+
onUpdate: () => {
|
|
60
|
+
this.$emit('update:modelValue', this.editor.getHTML());
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
beforeUnmount() {
|
|
66
|
+
this.editor.destroy();
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
</script>
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="mds-text-editor__menu" role="toolbar" :aria-label="i18nText.toolbarLabel" :aria-controls="id">
|
|
3
|
+
<TextEditorButton
|
|
4
|
+
ref="menuButton"
|
|
5
|
+
v-for="button in menuButtons"
|
|
6
|
+
:key="button.id"
|
|
7
|
+
:id="button.id"
|
|
8
|
+
:label="button.label"
|
|
9
|
+
:icon-name="button.iconName"
|
|
10
|
+
:isActive="button.isActive?.(editor)"
|
|
11
|
+
:disabled="button.isDisabled?.(editor)"
|
|
12
|
+
:initialTabindex="firstFocusableButton.id === button.id ? 0 : -1"
|
|
13
|
+
:aria-pressed="button.id === 'undo' || button.id === 'redo' ? null : button.isActive?.(editor)"
|
|
14
|
+
@click="button.onClick(editor)"
|
|
15
|
+
@keyup.left="setFocusToSibling('previous', $event)"
|
|
16
|
+
@keyup.up="setFocusToSibling('previous', $event)"
|
|
17
|
+
@keyup.right="setFocusToSibling('next', $event)"
|
|
18
|
+
@keyup.down="setFocusToSibling('next', $event)"
|
|
19
|
+
@update-tab-index="updateTabIndex"
|
|
20
|
+
/>
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script>
|
|
25
|
+
import TextEditorButton from './TextEditorButton.vue';
|
|
26
|
+
|
|
27
|
+
export default {
|
|
28
|
+
name: 'TextEditorToolbar',
|
|
29
|
+
|
|
30
|
+
components: {
|
|
31
|
+
TextEditorButton,
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
props: {
|
|
35
|
+
editor: {
|
|
36
|
+
type: Object,
|
|
37
|
+
required: true,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
inject: ['id', 'customMenuButtons', 'i18nText'],
|
|
42
|
+
|
|
43
|
+
data() {
|
|
44
|
+
return {
|
|
45
|
+
defaultMenuButtons: [
|
|
46
|
+
{
|
|
47
|
+
id: 'bold',
|
|
48
|
+
label: 'Bold',
|
|
49
|
+
iconName: 'text-bold',
|
|
50
|
+
onClick: (editor) => editor.commands.toggleBold(),
|
|
51
|
+
isActive: (editor) => editor.isActive('bold'),
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'italic',
|
|
55
|
+
label: 'Italic',
|
|
56
|
+
iconName: 'text-italic',
|
|
57
|
+
onClick: (editor) => editor.commands.toggleItalic(),
|
|
58
|
+
isActive: (editor) => editor.isActive('italic'),
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: 'strike',
|
|
62
|
+
label: 'Strike',
|
|
63
|
+
iconName: 'text-strike-through',
|
|
64
|
+
onClick: (editor) => editor.commands.toggleStrike(),
|
|
65
|
+
isActive: (editor) => editor.isActive('strike'),
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: 'bulletList',
|
|
69
|
+
label: 'Bullet list',
|
|
70
|
+
iconName: 'list-bullets',
|
|
71
|
+
onClick: (editor) => editor.commands.toggleBulletList(),
|
|
72
|
+
isActive: (editor) => editor.isActive('bulletList'),
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: 'orderedList',
|
|
76
|
+
label: 'Ordered list',
|
|
77
|
+
iconName: 'list-numbers',
|
|
78
|
+
onClick: (editor) => editor.commands.toggleOrderedList(),
|
|
79
|
+
isActive: (editor) => editor.isActive('orderedList'),
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: 'undo',
|
|
83
|
+
label: 'Undo',
|
|
84
|
+
iconName: 'undo',
|
|
85
|
+
onClick: (editor) => editor.commands.undo(),
|
|
86
|
+
isDisabled: (editor) => !editor.can().undo(),
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: 'redo',
|
|
90
|
+
label: 'Redo',
|
|
91
|
+
iconName: 'redo',
|
|
92
|
+
onClick: (editor) => editor.commands.redo(),
|
|
93
|
+
isDisabled: (editor) => !editor.can().redo(),
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
computed: {
|
|
100
|
+
menuButtons() {
|
|
101
|
+
if (this.customMenuButtons?.length) {
|
|
102
|
+
const toolbar = [];
|
|
103
|
+
this.customMenuButtons.forEach((customBtn) => {
|
|
104
|
+
const defaultButton = this.defaultMenuButtons.find((defaultBtn) => defaultBtn.id === customBtn.id);
|
|
105
|
+
toolbar.push({
|
|
106
|
+
...defaultButton,
|
|
107
|
+
...customBtn,
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
return toolbar;
|
|
111
|
+
}
|
|
112
|
+
return this.defaultMenuButtons;
|
|
113
|
+
},
|
|
114
|
+
firstFocusableButton() {
|
|
115
|
+
return this.menuButtons.find((button) => !button.isDisabled?.(this.editor));
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
methods: {
|
|
120
|
+
findSiblings(currentElement, position) {
|
|
121
|
+
let sibling = position === 'previous' ? currentElement.previousElementSibling : currentElement.nextElementSibling;
|
|
122
|
+
|
|
123
|
+
if (sibling?.hasAttribute('disabled')) {
|
|
124
|
+
sibling = this.findSiblings(sibling, position);
|
|
125
|
+
}
|
|
126
|
+
return sibling;
|
|
127
|
+
},
|
|
128
|
+
setFocusToSibling(position, event) {
|
|
129
|
+
const element = this.findSiblings(event.target, position);
|
|
130
|
+
if (element) {
|
|
131
|
+
element.focus();
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
updateTabIndex(buttonId) {
|
|
135
|
+
// if the id of the button is not passed we get the first focusable button from the list instead
|
|
136
|
+
if (!buttonId) {
|
|
137
|
+
buttonId = this.firstFocusableButton.id;
|
|
138
|
+
}
|
|
139
|
+
this.$refs.menuButton.forEach((button) => {
|
|
140
|
+
if (button.id === buttonId) {
|
|
141
|
+
button.tabindex = 0;
|
|
142
|
+
} else {
|
|
143
|
+
button.tabindex = -1;
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
</script>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import '@ungap/custom-elements';
|
|
2
|
+
/**
|
|
3
|
+
* We're using a modified `defineCustomElement` where we can choose not to use shadowDom
|
|
4
|
+
* shadowDom prevents access to external CSS, which is how design-system css works!
|
|
5
|
+
* https://github.com/vuejs/core/issues/4314#issuecomment-1021393430
|
|
6
|
+
*/
|
|
7
|
+
import { defineCustomElement } from '../temp-define-custom-element';
|
|
8
|
+
// --- Components ---
|
|
9
|
+
import Combobox from '../components/combobox/Combobox.ce.vue';
|
|
10
|
+
|
|
11
|
+
const MdsCombobox = defineCustomElement(Combobox, { shadowRoot: false });
|
|
12
|
+
|
|
13
|
+
export default MdsCombobox;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import '@ungap/custom-elements';
|
|
2
|
+
/**
|
|
3
|
+
* We're using a modified `defineCustomElement` where we can choose not to use shadowDom
|
|
4
|
+
* shadowDom prevents access to external CSS, which is how design-system css works!
|
|
5
|
+
* https://github.com/vuejs/core/issues/4314#issuecomment-1021393430
|
|
6
|
+
*/
|
|
7
|
+
import { defineCustomElement } from '../temp-define-custom-element';
|
|
8
|
+
import TextEditor from '../components/text-editor/TextEditor.ce.vue';
|
|
9
|
+
|
|
10
|
+
const MdsTextEditor = defineCustomElement(TextEditor, { shadowRoot: false });
|
|
11
|
+
|
|
12
|
+
export default MdsTextEditor;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{_ as h,o as a,c as l,a as c,w as r,t as m,b as v,r as I,n as g,d as p,e as x,f as _,g as C,h as B,F as k,i as w,j as L}from"../plugin-vue_export-helper.js";const V={name:"ComboboxClear",inject:["iconPath","clearInput"]},S=["aria-label","title"],T={"aria-hidden":"true",focusable:"false",class:"mds-icon mds-icon--close mds-icon--sm"},M=["href"];function E(t,i,n,u,o,e){return a(),l("button",{class:"mds-combobox__clear mds-button mds-button--plain",type:"button",onClick:i[0]||(i[0]=d=>t.$emit("clear",d)),onKeydown:i[1]||(i[1]=r(d=>t.$emit("clear",d),["enter"])),"aria-label":e.clearInput,title:e.clearInput},[(a(),l("svg",T,[c("use",{href:`${e.iconPath}#icon-close`},null,8,M)]))],40,S)}var H=h(V,[["render",E]]);const K={name:"ListBox",props:{hidden:{type:Boolean,default:!0},isLoading:{type:Boolean,default:!0},comboboxid:{type:String,required:!0}},inject:["iconPath","loadingText"]},F=["aria-labelledby","hidden"],A={key:0,class:"mds-combobox-loading"},q={"aria-hidden":"true",focusable:"true",class:"mds-icon mds-icon--spinner mds-icon--after"},G=["href"],P={class:"mds-visually-hidden"};function j(t,i,n,u,o,e){return a(),l("ul",{class:"mds-combobox__listbox",role:"listbox","aria-labelledby":`${n.comboboxid}-label`,hidden:n.hidden},[n.isLoading?(a(),l("li",A,[(a(),l("svg",q,[c("use",{href:`${e.iconPath}#icon-spinner`},null,8,G)])),c("span",P,m(e.loadingText),1)])):v("",!0),I(t.$slots,"default")],8,F)}var N=h(K,[["render",j]]);const D={name:"ListBoxOption",props:{option:{type:Object,required:!0},focused:{type:Boolean,default:!1},searchValue:{type:String,default:""}},watch:{searchValue(t){return t},focused(t){t&&this.$refs.listItem.scrollIntoView(!1)}},methods:{highlightOption(){return this.option.label.replace(new RegExp(this.searchValue,"gi"),i=>`<span class="mds-combobox__option--marked">${i}</span>`)}}},R=["aria-selected","innerHTML"];function U(t,i,n,u,o,e){return a(),l("li",{ref:"listItem",class:g(["mds-combobox__option",{"mds-combobox__option--focused":n.focused}]),role:"option","aria-selected":n.focused.toString(),onMousedown:i[0]||(i[0]=d=>t.$emit("mousedown",d)),innerHTML:e.highlightOption()},null,42,R)}var $=h(D,[["render",U]]);const z={name:"Combobox",components:{ComboboxClear:H,ListBox:N,ListBoxOption:$},emits:["search","select-option","clear-all"],props:{comboboxid:{type:String,required:!0},placeholder:{type:String,default:""},name:{type:[String,Boolean],default:!1},value:{type:String,default:""},options:{type:Array,default:()=>[]},filterOptions:{type:Boolean,default:!0},iconpath:{type:String,default:"/assets/icons.svg"},dataAriaInvalid:{type:String,default:""},i18n:{type:String,default:""}},data(){return{expanded:!1,selected:null,chosen:null,searchValue:this.$props.value,resultCountMessage:null}},provide(){return{iconPath:this.iconpath,loadingText:this.i18nText.loadingText,clearInput:this.i18nText.clearInput}},mounted(){var n,u,o,e;const t=(u=(n=this.$el.parentElement)==null?void 0:n.parentElement)==null?void 0:u.querySelector(".mds-form-element__fallback input"),i=(e=(o=this.$el.parentElement)==null?void 0:o.parentElement)==null?void 0:e.querySelector(".mds-form-element__fallback select");t&&t.remove(),i&&i.removeAttribute("id")},computed:{inputValue(){return this.chosenOption?this.chosenOption.label:this.searchValue},selectedOption:{get(){return this.selected},set(t){this.selected=t}},chosenOption:{get(){return this.chosen},set(t){this.chosen=t,this.selectedOption=t,this.$emit("select-option",this.chosen)}},visibleOptions(){return this.filterOptions?this.options.filter(t=>t.label.toLowerCase().includes(this.searchValue.toLowerCase())):this.options},listBoxId(){return`${this.comboboxid}-listbox`},optionId(){return`${this.comboboxid}-option`},describedBy(){return`${this.comboboxid}-assistiveHint`},isLoading(){return this.options.length===0&&this.expanded},selectedOptionId(){const t=this.visibleOptions.indexOf(this.selectedOption);if(t>-1)return`${this.optionId}-${t}`},listBoxHidden(){return!this.expanded},lastOptionIndex(){return this.visibleOptions.length-1},ariaExpanded(){return this.expanded?"true":"false"},ariaInvalid(){return this.dataAriaInvalid?"true":"false"},i18nText(){return this.i18n?JSON.parse(this.i18n):{loadingText:"Loading",describedByText:"When autocomplete results are available, use up and down arrows to review and enter to select.",resultsMessage:"{count} result available",resultsMessage_plural:"{count} results available",clearInput:"clear input"}}},methods:{makeActive(){this.expanded=!0},makeInactive(){this.expanded=!1},handleInput(t){this.chosenOption=null,this.searchValue=t.target?t.target.value:"",this.handleChange(),this.$emit("search",this.searchValue),this.visibleOptions.length>0&&this.updateCount()},handleChange(){this.searchValue.length===0&&this.clearField(),this.searchValue.length>1?(this.makeActive(),this.updateCount()):this.makeInactive()},handleFocus(){this.handleChange(),this.visibleOptions.length>1&&this.updateCount()},handleClear(){this.clearField(),this.$refs.comboInput.focus()},clearField(){this.searchValue="",this.chosenOption=null,this.$emit("clear-all")},clickOption(t=this.selectedOption){this.chosenOption=t,this.makeInactive()},chooseOption(){this.chosenOption=this.selectedOption,this.makeInactive(),this.clearCount()},hiddenGuard(t){this.listBoxHidden||t.call(this)},onInputBlur(){this.makeInactive(),this.clearCount()},onKeyDown(){if(this.selectedOption){const t=this.visibleOptions.findIndex(n=>n.value===this.selectedOption.value),i=t===this.lastOptionIndex?t:t+1;this.selectedOption=this.visibleOptions[i]}else[this.selectedOption]=this.visibleOptions},onKeyUp(){if(this.selectedOption){const t=this.visibleOptions.findIndex(n=>n.value===this.selectedOption.value),i=t===0?t:t-1;this.selectedOption=this.visibleOptions[i]}else this.selectedOption=this.visibleOptions[this.lastOptionIndex]},onKeyHome(){[this.selectedOption]=this.visibleOptions},onKeyEnd(){this.selectedOption=this.visibleOptions[this.lastOptionIndex]},updateCount(){this.clearCount(),setTimeout(()=>{const t=this.visibleOptions.length===1?this.i18nText.resultsMessage:this.i18nText.resultsMessage_plural;this.resultCountMessage=t.replace("{count}",this.visibleOptions.length)},1400)},clearCount(){this.resultCountMessage=null}}},J=["value","id","name","placeholder","aria-owns","aria-expanded","aria-activedescendant","aria-invalid","aria-describedby"],W={"aria-live":"polite",role:"status",class:"mds-visually-hidden"},Q=["id"];function X(t,i,n,u,o,e){const d=p("ComboboxClear"),O=p("ListBoxOption"),y=p("ListBox");return a(),l("div",{class:g(["mds-combobox",{"mds-combobox--active":!e.listBoxHidden}]),onKeydown:[i[4]||(i[4]=r(s=>e.hiddenGuard(e.onKeyDown),["down"])),i[5]||(i[5]=r(s=>e.hiddenGuard(e.onKeyUp),["up"])),i[6]||(i[6]=r(s=>e.hiddenGuard(e.onKeyHome),["home"])),i[7]||(i[7]=r(s=>e.hiddenGuard(e.onKeyEnd),["end"])),i[8]||(i[8]=r((...s)=>e.makeInactive&&e.makeInactive(...s),["esc"])),i[9]||(i[9]=r(B((...s)=>e.chooseOption&&e.chooseOption(...s),["stop","prevent"]),["enter"]))]},[c("input",{onInput:i[0]||(i[0]=(...s)=>e.handleInput&&e.handleInput(...s)),value:e.inputValue,class:"mds-form-control",autocomplete:"off",type:"text",role:"combobox",ref:"comboInput",id:n.comboboxid,name:n.name,placeholder:n.placeholder,"aria-owns":e.listBoxId,"aria-expanded":e.ariaExpanded,"aria-autocomplete":"list","aria-activedescendant":e.selectedOptionId,"aria-invalid":e.ariaInvalid,"aria-describedby":e.describedBy,onChange:i[1]||(i[1]=(...s)=>e.handleChange&&e.handleChange(...s)),onBlur:i[2]||(i[2]=(...s)=>e.onInputBlur&&e.onInputBlur(...s)),onFocus:i[3]||(i[3]=(...s)=>e.handleFocus&&e.handleFocus(...s))},null,40,J),o.searchValue.length>0?(a(),x(d,{key:0,onClear:e.handleClear},null,8,["onClear"])):v("",!0),_(y,{id:e.listBoxId,hidden:e.listBoxHidden,isLoading:e.isLoading,comboboxid:n.comboboxid},{default:C(()=>[(a(!0),l(k,null,w(e.visibleOptions,(s,b)=>{var f;return a(),x(O,{key:b,option:s,id:`${e.optionId}-${b}`,focused:((f=e.selectedOption)==null?void 0:f.value)===(s==null?void 0:s.value),onMousedown:Z=>e.clickOption(s),searchValue:o.searchValue},null,8,["option","id","focused","onMousedown","searchValue"])}),128))]),_:1},8,["id","hidden","isLoading","comboboxid"]),c("div",W,m(o.resultCountMessage),1),c("span",{id:e.describedBy,style:{display:"none"}},m(e.i18nText.describedByText),9,Q)],34)}var Y=h(z,[["render",X]]);const te=L(Y,{shadowRoot:!1});export{te as default};
|