1
1
import Vue from '../../utils/vue'
2
2
import { mergeData } from 'vue-functional-data-merge'
3
+
import KeyCodes from '../../utils/key-codes'
3
4
import pluckProps from '../../utils/pluck-props'
4
5
import { concat } from '../../utils/array'
5
6
import { getComponentConfig } from '../../utils/config'
@@ -47,8 +48,8 @@ const btnProps = {
47
48
default: false
48
49
},
49
50
pressed: {
50
-
// tri-state prop: true, false or null
51
-
// => on, off, not a toggle
51
+
// Tri-state: `true`, `false` or `null`
52
+
// => On, off, not a toggle
52
53
type: Boolean,
53
54
default: null
54
55
}
@@ -63,10 +64,11 @@ export const props = { ...linkProps, ...btnProps }
63
64
64
65
// --- Helper methods ---
65
66
66
-
// Returns true if a tag's name is name
67
+
// Returns `true` if a tag's name equals `name`
67
68
const tagIs = (tag, name) => toString(tag).toLowerCase() === toString(name).toLowerCase()
68
69
69
-
// Focus handler for toggle buttons. Needs class of 'focus' when focused.
70
+
// Focus handler for toggle buttons
71
+
// Needs class of 'focus' when focused
70
72
const handleFocus = evt => {
71
73
if (evt.type === 'focusin') {
72
74
addClass(evt.target, 'focus')
@@ -76,7 +78,7 @@ const handleFocus = evt => {
76
78
}
77
79
78
80
// Is the requested button a link?
79
-
// If tag prop is set to `a`, we use a b-link to get proper disabled handling
81
+
// If tag prop is set to `a`, we use a <b-link> to get proper disabled handling
80
82
const isLink = props => props.href || props.to || tagIs(props.tag, 'a')
81
83
82
84
// Is the button to be a toggle button?
@@ -109,31 +111,33 @@ const computeAttrs = (props, data) => {
109
111
const button = isButton(props)
110
112
const link = isLink(props)
111
113
const toggle = isToggle(props)
112
-
const nonStdTag = isNonStandardTag(props)
114
+
const nonStandardTag = isNonStandardTag(props)
115
+
const hashLink = link && props.href === '#'
113
116
const role = data.attrs && data.attrs.role ? data.attrs.role : null
114
117
let tabindex = data.attrs ? data.attrs.tabindex : null
115
-
if (nonStdTag) {
118
+
if (nonStandardTag || hashLink) {
116
119
tabindex = '0'
117
120
}
118
121
return {
119
122
// Type only used for "real" buttons
120
123
type: button && !link ? props.type : null,
121
124
// Disabled only set on "real" buttons
122
125
disabled: button ? props.disabled : null,
123
-
// We add a role of button when the tag is not a link or button for ARIA.
124
-
// Don't bork any role provided in data.attrs when isLink or isButton
125
-
role: nonStdTag ? 'button' : role,
126
-
// We set the aria-disabled state for non-standard tags
127
-
'aria-disabled': nonStdTag ? String(props.disabled) : null,
126
+
// We add a role of button when the tag is not a link or button for ARIA
127
+
// Don't bork any role provided in `data.attrs` when `isLink` or `isButton`
128
+
// Except when link has `href` of `#`
129
+
role: nonStandardTag || hashLink ? 'button' : role,
130
+
// We set the `aria-disabled` state for non-standard tags
131
+
'aria-disabled': nonStandardTag ? String(props.disabled) : null,
128
132
// For toggles, we need to set the pressed state for ARIA
129
133
'aria-pressed': toggle ? String(props.pressed) : null,
130
-
// autocomplete off is needed in toggle mode to prevent some browsers from
131
-
// remembering the previous setting when using the back button.
134
+
// `autocomplete="off"` is needed in toggle mode to prevent some browsers
135
+
// from remembering the previous setting when using the back button
132
136
autocomplete: toggle ? 'off' : null,
133
-
// Tab index is used when the component is not a button.
137
+
// `tabindex` is used when the component is not a button
134
138
// Links are tabbable, but don't allow disabled, while non buttons or links
135
139
// are not tabbable, so we mimic that functionality by disabling tabbing
136
-
// when disabled, and adding a tabindex of '0' to non buttons or non links.
140
+
// when disabled, and adding a `tabindex="0"` to non buttons or non links
137
141
tabindex: props.disabled && !button ? '-1' : tabindex
138
142
}
139
143
}
@@ -146,16 +150,33 @@ export const BButton = /*#__PURE__*/ Vue.extend({
146
150
render(h, { props, data, listeners, children }) {
147
151
const toggle = isToggle(props)
148
152
const link = isLink(props)
153
+
const nonStandardTag = isNonStandardTag(props)
154
+
const hashLink = link && props.href === '#'
149
155
const on = {
156
+
keydown(evt) {
157
+
// When the link is a `href="#"` or a non-standard tag (has `role="button"`),
158
+
// we add a keydown handlers for SPACE/ENTER
159
+
/* istanbul ignore next */
160
+
if (props.disabled || !(nonStandardTag || hashLink)) {
161
+
return
162
+
}
163
+
const { keyCode } = evt
164
+
// Add SPACE handler for `href="#"` and ENTER handler for non-standard tags
165
+
if (keyCode === KeyCodes.SPACE || (keyCode === KeyCodes.ENTER && nonStandardTag)) {
166
+
const target = evt.currentTarget || evt.target
167
+
evt.preventDefault()
168
+
target.click()
169
+
}
170
+
},
150
171
click(evt) {
151
172
/* istanbul ignore if: blink/button disabled should handle this */
152
173
if (props.disabled && isEvent(evt)) {
153
174
evt.stopPropagation()
154
175
evt.preventDefault()
155
176
} else if (toggle && listeners && listeners['update:pressed']) {
156
-
// Send .sync updates to any "pressed" prop (if .sync listeners)
157
-
// Concat will normalize the value to an array
158
-
// without double wrapping an array value in an array.
177
+
// Send `.sync` updates to any "pressed" prop (if `.sync` listeners)
178
+
// `concat()` will normalize the value to an array without
179
+
// double wrapping an array value in an array
159
180
concat(listeners['update:pressed']).forEach(fn => {
160
181
if (isFunction(fn)) {
161
182
fn(!props.pressed)
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