@everchron/ec-shards 6.2.2 → 7.0.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.
Files changed (111) hide show
  1. package/dist/ec-shards.common.js +3154 -2114
  2. package/dist/ec-shards.common.js.map +1 -1
  3. package/dist/ec-shards.css +1 -1
  4. package/dist/ec-shards.umd.js +3154 -2114
  5. package/dist/ec-shards.umd.js.map +1 -1
  6. package/dist/ec-shards.umd.min.js +2 -2
  7. package/dist/ec-shards.umd.min.js.map +1 -1
  8. package/package.json +1 -1
  9. package/src/components/action-toolbar/action-toolbar.vue +1 -1
  10. package/src/components/alert/alert.vue +27 -4
  11. package/src/components/avatar/avatar.vue +2 -1
  12. package/src/components/breadcrumb/breadcrumb.vue +2 -2
  13. package/src/components/breadcrumb-button/breadcrumb-button.vue +15 -3
  14. package/src/components/breadcrumb-title/breadcrumb-title.vue +1 -1
  15. package/src/components/button/button.vue +65 -54
  16. package/src/components/button-collapse/button-collapse.vue +49 -6
  17. package/src/components/button-context/button-context.vue +30 -1
  18. package/src/components/button-dialog/button-dialog.vue +22 -8
  19. package/src/components/button-more/button-more.vue +44 -4
  20. package/src/components/button-table/button-table.vue +13 -1
  21. package/src/components/button-toolbar/button-toolbar.vue +50 -19
  22. package/src/components/button-toolbar-icon/button-toolbar-icon.vue +23 -7
  23. package/src/components/checkbox/checkbox.vue +0 -1
  24. package/src/components/collapse/collapse.vue +28 -7
  25. package/src/components/collection-control/collection-control.vue +40 -7
  26. package/src/components/comment/comment.vue +1 -1
  27. package/src/components/context-menu/context-menu.vue +88 -5
  28. package/src/components/data-card/data-card.vue +52 -14
  29. package/src/components/data-card-list/data-card-list.vue +1 -1
  30. package/src/components/data-grid/data-grid-cell.vue +1 -1
  31. package/src/components/data-grid/data-grid-group.vue +6 -1
  32. package/src/components/data-grid/data-grid-head-cell.vue +32 -2
  33. package/src/components/data-grid/data-grid-row.vue +1 -1
  34. package/src/components/data-grid/data-grid.vue +2 -2
  35. package/src/components/data-list/data-list.vue +1 -1
  36. package/src/components/data-list-item/data-list-item.vue +28 -9
  37. package/src/components/directory-entry/directory-entry.vue +7 -4
  38. package/src/components/document-state/document-state.vue +1 -1
  39. package/src/components/dropdown/dropdown.vue +23 -1
  40. package/src/components/dropzone/dropzone.vue +21 -3
  41. package/src/components/empty-state/empty-state.vue +1 -1
  42. package/src/components/entry-link/entry-link.vue +16 -3
  43. package/src/components/favicon/favicon.vue +1 -1
  44. package/src/components/file-icon/file-icon.vue +1 -1
  45. package/src/components/file-list/file-list.vue +1 -1
  46. package/src/components/file-list-item/file-list-item.vue +79 -17
  47. package/src/components/flag/flag.vue +75 -1
  48. package/src/components/folder-selector/folder-selector.vue +1 -1
  49. package/src/components/form-check/form-check.vue +9 -2
  50. package/src/components/form-set/form-set.vue +4 -4
  51. package/src/components/index.js +2 -0
  52. package/src/components/input-clear/input-clear.vue +20 -3
  53. package/src/components/jumper-document/jumper-document.vue +16 -4
  54. package/src/components/jumper-index/jumper-index.vue +19 -4
  55. package/src/components/jumper-page/jumper-page.vue +3 -1
  56. package/src/components/layout-data-table/layout-data-table.vue +5 -5
  57. package/src/components/layout-directory/layout-directory.vue +4 -4
  58. package/src/components/layout-index/layout-index.vue +2 -2
  59. package/src/components/legend-item/legend-item.vue +15 -1
  60. package/src/components/log-message/log-message.vue +11 -1
  61. package/src/components/map/map.vue +20 -3
  62. package/src/components/mixins/focus-ring.vue +47 -0
  63. package/src/components/mixins/unique-id.js +17 -0
  64. package/src/components/modal/modal.vue +5 -2
  65. package/src/components/modal-header/modal-header.vue +43 -19
  66. package/src/components/multiselect-option/multiselect-option.vue +1 -1
  67. package/src/components/multiselect-search-token/multiselect-search-token.vue +33 -6
  68. package/src/components/multiselect-token/multiselect-token.vue +28 -3
  69. package/src/components/overlay/overlay.vue +6 -6
  70. package/src/components/pagination/pagination.vue +5 -5
  71. package/src/components/popover-list/popover-list.vue +5 -1
  72. package/src/components/popover-list-headline/popover-list-headline.vue +4 -1
  73. package/src/components/popover-list-item/popover-list-item.vue +27 -8
  74. package/src/components/progress/progress.vue +7 -1
  75. package/src/components/quicklink/quicklink.vue +29 -18
  76. package/src/components/radiobutton/radiobutton.vue +2 -2
  77. package/src/components/rating-favorability/rating-favorability.vue +5 -1
  78. package/src/components/rating-star-read/rating-star-read.vue +1 -1
  79. package/src/components/select/select.vue +12 -2
  80. package/src/components/select-text/select-text.vue +7 -2
  81. package/src/components/select-tile/select-tile.vue +26 -2
  82. package/src/components/separator/separator.vue +1 -1
  83. package/src/components/sequence-map/sequence-map.vue +1 -1
  84. package/src/components/sequence-map-button/sequence-map-button.vue +14 -2
  85. package/src/components/sidebar-footer/sidebar-footer.vue +2 -2
  86. package/src/components/sidebar-header/sidebar-header.vue +2 -2
  87. package/src/components/sortbutton/sortbutton.vue +22 -7
  88. package/src/components/sticker/sticker.vue +1 -1
  89. package/src/components/swatches-picker/swatches-picker.vue +28 -3
  90. package/src/components/switch/switch.vue +24 -8
  91. package/src/components/tab/tab.vue +16 -2
  92. package/src/components/tab-bar/tab-bar.vue +1 -1
  93. package/src/components/tab-button/tab-button.vue +61 -1
  94. package/src/components/tabs/tabs.vue +2 -1
  95. package/src/components/tag/tag.vue +17 -5
  96. package/src/components/tag-cloud/tag-cloud.vue +3 -1
  97. package/src/components/toast/toast.vue +18 -3
  98. package/src/components/toasts/toasts.vue +1 -1
  99. package/src/components/toolbar/toolbar.vue +1 -1
  100. package/src/components/transcript-state/transcript-state.vue +1 -1
  101. package/src/components/tree-list/tree-list-item.vue +77 -12
  102. package/src/components/tree-list/tree-list.vue +7 -1
  103. package/src/stories/Changelog.stories.mdx +8 -0
  104. package/src/stories/button/button.stories.js +7 -7
  105. package/src/stories/button-more/button-more.stories.js +8 -8
  106. package/src/stories/button-toolbar/button-toolbar.stories.js +5 -5
  107. package/src/stories/button-toolbar-icon/button-toolbar-icon.stories.js +6 -6
  108. package/src/stories/popover-list/popover-list.stories.js +7 -2
  109. package/src/stories/sortbutton/sortbutton.stories.js +4 -4
  110. package/src/stories/tag/tag.stories.js +7 -7
  111. package/src/stories/tree-list/tree-list.stories.js +3 -0
@@ -1,10 +1,25 @@
1
1
  <template>
2
- <div class="ecs-context-menu" :class="opened ? ' opened': ''" :id="elementId" :style="[postionStyles]" v-click-outside="onClickOutside">
3
- <ul>
2
+ <div
3
+ class="ecs-context-menu"
4
+ :class="opened ? ' opened': ''"
5
+ :id="elementId"
6
+ :style="[postionStyles]"
7
+ v-click-outside="onClickOutside"
8
+ >
9
+ <ul
10
+ role="menu"
11
+ aria-orientation="vertical"
12
+ tabindex="0"
13
+ @keydown.up.prevent="focusPrevious"
14
+ @keydown.down.prevent="focusNext"
15
+ ref="menu" id="my-menu">
4
16
  <li
5
17
  v-for="(option, index) in options"
6
18
  :key="index"
7
19
  @click.stop="optionClicked(option)"
20
+ :role="option.type === 'divider' ? 'separator' : 'menuitem'"
21
+ :tabindex="option.type === 'divider' || option.disabled ? '-1' : '0'"
22
+ :aria-disabled="option.disabled"
8
23
  :class="[
9
24
  option.type === 'divider' ? 'ecs-context-menu-divider' : 'ecs-context-menu-item',
10
25
  option.type === 'danger' ? 'danger' : '',
@@ -13,6 +28,7 @@
13
28
  >
14
29
  <ecs-icon v-if="option.icon" :type="option.icon" size="20" />
15
30
  <span v-if="option.type != 'divider'">{{ option.name}}</span>
31
+ <ecs-focus-ring :danger="option.type == 'danger'" />
16
32
  </li>
17
33
  </ul>
18
34
  </div>
@@ -23,9 +39,10 @@ import Vue from "vue";
23
39
  import vClickOutside from "v-click-outside"
24
40
  Vue.use(vClickOutside)
25
41
  import EcsIcon from '../icon/icon'
42
+ import EcsFocusRing from '../mixins/focus-ring'
26
43
 
27
44
  export default {
28
- components: { EcsIcon },
45
+ components: { EcsIcon, EcsFocusRing },
29
46
 
30
47
  props: {
31
48
  /** Unique String that acts as the id for the menu. */
@@ -97,6 +114,10 @@ export default {
97
114
  this.top = event.pageY - 2
98
115
  }
99
116
  this.opened = true
117
+
118
+ this.$nextTick(() => {
119
+ this.$refs.menu.focus();
120
+ });
100
121
  },
101
122
 
102
123
  hideContextMenu() {
@@ -126,11 +147,62 @@ export default {
126
147
  if (event.keyCode === 27) {
127
148
  this.hideContextMenu()
128
149
  }
150
+ },
151
+
152
+ // Focus the first menu item when the context menu opens
153
+ focusFirst() {
154
+ this.$refs.menu.children[0].focus();
155
+ },
156
+ // Focus the last menu item when the user presses the up arrow key on the first menu item
157
+ focusLast() {
158
+ const items = this.$refs.menu.children;
159
+ items[items.length - 1].focus();
160
+ },
161
+ // Focus the previous menu item when the user presses the up arrow key
162
+ focusPrevious(event) {
163
+ const items = this.$refs.menu.children;
164
+ const index = Array.prototype.indexOf.call(items, event.target);
165
+ if (index > 0) {
166
+ let prevIndex = index - 1;
167
+ while (prevIndex >= 0 && items[prevIndex].getAttribute('tabindex') === '-1') {
168
+ prevIndex--;
169
+ }
170
+ if (prevIndex >= 0) {
171
+ items[prevIndex].focus();
172
+ } else {
173
+ this.focusLast();
174
+ }
175
+ } else {
176
+ this.focusLast();
177
+ }
178
+ },
179
+
180
+ focusNext(event) {
181
+ const items = this.$refs.menu.children;
182
+ let index = Array.prototype.indexOf.call(items, event.target);
183
+
184
+ while (index < items.length - 1) {
185
+ index++;
186
+
187
+ if (items[index].getAttribute('tabindex') !== '-1') {
188
+ items[index].focus();
189
+ return;
190
+ }
191
+ }
192
+ this.focusFirst();
129
193
  }
130
194
  },
131
195
 
132
196
  mounted() {
133
197
  document.body.addEventListener("keyup", this.onEscKeyRelease)
198
+
199
+ this.$refs.menu.addEventListener("keydown", event => {
200
+ // Check if the Tab key was pressed
201
+ if (event.keyCode === 9) {
202
+ event.preventDefault();
203
+ this.focusFirst();
204
+ }
205
+ });
134
206
  },
135
207
 
136
208
  beforeDestroy() {
@@ -172,13 +244,23 @@ export default {
172
244
  line-height: $type-scale-3-line-height;
173
245
  color: $color-gray-15;
174
246
  cursor: pointer;
247
+ position: relative;
248
+
249
+ &:focus-visible{
250
+ z-index: 1;
251
+
252
+ .ecs-focus-ring{
253
+ display: block;
254
+ }
255
+ }
175
256
 
176
257
  .icon{
177
258
  color: $color-gray-8;
178
259
  }
179
260
 
180
261
  &:not(.disabled){
181
- &.danger:hover{
262
+ &.danger:hover,
263
+ &.danger:focus{
182
264
  background: $color-red-1;
183
265
 
184
266
  .icon{
@@ -186,7 +268,8 @@ export default {
186
268
  }
187
269
  }
188
270
 
189
- &:hover{
271
+ &:hover,
272
+ &:focus{
190
273
  background: $color-blue-1;
191
274
 
192
275
  .icon{
@@ -1,14 +1,18 @@
1
1
  <template>
2
- <div class="ecs-data-card" @click="$emit('click')"
3
- :class="[
4
- $slots.meta ? 'ecs-data-card-sml' : '',
5
- $slots.actions ? 'ecs-data-card-hover' : '',
6
- hover ? 'ecs-data-card-hover' : '',
7
- active ? 'active' : '',
8
- shadow ? 'shadow' : '',
9
- isExpanded ? 'expanded' : '',
10
- loading ? 'loading' : ''
11
- ]">
2
+ <div @click="$emit('click')"
3
+ class="ecs-data-card"
4
+ role="listitem"
5
+ :aria-busy="loading"
6
+ :tabindex="hover ? '0' : '-1'"
7
+ :class="[
8
+ $slots.meta ? 'ecs-data-card-sml' : '',
9
+ $slots.actions ? 'ecs-data-card-hover' : '',
10
+ hover ? 'ecs-data-card-hover' : '',
11
+ active ? 'active' : '',
12
+ shadow ? 'shadow' : '',
13
+ isExpanded ? 'expanded' : '',
14
+ loading ? 'loading' : ''
15
+ ]">
12
16
 
13
17
  <div v-if="control && $slots.control" class="control">
14
18
  <!-- @slot Slot for adding a control, such as a checkbox or radiobutton. -->
@@ -29,7 +33,18 @@
29
33
  <!-- @slot Slot for adding action buttons. -->
30
34
  <slot name="actions"></slot>
31
35
  </div>
32
- <ecs-button-table @click="isExpanded = !isExpanded" v-if="expandable" pale chevron size="sml" :active="isExpanded" :icon="expandIcon" :label="expandLabel" class="expand-button" />
36
+ <ecs-button-table
37
+ @click="isExpanded = !isExpanded"
38
+ v-if="expandable"
39
+ :aria-controls="expandId"
40
+ :aria-expanded="isExpanded ? 'true' : 'false'"
41
+ pale
42
+ chevron
43
+ size="sml"
44
+ :active="isExpanded"
45
+ :icon="expandIcon"
46
+ :label="expandLabel"
47
+ class="expand-button" />
33
48
  </div>
34
49
  </div>
35
50
  <div v-if="$slots.meta" class="ecs-data-card-row">
@@ -39,13 +54,19 @@
39
54
  <ecs-skeleton-loader v-if="loading" type="single" :width="skeletonWidth(15, 30)" />
40
55
  </div>
41
56
  </div>
42
- <div v-if="$slots.expand" v-show="isExpanded" class="ecs-data-card-expand">
57
+ <div
58
+ v-if="$slots.expand"
59
+ v-show="isExpanded"
60
+ :id="expandId"
61
+ :aria-hidden="isExpanded ? 'false' : 'true'"
62
+ class="ecs-data-card-expand">
43
63
  <div class="ecs-data-card-expand-inner">
44
64
  <!-- @slot Slot for expandable content. -->
45
65
  <slot name="expand"></slot>
46
66
  </div>
47
67
  </div>
48
68
  </div>
69
+ <ecs-focus-ring v-if="hover" :inset="0" :radius="0" />
49
70
  </div>
50
71
  </template>
51
72
 
@@ -53,9 +74,12 @@
53
74
  import EcsIcon from '../icon/icon'
54
75
  import EcsSkeletonLoader from '../skeleton-loader/skeleton-loader'
55
76
  import EcsButtonTable from '../button-table/button-table'
77
+ import EcsFocusRing from '../mixins/focus-ring'
78
+ import { uniqueIdMixin } from '../mixins/unique-id'
56
79
 
57
80
  export default {
58
- components: { EcsIcon, EcsSkeletonLoader, EcsButtonTable },
81
+ components: { EcsIcon, EcsSkeletonLoader, EcsButtonTable, EcsFocusRing },
82
+ mixins: [uniqueIdMixin],
59
83
 
60
84
  props: {
61
85
  /** If passed, an icon will be displayed in the data card. The icon prop must match a specific icons name. The list of available icon names can be found [here](https://github.com/everchron/ec-shards/tree/main/src/assets/icons). */
@@ -118,7 +142,8 @@
118
142
 
119
143
  data () {
120
144
  return {
121
- isExpanded: this.expanded
145
+ isExpanded: this.expanded,
146
+ expandId: ''
122
147
  }
123
148
  },
124
149
 
@@ -126,6 +151,10 @@
126
151
  skeletonWidth : function(min, max){
127
152
  return Math.floor(Math.random() * (max - min + 1) + min)
128
153
  }
154
+ },
155
+
156
+ created(){
157
+ this.expandId = this.generateUniqueId()
129
158
  }
130
159
  }
131
160
  </script>
@@ -144,6 +173,15 @@
144
173
  min-height: 46px;
145
174
  user-select: none;
146
175
 
176
+ &:focus-visible{
177
+ z-index: 1;
178
+ outline: none;
179
+
180
+ .ecs-focus-ring{
181
+ display: block;
182
+ }
183
+ }
184
+
147
185
  &:before,
148
186
  &:after{
149
187
  content: "";
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="ecs-data-card-list">
2
+ <div class="ecs-data-card-list" role="list">
3
3
  <slot></slot>
4
4
  </div>
5
5
  </template>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="ecs-data-grid-cell" :style="[fixedStyles]" :class="[fixedLeft ? 'fixed-left' : '', fixedLeftLast ? 'fixed-left-last' : '', fixedRight ? 'fixed-right' : '']">
2
+ <div class="ecs-data-grid-cell" :style="[fixedStyles]" :class="[fixedLeft ? 'fixed-left' : '', fixedLeftLast ? 'fixed-left-last' : '', fixedRight ? 'fixed-right' : '']" role="cell">
3
3
  <div v-if="fixedRight" class="shadow" :class="fixedRight ? 'left' : ''" />
4
4
  <div class="ecs-data-grid-cell-inner" :style="[widthStyles, paddingStyles]" :data-column="computedId" :data-test="computedId">
5
5
  <div v-if="firstNonStaticCell" class="first-cell-spacer" />
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div v-show="show" class="ecs-data-grid-group">
2
+ <div v-show="show" class="ecs-data-grid-group" role="tabpanel" :aria-labeled-by="ariaLabeledBy">
3
3
  <template v-if="show">
4
4
  <slot></slot>
5
5
  </template>
@@ -13,6 +13,11 @@
13
13
  show: {
14
14
  type: Boolean,
15
15
  default: false
16
+ },
17
+ /** Sets the aria-labeled-by attribute. Should match the ID of the tab button which controls this tab panel. */
18
+ ariaLabeledBy: {
19
+ type: String,
20
+ required: true
16
21
  }
17
22
  }
18
23
  }
@@ -1,5 +1,12 @@
1
1
  <template>
2
- <div class="ecs-data-grid-head-cell" :style="[fixedStyles]" :class="[fixedLeft ? 'fixed-left' : '', fixedLeftLast ? 'fixed-left-last' : '', fixedRight ? 'fixed-right' : '']">
2
+ <div
3
+ class="ecs-data-grid-head-cell"
4
+ :style="[fixedStyles]"
5
+ :class="[fixedLeft ? 'fixed-left' : '', fixedLeftLast ? 'fixed-left-last' : '', fixedRight ? 'fixed-right' : '']"
6
+ role="columnheader"
7
+ :aria-sort="ariaSort"
8
+ :aria-label="icon ? name : false">
9
+
3
10
  <div v-if="fixedRight" class="shadow" :class="fixedRight ? 'left' : ''" />
4
11
  <div ref="resizer" class="ecs-data-grid-head-cell-inner" :style="[widthStyles, paddingStyles, resizeStyles]" :class="resizable ? 'resizable' : ''" :data-column="computedId" :data-headname="beingResizedName" :data-test="computedId">
5
12
  <div v-if="firstNonStaticCell" class="first-cell-spacer" />
@@ -17,6 +24,7 @@
17
24
  <path d="M3.99023 11.802L6.76923 14.722L9.54823 11.802" :stroke="sorting == 'desc' ? '#157EFB' : '#B9BCC2'" :stroke-width="sorting == 'desc' ? '1.5' : '1'" :opacity="sorting == 'desc' || sorting == 'none' ? '1' : '0.5'" stroke-linecap="round" stroke-linejoin="round"/>
18
25
  <path d="M3.99023 8.722L6.76923 5.802L9.54823 8.722" :stroke="sorting == 'asc' ? '#157EFB' : '#B9BCC2'" :stroke-width="sorting == 'asc' ? '1.5' : '1'" :opacity="sorting == 'asc' || sorting == 'none' ? '1' : '0.5'" stroke-linecap="round" stroke-linejoin="round"/>
19
26
  </svg>
27
+ <ecs-focus-ring />
20
28
  </button>
21
29
  </div>
22
30
  <div v-if="fixedLeftLast" class="shadow" :class="fixedLeftLast ? 'right' : ''" />
@@ -26,10 +34,13 @@
26
34
  <script>
27
35
  import EcsIcon from '../icon/icon'
28
36
  import EcsSelect from '../select/select'
37
+ import EcsFocusRing from '../mixins/focus-ring'
29
38
 
30
39
  export default {
31
40
  components: {
32
- EcsIcon, EcsSelect
41
+ EcsIcon,
42
+ EcsSelect,
43
+ EcsFocusRing
33
44
  },
34
45
 
35
46
  props: {
@@ -179,6 +190,15 @@
179
190
 
180
191
  beingResizedName(){
181
192
  return this.beingResized ? this.uniformName + '-noresize' : this.uniformName
193
+ },
194
+
195
+ ariaSort(){
196
+ switch (this.sorting) {
197
+ case 'asc':
198
+ return 'ascending';
199
+ case 'desc':
200
+ return 'descending';
201
+ }
182
202
  }
183
203
  },
184
204
 
@@ -341,7 +361,17 @@
341
361
  background: none;
342
362
  padding: 0 1px;
343
363
  height: 24px;
364
+ position: relative;
344
365
  cursor: pointer;
366
+
367
+ &:focus-visible{
368
+ z-index: 1;
369
+ outline: none;
370
+
371
+ .ecs-focus-ring{
372
+ display: block;
373
+ }
374
+ }
345
375
  }
346
376
 
347
377
  .shadow{
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="ecs-data-grid-row" :class="state" ref="grid_row">
2
+ <div class="ecs-data-grid-row" :class="state" ref="grid_row" role="row">
3
3
  <div v-if="state == 'droppable'" @click="handleDropzoneClick" class="ecs-data-grid-row-drop-zone" />
4
4
 
5
5
  <!-- @slot All of the row's cells go here. There should **never** be any other child component other than EcsDataGridCell be used. -->
@@ -1,6 +1,6 @@
1
1
  <template>
2
- <div v-on:scroll="tableScroll" class="ecs-data-grid scrollbar" :class="$slots.empty ? 'empty' : ''" ref="dataGridScroller">
3
- <div class="ecs-data-grid-head" :class="sidebarOverlay ? 'sidebar-space' : ''">
2
+ <div v-on:scroll="tableScroll" class="ecs-data-grid scrollbar" :class="$slots.empty ? 'empty' : ''" ref="dataGridScroller" role="table">
3
+ <div class="ecs-data-grid-head" :class="sidebarOverlay ? 'sidebar-space' : ''" role="row">
4
4
  <!-- @slot Slot for the table head row cells. -->
5
5
  <slot name="head"></slot>
6
6
  </div>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="ecs-data-list">
2
+ <div class="ecs-data-list" role="list">
3
3
  <slot></slot>
4
4
  </div>
5
5
  </template>
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div>
3
- <div class="ecs-data-list-item"
3
+ <div class="ecs-data-list-item" role="listitem"
4
4
  :class="[
5
5
  small ? 'ecs-data-list-item-sml' : '',
6
6
  full ? 'ecs-data-list-item-full' : '',
@@ -14,21 +14,33 @@
14
14
  v-if="$slots.collapse"
15
15
  class="ecs-data-list-expand-button"
16
16
  :active="isVisible"
17
+ :aria-controls="expandId"
18
+ :aria-expanded="isVisible ? 'true' : 'false'"
17
19
  @click="toggleCollapse" />
18
20
  </div>
19
21
  <div class="ecs-data-list-data"
20
- :class="[
21
- escape ? 'ecs-data-list-data-escape' : '',
22
- error ? 'ecs-data-list-data-error' : '',
23
- typeClass
24
- ]">
22
+ :aria-busy="loading"
23
+ :class="[
24
+ escape ? 'ecs-data-list-data-escape' : '',
25
+ error ? 'ecs-data-list-data-error' : '',
26
+ typeClass
27
+ ]">
25
28
  <slot v-if="!loading"></slot>
26
29
  <ecs-skeleton-loader v-else type="single" :width="skeletonWidth(25, 70)" />
27
- <div v-if="progress" class="progress" :style="{ width: progress + '%' }"></div>
30
+ <div v-if="progress"
31
+ class="progress"
32
+ role="progressbar"
33
+ :style="{ width: progress + '%' }"
34
+ :aria-valuenow="progress">
35
+ </div>
28
36
  </div>
29
37
  </div>
30
38
 
31
- <div v-if="$slots.collapse" :class="isVisible ? 'collapse-show' : 'collapse-hide'">
39
+ <div v-if="$slots.collapse"
40
+ :class="isVisible ? 'collapse-show' : 'collapse-hide'"
41
+ role="list"
42
+ :id="expandId"
43
+ :aria-hidden="isVisible ? 'false' : 'true'">
32
44
  <!-- @slot Slot for expandable content. -->
33
45
  <slot name="collapse"></slot>
34
46
  </div>
@@ -38,9 +50,11 @@
38
50
  <script>
39
51
  import EcsButtonMore from '../button-more/button-more'
40
52
  import EcsSkeletonLoader from '../skeleton-loader/skeleton-loader'
53
+ import { uniqueIdMixin } from '../mixins/unique-id'
41
54
 
42
55
  export default {
43
56
  components: { EcsButtonMore, EcsSkeletonLoader },
57
+ mixins: [uniqueIdMixin],
44
58
 
45
59
  props: {
46
60
  /** The label that shows up to the left of the list item. Usually describes the content to the left, e.g.: "Type", "Profiles", etc. */
@@ -106,7 +120,8 @@
106
120
 
107
121
  data () {
108
122
  return {
109
- isVisible: this.visible
123
+ isVisible: this.visible,
124
+ expandId: ''
110
125
  }
111
126
  },
112
127
 
@@ -138,6 +153,10 @@
138
153
  visible(){
139
154
  this.isVisible = this.visible
140
155
  }
156
+ },
157
+
158
+ created() {
159
+ this.expandId = this.generateUniqueId()
141
160
  }
142
161
  }
143
162
  </script>
@@ -83,14 +83,17 @@
83
83
  display: inline-block;
84
84
  position: relative;
85
85
  z-index: 1;
86
+ padding: 2px 4px;
87
+ border-radius: $border-radius-small;
88
+
89
+ &:focus-visible{
90
+ box-shadow: 0 0 0 2px $color-blue-9;
91
+ }
86
92
 
87
93
  &:after{
88
94
  content: "";
89
95
  position: absolute;
90
- top: -2px;
91
- left: -4px;
92
- bottom: -2px;
93
- right: -4px;
96
+ inset: 0;
94
97
  opacity: 0;
95
98
  transform: scale(.6);
96
99
  transition: opacity .15s ease-in-out, transform .3s cubic-bezier(0.3, 0.76, 0.27, 1.5);
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="ecs-document-state">
2
+ <div class="ecs-document-state" :aria-busy="loading">
3
3
  <div v-if="ocr" class="txt" />
4
4
  <div v-else class="no-txt" />
5
5
  <div v-if="instantView" class="instant" />
@@ -1,13 +1,25 @@
1
1
  <template>
2
- <div @click="handleClick" class="ecs-dropdown" :class="[sizeClass, disabled ? 'disabled' : '', inline ? 'inline' : '']">
2
+ <div @click="handleClick"
3
+ class="ecs-dropdown"
4
+ :class="[sizeClass, disabled ? 'disabled' : '', inline ? 'inline' : '']"
5
+ role="button"
6
+ :aria-disabled="disabled"
7
+ :tabindex="disabled ? '-1' : '0'">
3
8
  <div class="ecs-dropdown-inner">
4
9
  <slot></slot>
5
10
  </div>
11
+ <ecs-focus-ring :inset="-5" />
6
12
  </div>
7
13
  </template>
8
14
 
9
15
  <script>
16
+ import EcsFocusRing from '../mixins/focus-ring'
17
+
10
18
  export default {
19
+ components: {
20
+ EcsFocusRing
21
+ },
22
+
11
23
  props: {
12
24
  /** Sets the size of the dropdown component. */
13
25
  size: {
@@ -60,10 +72,20 @@ export default {
60
72
  cursor: pointer;
61
73
  user-select: none;
62
74
 
75
+ &:focus-visible{
76
+ z-index: 1;
77
+ outline: none;
78
+
79
+ .ecs-focus-ring{
80
+ display: block;
81
+ }
82
+ }
83
+
63
84
  &:hover,
64
85
  &:focus{
65
86
  border-color: darken(rgba($color-gray-8, .4), 4%);
66
87
  box-shadow: 0 1px 1px rgba($color-gray-8, .1);
88
+ outline: none;
67
89
 
68
90
  &:after{
69
91
  opacity: .5;
@@ -8,7 +8,9 @@
8
8
  @dragenter="dragging=true"
9
9
  @dragleave="dragging=false"
10
10
  @drop.prevent="drop"
11
- @dragover.prevent>
11
+ @dragover.prevent
12
+ :aria-busy="loading || progress"
13
+ :aria-invalid="error">
12
14
 
13
15
  <input @change="change" type="file" :multiple="multiple" ref="file" />
14
16
 
@@ -16,7 +18,7 @@
16
18
  <ecs-skeleton-loader v-if="initializing" type="single" :width="100" class="ecs-dropzone-skeleton" />
17
19
  <div v-else>
18
20
  <template v-if="!$slots.customlabel">
19
- Drag and drop your {{ fileTypeLabel }} or <i @click="() => this.$refs.file.click()">browse</i> to upload.
21
+ Drag and drop your {{ fileTypeLabel }} or <i @click="browseFile" @keydown.enter="browseFile" tabindex="0">browse<ecs-focus-ring /></i> to upload.
20
22
  </template>
21
23
  <div v-if="$slots.customlabel">
22
24
  <!-- @slot Slot for a custom main label. Note: this will replace the file selector button as well as drag & drop label. Should only be used for states that do not require a drop action, such as active virus scanning. -->
@@ -40,13 +42,15 @@
40
42
  import EcsSkeletonLoader from '../skeleton-loader/skeleton-loader'
41
43
  import EcsProgress from '../progress/progress'
42
44
  import EcsButton from '../button/button'
45
+ import EcsFocusRing from '../mixins/focus-ring'
43
46
 
44
47
  export default {
45
48
  components: {
46
49
  EcsEmptyState,
47
50
  EcsSkeletonLoader,
48
51
  EcsProgress,
49
- EcsButton
52
+ EcsButton,
53
+ EcsFocusRing
50
54
  },
51
55
 
52
56
  props: {
@@ -149,6 +153,10 @@
149
153
  },
150
154
 
151
155
  methods: {
156
+ browseFile() {
157
+ this.$refs.file.click()
158
+ },
159
+
152
160
  drop({ dataTransfer }) {
153
161
  this.dragging = false
154
162
  const files = dataTransfer.files
@@ -220,6 +228,16 @@
220
228
  font-weight: $font-weight-medium;
221
229
  font-style: normal;
222
230
  cursor: pointer;
231
+ position: relative;
232
+
233
+ &:focus-visible{
234
+ z-index: 1;
235
+ outline: none;
236
+
237
+ .ecs-focus-ring{
238
+ display: block;
239
+ }
240
+ }
223
241
  }
224
242
 
225
243
  &-skeleton{
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="ecs-empty-state">
2
+ <div class="ecs-empty-state" :aria-busy="type == 'loading'">
3
3
  <ecs-icon v-if="type!='loading'" :type="type" :color="iconColor" :size="iconSize" />
4
4
  <div v-else class="ecs-empty-state-loading" />
5
5
  <div v-if="type!='loading'" class="ecs-empty-state-message" :class="size">