@mozaic-ds/vue 0.36.1 → 0.37.1-beta.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mozaic-ds/vue",
3
- "version": "0.36.1",
3
+ "version": "0.37.1-beta.0",
4
4
  "description": "Vue.js implementation of Mozaic Design System",
5
5
  "author": "Adeo - Mozaic Design System",
6
6
  "scripts": {
@@ -26,10 +26,10 @@
26
26
  "@linusborg/vue-simple-portal": "^0.1.5",
27
27
  "@mozaic-ds/css-dev-tools": "1.50.0",
28
28
  "@mozaic-ds/icons": "1.52.0",
29
- "@mozaic-ds/styles": "1.52.0",
29
+ "@mozaic-ds/styles": "1.53.0",
30
30
  "@mozaic-ds/web-fonts": "1.22.0",
31
31
  "core-js": "^3.27.2",
32
- "libphonenumber-js": "^1.10.18",
32
+ "libphonenumber-js": "^1.10.19",
33
33
  "vue": "^2.6.14",
34
34
  "vue-country-flag": "2.3.2"
35
35
  },
@@ -42,14 +42,14 @@
42
42
  "@vue/compiler-sfc": "^3.2.45",
43
43
  "@vue/eslint-config-prettier": "^7.0.0",
44
44
  "babel-eslint": "^10.1.0",
45
- "eslint": "^8.32.0",
45
+ "eslint": "^8.33.0",
46
46
  "eslint-config-prettier": "^8.6.0",
47
47
  "eslint-plugin-vue": "^9.9.0",
48
48
  "postcss": "^8.4.21",
49
49
  "postcss-loader": "^7.0.2",
50
50
  "postcss-scss": "^4.0.6",
51
51
  "prettier": "^2.8.3",
52
- "sass": "^1.57.1",
52
+ "sass": "^1.58.0",
53
53
  "sass-loader": "^13.2.0",
54
54
  "vue-template-compiler": "^2.7.14"
55
55
  },
@@ -2,7 +2,7 @@
2
2
  <div
3
3
  v-click-outside="closeListBox"
4
4
  class="mc-autocomplete"
5
- :class="classObject"
5
+ :class="[classObject, cssFieldElementClass]"
6
6
  :style="setStyles"
7
7
  >
8
8
  <div class="mc-autocomplete__main">
@@ -100,6 +100,12 @@ export default {
100
100
  },
101
101
  },
102
102
 
103
+ inject: {
104
+ cssFieldElementClass: {
105
+ default: '',
106
+ },
107
+ },
108
+
103
109
  model: {
104
110
  event: 'change',
105
111
  },
@@ -3,7 +3,7 @@
3
3
  ref="dropdown"
4
4
  v-click-outside="closeListBox"
5
5
  class="mc-dropdown"
6
- :class="classObject"
6
+ :class="[classObject, cssFieldElementClass]"
7
7
  :style="setStyles"
8
8
  >
9
9
  <div class="mc-dropdown__main">
@@ -86,6 +86,12 @@ export default {
86
86
  },
87
87
  },
88
88
 
89
+ inject: {
90
+ cssFieldElementClass: {
91
+ default: '',
92
+ },
93
+ },
94
+
89
95
  model: {
90
96
  event: 'change',
91
97
  },
@@ -228,22 +234,28 @@ export default {
228
234
  },
229
235
  immediate: true,
230
236
  },
231
- listboxValue: function (val) {
232
- const selectedItems = this.getSelectedItems(val);
233
- const seletedLabels = selectedItems.map(
234
- (item) => item[this.dataTextExpr]
235
- );
237
+ listboxValue: {
238
+ handler: function (val) {
239
+ const selectedItems = this.getSelectedItems(val);
240
+ const seletedLabels = selectedItems.map(
241
+ (item) => item[this.dataTextExpr]
242
+ );
236
243
 
237
- this.buttonValue =
238
- ((!val || val.length === 0) && this.placeholder) ||
239
- seletedLabels.join(', ');
244
+ this.buttonValue =
245
+ ((!val || val.length === 0) && this.placeholder) ||
246
+ seletedLabels.join(', ');
240
247
 
241
- if (this.multiple) {
242
- this.tagValue = val;
243
- }
248
+ if (this.multiple) {
249
+ this.tagValue = val;
250
+ }
251
+ },
252
+ immediate: true,
244
253
  },
245
- tagValue: function () {
246
- this.setTagWidth();
254
+ tagValue: {
255
+ handler() {
256
+ this.setTagWidth();
257
+ },
258
+ immediate: true,
247
259
  },
248
260
  openState: function (val) {
249
261
  const eventName = val ? 'open' : 'close';
@@ -0,0 +1,374 @@
1
+ <template>
2
+ <div
3
+ ref="header"
4
+ class="mc-header"
5
+ :class="{
6
+ 'mc-header--shadow': showShadow,
7
+ 'mc-header--animate': animate,
8
+ 'mc-header--sticky': sticky,
9
+ 'mc-header--up': direction === 'up',
10
+ 'mc-header--down': direction === 'down',
11
+ }"
12
+ >
13
+ <div class="mc-header__container">
14
+ <MBreadcrumb
15
+ v-if="hasBreadcrumb"
16
+ class="mc-header__breadcrumb mc-breadcrumb--no-padding"
17
+ :responsive="true"
18
+ :items="items"
19
+ />
20
+ <div class="mc-header__content">
21
+ <div class="mc-header__content-main">
22
+ <component
23
+ :is="backHref ? 'a' : 'button'"
24
+ v-if="hasBack"
25
+ class="mc-header__back"
26
+ :href="backHref ?? null"
27
+ :type="!backHref ? 'button' : null"
28
+ @click="!backHref && $emit('click-back')"
29
+ >
30
+ <MIcon name="ArrowBack24" class="mc-header__back-icon" />
31
+ <span class="mc-header__back-label">
32
+ {{ backButtonLabel }}
33
+ </span>
34
+ </component>
35
+
36
+ <h1 class="mc-header__title" :class="`mc-header__title--${size}`">
37
+ {{ title }}
38
+ </h1>
39
+ </div>
40
+ <div
41
+ v-if="subTitle || status"
42
+ class="mc-header__content-aside"
43
+ :class="{ 'can-navigate': hasBack }"
44
+ >
45
+ <span v-if="subTitle" class="mc-header__subtitle">
46
+ {{ subTitle }}
47
+ </span>
48
+ <MBadge v-if="status" :type="status.type">{{ status.text }}</MBadge>
49
+ </div>
50
+ </div>
51
+
52
+ <div v-if="$slots.icons || $slots.selector" class="mc-header__actions">
53
+ <div v-if="$slots.icons" class="mc-header__icons">
54
+ <slot name="icons" />
55
+ </div>
56
+ <div v-if="$slots.selector" class="mc-header__selector">
57
+ <slot name="selector" />
58
+ </div>
59
+ </div>
60
+ </div>
61
+
62
+ <div
63
+ v-if="showTabs && hasTabs"
64
+ class="mc-header__tabs mc-divider-top mc-divider-top--light"
65
+ >
66
+ <MTab
67
+ :tabs="tabs"
68
+ :shadow="false"
69
+ :active-index="selectedTabIndex"
70
+ @tab-clicked="onTabClicked"
71
+ />
72
+ </div>
73
+ </div>
74
+ </template>
75
+
76
+ <script>
77
+ import MBreadcrumb from '../breadcrumb/MBreadcrumb.vue';
78
+ import MIcon from '../icon/MIcon.vue';
79
+ import MBadge from '../badge/MBadge.vue';
80
+ import MTab from '../tabs/MTab.vue';
81
+
82
+ export default {
83
+ name: 'MHeader',
84
+ components: {
85
+ MBreadcrumb,
86
+ MIcon,
87
+ MBadge,
88
+ MTab,
89
+ },
90
+ props: {
91
+ /** Title of header. */
92
+ title: {
93
+ type: String,
94
+ required: true,
95
+ },
96
+ /** Sub title of header. */
97
+ subTitle: {
98
+ type: String,
99
+ default: undefined,
100
+ },
101
+ /** The badge information. */
102
+ status: {
103
+ type: Object,
104
+ default: undefined,
105
+ },
106
+ /** Items used by breadcrumb. */
107
+ items: {
108
+ type: Array,
109
+ default: () => [],
110
+ },
111
+ /** Items used by tabs. */
112
+ tabs: {
113
+ type: Array,
114
+ default: () => [],
115
+ },
116
+ /** Set selected tab by index. */
117
+ selectedTabIndex: {
118
+ type: Number,
119
+ default: -1,
120
+ },
121
+ /** Display shadow to bottom of the header. */
122
+ showShadow: {
123
+ type: Boolean,
124
+ default: false,
125
+ },
126
+ /** Show breadcrumb or not. */
127
+ showBreadcrumb: {
128
+ type: Boolean,
129
+ default: false,
130
+ },
131
+ /** Show tabs or not. */
132
+ showTabs: {
133
+ type: Boolean,
134
+ default: false,
135
+ },
136
+ /** Show back button or not. */
137
+ showBack: {
138
+ type: Boolean,
139
+ default: false,
140
+ },
141
+ /** Animate when user scroll. */
142
+ animate: {
143
+ type: Boolean,
144
+ default: false,
145
+ },
146
+ /** Set sticky position. */
147
+ sticky: {
148
+ type: Boolean,
149
+ default: false,
150
+ },
151
+ /** The size of title (l, s, m, or xl).*/
152
+ size: {
153
+ type: String,
154
+ default: 'l',
155
+ validator: (value) => ['s', 'm', 'l', 'xl'].includes(value),
156
+ },
157
+ /** Label of the back button. Useful for accessibilty reason */
158
+ backButtonLabel: {
159
+ type: String,
160
+ default: 'Back',
161
+ },
162
+ /** Href url of the back button */
163
+ backHref: {
164
+ type: String,
165
+ default: undefined,
166
+ },
167
+ },
168
+ data: () => ({
169
+ originalScrollPos: 0,
170
+ localDirection: undefined,
171
+ }),
172
+ computed: {
173
+ hasTabs() {
174
+ return this.tabs.length > 0;
175
+ },
176
+ hasBreadcrumb() {
177
+ return this.showBreadcrumb && this.items.length > 1;
178
+ },
179
+ hasBack() {
180
+ return this.showBack && !this.hasBreadcrumb;
181
+ },
182
+ direction() {
183
+ return this.localDirection;
184
+ },
185
+ },
186
+ watch: {
187
+ animate: {
188
+ handler(val) {
189
+ if (val) {
190
+ window.addEventListener('scroll', this.onScroll, { capture: true });
191
+ } else {
192
+ window.removeEventListener('scroll', this.onScroll, {
193
+ capture: true,
194
+ });
195
+ }
196
+ },
197
+ immediate: true,
198
+ },
199
+ },
200
+ beforeDestroy() {
201
+ if (this.animate) {
202
+ window.removeEventListener('scroll', this.onScroll, { capture: true });
203
+ }
204
+ },
205
+ methods: {
206
+ onTabClicked(_, e) {
207
+ const tabItemIndex = this.tabs.findIndex((tab) => tab.id === e.id);
208
+
209
+ if (tabItemIndex > -1 && this.selectedTabIndex !== tabItemIndex) {
210
+ this.$emit('update:selectedTabIndex', tabItemIndex);
211
+ }
212
+ },
213
+ onScroll(e) {
214
+ const element = this.$refs.header;
215
+
216
+ if (element) {
217
+ const container = element.parentElement;
218
+
219
+ if (container && e.target === container) {
220
+ const currentScrollPos = container.scrollTop;
221
+
222
+ if (currentScrollPos <= element.offsetHeight) {
223
+ this.localDirection = undefined;
224
+ } else if (currentScrollPos < this.originalScrollPos) {
225
+ this.localDirection = 'up';
226
+ } else {
227
+ this.localDirection = 'down';
228
+ }
229
+ this.originalScrollPos = currentScrollPos;
230
+ }
231
+ }
232
+ },
233
+ },
234
+ };
235
+ </script>
236
+
237
+ <style lang="scss">
238
+ @import 'settings-tools/all-settings';
239
+ @import 'components/c.divider';
240
+ .mc-header {
241
+ @include set-font-face();
242
+ background-color: $color-grey-000;
243
+ z-index: 10;
244
+ &__container {
245
+ display: grid;
246
+ padding: $mu050 $mu150 $mu100;
247
+ @include set-from-screen('l') {
248
+ padding-left: $mu200;
249
+ padding-right: $mu200;
250
+ }
251
+ }
252
+ &__breadcrumb {
253
+ grid-column: 1;
254
+ grid-row: auto;
255
+ }
256
+ &__content {
257
+ color: $color-font-darkest;
258
+ grid-column: 1;
259
+ grid-row: auto;
260
+ padding-top: $mu050;
261
+ &-main {
262
+ display: flex;
263
+ align-items: center;
264
+ gap: $mu100;
265
+ &:not(:only-child) {
266
+ margin-bottom: $mu025;
267
+ }
268
+ }
269
+ &-aside {
270
+ display: flex;
271
+ align-items: flex-start;
272
+ flex-direction: column;
273
+ gap: $mu050;
274
+ padding-bottom: $mu050;
275
+ &.can-navigate {
276
+ padding-left: $mu300;
277
+ }
278
+ @include set-from-screen('l') {
279
+ align-items: center;
280
+ flex-direction: row;
281
+ gap: $mu100;
282
+ padding-bottom: 0;
283
+ }
284
+ }
285
+ }
286
+ &__back {
287
+ @include unstyle-button();
288
+ align-items: center;
289
+ background-color: transparent;
290
+ justify-content: center;
291
+ color: currentColor;
292
+ display: flex;
293
+ height: $mu200;
294
+ width: $mu200;
295
+ &-icon {
296
+ color: $color-grey-800;
297
+ height: $mu150;
298
+ width: $mu150;
299
+ }
300
+ &-label {
301
+ @include visually-hidden();
302
+ }
303
+ }
304
+ &__title {
305
+ margin-top: 0;
306
+ margin-bottom: 0;
307
+ &--s {
308
+ @include set-font-scale('07', 'm'); // 23px / 32px
309
+ }
310
+ &--m {
311
+ @include set-font-scale('08', 'm'); // 28px / 36px
312
+ }
313
+ &--l {
314
+ @include set-font-scale('09', 'm'); // 34px / 44px
315
+ }
316
+ &--xl {
317
+ @include set-font-scale('10', 'm'); // 41px / 56px
318
+ }
319
+ }
320
+ &__subtitle {
321
+ @include set-font-scale('05', 'm'); // 16px / 22px
322
+ }
323
+ &__actions,
324
+ &__icons {
325
+ display: flex;
326
+ gap: $mu150;
327
+ }
328
+ &__actions {
329
+ align-items: flex-end;
330
+ align-self: flex-start;
331
+ grid-column: 1;
332
+ grid-row: 1;
333
+ justify-self: end;
334
+ margin-bottom: $mu050;
335
+ min-height: $mu250;
336
+ @include set-from-screen('l') {
337
+ grid-column: 2;
338
+ grid-row: 1;
339
+ margin-bottom: 0;
340
+ }
341
+ }
342
+ &__selector {
343
+ &:not(:only-child) {
344
+ @include set-divider('left', 'light', '100%', 's');
345
+ padding-left: px-to-rem(25);
346
+ position: relative;
347
+ }
348
+ }
349
+ &__tabs {
350
+ padding-left: $mu200;
351
+ padding-right: $mu200;
352
+ }
353
+ // Modifiers
354
+ &--shadow {
355
+ @include set-box-shadow('s');
356
+ }
357
+ &--animate {
358
+ left: 0;
359
+ position: absolute;
360
+ right: 0;
361
+ transition: transform ease-out 0.4s;
362
+ }
363
+ &--sticky {
364
+ position: sticky;
365
+ top: 0;
366
+ }
367
+ &--up {
368
+ transform: translateY(0);
369
+ }
370
+ &--down {
371
+ transform: translateY(calc(-100% - 5px));
372
+ }
373
+ }
374
+ </style>
@@ -0,0 +1,7 @@
1
+ import MHeader from './MHeader.vue';
2
+
3
+ MHeader.install = function (Vue) {
4
+ Vue.component(MHeader.name, MHeader);
5
+ };
6
+
7
+ export { MHeader };
@@ -15,8 +15,10 @@ export { MField } from './field';
15
15
  export { MDropdown } from './dropdown';
16
16
  export { MFileUploader } from './fileuploader';
17
17
  export { MFlag } from './flag';
18
+ export { MHeader } from './header';
18
19
  export { MHero } from './hero';
19
20
  export { MIcon } from './icon';
21
+ export { MKpi } from './kpi';
20
22
  export { MLayer } from './layer';
21
23
  export { MLink } from './link';
22
24
  export { MListBox, MListBoxActions } from './listbox';