@carbon/vue 2.38.1 → 2.42.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,7 +1,7 @@
1
1
  {
2
2
  "name": "@carbon/vue",
3
3
  "description": "A collection of components for the Carbon Design System built using Vue.js",
4
- "version": "2.38.1",
4
+ "version": "2.42.0",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -64,16 +64,16 @@
64
64
  },
65
65
  "sideEffects": true,
66
66
  "dependencies": {
67
- "@carbon/icons-vue": "10.27.0",
67
+ "@carbon/icons-vue": "10.41.0",
68
68
  "@carbon/telemetry": "^0.0.0-alpha.6",
69
- "carbon-components": "10.30.0",
69
+ "carbon-components": "10.46.0",
70
70
  "flatpickr": "4.6.9",
71
- "vue": "^2.6.12"
71
+ "vue": "^2.6.14"
72
72
  },
73
73
  "devDependencies": {
74
74
  "@vue/cli-service": "^3.11.0",
75
75
  "eslint-plugin-prettier": "^3.3.1",
76
- "vue-template-compiler": "^2.6.12"
76
+ "vue-template-compiler": "^2.6.14"
77
77
  },
78
- "gitHead": "064eba8435b5ad7c556b1eaf406c7753c0c0105e"
78
+ "gitHead": "ab0c2e9ac8f61f208d73291274108ce5c25cb527"
79
79
  }
@@ -29,7 +29,7 @@ export default {
29
29
  mixins: [buttonMixin, carbonPrefixMixin],
30
30
  components: { CvSvg },
31
31
  props: {
32
- label: { type: String, default: undefined },
32
+ label: { type: String, required: true },
33
33
  selected: Boolean,
34
34
  tipPosition: {
35
35
  type: String,
@@ -85,80 +85,86 @@
85
85
  </div>
86
86
  </section>
87
87
 
88
- <table
89
- :class="[
90
- `${carbonPrefix}--data-table`,
91
- {
92
- [`${carbonPrefix}--data-table--${rowSize} `]: !(rowSize.length === 0 || rowSize === 'standard'),
93
- [`${carbonPrefix}--data-table--zebra `]: zebra,
94
- [`${carbonPrefix}--data-table--no-border `]: borderless,
95
- [`${carbonPrefix}--skeleton `]: skeleton,
96
- [`${carbonPrefix}--data-table--sort `]: isSortable,
97
- },
98
- ]"
99
- >
100
- <thead>
101
- <tr>
102
- <th
103
- v-if="hasExpandables"
104
- :class="`${carbonPrefix}--table-expand`"
105
- :data-previous-value="dataExpandAll ? 'collapsed' : 'expanded'"
106
- >
107
- <button
108
- v-if="hasExpandAll"
109
- :class="`${carbonPrefix}--table-expand__button`"
110
- @click="toggleExpandAll"
111
- type="button"
112
- :aria-label="dataExpandAll ? collapseAllAriaLabel : expandAllAriaLabel"
113
- >
114
- <ChevronRight16 :class="`${carbonPrefix}--table-expand__svg`" />
115
- </button>
116
- </th>
117
- <th v-if="hasBatchActions" :class="`${carbonPrefix}--table-column-checkbox`">
118
- <cv-checkbox
119
- :form-item="false"
120
- value="headingCheck"
121
- v-model="headingChecked"
122
- @change="onHeadingCheckChange"
123
- :label="selectAllAriaLabel"
124
- hideLabel
125
- />
126
- </th>
127
- <slot name="headings">
128
- <cv-data-table-heading
129
- v-for="(column, index) in columns"
130
- :key="`${index}:${column}`"
131
- :heading="columnHeading(column)"
132
- :sortable="isColSortable(column)"
133
- :order="column.order"
134
- :heading-style="headingStyle(column)"
135
- :skeleton="skeleton"
136
- />
137
- </slot>
138
- <th v-if="hasOverflowMenu"></th>
139
- </tr>
140
- </thead>
88
+ <div :class="`${carbonPrefix}--data-table-content`">
89
+ <cv-wrapper :tagType="stickyHeader ? section : ''" :class="`${carbonPrefix}--data-table_inner-container`">
90
+ <table
91
+ :class="[
92
+ `${carbonPrefix}--data-table`,
93
+ {
94
+ [`${carbonPrefix}--data-table--${rowSize} `]: !(rowSize.length === 0 || rowSize === 'standard'),
95
+ [`${carbonPrefix}--data-table--zebra `]: zebra,
96
+ [`${carbonPrefix}--data-table--sticky-header `]: stickyHeader,
97
+ [`${carbonPrefix}--data-table--no-border `]: borderless,
98
+ [`${carbonPrefix}--skeleton `]: skeleton,
99
+ [`${carbonPrefix}--data-table--sort `]: isSortable,
100
+ [`${carbonPrefix}--data-table--static `]: staticWidth,
101
+ },
102
+ ]"
103
+ >
104
+ <thead>
105
+ <tr>
106
+ <th
107
+ v-if="hasExpandables"
108
+ :class="`${carbonPrefix}--table-expand`"
109
+ :data-previous-value="dataExpandAll ? 'collapsed' : 'expanded'"
110
+ >
111
+ <button
112
+ v-if="hasExpandAll"
113
+ :class="`${carbonPrefix}--table-expand__button`"
114
+ @click="toggleExpandAll"
115
+ type="button"
116
+ :aria-label="dataExpandAll ? collapseAllAriaLabel : expandAllAriaLabel"
117
+ >
118
+ <ChevronRight16 :class="`${carbonPrefix}--table-expand__svg`" />
119
+ </button>
120
+ </th>
121
+ <th v-if="hasBatchActions" :class="`${carbonPrefix}--table-column-checkbox`">
122
+ <cv-checkbox
123
+ :form-item="false"
124
+ value="headingCheck"
125
+ v-model="headingChecked"
126
+ @change="onHeadingCheckChange"
127
+ :label="selectAllAriaLabel"
128
+ hideLabel
129
+ />
130
+ </th>
131
+ <slot name="headings">
132
+ <cv-data-table-heading
133
+ v-for="(column, index) in columns"
134
+ :key="`${index}:${column}`"
135
+ :heading="columnHeading(column)"
136
+ :sortable="isColSortable(column)"
137
+ :order="column.order"
138
+ :heading-style="headingStyle(column)"
139
+ :skeleton="skeleton"
140
+ />
141
+ </slot>
142
+ <th v-if="hasOverflowMenu"></th>
143
+ </tr>
144
+ </thead>
141
145
 
142
- <cv-wrapper :tag-type="hasExpandables ? '' : 'tbody'">
143
- <slot name="data">
144
- <cv-data-table-row
145
- v-for="(row, rowIndex) in data"
146
- :key="`row:${rowIndex}`"
147
- :value="`${rowIndex}`"
148
- ref="dataRows"
149
- :overflow-menu="overflowMenu"
150
- >
151
- <cv-data-table-cell
152
- v-for="(cell, colIndex) in row"
153
- :key="`cell:${colIndex}:${rowIndex}`"
154
- :style="dataStyle(colIndex)"
155
- >
156
- <cv-wrapper :tag-type="skeleton ? 'span' : ''">{{ cell }}</cv-wrapper>
157
- </cv-data-table-cell>
158
- </cv-data-table-row>
159
- </slot>
146
+ <cv-wrapper :tag-type="hasExpandables ? '' : 'tbody'">
147
+ <slot name="data">
148
+ <cv-data-table-row
149
+ v-for="(row, rowIndex) in data"
150
+ :key="`row:${rowIndex}`"
151
+ :value="`${rowIndex}`"
152
+ ref="dataRows"
153
+ :overflow-menu="overflowMenu"
154
+ >
155
+ <cv-data-table-cell
156
+ v-for="(cell, colIndex) in row"
157
+ :key="`cell:${colIndex}:${rowIndex}`"
158
+ :style="dataStyle(colIndex)"
159
+ >
160
+ <cv-wrapper :tag-type="skeleton ? 'span' : ''">{{ cell }}</cv-wrapper>
161
+ </cv-data-table-cell>
162
+ </cv-data-table-row>
163
+ </slot>
164
+ </cv-wrapper>
165
+ </table>
160
166
  </cv-wrapper>
161
- </table>
167
+ </div>
162
168
  </div>
163
169
  <cv-pagination
164
170
  v-if="pagination"
@@ -226,16 +232,19 @@ export default {
226
232
  searchLabel: { type: String, default: 'Search' },
227
233
  searchPlaceholder: { type: String, default: 'Search' },
228
234
  searchClearLabel: { type: String, default: 'Clear search' },
235
+ initialSearchValue: { type: String, default: '' },
229
236
  sortable: Boolean,
230
237
  title: String,
231
238
  columns: Array,
232
239
  data: Array,
233
240
  zebra: Boolean,
241
+ stickyHeader: Boolean,
234
242
  rowsSelected: { type: Array, default: () => [] },
235
243
  helperText: { type: String, default: undefined },
236
244
  expandingSearch: { type: Boolean, default: true },
237
245
  skeleton: Boolean,
238
246
  hasExpandAll: Boolean,
247
+ staticWidth: Boolean,
239
248
  },
240
249
  model: {
241
250
  prop: 'rows-selected',
@@ -250,7 +259,7 @@ export default {
250
259
  batchActive: false,
251
260
  headingChecked: false,
252
261
  dataRowsSelected: this.rowsSelected,
253
- searchValue: '',
262
+ searchValue: this.initialSearchValue,
254
263
  clearSearchVisible: false,
255
264
  searchActive: false,
256
265
  registeredRows: [],
@@ -507,6 +516,7 @@ export default {
507
516
  } else {
508
517
  this.dataExpandAll = false;
509
518
  }
519
+ this.$emit('row-expanded', row);
510
520
  },
511
521
  },
512
522
  };
@@ -81,16 +81,6 @@ import { uidMixin, themeMixin, carbonPrefixMixin } from '../../mixins';
81
81
  import Calendar16 from '@carbon/icons-vue/es/calendar/16';
82
82
  import CvWrapper from '../cv-wrapper/_cv-wrapper';
83
83
 
84
- // Weekdays shorthand for english locale
85
- l10n.en.weekdays.shorthand.forEach((day, index) => {
86
- const currentDay = l10n.en.weekdays.shorthand;
87
- if (currentDay[index] === 'Thu' || currentDay[index] === 'Th') {
88
- currentDay[index] = 'Th';
89
- } else {
90
- currentDay[index] = currentDay[index].charAt(0);
91
- }
92
- });
93
-
94
84
  export default {
95
85
  name: 'CvDatePicker',
96
86
  mixins: [uidMixin, themeMixin, carbonPrefixMixin],
@@ -338,6 +328,17 @@ export default {
338
328
  this.$refs.todate.click();
339
329
  },
340
330
  },
331
+ created() {
332
+ // Weekdays shorthand for english locale
333
+ l10n.en.weekdays.shorthand.forEach((day, index) => {
334
+ const currentDay = l10n.en.weekdays.shorthand;
335
+ if (currentDay[index] === 'Thu' || currentDay[index] === 'Th') {
336
+ currentDay[index] = 'Th';
337
+ } else {
338
+ currentDay[index] = currentDay[index].charAt(0);
339
+ }
340
+ });
341
+ },
341
342
  mounted() {
342
343
  this.initFlatpickr();
343
344
  this.checkSlots();
@@ -32,6 +32,7 @@
32
32
  v-if="kind !== 'button'"
33
33
  v-bind="$attrs"
34
34
  type="file"
35
+ :accept="accept"
35
36
  :class="`${carbonPrefix}--file-input`"
36
37
  :id="uid"
37
38
  data-file-uploader
@@ -45,6 +46,7 @@
45
46
  v-if="kind === 'button'"
46
47
  v-bind="$attrs"
47
48
  type="file"
49
+ :accept="accept"
48
50
  :class="`${carbonPrefix}--file-input`"
49
51
  :id="uid"
50
52
  data-file-uploader
@@ -140,6 +142,7 @@ export default {
140
142
  },
141
143
  label: String,
142
144
  helperText: String,
145
+ accept: String,
143
146
  initialStateUploading: Boolean,
144
147
  removable: Boolean,
145
148
  buttonLabel: {
@@ -210,12 +213,19 @@ export default {
210
213
  },
211
214
  addFiles(files) {
212
215
  for (const file of files) {
213
- this.internalFiles.push({
216
+ const internalFile = {
214
217
  state: this.initialStateUploading ? STATES.UPLOADING : STATES.NONE,
215
218
  file,
216
219
  invalidMessageTitle: '',
217
220
  invalidMessage: '',
218
- });
221
+ };
222
+
223
+ if (file.messageBundle) {
224
+ internalFile.invalidMessageTitle = file.messageBundle.invalidMessageTitle;
225
+ internalFile.invalidMessage = file.messageBundle.invalidMessage;
226
+ delete file.messageBundle;
227
+ }
228
+ this.internalFiles.push(internalFile);
219
229
  }
220
230
  this.$emit('change', this.internalFiles);
221
231
  },
@@ -241,32 +251,55 @@ export default {
241
251
  this.internalFiles[index].invalidMessage = message;
242
252
  },
243
253
  onDragEvent(evt) {
244
- // NOTE: Validation of dragged files is not currently done.
245
- // It may be possible to do this here or defer to the caller.
246
- // It is certainly possible for the user to remove files after they are dropped.
254
+ if (Array.prototype.indexOf.call(evt.dataTransfer.types, 'Files') === -1) {
255
+ return;
256
+ }
247
257
 
248
- if (Array.prototype.indexOf.call(evt.dataTransfer.types, 'Files') >= 0) {
249
- if (evt.type === 'dragover') {
250
- evt.preventDefault();
251
- const dropEffect = 'copy';
252
- if (Array.isArray(evt.dataTransfer.types)) {
253
- try {
254
- // IE11 throws a "permission denied" error accessing `.effectAllowed`
255
- evt.dataTransfer.effectAllowed = dropEffect;
256
- } catch (e) {
257
- // ignore
258
- }
258
+ if (evt.type === 'dragleave') {
259
+ this.allowDrop = false;
260
+ return;
261
+ }
262
+
263
+ if (evt.type === 'dragover') {
264
+ evt.preventDefault();
265
+ const dropEffect = 'copy';
266
+ if (Array.isArray(evt.dataTransfer.types)) {
267
+ try {
268
+ // IE11 throws a "permission denied" error accessing `.effectAllowed`
269
+ evt.dataTransfer.effectAllowed = dropEffect;
270
+ } catch (e) {
271
+ // ignore
259
272
  }
260
- evt.dataTransfer.dropEffect = dropEffect;
261
- this.allowDrop = true;
262
273
  }
263
- if (evt.type === 'dragleave') {
264
- this.allowDrop = false;
274
+ evt.dataTransfer.dropEffect = dropEffect;
275
+ this.allowDrop = true;
276
+ }
277
+
278
+ if (evt.type === 'drop') {
279
+ evt.preventDefault();
280
+ if (this.accept) {
281
+ this.markInvalidFileTypes(evt.dataTransfer.files);
265
282
  }
266
- if (evt.type === 'drop') {
267
- evt.preventDefault();
268
- this.addFiles(evt.dataTransfer.files);
269
- this.allowDrop = false;
283
+ this.addFiles(evt.dataTransfer.files);
284
+ this.allowDrop = false;
285
+ }
286
+ },
287
+ markInvalidFileTypes(files) {
288
+ const isFileAllowed = file => {
289
+ const extension = '.' + file.name.split('.').pop();
290
+ const allowed = this.accept.split(',').map(x => x.trim());
291
+ if (allowed.includes('.jpg')) {
292
+ allowed.push('.jpeg');
293
+ }
294
+ return allowed.includes(file.type) || allowed.includes(extension);
295
+ };
296
+
297
+ for (const file of files) {
298
+ if (!isFileAllowed(file)) {
299
+ file.messageBundle = {
300
+ invalidMessageTitle: 'Invalid file type',
301
+ invalidMessage: `"${file.name}" does not have a valid file type.`,
302
+ };
270
303
  }
271
304
  }
272
305
  },
@@ -34,6 +34,7 @@
34
34
  {{ actionLabel }}
35
35
  </button>
36
36
  <button
37
+ v-if="!hideCloseButton"
37
38
  type="button"
38
39
  :aria-label="closeAriaLabel"
39
40
  data-notification-btn
@@ -66,6 +67,7 @@ export default {
66
67
  validator: val => ['error', 'info', 'warning', 'success'].includes(val),
67
68
  },
68
69
  lowContrast: Boolean,
70
+ hideCloseButton: Boolean,
69
71
  },
70
72
  computed: {
71
73
  icon() {
@@ -71,7 +71,7 @@
71
71
  :disabled="primaryButtonDisabled"
72
72
  type="button"
73
73
  :kind="primaryKind"
74
- @click="() => onPrimaryClick"
74
+ @click="onPrimaryClick"
75
75
  v-if="hasPrimary"
76
76
  ref="primary"
77
77
  >
@@ -131,6 +131,7 @@
131
131
  :name="item.name"
132
132
  :data-test="item.name"
133
133
  :label="item.label"
134
+ :disabled="item.disabled"
134
135
  style="pointer-events: none;"
135
136
  />
136
137
  </div>
@@ -407,7 +408,9 @@ export default {
407
408
  onEnter() {
408
409
  if (this.open) {
409
410
  this.onItemClick(this.highlighted);
410
- this.$refs.input.focus();
411
+ if (this.$refs.input) {
412
+ this.$refs.input.focus();
413
+ }
411
414
  this.filter = '';
412
415
 
413
416
  this.doOpen(false);
@@ -446,17 +449,20 @@ export default {
446
449
  this.highlighted = val;
447
450
  },
448
451
  onItemClick(val) {
449
- const index = this.dataValue.findIndex(item => val === item);
450
- if (index > -1) {
451
- this.dataValue.splice(index, 1);
452
- } else {
453
- this.dataValue.push(val);
454
- }
455
- if (this.selectionFeedback === selectionFeedbackOptions[TOP]) {
456
- this.updateOptions();
452
+ const option = this.options.find(item => item.value === val);
453
+ if (option && !option.disabled) {
454
+ const index = this.dataValue.findIndex(item => val === item);
455
+ if (index > -1) {
456
+ this.dataValue.splice(index, 1);
457
+ } else {
458
+ this.dataValue.push(val);
459
+ }
460
+ if (this.selectionFeedback === selectionFeedbackOptions[TOP]) {
461
+ this.updateOptions();
462
+ }
463
+ this.$refs.button.focus();
464
+ this.$emit('change', this.dataValue);
457
465
  }
458
- this.$refs.button.focus();
459
- this.$emit('change', this.dataValue);
460
466
  },
461
467
  inputClick() {
462
468
  if (!this.open) {
@@ -18,6 +18,7 @@
18
18
  :class="[`${carbonPrefix}--progress-label`, { [`${carbonPrefix}--progress-label-overflow`]: showOverflow }]"
19
19
  @mouseenter="onMouseEnter"
20
20
  @mouseleave="onMouseLeave"
21
+ @click="$emit('step-clicked', $event)"
21
22
  ref="label"
22
23
  >
23
24
  {{ label }}
@@ -11,6 +11,7 @@
11
11
  :label="step"
12
12
  :complete="initialStep > index"
13
13
  ref="steps"
14
+ @step-clicked="$emit('step-clicked', $event)"
14
15
  />
15
16
  </slot>
16
17
  </ul>
@@ -196,7 +196,7 @@ export default {
196
196
  },
197
197
  doScrollIntoView(index) {
198
198
  const tab = this.$refs.link[index];
199
- const scrollContainer = tab.parentNode ? tab.parentNode.parentNode : null;
199
+ const scrollContainer = tab && tab.parentNode ? tab.parentNode.parentNode : null;
200
200
  let newScrollLeft;
201
201
 
202
202
  if (tab && scrollContainer) {
@@ -2,7 +2,7 @@
2
2
  <div
3
3
  data-notification
4
4
  :class="[
5
- `cv-notifiation ${carbonPrefix}--toast-notification`,
5
+ `cv-notification ${carbonPrefix}--toast-notification`,
6
6
  `${carbonPrefix}--toast-notification--${kind.toLowerCase()}`,
7
7
  { [`${carbonPrefix}--toast-notification--low-contrast`]: lowContrast },
8
8
  ]"
@@ -17,6 +17,7 @@
17
17
  <p :class="`${carbonPrefix}--toast-notification__caption`" v-html="caption"></p>
18
18
  </div>
19
19
  <button
20
+ v-if="!hideCloseButton"
20
21
  :aria-label="closeAriaLabel"
21
22
  type="button"
22
23
  data-notification-btn
@@ -43,6 +44,7 @@ export default {
43
44
  props: {
44
45
  caption: String,
45
46
  closeAriaLabel: { type: String, default: 'Dismiss notification' },
47
+ hideCloseButton: Boolean,
46
48
  kind: {
47
49
  type: String,
48
50
  default: 'info',