A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/bootstrap-vue/bootstrap-vue/commit/2328630542defc395912165a964a95107f8a4ba9 below:

improve accessibility for screen reader users (#4775) · bootstrap-vue/bootstrap-vue@2328630 · GitHub

1 1

// Tagged input form control

2 2

// Based loosely on https://adamwathan.me/renderless-components-in-vuejs/

3 3

import Vue from '../../utils/vue'

4 -

import identity from '../../utils/identity'

5 4

import KeyCodes from '../../utils/key-codes'

5 +

import identity from '../../utils/identity'

6 6

import looseEqual from '../../utils/loose-equal'

7 7

import { arrayIncludes, concat } from '../../utils/array'

8 8

import { getComponentConfig } from '../../utils/config'

@@ -11,10 +11,10 @@ import { isEvent, isFunction, isString } from '../../utils/inspect'

11 11

import { escapeRegExp, toString, trim, trimLeft } from '../../utils/string'

12 12

import idMixin from '../../mixins/id'

13 13

import normalizeSlotMixin from '../../mixins/normalize-slot'

14 -

import { BFormTag } from './form-tag'

14 +

import { BButton } from '../button/button'

15 15

import { BFormInvalidFeedback } from '../form/form-invalid-feedback'

16 16

import { BFormText } from '../form/form-text'

17 -

import { BButton } from '../button/button'

17 +

import { BFormTag } from './form-tag'

18 18 19 19

// --- Constants ---

20 20

@@ -26,6 +26,9 @@ const TYPES = ['text', 'email', 'tel', 'url', 'number']

26 26

// Pre-compiled regular expressions for performance reasons

27 27

const RX_SPACES = /[\s\uFEFF\xA0]+/g

28 28 29 +

// KeyCode constants

30 +

const { ENTER, BACKSPACE, DELETE } = KeyCodes

31 + 29 32

// --- Utility methods ---

30 33 31 34

// Escape special chars in string and replace

@@ -132,6 +135,10 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({

132 135

type: String,

133 136

default: () => getComponentConfig(NAME, 'tagRemoveLabel')

134 137

},

138 +

tagRemovedLabel: {

139 +

type: String,

140 +

default: () => getComponentConfig(NAME, 'tagRemovedLabel')

141 +

},

135 142

tagValidator: {

136 143

type: Function,

137 144

default: null

@@ -182,6 +189,8 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({

182 189

hasFocus: false,

183 190

newTag: '',

184 191

tags: [],

192 +

// Tags that were removed

193 +

removedTags: [],

185 194

// Populated when tags are parsed

186 195

tagsState: cleanTagsState()

187 196

}

@@ -263,11 +272,16 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({

263 272

value(newVal) {

264 273

this.tags = cleanTags(newVal)

265 274

},

266 -

tags(newVal) {

275 +

tags(newVal, oldVal) {

267 276

// Update the `v-model` (if it differs from the value prop)

268 277

if (!looseEqual(newVal, this.value)) {

269 278

this.$emit('input', newVal)

270 279

}

280 +

if (!looseEqual(newVal, oldVal)) {

281 +

newVal = concat(newVal).filter(identity)

282 +

oldVal = concat(oldVal).filter(identity)

283 +

this.removedTags = oldVal.filter(old => !arrayIncludes(newVal, old))

284 +

}

271 285

},

272 286

tagsState(newVal, oldVal) {

273 287

// Emit a tag-state event when the `tagsState` object changes

@@ -336,7 +350,9 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({

336 350

// Or emit cancelable `BvEvent`

337 351

this.tags = this.tags.filter(t => t !== tag)

338 352

// Return focus to the input (if possible)

339 -

this.focus()

353 +

this.$nextTick(() => {

354 +

this.focus()

355 +

})

340 356

},

341 357

// --- Input element event handlers ---

342 358

onInputInput(evt) {

@@ -383,20 +399,26 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({

383 399

const keyCode = evt.keyCode

384 400

const value = evt.target.value || ''

385 401

/* istanbul ignore else: testing to be added later */

386 -

if (!this.noAddOnEnter && keyCode === KeyCodes.ENTER) {

402 +

if (!this.noAddOnEnter && keyCode === ENTER) {

387 403

// Attempt to add the tag when user presses enter

388 404

evt.preventDefault()

389 405

this.addTag()

390 -

} else if (this.removeOnDelete && keyCode === KeyCodes.BACKSPACE && value === '') {

391 -

// Remove the last tag if the user pressed backspace and the input is empty

406 +

} else if (

407 +

this.removeOnDelete &&

408 +

(keyCode === BACKSPACE || keyCode === DELETE) &&

409 +

value === ''

410 +

) {

411 +

// Remove the last tag if the user pressed backspace/delete and the input is empty

392 412

evt.preventDefault()

393 -

this.tags.pop()

413 +

this.tags = this.tags.slice(0, -1)

394 414

}

395 415

},

396 416

// --- Wrapper event handlers ---

397 417

onClick(evt) {

398 418

if (!this.disabled && isEvent(evt) && evt.target === evt.currentTarget) {

399 -

this.$nextTick(this.focus)

419 +

this.$nextTick(() => {

420 +

this.focus()

421 +

})

400 422

}

401 423

},

402 424

onFocusin() {

@@ -512,7 +534,7 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({

512 534

staticClass: 'mt-1 mr-1',

513 535

class: tagClass,

514 536

props: {

515 -

// 'BFormTag' will auto generate an ID

537 +

// `BFormTag` will auto generate an ID

516 538

// so we do not need to set the ID prop

517 539

tag: 'li',

518 540

title: tag,

@@ -591,10 +613,14 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({

591 613

'li',

592 614

{

593 615

key: '__li-input__',

594 -

staticClass: 'd-inline-flex flex-grow-1 mt-1',

595 -

attrs: { role: 'group', 'aria-live': 'off', 'aria-controls': tagListId }

616 +

staticClass: 'flex-grow-1 mt-1',

617 +

attrs: {

618 +

role: 'none',

619 +

'aria-live': 'off',

620 +

'aria-controls': tagListId

621 +

}

596 622

},

597 -

[$input, $button]

623 +

[h('div', { staticClass: 'd-flex', attrs: { role: 'group' } }, [$input, $button])]

598 624

)

599 625 600 626

// Wrap in an unordered list element (we use a list for accessibility)

@@ -603,16 +629,7 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({

603 629

{

604 630

key: '_tags_list_',

605 631

staticClass: 'list-unstyled mt-n1 mb-0 d-flex flex-wrap align-items-center',

606 -

attrs: {

607 -

id: tagListId,

608 -

// Don't interrupt the user abruptly

609 -

// Although maybe this should be 'assertive'

610 -

// to provide immediate feedback of the tag added/removed

611 -

'aria-live': 'polite',

612 -

// Only read elements that have been added or removed

613 -

'aria-atomic': 'false',

614 -

'aria-relevant': 'additions removals'

615 -

}

632 +

attrs: { id: tagListId }

616 633

},

617 634

// `concat()` is faster than array spread when args are known to be arrays

618 635

concat($tags, $field)

@@ -707,6 +724,38 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({

707 724

// Generate the user interface

708 725

const $content = this.normalizeSlot('default', scope) || this.defaultRender(scope)

709 726 727 +

// Generate the `aria-live` region for the current value(s)

728 +

const $output = h(

729 +

'output',

730 +

{

731 +

staticClass: 'sr-only',

732 +

attrs: {

733 +

id: this.safeId('_selected-tags_'),

734 +

role: 'status',

735 +

for: this.computedInputId,

736 +

'aria-live': this.hasFocus ? 'polite' : 'off',

737 +

'aria-atomic': 'true',

738 +

'aria-relevant': 'additions text'

739 +

}

740 +

},

741 +

this.tags.join(', ')

742 +

)

743 + 744 +

// Removed tag live region

745 +

const $removed = h(

746 +

'div',

747 +

{

748 +

staticClass: 'sr-only',

749 +

attrs: {

750 +

id: this.safeId('_removed-tags_'),

751 +

role: 'status',

752 +

'aria-live': this.hasFocus ? 'assertive' : 'off',

753 +

'aria-atomic': 'true'

754 +

}

755 +

},

756 +

this.removedTags.length > 0 ? `(${this.tagRemovedLabel}) ${this.removedTags.join(', ')}` : ''

757 +

)

758 + 710 759

// Add hidden inputs for form submission

711 760

let $hidden = h()

712 761

if (this.name && !this.disabled) {

@@ -740,15 +789,16 @@ export const BFormTags = /*#__PURE__*/ Vue.extend({

740 789

attrs: {

741 790

id: this.safeId(),

742 791

role: 'group',

743 -

tabindex: this.disabled || this.noOuterFocus ? null : '-1'

792 +

tabindex: this.disabled || this.noOuterFocus ? null : '-1',

793 +

'aria-describedby': this.safeId('_selected_')

744 794

},

745 795

on: {

746 796

focusin: this.onFocusin,

747 797

focusout: this.onFocusout,

748 798

click: this.onClick

749 799

}

750 800

},

751 -

concat($content, $hidden)

801 +

concat($output, $removed, $content, $hidden)

752 802

)

753 803

}

754 804

})


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4