Skip to content

Commit c7dfd56

Browse files
authored
Merge branch 'dev' into fix-form-group-feedback-aria-role
2 parents 9913d86 + 05b8ffd commit c7dfd56

File tree

8 files changed

+162
-80
lines changed

8 files changed

+162
-80
lines changed

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,14 @@
9797
"@babel/plugin-transform-runtime": "^7.12.10",
9898
"@babel/preset-env": "^7.12.11",
9999
"@babel/standalone": "^7.12.12",
100-
"@nuxt/content": "^1.11.1",
100+
"@nuxt/content": "^1.12.0",
101101
"@nuxtjs/google-analytics": "^2.4.0",
102102
"@nuxtjs/pwa": "^3.3.5",
103103
"@nuxtjs/robots": "^2.4.2",
104104
"@nuxtjs/sitemap": "^2.4.0",
105105
"@testing-library/jest-dom": "^5.11.9",
106106
"@vue/test-utils": "^1.1.2",
107-
"autoprefixer": "^10.2.3",
107+
"autoprefixer": "^10.2.4",
108108
"babel-core": "^7.0.0-bridge.0",
109109
"babel-eslint": "^10.1.0",
110110
"babel-jest": "^26.6.3",
@@ -116,7 +116,7 @@
116116
"codesandbox": "^2.2.1",
117117
"core-js": "^3.8.3",
118118
"cross-env": "^7.0.3",
119-
"eslint": "^7.18.0",
119+
"eslint": "^7.19.0",
120120
"eslint-config-prettier": "^7.2.0",
121121
"eslint-config-standard": "^16.0.2",
122122
"eslint-config-vue": "^2.0.2",
@@ -143,7 +143,7 @@
143143
"postcss-cli": "^8.3.1",
144144
"prettier": "1.14.3",
145145
"require-context": "^1.1.0",
146-
"rollup": "^2.38.1",
146+
"rollup": "^2.38.3",
147147
"rollup-plugin-babel": "^4.4.0",
148148
"rollup-plugin-commonjs": "^10.1.0",
149149
"rollup-plugin-node-resolve": "^5.2.0",

src/components/form-tags/_form-tags.scss

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,4 @@
11
.b-form-tags {
2-
.b-form-tags-list {
3-
margin-top: -0.25rem;
4-
5-
.b-from-tags-field,
6-
.b-form-tag {
7-
margin-top: 0.25rem;
8-
}
9-
}
10-
112
&.focus {
123
color: $input-focus-color;
134
background-color: $input-focus-bg;
@@ -35,6 +26,19 @@
3526
}
3627
}
3728

29+
.b-form-tags-list {
30+
margin-top: -0.25rem;
31+
32+
.b-from-tags-field,
33+
.b-form-tag {
34+
margin-top: 0.25rem;
35+
}
36+
}
37+
38+
.b-form-tags-input {
39+
color: $input-color;
40+
}
41+
3842
.b-form-tag {
3943
// Override default badge settings
4044
// Due to using text-truncate on the inner content

src/components/form-tags/form-tags.js

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,7 @@ import { RX_SPACES } from '../../constants/regex'
1818
import { SLOT_NAME_DEFAULT, SLOT_NAME_ADD_BUTTON_TEXT } from '../../constants/slots'
1919
import { arrayIncludes, concat } from '../../utils/array'
2020
import { cssEscape } from '../../utils/css-escape'
21-
import {
22-
attemptBlur,
23-
attemptFocus,
24-
closest,
25-
isActiveElement,
26-
matches,
27-
requestAF,
28-
select
29-
} from '../../utils/dom'
21+
import { attemptBlur, attemptFocus, closest, matches, requestAF, select } from '../../utils/dom'
3022
import { eventOn, eventOff, stopEvent } from '../../utils/events'
3123
import { identity } from '../../utils/identity'
3224
import { isEvent, isNumber, isString } from '../../utils/inspect'
@@ -39,6 +31,7 @@ import { formControlMixin, props as formControlProps } from '../../mixins/form-c
3931
import { formSizeMixin, props as formSizeProps } from '../../mixins/form-size'
4032
import { formStateMixin, props as formStateProps } from '../../mixins/form-state'
4133
import { idMixin, props as idProps } from '../../mixins/id'
34+
import { listenersMixin } from '../../mixins/listeners'
4235
import { normalizeSlotMixin } from '../../mixins/normalize-slot'
4336
import { BButton } from '../button/button'
4437
import { BFormInvalidFeedback } from '../form/form-invalid-feedback'
@@ -144,6 +137,7 @@ const props = makePropsConfigurable(
144137
export const BFormTags = /*#__PURE__*/ Vue.extend({
145138
name: NAME_FORM_TAGS,
146139
mixins: [
140+
listenersMixin,
147141
idMixin,
148142
modelMixin,
149143
formControlMixin,
@@ -186,6 +180,7 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({
186180
},
187181
computedInputHandlers() {
188182
return {
183+
...this.bvListeners,
189184
input: this.onInputInput,
190185
change: this.onInputChange,
191186
keydown: this.onInputKeydown,
@@ -338,10 +333,6 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({
338333
// will prevent the tag from being removed (i.e. confirmation)
339334
// Or emit cancelable `BvEvent`
340335
this.tags = this.tags.filter(t => t !== tag)
341-
// Return focus to the input (if possible)
342-
this.$nextTick(() => {
343-
this.focus()
344-
})
345336
},
346337
reset() {
347338
this.newTag = ''
@@ -413,13 +404,8 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({
413404
},
414405
// --- Wrapper event handlers ---
415406
onClick(event) {
416-
const ignoreFocusSelector = this.computeIgnoreInputFocusSelector
417-
const { target } = event
418-
if (
419-
!this.disabled &&
420-
!isActiveElement(target) &&
421-
(!ignoreFocusSelector || !closest(ignoreFocusSelector, target, true))
422-
) {
407+
const { computeIgnoreInputFocusSelector: ignoreFocusSelector } = this
408+
if (!ignoreFocusSelector || !closest(ignoreFocusSelector, event.target, true)) {
423409
this.$nextTick(() => {
424410
this.focus()
425411
})
@@ -434,7 +420,7 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({
434420
handleAutofocus() {
435421
this.$nextTick(() => {
436422
requestAF(() => {
437-
if (this.autofocus && !this.disabled) {
423+
if (this.autofocus) {
438424
this.focus()
439425
}
440426
})

src/components/form-tags/form-tags.spec.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,4 +842,41 @@ describe('form-tags', () => {
842842

843843
wrapper.destroy()
844844
})
845+
846+
it('emits focus and blur events', async () => {
847+
const onFocus = jest.fn()
848+
const onBlur = jest.fn()
849+
const wrapper = mount(BFormTags, {
850+
propsData: {
851+
value: ['apple', 'orange']
852+
},
853+
listeners: {
854+
focus: onFocus,
855+
blur: onBlur
856+
}
857+
})
858+
859+
expect(onFocus).not.toHaveBeenCalled()
860+
expect(onBlur).not.toHaveBeenCalled()
861+
862+
const $input = wrapper.find('input')
863+
expect(typeof wrapper.vm.$listeners.focus).toBe('function')
864+
865+
$input.trigger('focus')
866+
$input.trigger('focusin')
867+
await waitNT(wrapper.vm)
868+
await waitRAF()
869+
870+
expect(onFocus).toHaveBeenCalled()
871+
expect(onBlur).not.toHaveBeenCalled()
872+
873+
$input.trigger('blur')
874+
$input.trigger('focusout')
875+
await waitNT(wrapper.vm)
876+
await waitRAF()
877+
878+
expect(onBlur).toHaveBeenCalled()
879+
880+
wrapper.destroy()
881+
})
845882
})

src/components/table/helpers/mixin-selectable.js

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,15 @@ import { isArray, isNumber } from '../../../utils/inspect'
1212
import { looseEqual } from '../../../utils/loose-equal'
1313
import { mathMax, mathMin } from '../../../utils/math'
1414
import { makeProp } from '../../../utils/props'
15+
import { toString } from '../../../utils/string'
1516
import { sanitizeRow } from './sanitize-row'
1617

1718
// --- Constants ---
1819

1920
const SELECT_MODES = ['range', 'multi', 'single']
2021

22+
const ROLE_GRID = 'grid'
23+
2124
// --- Props ---
2225

2326
export const props = {
@@ -70,17 +73,19 @@ export const selectableMixin = Vue.extend({
7073
}
7174
},
7275
selectableTableAttrs() {
73-
const role = this.bvAttrs.role || 'grid'
76+
if (!this.isSelectable) {
77+
return {}
78+
}
7479

75-
return this.isSelectable
76-
? {
77-
role,
78-
// TODO:
79-
// Should this attribute not be included when `no-select-on-click` is set
80-
// since this attribute implies keyboard navigation?
81-
'aria-multiselectable': role === 'grid' ? String(this.selectableIsMultiSelect) : null
82-
}
83-
: {}
80+
const role = this.bvAttrs.role || ROLE_GRID
81+
82+
return {
83+
role,
84+
// TODO:
85+
// Should this attribute not be included when `no-select-on-click` is set
86+
// since this attribute implies keyboard navigation?
87+
'aria-multiselectable': role === ROLE_GRID ? toString(this.selectableIsMultiSelect) : null
88+
}
8489
}
8590
},
8691
watch: {

src/components/table/helpers/mixin-table-renderer.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ export const tableRendererMixin = Vue.extend({
115115
const ariaAttrs = this.isTableSimple
116116
? {}
117117
: {
118-
'aria-busy': this.computedBusy ? 'true' : 'false',
118+
'aria-busy': toString(this.computedBusy),
119119
'aria-colcount': toString(fields.length),
120120
// Preserve user supplied `aria-describedby`, if provided
121121
'aria-describedby':
@@ -135,7 +135,7 @@ export const tableRendererMixin = Vue.extend({
135135
...this.bvAttrs,
136136
// Now we can override any `$attrs` here
137137
id: this.safeId(),
138-
role: 'table',
138+
role: this.bvAttrs.role || 'table',
139139
...ariaAttrs,
140140
...selectableTableAttrs
141141
}

src/components/table/table-selectable.spec.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,47 @@ describe('table > row select', () => {
5252
wrapper.destroy()
5353
})
5454

55+
it('should apply user role if provided, grid role if multiselectable or table role otherwise', async () => {
56+
let wrapper = mount(BTable, {
57+
propsData: {
58+
fields: testFields,
59+
items: testItems
60+
}
61+
})
62+
63+
expect(wrapper).toBeDefined()
64+
await waitNT(wrapper.vm)
65+
66+
expect(wrapper.attributes('role')).toBe('table')
67+
wrapper.destroy()
68+
69+
wrapper = mount(BTable, {
70+
propsData: {
71+
fields: testFields,
72+
items: testItems,
73+
role: 'foobar'
74+
}
75+
})
76+
77+
await waitNT(wrapper.vm)
78+
79+
expect(wrapper.attributes('role')).toBe('foobar')
80+
wrapper.destroy()
81+
82+
wrapper = mount(BTable, {
83+
propsData: {
84+
fields: testFields,
85+
items: testItems,
86+
selectable: true
87+
}
88+
})
89+
90+
await waitNT(wrapper.vm)
91+
92+
expect(wrapper.attributes('role')).toBe('grid')
93+
wrapper.destroy()
94+
})
95+
5596
it('should have tabindex but not aria-selected when not selectable and has row-clicked listener', async () => {
5697
const wrapper = mount(BTable, {
5798
propsData: {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy