@mozaic-ds/vue 1.0.0-rc.0 → 1.0.0-rc.2

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.
Files changed (41) hide show
  1. package/README.md +10 -8
  2. package/dist/mozaic-vue.adeo.css +45 -43
  3. package/dist/mozaic-vue.adeo.umd.js +11694 -22360
  4. package/dist/mozaic-vue.common.js +11694 -22360
  5. package/dist/mozaic-vue.common.js.map +1 -1
  6. package/dist/mozaic-vue.css +1 -1
  7. package/dist/mozaic-vue.umd.js +11694 -22360
  8. package/dist/mozaic-vue.umd.js.map +1 -1
  9. package/dist/mozaic-vue.umd.min.js +2 -2
  10. package/dist/mozaic-vue.umd.min.js.map +1 -1
  11. package/package.json +23 -22
  12. package/src/components/autocomplete/MAutocomplete.vue +294 -111
  13. package/src/components/checkbox/MCheckboxGroup.vue +8 -0
  14. package/src/components/dropdown/MDropdown.vue +317 -0
  15. package/src/components/dropdown/index.js +7 -0
  16. package/src/components/flag/MFlag.vue +1 -1
  17. package/src/components/icon/MIcon.vue +18 -2
  18. package/src/components/index.js +2 -1
  19. package/src/components/link/MLink.vue +14 -3
  20. package/src/components/listbox/MListBox.vue +97 -57
  21. package/src/components/listbox/MListBoxActions.vue +251 -0
  22. package/src/components/listbox/index.js +6 -1
  23. package/src/components/passwordinput/MPasswordInput.vue +1 -0
  24. package/src/components/phonenumber/MPhoneNumber.vue +11 -3
  25. package/src/components/quantityselector/MQuantitySelector.vue +15 -2
  26. package/src/components/ratingstars/MStarsInput.vue +1 -0
  27. package/src/components/stepper/MStepper.vue +68 -27
  28. package/src/components/tabs/MTab.vue +73 -59
  29. package/src/components/textarea/MTextArea.vue +1 -0
  30. package/src/components/textinput/MTextInputField.vue +1 -1
  31. package/src/index.js +2 -1
  32. package/src/tokens/adeo/android/colors.xml +183 -126
  33. package/src/tokens/adeo/css/_variables.scss +183 -126
  34. package/src/tokens/adeo/css/root.scss +80 -23
  35. package/src/tokens/adeo/ios/StyleDictionaryColor.h +60 -3
  36. package/src/tokens/adeo/ios/StyleDictionaryColor.m +187 -130
  37. package/src/tokens/adeo/ios/StyleDictionaryColor.swift +183 -126
  38. package/src/tokens/adeo/js/tokens.js +183 -126
  39. package/src/tokens/adeo/js/tokensObject.js +1570 -283
  40. package/src/tokens/adeo/scss/_tokens.scss +342 -128
  41. package/types/index.d.ts +4 -0
@@ -0,0 +1,317 @@
1
+ <template>
2
+ <div
3
+ ref="dropdown"
4
+ v-click-outside="onClickOutside"
5
+ class="mc-dropdown"
6
+ :class="{ 'mc-dropdown--multi': multiple }"
7
+ :style="setStyles"
8
+ >
9
+ <MTag
10
+ v-if="multiple && listboxValue.length > 0"
11
+ :id="tagId ? tagId : `autoCompleteTag-${uuid}`"
12
+ ref="tag"
13
+ :label="setTagLabel"
14
+ :disabled="disabled"
15
+ type="removable"
16
+ class="mc-dropdown__tag"
17
+ size="s"
18
+ @remove-tag="clearAutocomplete()"
19
+ />
20
+ <button
21
+ type="button"
22
+ class="mc-select mc-dropdown__trigger"
23
+ :class="{ 'is-open': openState }"
24
+ :disabled="disabled"
25
+ @click="openState = !openState"
26
+ >
27
+ {{ buttonValue }}
28
+ </button>
29
+ <MListBox
30
+ v-model="listboxValue"
31
+ :open="openState"
32
+ :items="localItems"
33
+ :multiple="multiple"
34
+ :empty-search-label="emptySearchLabel"
35
+ :data-key-expr="dataKeyExpr"
36
+ :data-text-expr="dataTextExpr"
37
+ :data-value-expr="dataValueExpr"
38
+ @change="onChange"
39
+ >
40
+ <template #item="{ item }">
41
+ <slot name="item" :item="item"></slot>
42
+ </template>
43
+ </MListBox>
44
+ </div>
45
+ </template>
46
+
47
+ <script>
48
+ import MTag from '../tags/MTag.vue';
49
+ import MListBox from '../listbox/MListBox.vue';
50
+
51
+ export default {
52
+ name: 'MDropdown',
53
+
54
+ components: {
55
+ MTag,
56
+ MListBox,
57
+ },
58
+
59
+ directives: {
60
+ 'click-outside': {
61
+ bind(el, binding, vnode) {
62
+ el.clickOutsideEvent = (event) => {
63
+ if (!(el === event.target || el.contains(event.target))) {
64
+ vnode.context[binding.expression](event);
65
+ }
66
+ };
67
+ document.body.addEventListener('click', el.clickOutsideEvent);
68
+ },
69
+ unbind(el) {
70
+ document.body.removeEventListener('click', el.clickOutsideEvent);
71
+ },
72
+ },
73
+ },
74
+
75
+ model: {
76
+ event: 'change',
77
+ },
78
+
79
+ props: {
80
+ // Tag Element
81
+ tagId: {
82
+ type: String,
83
+ default: null,
84
+ },
85
+ tagLabel: {
86
+ type: String,
87
+ default: '',
88
+ },
89
+ // Input Element
90
+ placeholder: {
91
+ type: String,
92
+ default: '-- Placeholder --',
93
+ },
94
+ filter: {
95
+ type: Function,
96
+ default: null,
97
+ },
98
+ disabled: {
99
+ type: Boolean,
100
+ default: false,
101
+ },
102
+ // Listbox Element
103
+ items: {
104
+ type: Array,
105
+ required: true,
106
+ },
107
+ value: {
108
+ type: [Array, String, Number],
109
+ default: undefined,
110
+ },
111
+ open: {
112
+ type: Boolean,
113
+ default: false,
114
+ },
115
+ multiple: {
116
+ type: Boolean,
117
+ default: false,
118
+ },
119
+ emptySearchLabel: {
120
+ type: String,
121
+ default: 'No results found',
122
+ },
123
+ dataKeyExpr: {
124
+ type: String,
125
+ default: 'id',
126
+ },
127
+ dataTextExpr: {
128
+ type: String,
129
+ default: 'label',
130
+ },
131
+ dataValueExpr: {
132
+ type: String,
133
+ default: 'value',
134
+ },
135
+ sort: {
136
+ type: Boolean,
137
+ default: true,
138
+ },
139
+ // Global
140
+ maxWidth: {
141
+ type: String,
142
+ default: '17.875rem',
143
+ },
144
+ },
145
+
146
+ data() {
147
+ return {
148
+ uuid: Math.random(),
149
+ openState: this.open,
150
+ tagWidth: '0px',
151
+ tagValue: null,
152
+ buttonValue: this.placeholder,
153
+ localItems: null,
154
+ sortedListItems: null,
155
+ listboxValue: null,
156
+ };
157
+ },
158
+
159
+ computed: {
160
+ setTagLabel() {
161
+ return this.listboxValue.length.toString() + ' ' + this.tagLabel;
162
+ },
163
+ setStyles() {
164
+ return {
165
+ '--tag-width': this.tagWidth,
166
+ '--max-width': this.maxWidth,
167
+ };
168
+ },
169
+ },
170
+
171
+ watch: {
172
+ value: {
173
+ handler: function (val) {
174
+ if (!val && this.multiple) {
175
+ this.listboxValue = [];
176
+ } else {
177
+ this.listboxValue = val;
178
+ }
179
+ },
180
+ immediate: true,
181
+ },
182
+
183
+ items: {
184
+ handler: function (val) {
185
+ this.localItems = val;
186
+ // this.clearAutocomplete();
187
+ },
188
+ immediate: true,
189
+ },
190
+
191
+ listboxValue: function (val) {
192
+ const value = Array.isArray(val) ? val : val.toString();
193
+ const selectedItems = this.getSelectedItems(value);
194
+
195
+ const seletedLabels = selectedItems.map(
196
+ (item) => item[this.dataTextExpr]
197
+ );
198
+
199
+ this.buttonValue = seletedLabels.join(', ');
200
+
201
+ if (val.length === 0) {
202
+ this.buttonValue = this.placeholder;
203
+ }
204
+
205
+ if (this.multiple) {
206
+ this.tagValue = val;
207
+ }
208
+ },
209
+
210
+ tagValue: function () {
211
+ this.setTagWidth();
212
+ },
213
+
214
+ openState: function (val) {
215
+ const eventName = val ? 'open' : 'close';
216
+ this.$emit(eventName);
217
+ this.$emit('update:open', val);
218
+ },
219
+ },
220
+
221
+ methods: {
222
+ setTagWidth() {
223
+ this.$nextTick(() => {
224
+ if (this.$refs.tag && this.$refs.tag.$el) {
225
+ this.tagWidth = this.$refs.tag.$el.clientWidth + 8 + 'px';
226
+ } else {
227
+ this.tagWidth = '0px';
228
+ }
229
+ });
230
+ },
231
+
232
+ clearAutocomplete() {
233
+ this.listboxValue = this.multiple ? [] : undefined;
234
+ this.onChange();
235
+ this.$emit('clear');
236
+ },
237
+
238
+ onClickOutside() {
239
+ this.openState = false;
240
+
241
+ if (this.multiple && this.sort) {
242
+ this.sortItems();
243
+ } else {
244
+ this.localItems = this.items;
245
+ }
246
+ },
247
+
248
+ onChange() {
249
+ this.$emit('change', this.listboxValue);
250
+
251
+ if (!this.multiple) {
252
+ this.onClickOutside();
253
+ }
254
+ },
255
+
256
+ getSelectedItems(val) {
257
+ const value = val ? val : this.listboxValue;
258
+
259
+ const selectedItems = this.items.filter((item) =>
260
+ value.includes(item[this.dataValueExpr])
261
+ );
262
+
263
+ return selectedItems;
264
+ },
265
+
266
+ sortItems() {
267
+ this.sortedListItems = this.items;
268
+ const selectedItems = this.getSelectedItems();
269
+
270
+ this.sortedListItems.sort((a, b) => {
271
+ const hasItemA = selectedItems.includes(a);
272
+ const hasItemB = selectedItems.includes(b);
273
+
274
+ if (hasItemA === hasItemB) {
275
+ return a[this.dataValueExpr] - b[this.dataValueExpr];
276
+ } else if (hasItemA < hasItemB) {
277
+ return 1;
278
+ } else {
279
+ return -1;
280
+ }
281
+ });
282
+ },
283
+ },
284
+ };
285
+ </script>
286
+
287
+ <style lang="scss">
288
+ @import 'settings-tools/all-settings';
289
+ @import 'components/c.checkbox';
290
+ @import 'components/_c.dropdown';
291
+
292
+ .mc-dropdown {
293
+ max-width: var(--max-width);
294
+
295
+ &__tag {
296
+ position: absolute;
297
+ top: 0;
298
+ transform: translateY(50%);
299
+ }
300
+
301
+ &__trigger {
302
+ display: block;
303
+ text-align: left;
304
+
305
+ &.is-open {
306
+ background-image: url(inline-icons('arrow-top-16', black));
307
+ }
308
+ }
309
+ }
310
+
311
+ .mc-dropdown--multi .mc-dropdown__trigger {
312
+ overflow: hidden;
313
+ padding-left: calc(0.75rem + var(--tag-width));
314
+ text-overflow: ellipsis;
315
+ white-space: nowrap;
316
+ }
317
+ </style>
@@ -0,0 +1,7 @@
1
+ import MDropdown from './MDropdown.vue';
2
+
3
+ MDropdown.install = function (Vue) {
4
+ Vue.component(MDropdown.name, MDropdown);
5
+ };
6
+
7
+ export { MDropdown };
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <component :is="htmlTag" class="mc-flag" :class="setClasses">
3
- {{ label }}
3
+ <span class="mc-flag__label">{{ label }}</span>
4
4
  </component>
5
5
  </template>
6
6
 
@@ -25,6 +25,7 @@ export default {
25
25
  viewbox: null,
26
26
  size: null,
27
27
  paths: null,
28
+ type: null,
28
29
  };
29
30
  },
30
31
 
@@ -79,8 +80,17 @@ export default {
79
80
  this.viewbox = selectedIcon.viewBox;
80
81
  this.size = selectedIcon.size;
81
82
  this.paths = selectedIcon.paths;
83
+ this.type = selectedIcon.type;
82
84
  });
83
85
  },
86
+ setSizeFromViewbox(viewbox) {
87
+ const viewboxSizes = viewbox.split(' ').filter((size) => size > 0);
88
+
89
+ return {
90
+ width: `${viewboxSizes[0]}px`,
91
+ height: `${viewboxSizes[1]}px`,
92
+ };
93
+ },
84
94
  },
85
95
 
86
96
  render: function (createElement) {
@@ -88,8 +98,14 @@ export default {
88
98
  const svgAttrs = {
89
99
  id: `MIcon-${this.name}-${this.id}`,
90
100
  viewBox: this.viewbox,
91
- height: this.size,
92
- width: this.size,
101
+ height:
102
+ this.type !== 'logotypes'
103
+ ? this.size
104
+ : this.setSizeFromViewbox(this.viewbox).height,
105
+ width:
106
+ this.type !== 'logotypes'
107
+ ? this.size
108
+ : this.setSizeFromViewbox(this.viewbox).width,
93
109
  fill: this.color,
94
110
  'aria-hidden': 'true',
95
111
  };
@@ -12,13 +12,14 @@ export { MCard } from './card';
12
12
  export { MCheckbox, MCheckboxGroup } from './checkbox';
13
13
  export { MDataTable, MDataTableHeader } from './datatable';
14
14
  export { MField } from './field';
15
+ export { MDropdown } from './dropdown';
15
16
  export { MFileUploader } from './fileuploader';
16
17
  export { MFlag } from './flag';
17
18
  export { MHero } from './hero';
18
19
  export { MIcon } from './icon';
19
20
  export { MLayer } from './layer';
20
21
  export { MLink } from './link';
21
- export { MListBox } from './listbox';
22
+ export { MListBox, MListBoxActions } from './listbox';
22
23
  export { MLoader } from './loader';
23
24
  export { MModal } from './modal';
24
25
  export { MNotification } from './notification';
@@ -1,6 +1,7 @@
1
1
  <template>
2
2
  <component
3
- :is="router ? router : href && !disabled ? 'a' : 'span'"
3
+ :is="linkComponentName"
4
+ v-bind="linkComponentProps"
4
5
  :href="router ? null : href && !disabled ? href : null"
5
6
  class="mc-link"
6
7
  :class="setClasses"
@@ -37,7 +38,7 @@ export default {
37
38
 
38
39
  props: {
39
40
  router: {
40
- type: [String, Object],
41
+ type: Object,
41
42
  default: null,
42
43
  },
43
44
  href: {
@@ -105,10 +106,20 @@ export default {
105
106
 
106
107
  return classes;
107
108
  },
109
+ linkComponentName() {
110
+ const isLinkValid = this.href && !this.disabled;
111
+ const routerComponent = this.router?.name ?? null;
112
+ const defaultComponent = isLinkValid ? 'a' : 'span';
113
+
114
+ return routerComponent ?? defaultComponent;
115
+ },
116
+ linkComponentProps() {
117
+ return this.router?.props ?? {};
118
+ },
108
119
  },
109
120
  methods: {
110
121
  onClick(event) {
111
- if(!this.disabled){
122
+ if (!this.disabled) {
112
123
  this.$emit('click', event);
113
124
  }
114
125
  },
@@ -1,50 +1,72 @@
1
1
  <template>
2
2
  <ul
3
- v-if="items.length > 0"
4
- ref="listbox"
5
3
  role="listbox"
6
4
  class="mc-listbox"
7
5
  aria-labelledby="listbox"
8
6
  :class="{ 'is-open': open, 'mc-listbox--multi': multiple }"
7
+ :style="{ '--listbox-width': maxWidth }"
9
8
  >
10
- <li
11
- v-for="item in selectableItems"
12
- :key="item.id"
13
- class="mc-listbox__item"
14
- @change="$emit('update:itemSelected', item)"
15
- @click.self="updateList(item.id, item.text, !item.selected, true)"
16
- >
17
- <slot name="item" :item="item">
18
- <span class="mc-listbox__text">{{ item.text }} </span>
19
- </slot>
20
- <m-checkbox
21
- v-if="multiple"
22
- :id="`checkbox-dropdown-${item.id}`"
23
- v-model="selectableItems.find((elem) => elem.id === item.id).selected"
24
- class="mc-listbox__input"
25
- @change="updateList(item.id, item.text, !item.selected, $e)"
26
- />
9
+ <template v-if="!isFiltered">
10
+ <li
11
+ v-for="(item, index) in localItems"
12
+ :key="item.id"
13
+ class="mc-listbox__item"
14
+ >
15
+ <MIcon
16
+ v-if="item.icon"
17
+ :name="item.icon"
18
+ class="mc-listbox__icon"
19
+ color="#666666"
20
+ />
21
+ <input
22
+ :id="setItemId(index)"
23
+ v-model="localValue"
24
+ class="mc-listbox__input"
25
+ :class="{ 'mc-checkbox__input': multiple }"
26
+ :type="multiple ? 'checkbox' : 'radio'"
27
+ :value="item[dataValueExpr]"
28
+ :name="!multiple ? `listboxradio-${uuid}` : null"
29
+ @change="onChange"
30
+ />
31
+ <label :for="setItemId(index)" class="mc-listbox__label">
32
+ <slot name="item" :item="item">
33
+ {{ item[dataTextExpr] }}
34
+ </slot>
35
+ </label>
36
+ </li>
37
+ </template>
38
+ <li v-else class="mc-listbox__item">
39
+ <span class="mc-listbox__empty">{{ emptySearchLabel }}</span>
27
40
  </li>
28
41
  </ul>
29
- <div v-else class="mc-list-box__empty">
30
- {{ emptySearchLabel }}
31
- </div>
32
42
  </template>
43
+
33
44
  <script>
34
- import MCheckbox from '../checkbox/MCheckbox.vue';
45
+ import MIcon from '../icon/MIcon.vue';
46
+
35
47
  export default {
36
- name: 'MListbox',
48
+ name: 'MListBox',
37
49
 
38
- components: { MCheckbox },
50
+ components: {
51
+ MIcon,
52
+ },
53
+
54
+ model: {
55
+ event: 'change',
56
+ },
39
57
 
40
58
  props: {
59
+ items: {
60
+ type: Array,
61
+ required: true,
62
+ },
41
63
  open: {
42
64
  type: Boolean,
43
65
  default: false,
44
66
  },
45
- items: {
46
- type: Array,
47
- default: () => [],
67
+ isFiltered: {
68
+ type: Boolean,
69
+ default: false,
48
70
  },
49
71
  multiple: {
50
72
  type: Boolean,
@@ -54,53 +76,71 @@ export default {
54
76
  type: String,
55
77
  default: 'No item matching your criteria found',
56
78
  },
57
- icon: {
58
- type: Boolean,
59
- default: false,
79
+ dataKeyExpr: {
80
+ type: String,
81
+ default: 'id',
82
+ },
83
+ dataTextExpr: {
84
+ type: String,
85
+ default: 'label',
86
+ },
87
+ dataValueExpr: {
88
+ type: String,
89
+ default: 'value',
90
+ },
91
+ value: {
92
+ type: [Array, String, Number],
93
+ default: undefined,
94
+ },
95
+ maxWidth: {
96
+ type: String,
97
+ default: '17.875rem',
60
98
  },
61
99
  },
100
+
62
101
  data() {
63
102
  return {
64
- selectableItems: null,
65
- selected: [],
103
+ uuid: Math.random(),
104
+ localItems: undefined,
105
+ localValue: undefined,
66
106
  };
67
107
  },
108
+
109
+ computed: {
110
+ setItemId() {
111
+ return (index) => `listboxItem-${index + this.uuid}`;
112
+ },
113
+ },
114
+
68
115
  watch: {
69
116
  items: {
70
117
  handler: function (val) {
71
- this.selectableItems = val;
118
+ this.localItems = val;
119
+ },
120
+ immediate: true,
121
+ },
122
+ value: {
123
+ handler: function (val) {
124
+ this.localValue = val;
72
125
  },
73
126
  immediate: true,
74
127
  },
75
128
  },
76
- methods: {
77
- updateList(id, text, value, isCheckboxUpdate) {
78
- if (!this.multiple) {
79
- this.$emit('update:itemSelected', [{ id, selected: value, text }]);
80
129
 
81
- this.$emit('close-list-box');
82
- return;
83
- }
84
-
85
- if (
86
- isCheckboxUpdate &&
87
- this.selectableItems.find((item) => item.id === id)
88
- ) {
89
- this.selectableItems.find((item) => item.id === id).selected = value;
90
- }
91
-
92
- if (value) {
93
- this.selected = [...this.selected, { id, selected: value, text }];
94
- } else {
95
- this.selected = this.selected.filter((item) => item.id !== id);
96
- }
97
- this.$emit('update:itemSelected', this.selectableItems);
130
+ methods: {
131
+ onChange() {
132
+ this.$emit('change', this.localValue);
98
133
  },
99
134
  },
100
135
  };
101
136
  </script>
102
137
 
103
138
  <style lang="scss">
104
- @import 'settings-tools/_all-settings';
105
- @import 'components/_c.listbox';
139
+ @import 'settings-tools/all-settings';
140
+ @import 'components/c.checkbox';
141
+ @import 'components/c.listbox';
142
+
143
+ .mc-listbox__empty {
144
+ margin-top: 0;
145
+ }
106
146
  </style>