@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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@everchron/ec-shards",
3
- "version": "6.2.2",
3
+ "version": "7.0.0",
4
4
  "private": false,
5
5
  "description": "Everchron Shards UI Library",
6
6
  "repository": "https://github.com/everchron/ec-shards.git",
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <transition name="action-bar">
3
- <div class="ecs-action-toolbar">
3
+ <div class="ecs-action-toolbar" role="toolbar" aria-label="Actions">
4
4
  <slot></slot>
5
5
  </div>
6
6
  </transition>
@@ -1,7 +1,8 @@
1
1
  <template>
2
- <div v-if="show" class="ecs-alert" :class="[typeClass, dismissable ? 'ecs-alert-dismissable' : '', inset ? 'ecs-alert-inset' : '']">
3
- <button v-if="dismissable" @click="dismiss" class="close">
2
+ <div v-if="show" class="ecs-alert" :class="[typeClass, dismissable ? 'ecs-alert-dismissable' : '', inset ? 'ecs-alert-inset' : '']" role="alert">
3
+ <button v-if="dismissable" @click="dismiss" class="close" aria-label="Dismiss">
4
4
  <ecs-icon type="close" size="20" />
5
+ <ecs-focus-ring />
5
6
  </button>
6
7
  <div class="ecs-alert-inner">
7
8
  <h4 v-if="headline" class="ecs-alert-headline">
@@ -12,15 +13,19 @@
12
13
  <slot></slot>
13
14
  </div>
14
15
  </div>
15
- <button v-if="actionLabel" @click="$emit('action')" class="action">{{ actionLabel }}</button>
16
+ <button v-if="actionLabel" @click="$emit('action')" class="action">
17
+ {{ actionLabel }}
18
+ <ecs-focus-ring />
19
+ </button>
16
20
  </div>
17
21
  </template>
18
22
 
19
23
  <script>
20
24
  import EcsIcon from '../icon/icon'
25
+ import EcsFocusRing from '../mixins/focus-ring'
21
26
 
22
27
  export default {
23
- components: { EcsIcon },
28
+ components: { EcsIcon, EcsFocusRing },
24
29
 
25
30
  props: {
26
31
  /** The alert variant, which defines it's background color. */
@@ -166,6 +171,15 @@
166
171
  border-radius: 0 0 3px 3px;
167
172
  position: relative;
168
173
 
174
+ &:focus-visible{
175
+ z-index: 1;
176
+ outline: none;
177
+
178
+ .ecs-focus-ring{
179
+ display: block;
180
+ }
181
+ }
182
+
169
183
  &:before,
170
184
  &:after{
171
185
  content: "";
@@ -244,6 +258,15 @@
244
258
  opacity: .15;
245
259
  }
246
260
  }
261
+
262
+ &:focus-visible{
263
+ z-index: 1;
264
+ outline: none;
265
+
266
+ .ecs-focus-ring{
267
+ display: block;
268
+ }
269
+ }
247
270
  }
248
271
  }
249
272
  </style>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="avatar" :style="[style, customStyle]" :class="partyClass">
2
+ <div class="avatar" :style="[style, customStyle]" :class="partyClass" :role="image ? 'img' : 'none'" :aria-label="name">
3
3
  <span v-if="!this.image">{{ userInitial }}</span>
4
4
  </div>
5
5
  </template>
@@ -165,6 +165,7 @@ export default {
165
165
  justify-content: center;
166
166
  align-items: center;
167
167
  position: relative;
168
+ user-select: none;
168
169
  font-weight: 700;
169
170
  color: rgba(#000, .2);
170
171
 
@@ -1,7 +1,7 @@
1
1
  <template>
2
- <div class="ecs-breadcrumb" :class="sizeClass">
2
+ <nav class="ecs-breadcrumb" :class="sizeClass" aria-label="breadcrumb">
3
3
  <slot></slot>
4
- </div>
4
+ </nav>
5
5
  </template>
6
6
 
7
7
  <script>
@@ -9,18 +9,21 @@
9
9
  >
10
10
  <ecs-icon v-if="icon" :type="icon" size="20" />
11
11
  <ecs-icon v-if="type == 'more'" type="more" size="20" />
12
- <span v-if="type != 'more'">
12
+ <span v-if="type != 'more'" class="ecs-breadcrumb-button-label">
13
13
  <slot></slot>
14
14
  </span>
15
+ <ecs-focus-ring />
15
16
  </button>
16
17
  </template>
17
18
 
18
19
  <script>
19
20
  import EcsIcon from '../icon/icon'
21
+ import EcsFocusRing from '../mixins/focus-ring'
20
22
 
21
23
  export default {
22
24
  components: {
23
- EcsIcon
25
+ EcsIcon,
26
+ EcsFocusRing
24
27
  },
25
28
 
26
29
  props: {
@@ -69,7 +72,16 @@
69
72
  max-width: 13%;
70
73
  cursor: default;
71
74
 
72
- > span{
75
+ &:focus-visible{
76
+ z-index: 1;
77
+ outline: none;
78
+
79
+ .ecs-focus-ring{
80
+ display: block;
81
+ }
82
+ }
83
+
84
+ &-label{
73
85
  text-overflow: ellipsis;
74
86
  overflow: hidden;
75
87
  white-space: nowrap;
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="ecs-breadcrumb-title">
2
+ <div class="ecs-breadcrumb-title" aria-current="page">
3
3
  <slot></slot>
4
4
  </div>
5
5
  </template>
@@ -1,5 +1,10 @@
1
1
  <template>
2
- <a v-if="href && !addon" :href="href" :target="target"
2
+ <a v-if="href && !addon"
3
+ :href="href"
4
+ :target="target"
5
+ :aria-label="ariaLabel"
6
+ :aria-busy="loading"
7
+ role="button"
3
8
  class="ecs-button"
4
9
  :class="[
5
10
  typeClass,
@@ -15,9 +20,12 @@
15
20
 
16
21
  <ecs-icon v-if="icon || loading" :type="iconType" :size="iconSize" />
17
22
  <slot></slot>
23
+ <ecs-focus-ring :inset="focusInset" :danger="type == 'danger' || type == 'danger-vibrant'" />
18
24
  </a>
19
25
 
20
- <button v-else-if="!addon"
26
+ <button v-else-if="!addon"
27
+ :aria-label="ariaLabel"
28
+ :aria-busy="loading"
21
29
  class="ecs-button"
22
30
  :class="[
23
31
  typeClass,
@@ -33,9 +41,11 @@
33
41
 
34
42
  <ecs-icon v-if="icon || loading" :type="iconType" :size="iconSize" />
35
43
  <slot></slot>
44
+ <ecs-focus-ring :inset="focusInset" :danger="type == 'danger' || type == 'danger-vibrant'" />
36
45
  </button>
37
46
 
38
- <button v-else
47
+ <button v-else
48
+ aria-label="More"
39
49
  class="ecs-button ecs-button-addon"
40
50
  :class="[
41
51
  typeClass,
@@ -45,17 +55,20 @@
45
55
  <svg width="8" height="6" viewBox="0 0 8 6" fill="none" xmlns="http://www.w3.org/2000/svg">
46
56
  <path d="M1 1.5L4 4.5L7 1.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
47
57
  </svg>
58
+ <ecs-focus-ring :inset="focusInset" :danger="type == 'danger' || type == 'danger-vibrant'" />
48
59
  </button>
49
60
  </template>
50
61
 
51
62
  <script>
52
63
  import EcsIcon from '../icon/icon'
53
64
  import EcsAnimations from '../animations/animations'
65
+ import EcsFocusRing from '../mixins/focus-ring'
54
66
 
55
67
  export default {
56
68
  components: {
57
69
  EcsIcon,
58
- EcsAnimations
70
+ EcsAnimations,
71
+ EcsFocusRing
59
72
  },
60
73
  props: {
61
74
  /** Defines the type of button, as well as it's designated importance. */
@@ -79,7 +92,10 @@
79
92
  /** Turns the button into a loading state, which makes it appear disabled and replaces the default icon (if set) with a spinner. */
80
93
  loading: Boolean,
81
94
  /** Shows only an icon, without any text labels. The `icon` prop is required. */
82
- iconOnly: Boolean,
95
+ iconOnly: {
96
+ type: Boolean,
97
+ default: false
98
+ },
83
99
  /** Makes the button to go full-width and take all available space of it's parent element. */
84
100
  fullWidth: Boolean,
85
101
  /** If the button should act as a link, you can set the href with this prop. */
@@ -87,7 +103,15 @@
87
103
  /** If the button should act as a link, this allows you to modify the target attribute. */
88
104
  target: String,
89
105
  /** Renders a small dropdown add-on button variant, which should only be used in combination with a regular button, and within an `EcsButtonGroup`. */
90
- addon: Boolean
106
+ addon: Boolean,
107
+ /** Aria-label is needed for iconOnly buttons to improve accessibility for screenreaders. */
108
+ ariaLabel: {
109
+ type: String
110
+ },
111
+ /** Allows to customize the margin of the focus ring, which can be helpful when the button is placed inside overflow containers. */
112
+ focusInset: {
113
+ type: Number
114
+ }
91
115
  },
92
116
 
93
117
  computed: {
@@ -96,17 +120,20 @@
96
120
  return `ecs-button-${this.type}`
97
121
  return this.type
98
122
  },
123
+
99
124
  iconType() {
100
125
  if (this.loading)
101
126
  return `loading`
102
127
  else
103
128
  return this.icon
104
129
  },
130
+
105
131
  sizeClass() {
106
132
  if (this.size && this.size !== '')
107
133
  return `ecs-button-${this.size}`
108
134
  return this.size
109
135
  },
136
+
110
137
  iconSize() {
111
138
  if (this.size == 'sml')
112
139
  return '20'
@@ -117,6 +144,12 @@
117
144
  else
118
145
  return '30'
119
146
  }
147
+ },
148
+
149
+ mounted() {
150
+ if (this.iconOnly && (!this.ariaLabel || this.ariaLabel.trim() === '')) {
151
+ console.warn('Warning: ariaLabel must be provided on buttons with only an icon and no label.');
152
+ }
120
153
  }
121
154
  }
122
155
  </script>
@@ -169,6 +202,14 @@
169
202
  outline: none;
170
203
  }
171
204
 
205
+ &:focus-visible{
206
+ z-index: 2;
207
+
208
+ .ecs-focus-ring{
209
+ display: block;
210
+ }
211
+ }
212
+
172
213
  .icon{
173
214
  margin-right: .4em;
174
215
  margin-left: -.4em;
@@ -233,10 +274,6 @@
233
274
  color: $color-blue-11;
234
275
  }
235
276
 
236
- &:focus{
237
- box-shadow: 0 0 0 2px rgba($color-blue-8, .1);
238
- }
239
-
240
277
  &:active,
241
278
  &.active{
242
279
  color: $color-blue-10;
@@ -251,99 +288,81 @@
251
288
  }
252
289
 
253
290
  &-secondary{
254
- color: $color-gray-8;
291
+ color: $color-gray-10;
255
292
 
256
293
  &:after{
257
- background: rgba($color-gray-8, .07);
294
+ background: rgba($color-gray-10, .07);
258
295
  }
259
296
 
260
297
  &:hover{
261
- color: $color-gray-10;
262
- }
263
-
264
- &:focus{
265
- box-shadow: 0 0 0 2px rgba($color-gray-8, .1);
298
+ color: $color-gray-11;
266
299
  }
267
300
 
268
301
  &:active,
269
302
  &.active{
270
- color: $color-gray-9;
303
+ color: $color-gray-11;
271
304
  background: $color-gray-1;
272
305
  box-shadow: none;
273
306
  }
274
307
 
275
308
  &.highlighted{
276
- background: $color-gray-8;
309
+ background: $color-gray-10;
277
310
  color: #FFF;
278
311
  }
279
312
  }
280
313
 
281
314
  &-danger{
282
- color: $color-gray-8;
315
+ color: $color-gray-10;
283
316
 
284
317
  &:after{
285
318
  background: rgba($color-red-8, .07);
286
319
  }
287
320
 
288
321
  &:hover{
289
- color: $color-red-10;
290
- }
291
-
292
- &:focus{
293
- box-shadow: 0 0 0 2px rgba($color-red-8, .1);
294
- color: $color-red-9;
322
+ color: $color-red-12;
295
323
  }
296
324
 
297
325
  &:active,
298
326
  &.active{
299
- color: $color-red-9;
327
+ color: $color-red-12;
300
328
  background: $color-red-2;
301
329
  box-shadow: none;
302
330
  }
303
331
  }
304
332
 
305
333
  &-danger-vibrant{
306
- color: $color-red-9;
334
+ color: $color-red-11;
307
335
 
308
336
  &:after{
309
337
  background: rgba($color-red-8, .07);
310
338
  }
311
339
 
312
340
  &:hover{
313
- color: $color-red-10;
314
- }
315
-
316
- &:focus{
317
- box-shadow: 0 0 0 2px rgba($color-red-8, .1);
318
- color: $color-red-9;
341
+ color: $color-red-12;
319
342
  }
320
343
 
321
344
  &:active,
322
345
  &.active{
323
- color: $color-red-9;
346
+ color: $color-red-12;
324
347
  background: $color-red-2;
325
348
  box-shadow: none;
326
349
  }
327
350
  }
328
351
 
329
352
  &-warning{
330
- color: $color-yellow-9;
353
+ color: $color-yellow-12;
331
354
 
332
355
  &:after{
333
356
  background: rgba($color-yellow-7, .14);
334
357
  }
335
358
 
336
359
  &:hover{
337
- color: $color-yellow-10;
338
- }
339
-
340
- &:focus{
341
- box-shadow: 0 0 0 2px rgba($color-yellow-7, .2);
360
+ color: $color-yellow-12;
342
361
  }
343
362
 
344
363
  &:active,
345
364
  &.active{
346
- color: $color-yellow-10;
365
+ color: $color-yellow-12;
347
366
  background: $color-yellow-2;
348
367
  box-shadow: none;
349
368
  }
@@ -351,24 +370,20 @@
351
370
 
352
371
  &-create{
353
372
  color: #FFF;
354
- background: $color-green-9;
373
+ background: $color-green-10;
355
374
 
356
375
  .icon{
357
376
  color: #FFF;
358
377
  }
359
378
 
360
379
  &:hover{
361
- background: $color-green-10;
380
+ background: $color-green-11;
362
381
  box-shadow: 0 1px 0 rgba(#000, 0.02);
363
382
  }
364
383
 
365
- &:focus{
366
- box-shadow: 0 0 0 3px rgba($color-green-10, .1);
367
- }
368
-
369
384
  &:active,
370
385
  &.active{
371
- background: $color-green-10;
386
+ background: $color-green-11;
372
387
  box-shadow: none;
373
388
  }
374
389
  }
@@ -381,10 +396,6 @@
381
396
  background: $color-blue-10;
382
397
  }
383
398
 
384
- &:focus{
385
- box-shadow: 0 0 0 3px rgba($color-blue-10, .1);
386
- }
387
-
388
399
  &:active,
389
400
  &.active{
390
401
  background: $color-blue-10;
@@ -418,7 +429,7 @@
418
429
 
419
430
  .ecs-button-addon{
420
431
  &.ecs-button-sml{
421
- padding: 0 $spacing-5;
432
+ padding: 0 6px;
422
433
  }
423
434
 
424
435
  &.ecs-button-md{
@@ -1,16 +1,30 @@
1
1
  <template>
2
2
  <button
3
3
  class="ecs-collapse-button"
4
+ :aria-expanded="!collapsed"
5
+ :aria-label="collapsed ? 'Expand' : 'Collapse'"
6
+ :aria-controls="ariaControls"
7
+ :aria-busy="loading"
8
+ :aria-disabled="disabled"
9
+ :disabled="disabled"
4
10
  :class="[
5
11
  typeClass,
6
12
  collapsed ? `collapsed` : '',
7
13
  loading ? `loading` : '']"
8
14
  @click="$emit('click', $event)">
15
+
16
+ <ecs-focus-ring />
9
17
  </button>
10
18
  </template>
11
19
 
12
20
  <script>
21
+ import EcsFocusRing from '../mixins/focus-ring'
22
+
13
23
  export default {
24
+ components: {
25
+ EcsFocusRing
26
+ },
27
+
14
28
  props: {
15
29
  /** Defines the type of button: `classic` shows a +/-, while `chevron` shows a rotating arrow. */
16
30
  type: {
@@ -22,6 +36,15 @@
22
36
  collapsed: Boolean,
23
37
  /** Turns the button into a loading state. */
24
38
  loading: Boolean,
39
+ /** Sets the button state to disabled and prevents click events. */
40
+ disabled: {
41
+ type: Boolean,
42
+ default: false
43
+ },
44
+ /** Pass the ID of the element which is expanded/collapsed by this button to improve accessiblity. */
45
+ ariaControls: {
46
+ type: String
47
+ }
25
48
  },
26
49
 
27
50
  computed: {
@@ -46,6 +69,14 @@
46
69
  cursor: pointer;
47
70
  flex-shrink: 0;
48
71
 
72
+ &:focus-visible{
73
+ z-index: 1;
74
+
75
+ .ecs-focus-ring{
76
+ display: block;
77
+ }
78
+ }
79
+
49
80
  &-chevron{
50
81
  transition: .3s;
51
82
  transform: rotate(45deg);
@@ -76,20 +107,20 @@
76
107
  &:after{
77
108
  content: "";
78
109
  position: absolute;
79
- width: 11px;
80
- height: 11px;
81
- top: 4px;
82
- left: 4px;
110
+ width: 20px;
111
+ height: 20px;
112
+ top: 0;
113
+ left: 0;
83
114
  transition: .2s;
84
115
  }
85
116
 
86
117
  &:before{
87
118
  opacity: 0;
88
- background: svg-uri('<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 11 11"><g fill="none" fill-rule="evenodd"><rect width="10" height="10" x=".5" y=".5" fill="#858E9E" fill-opacity=".1" stroke="#858E9E" stroke-opacity=".5" rx="2"/><rect width="5" height="1" x="3" y="5" fill="#858E9E"/><rect width="1" height="5" x="5" y="3" fill="#858E9E"/></g></svg>');
119
+ background: svg-uri('<svg width="20" height="20" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="5" y="5" width="11" height="11" rx="2" fill="#858E9E" fill-opacity=".1"/><rect x="5.5" y="5.5" width="10" height="10" rx="1.5" stroke="#858E9E" stroke-opacity=".5"/><path fill-rule="evenodd" clip-rule="evenodd" d="M11 8h-1v2H8v1h2v2h1v-2h2v-1h-2V8Z" fill="#858E9E"/></svg>');
89
120
  }
90
121
 
91
122
  &:after{
92
- background: svg-uri('<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 11 11"><g fill="none" fill-rule="evenodd"><rect width="10" height="10" x=".5" y=".5" fill="#FFFFFF" stroke="#858E9E" stroke-opacity=".5" rx="2"/><rect width="5" height="1" x="3" y="5" fill="#717987"/></g></svg>');
123
+ background: svg-uri('<svg width="20" height="20" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="5" y="5" width="11" height="11" rx="2" fill="#fff"/><rect x="5.5" y="5.5" width="10" height="10" rx="1.5" stroke="#858E9E" stroke-opacity=".5"/><path d="M13 10v1H8v-1h5Z" fill="#75798F"/></svg>');
93
124
  }
94
125
  }
95
126
 
@@ -127,4 +158,16 @@
127
158
  cursor: not-allowed;
128
159
  }
129
160
  }
161
+
162
+ @media (-webkit-min-device-pixel-ratio: 2),(min-resolution: 192dpi){
163
+ .ecs-collapse-button-classic{
164
+ &:before{
165
+ background: svg-uri('<svg width="20" height="20" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="4" y="4" width="12" height="12" rx="3" fill="#858E9E" fill-opacity=".1"/><rect x="4.5" y="4.5" width="11" height="11" rx="2.5" stroke="#858E9E" stroke-opacity=".5"/><path fill-rule="evenodd" clip-rule="evenodd" d="M10.5 7.5h-1v2h-2v1h2v2h1v-2h2v-1h-2v-2Z" fill="#858E9E"/></svg>');
166
+ }
167
+
168
+ &:after{
169
+ background: svg-uri('<svg width="20" height="20" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="4" y="4" width="12" height="12" rx="3" fill="#fff"/><rect x="4.5" y="4.5" width="11" height="11" rx="2.5" stroke="#858E9E" stroke-opacity=".5"/><path d="M12.5 9.5v1h-5v-1h5Z" fill="#75798F"/></svg>');
170
+ }
171
+ }
172
+ }
130
173
  </style>
@@ -1,6 +1,8 @@
1
1
  <template>
2
2
  <button
3
3
  class="ecs-context-button"
4
+ :aria-label="ariaLabel"
5
+ :arial-busy="loading"
4
6
  :class="[loading ? `loading` : '', iconOnly ? 'ecs-context-button-icon-only' : '']"
5
7
  :style="selectedColorText"
6
8
  @click="$emit('click', $event)">
@@ -8,15 +10,20 @@
8
10
  <ecs-icon v-if="icon || loading" :type="iconType" size="20" />
9
11
  <div v-if="selectedColor" class="ecs-context-button-color" :style="selectedColorBackground" />
10
12
  <slot></slot>
13
+ <ecs-focus-ring />
11
14
  </button>
12
15
  </template>
13
16
 
14
17
  <script>
15
18
  import EcsIcon from '../icon/icon'
19
+ import EcsFocusRing from '../mixins/focus-ring'
20
+
16
21
  export default {
17
22
  components: {
18
- EcsIcon
23
+ EcsIcon,
24
+ EcsFocusRing
19
25
  },
26
+
20
27
  props: {
21
28
  /** If set, an icon will be added to the left of the button. The list of available icon names can be found [here](https://github.com/everchron/ec-shards/tree/main/src/assets/icons). */
22
29
  icon: {
@@ -33,6 +40,10 @@
33
40
  type: String,
34
41
  default: null
35
42
  },
43
+ /** Aria-label is needed for iconOnly buttons to improve accessibility for screenreaders. */
44
+ ariaLabel: {
45
+ type: String
46
+ }
36
47
  },
37
48
 
38
49
  computed: {
@@ -43,17 +54,26 @@
43
54
  return this.icon
44
55
  return this.icon
45
56
  },
57
+
46
58
  iconOnly() {
47
59
  return this.icon && !this.$slots.default
48
60
  },
61
+
49
62
  selectedColorBackground() {
50
63
  if (this.selectedColor)
51
64
  return `background-color:${this.selectedColor};`
52
65
  },
66
+
53
67
  selectedColorText() {
54
68
  if (this.selectedColor)
55
69
  return `color:${this.selectedColor};`
56
70
  }
71
+ },
72
+
73
+ mounted() {
74
+ if (this.iconOnly && (!this.ariaLabel || this.ariaLabel.trim() === '')) {
75
+ console.warn('Warning: ariaLabel must be provided on buttons with only an icon and no label.');
76
+ }
57
77
  }
58
78
  }
59
79
  </script>
@@ -75,6 +95,15 @@
75
95
  cursor: pointer;
76
96
  border-right: 1px solid #5D6067;
77
97
  flex-shrink: 0;
98
+ position: relative;
99
+
100
+ &:focus-visible{
101
+ z-index: 1;
102
+
103
+ .ecs-focus-ring{
104
+ display: block;
105
+ }
106
+ }
78
107
 
79
108
  .icon{
80
109
  margin: 0 4px 0 -4px;