@mozaic-ds/vue 1.0.0-beta.3 → 1.0.0-rc.1

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 (39) 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 +11552 -22322
  4. package/dist/mozaic-vue.common.js +11552 -22322
  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 +11552 -22322
  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 +24 -23
  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 +316 -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/phonenumber/MPhoneNumber.vue +10 -3
  24. package/src/components/quantityselector/MQuantitySelector.vue +15 -2
  25. package/src/components/ratingstars/MStarsInput.vue +1 -0
  26. package/src/components/stepper/MStepper.vue +68 -27
  27. package/src/components/tabs/MTab.vue +69 -59
  28. package/src/components/textinput/MTextInputField.vue +0 -1
  29. package/src/index.js +2 -1
  30. package/src/tokens/adeo/android/colors.xml +183 -126
  31. package/src/tokens/adeo/css/_variables.scss +183 -126
  32. package/src/tokens/adeo/css/root.scss +80 -23
  33. package/src/tokens/adeo/ios/StyleDictionaryColor.h +60 -3
  34. package/src/tokens/adeo/ios/StyleDictionaryColor.m +187 -130
  35. package/src/tokens/adeo/ios/StyleDictionaryColor.swift +183 -126
  36. package/src/tokens/adeo/js/tokens.js +183 -126
  37. package/src/tokens/adeo/js/tokensObject.js +1570 -283
  38. package/src/tokens/adeo/scss/_tokens.scss +342 -128
  39. package/types/index.d.ts +4 -0
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@mozaic-ds/vue",
3
- "version": "1.0.0-beta.3",
3
+ "version": "1.0.0-rc.1",
4
4
  "description": "Vue.js implementation of Mozaic Design System",
5
5
  "author": "Adeo - Mozaic Design System",
6
6
  "scripts": {
7
7
  "serve": "vue-cli-service serve",
8
8
  "build": "vue-cli-service build ./src/index.js",
9
9
  "lint": "vue-cli-service lint",
10
- "build:bundle": "vue-cli-service build --target lib --name mozaic-vue ./src/index.js",
11
- "build:bundleAdeo": "vue-cli-service build --target lib --formats umd --mode adeo --filename mozaic-vue.adeo ./src/index.js --no-clean",
10
+ "build:bundle": "MOZAIC_PRESET=lm vue-cli-service build --target lib --name mozaic-vue ./src/index.js",
11
+ "build:bundleAdeo": "MOZAIC_PRESET=adeo vue-cli-service build --target lib --formats umd --mode adeo --filename mozaic-vue.adeo ./src/index.js --no-clean",
12
12
  "postinstall": "node postinstall.js",
13
13
  "prepublishOnly": "npm run-script build:bundle && npm run-script build:bundleAdeo",
14
14
  "publish:beta": "npm publish --access public --tag alpha",
@@ -23,33 +23,34 @@
23
23
  "postinstall.js"
24
24
  ],
25
25
  "dependencies": {
26
- "@mozaic-ds/css-dev-tools": "2.0.0-rc.1",
27
- "@mozaic-ds/icons": "1.34.0",
28
- "@mozaic-ds/styles": "2.0.0-rc.4",
29
- "@mozaic-ds/web-fonts": "1.22.0",
30
- "core-js": "^3.18.3",
31
- "libphonenumber-js": "1.9.50",
32
- "postcss-scss": "^4.0.1",
26
+ "@mozaic-ds/css-dev-tools": "^1.44.0",
27
+ "@mozaic-ds/icons": "^1.44.0",
28
+ "@mozaic-ds/styles": "^1.44.0",
29
+ "@mozaic-ds/web-fonts": "^1.22.0",
30
+ "core-js": "^3.25.5",
31
+ "libphonenumber-js": "^1.10.14",
33
32
  "vue": "^2.6.14",
34
33
  "vue-country-flag": "2.3.2"
35
34
  },
36
35
  "devDependencies": {
37
- "@babel/core": "^7.15.8",
38
- "@babel/eslint-parser": "^7.15.8",
36
+ "@babel/core": "^7.19.3",
37
+ "@babel/eslint-parser": "^7.19.1",
38
+ "@rushstack/eslint-patch": "^1.2.0",
39
39
  "@vue/cli-plugin-babel": "~5.0.4",
40
40
  "@vue/cli-service": "~5.0.4",
41
- "@vue/compiler-sfc": "^3.2.20",
42
- "@vue/eslint-config-prettier": "^6.0.0",
41
+ "@vue/compiler-sfc": "^3.2.41",
42
+ "@vue/eslint-config-prettier": "^7.0.0",
43
43
  "babel-eslint": "^10.1.0",
44
- "eslint": "^7.30.0",
45
- "eslint-config-prettier": "^8.3.0",
46
- "eslint-plugin-vue": "^7.19.1",
47
- "postcss": "^8.3.9",
48
- "postcss-loader": "^4.3.0",
49
- "prettier": "^2.4.1",
50
- "sass": "^1.42.1",
51
- "sass-loader": "^10.2.0",
52
- "vue-template-compiler": "^2.6.14"
44
+ "eslint": "^8.25.0",
45
+ "eslint-config-prettier": "^8.5.0",
46
+ "eslint-plugin-vue": "^9.6.0",
47
+ "postcss": "^8.4.18",
48
+ "postcss-loader": "^7.0.1",
49
+ "postcss-scss": "^4.0.5",
50
+ "prettier": "^2.7.1",
51
+ "sass": "^1.55.0",
52
+ "sass-loader": "^13.1.0",
53
+ "vue-template-compiler": "^2.7.13"
53
54
  },
54
55
  "bugs": {
55
56
  "url": "https://github.com/adeo/mozaic-vue/issues"
@@ -1,198 +1,381 @@
1
1
  <template>
2
2
  <div
3
- ref="autocomplete"
3
+ v-click-outside="onClickOutside"
4
4
  class="mc-autocomplete"
5
5
  :class="{ 'mc-autocomplete--multi': multiple }"
6
- :style="tagStyle"
7
- @keyup.esc="isOpen = true"
6
+ :style="setStyles"
8
7
  >
9
- <m-tag
10
- v-if="multiple && selectedItems().length > 0"
11
- id="tag"
8
+ <MTag
9
+ v-if="multiple && listboxValue.length > 0"
10
+ :id="tagId ? tagId : `autocompleteTag-${uuid}`"
11
+ ref="tag"
12
+ :label="setTagLabel"
13
+ :disabled="disabled"
12
14
  type="removable"
13
- :label="selectedItems().length.toString() + ' ' + labelTag"
14
15
  class="mc-autocomplete__tag"
15
16
  size="s"
16
- @remove-tag="removeElementsFromList()"
17
+ @remove-tag="clearAutocomplete()"
17
18
  />
18
- <m-text-input
19
- v-model="itemDisplayed"
19
+ <MLoader v-if="loading" class="mc-autocomplete__loader" size="s" />
20
+ <MTextInput
21
+ :id="id"
22
+ v-model="inputValue"
20
23
  :placeholder="placeholder"
24
+ :is-invalid="invalid"
25
+ :disabled="disabled"
21
26
  text-input-field-class="mc-autocomplete__trigger"
22
27
  icon-position="left"
23
28
  icon="DisplaySearch48"
24
29
  autocomplete="off"
25
- :style="{ width: boxWidth + 'px' }"
26
- @input="filerList"
27
- @click="isOpen = true"
30
+ type="search"
31
+ @input="onInput"
32
+ @click="openState = true"
28
33
  />
29
- <m-list-box
30
- :open="isOpen"
31
- :items="sort ? orderedItems() : itemListForDropdown"
34
+ <MListBox
35
+ v-model="listboxValue"
36
+ :open="openState"
37
+ :items="localItems"
32
38
  :multiple="multiple"
33
39
  :empty-search-label="emptySearchLabel"
34
- :style="{ width: boxWidth + 'px' }"
35
- @update:itemSelected="updateList"
36
- @close-list-box="isOpen = false"
40
+ :data-key-expr="dataKeyExpr"
41
+ :data-text-expr="dataTextExpr"
42
+ :data-value-expr="dataValueExpr"
43
+ :is-filtered="isFiltered"
44
+ :max-width="maxWidth"
45
+ @change="onChange"
37
46
  >
38
47
  <template #item="{ item }">
39
- <slot name="item" :item="item"> </slot>
48
+ <slot name="item" :item="item"></slot>
40
49
  </template>
41
- </m-list-box>
50
+ </MListBox>
42
51
  </div>
43
52
  </template>
44
53
 
45
54
  <script>
46
- import MTextInput from '../textinput/MTextInput.vue';
47
55
  import MTag from '../tags/MTag.vue';
56
+ import MLoader from '../loader/MLoader.vue';
57
+ import MTextInput from '../textinput/MTextInput.vue';
48
58
  import MListBox from '../listbox/MListBox.vue';
49
59
 
50
60
  export default {
51
61
  name: 'MAutocomplete',
52
62
 
53
- components: { MListBox, MTag, MTextInput },
63
+ components: {
64
+ MTag,
65
+ MLoader,
66
+ MTextInput,
67
+ MListBox,
68
+ },
69
+
70
+ directives: {
71
+ 'click-outside': {
72
+ bind(el, binding, vnode) {
73
+ el.clickOutsideEvent = (event) => {
74
+ if (!(el === event.target || el.contains(event.target))) {
75
+ vnode.context[binding.expression](event);
76
+ }
77
+ };
78
+ document.body.addEventListener('click', el.clickOutsideEvent);
79
+ },
80
+ unbind(el) {
81
+ document.body.removeEventListener('click', el.clickOutsideEvent);
82
+ },
83
+ },
84
+ },
85
+
86
+ model: {
87
+ event: 'change',
88
+ },
54
89
 
55
90
  props: {
56
- multiple: {
57
- type: Boolean,
58
- default: false,
91
+ // Tag Element
92
+ tagId: {
93
+ type: String,
94
+ default: null,
59
95
  },
60
- placeholder: {
96
+ tagLabel: {
61
97
  type: String,
62
98
  default: '',
63
99
  },
64
- items: {
65
- type: Array,
66
- required: true,
67
- default: () => [],
100
+ // Input Element
101
+ id: {
102
+ type: String,
103
+ default: null,
104
+ },
105
+ input: {
106
+ type: String,
107
+ default: null,
108
+ },
109
+ placeholder: {
110
+ type: String,
111
+ default: null,
68
112
  },
69
113
  filter: {
70
114
  type: Function,
71
115
  default: null,
72
116
  },
73
- emptySearchLabel: {
74
- type: String,
75
- default: 'No item matching your criteria found',
117
+ filterOnType: {
118
+ type: Boolean,
119
+ default: true,
76
120
  },
77
- sort: {
121
+ disabled: {
78
122
  type: Boolean,
79
123
  default: false,
80
124
  },
81
- labelTag: {
82
- type: String,
83
- default: '',
125
+ invalid: {
126
+ type: Boolean,
127
+ default: false,
128
+ },
129
+ loading: {
130
+ type: Boolean,
131
+ default: false,
132
+ },
133
+ // Listbox Element
134
+ items: {
135
+ type: Array,
136
+ required: true,
137
+ },
138
+ value: {
139
+ type: [Array, String, Number],
140
+ default: undefined,
84
141
  },
85
142
  open: {
86
143
  type: Boolean,
87
144
  default: false,
88
145
  },
146
+ multiple: {
147
+ type: Boolean,
148
+ default: false,
149
+ },
150
+ emptySearchLabel: {
151
+ type: String,
152
+ default: 'No results found',
153
+ },
154
+ dataKeyExpr: {
155
+ type: String,
156
+ default: 'id',
157
+ },
158
+ dataTextExpr: {
159
+ type: String,
160
+ default: 'label',
161
+ },
162
+ dataValueExpr: {
163
+ type: String,
164
+ default: 'value',
165
+ },
166
+ sort: {
167
+ type: Boolean,
168
+ default: true,
169
+ },
170
+ // Global
171
+ maxWidth: {
172
+ type: String,
173
+ default: '100%', // 17.875rem
174
+ },
89
175
  },
176
+
90
177
  data() {
91
178
  return {
92
- itemListForDropdown: this.$props.items,
93
- selected: this.$props.items,
94
- itemDisplayed: '',
95
- isOpen: this.$props.open,
179
+ uuid: Math.random(),
180
+ openState: this.open,
96
181
  tagWidth: '0px',
97
- boxWidth: '288px',
182
+ tagValue: null,
183
+ inputValue: null,
184
+ localItems: null,
185
+ sortedListItems: null,
186
+ listboxValue: null,
187
+ isFiltered: null,
98
188
  };
99
189
  },
190
+
100
191
  computed: {
101
- tagStyle() {
102
- return {
103
- '--tag-width': this.tagWidth,
104
- };
192
+ setTagLabel() {
193
+ return this.listboxValue.length.toString() + ' ' + this.tagLabel;
105
194
  },
106
- boxStyle() {
195
+ setStyles() {
107
196
  return {
108
- '--box-width': this.boxWidth,
197
+ '--tag-width': this.tagWidth,
198
+ '--max-width': this.maxWidth,
109
199
  };
110
200
  },
111
201
  },
112
- mounted() {
113
- this.selectedItems();
114
- this.tagWidthCalcul();
115
- this.boxWidthCalcul();
202
+
203
+ watch: {
204
+ value: {
205
+ handler: function (val) {
206
+ if (!val && this.multiple) {
207
+ this.listboxValue = [];
208
+ } else {
209
+ this.listboxValue = val;
210
+ }
211
+ },
212
+ immediate: true,
213
+ },
214
+
215
+ items: {
216
+ handler: function (val) {
217
+ this.localItems = val;
218
+ // this.clearAutocomplete();
219
+ },
220
+ immediate: true,
221
+ },
222
+
223
+ listboxValue: function (val) {
224
+ const selectedItems = this.getSelectedItems(val);
225
+
226
+ const seletedLabels = selectedItems.map(
227
+ (item) => item[this.dataTextExpr]
228
+ );
229
+
230
+ this.inputValue = seletedLabels.join(', ');
231
+
232
+ if (this.multiple) {
233
+ this.tagValue = val;
234
+ }
235
+ },
236
+
237
+ tagValue: function () {
238
+ this.setTagWidth();
239
+ },
240
+
241
+ openState: function (val) {
242
+ const eventName = val ? 'open' : 'close';
243
+ this.$emit(eventName);
244
+ this.$emit('update:open', val);
245
+ },
246
+
247
+ input: {
248
+ handler: function (val) {
249
+ this.inputValue = val;
250
+ },
251
+ immediate: true,
252
+ },
116
253
  },
254
+
117
255
  methods: {
118
- tagWidthCalcul() {
256
+ setTagWidth() {
119
257
  this.$nextTick(() => {
120
- this.tagWidth =
121
- document && document.querySelector('.mc-autocomplete__tag')
122
- ? document.querySelector('.mc-autocomplete__tag').clientWidth + 'px'
123
- : '0px';
124
- });
125
- },
126
- selectedItems() {
127
- return this.selected.filter((item) => {
128
- return item.selected;
129
- });
130
- },
131
- orderedItems() {
132
- this.itemListForDropdown.sort((a, b) => {
133
- if (a.selected === b.selected) {
134
- return a.id - b.id;
135
- } else if (a.selected < b.selected) {
136
- return 1;
258
+ if (this.$refs.tag && this.$refs.tag.$el) {
259
+ this.tagWidth = this.$refs.tag.$el.clientWidth + 'px';
137
260
  } else {
138
- return -1;
261
+ this.tagWidth = '0px';
139
262
  }
140
263
  });
141
264
  },
142
- updateList(list) {
143
- if (!this.$props.multiple && list) {
144
- this.itemDisplayed = list[0].text;
265
+
266
+ clearAutocomplete() {
267
+ this.listboxValue = this.multiple ? [] : undefined;
268
+ this.onChange();
269
+ this.$emit('clear');
270
+ },
271
+
272
+ filterList(value) {
273
+ if (value.length && this.filter) {
274
+ this.filter(value);
275
+ } else if (value.length && this.filterOnType) {
276
+ this.localItems = this.items.filter((item) =>
277
+ item[this.dataTextExpr].toUpperCase().includes(value.toUpperCase())
278
+ );
279
+
280
+ this.isFiltered = !this.localItems.length;
145
281
  } else {
146
- this.isOpen = true;
147
- this.selectedItems();
282
+ this.localItems = this.items;
283
+ this.isFiltered = !this.localItems.length;
148
284
  }
149
- this.itemListForDropdown.forEach((elem) => {
150
- if (elem.id === list.id) {
151
- elem.selected = false;
152
- }
153
- });
154
- this.tagWidthCalcul();
155
- this.$emit(
156
- 'update:modelValue',
157
- this.$props.multiple ? this.selectedItems().value : list
158
- );
285
+ this.$emit('list-filtered', this.localItems);
159
286
  },
160
- removeElementsFromList() {
161
- this.itemListForDropdown.forEach((elem) => {
162
- elem.selected = false;
163
- });
164
- this.selectedItems();
165
- this.tagWidthCalcul();
166
- this.$emit('list-removed');
167
- },
168
- filerList(value) {
169
- if (value.length && this.$props.filter) {
170
- this.$props.filter(value);
171
- } else if (value.length) {
172
- this.itemListForDropdown = this.itemListForDropdown.filter((item) =>
173
- item.text.toUpperCase().includes(value.toUpperCase())
174
- );
287
+
288
+ onClickOutside() {
289
+ this.openState = false;
290
+
291
+ if (this.multiple && this.sort) {
292
+ this.sortItems();
175
293
  } else {
176
- this.itemListForDropdown = this.$props.items;
294
+ this.localItems = this.items;
177
295
  }
178
- this.$emit('list-filtered', this.itemListForDropdown);
179
296
  },
180
- boxWidthCalcul() {
181
- this.$nextTick(() => {
182
- this.boxWidth = document.querySelector('.mc-autocomplete').clientWidth;
183
- console.log(this.boxWidth);
297
+
298
+ onChange() {
299
+ this.$emit('change', this.listboxValue);
300
+
301
+ if (!this.multiple) {
302
+ this.onClickOutside();
303
+ }
304
+ },
305
+
306
+ getSelectedItems(val) {
307
+ const value = val ? val : this.listboxValue;
308
+
309
+ const selectedItems = this.items.filter((item) => {
310
+ return this.multiple
311
+ ? value.includes(item[this.dataValueExpr])
312
+ : value === item[this.dataValueExpr];
184
313
  });
185
- return;
314
+
315
+ return selectedItems;
316
+ },
317
+
318
+ sortItems() {
319
+ this.sortedListItems = this.items;
320
+ const selectedItems = this.getSelectedItems();
321
+
322
+ this.sortedListItems.sort((a, b) => {
323
+ const hasItemA = selectedItems.includes(a);
324
+ const hasItemB = selectedItems.includes(b);
325
+
326
+ if (hasItemA === hasItemB) {
327
+ return a[this.dataValueExpr] - b[this.dataValueExpr];
328
+ } else if (hasItemA < hasItemB) {
329
+ return 1;
330
+ } else {
331
+ return -1;
332
+ }
333
+ });
334
+
335
+ this.localItems = this.sortedListItems;
336
+ },
337
+
338
+ handleInputValue(value) {
339
+ this.$emit('update:input', value);
340
+ },
341
+
342
+ onInput(value) {
343
+ this.handleInputValue(value);
344
+ this.filterList(value);
186
345
  },
187
346
  },
188
347
  };
189
348
  </script>
190
349
 
191
350
  <style lang="scss">
192
- @import 'settings-tools/_all-settings';
193
- @import 'components/_c.autocomplete';
351
+ @import 'settings-tools/all-settings';
352
+ @import 'components/c.autocomplete';
353
+
354
+ .mc-autocomplete {
355
+ max-width: var(--max-width);
356
+
357
+ &__tag {
358
+ position: absolute;
359
+ top: 0;
360
+ transform: translateY(50%);
361
+ }
362
+
363
+ &__loader {
364
+ position: absolute;
365
+ right: $mu075;
366
+ top: $mu075;
367
+ z-index: 10;
368
+ }
369
+
370
+ &__trigger {
371
+ width: 100%;
372
+ }
373
+ }
194
374
 
195
375
  .mc-autocomplete--multi .mc-autocomplete__trigger {
376
+ overflow: hidden;
196
377
  padding-left: calc(2.9375rem + var(--tag-width));
378
+ text-overflow: ellipsis;
379
+ white-space: nowrap;
197
380
  }
198
381
  </style>
@@ -22,6 +22,7 @@
22
22
  v-bind="option"
23
23
  :key="option.id ? option.id : option.value"
24
24
  class="mc-field__item"
25
+ :disabled="disabled"
25
26
  :checked="value ? value.includes(option.value) : undefined"
26
27
  @change="(v) => onChange(v, option.value)"
27
28
  >
@@ -124,6 +125,13 @@ export default {
124
125
  type: Boolean,
125
126
  default: false,
126
127
  },
128
+ /**
129
+ * Disabled
130
+ */
131
+ disabled: {
132
+ type: Boolean,
133
+ default: false,
134
+ },
127
135
  },
128
136
 
129
137
  data() {