bootstrap-vue
Version:
BootstrapVue, with more than 85 custom components, over 45 plugins, several custom directives, and over 300 icons, provides one of the most comprehensive implementations of Bootstrap v4 components and grid system for Vue.js. With extensive and automated W
220 lines (189 loc) • 8.35 kB
JavaScript
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import Vue from '../../utils/vue';
import { mergeData } from 'vue-functional-data-merge';
import KeyCodes from '../../utils/key-codes';
import pluckProps from '../../utils/pluck-props';
import { concat } from '../../utils/array';
import { getComponentConfig } from '../../utils/config';
import { addClass, removeClass } from '../../utils/dom';
import { isBoolean, isEvent, isFunction } from '../../utils/inspect';
import { keys } from '../../utils/object';
import { toString } from '../../utils/string';
import { BLink, propsFactory as linkPropsFactory } from '../link/link'; // --- Constants --
var NAME = 'BButton';
var btnProps = {
block: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
size: {
type: String,
default: function _default() {
return getComponentConfig(NAME, 'size');
}
},
variant: {
type: String,
default: function _default() {
return getComponentConfig(NAME, 'variant');
}
},
type: {
type: String,
default: 'button'
},
tag: {
type: String,
default: 'button'
},
pill: {
type: Boolean,
default: false
},
squared: {
type: Boolean,
default: false
},
pressed: {
// Tri-state: `true`, `false` or `null`
// => On, off, not a toggle
type: Boolean,
default: null
}
};
var linkProps = linkPropsFactory();
delete linkProps.href.default;
delete linkProps.to.default;
var linkPropKeys = keys(linkProps);
export var props = _objectSpread(_objectSpread({}, linkProps), btnProps); // --- Helper methods ---
// Returns `true` if a tag's name equals `name`
var tagIs = function tagIs(tag, name) {
return toString(tag).toLowerCase() === toString(name).toLowerCase();
}; // Focus handler for toggle buttons
// Needs class of 'focus' when focused
var handleFocus = function handleFocus(evt) {
if (evt.type === 'focusin') {
addClass(evt.target, 'focus');
} else if (evt.type === 'focusout') {
removeClass(evt.target, 'focus');
}
}; // Is the requested button a link?
// If tag prop is set to `a`, we use a <b-link> to get proper disabled handling
var isLink = function isLink(props) {
return props.href || props.to || tagIs(props.tag, 'a');
}; // Is the button to be a toggle button?
var isToggle = function isToggle(props) {
return isBoolean(props.pressed);
}; // Is the button "really" a button?
var isButton = function isButton(props) {
return !(isLink(props) || props.tag && !tagIs(props.tag, 'button'));
}; // Is the requested tag not a button or link?
var isNonStandardTag = function isNonStandardTag(props) {
return !isLink(props) && !isButton(props);
}; // Compute required classes (non static classes)
var computeClass = function computeClass(props) {
var _ref;
return ["btn-".concat(props.variant || getComponentConfig(NAME, 'variant')), (_ref = {}, _defineProperty(_ref, "btn-".concat(props.size), props.size), _defineProperty(_ref, 'btn-block', props.block), _defineProperty(_ref, 'rounded-pill', props.pill), _defineProperty(_ref, 'rounded-0', props.squared && !props.pill), _defineProperty(_ref, "disabled", props.disabled), _defineProperty(_ref, "active", props.pressed), _ref)];
}; // Compute the link props to pass to b-link (if required)
var computeLinkProps = function computeLinkProps(props) {
return isLink(props) ? pluckProps(linkPropKeys, props) : null;
}; // Compute the attributes for a button
var computeAttrs = function computeAttrs(props, data) {
var button = isButton(props);
var link = isLink(props);
var toggle = isToggle(props);
var nonStandardTag = isNonStandardTag(props);
var hashLink = link && props.href === '#';
var role = data.attrs && data.attrs.role ? data.attrs.role : null;
var tabindex = data.attrs ? data.attrs.tabindex : null;
if (nonStandardTag || hashLink) {
tabindex = '0';
}
return {
// Type only used for "real" buttons
type: button && !link ? props.type : null,
// Disabled only set on "real" buttons
disabled: button ? props.disabled : null,
// We add a role of button when the tag is not a link or button for ARIA
// Don't bork any role provided in `data.attrs` when `isLink` or `isButton`
// Except when link has `href` of `#`
role: nonStandardTag || hashLink ? 'button' : role,
// We set the `aria-disabled` state for non-standard tags
'aria-disabled': nonStandardTag ? String(props.disabled) : null,
// For toggles, we need to set the pressed state for ARIA
'aria-pressed': toggle ? String(props.pressed) : null,
// `autocomplete="off"` is needed in toggle mode to prevent some browsers
// from remembering the previous setting when using the back button
autocomplete: toggle ? 'off' : null,
// `tabindex` is used when the component is not a button
// Links are tabbable, but don't allow disabled, while non buttons or links
// are not tabbable, so we mimic that functionality by disabling tabbing
// when disabled, and adding a `tabindex="0"` to non buttons or non links
tabindex: props.disabled && !button ? '-1' : tabindex
};
}; // @vue/component
export var BButton = /*#__PURE__*/Vue.extend({
name: NAME,
functional: true,
props: props,
render: function render(h, _ref2) {
var props = _ref2.props,
data = _ref2.data,
listeners = _ref2.listeners,
children = _ref2.children;
var toggle = isToggle(props);
var link = isLink(props);
var nonStandardTag = isNonStandardTag(props);
var hashLink = link && props.href === '#';
var on = {
keydown: function keydown(evt) {
// When the link is a `href="#"` or a non-standard tag (has `role="button"`),
// we add a keydown handlers for SPACE/ENTER
/* istanbul ignore next */
if (props.disabled || !(nonStandardTag || hashLink)) {
return;
}
var keyCode = evt.keyCode; // Add SPACE handler for `href="#"` and ENTER handler for non-standard tags
if (keyCode === KeyCodes.SPACE || keyCode === KeyCodes.ENTER && nonStandardTag) {
var target = evt.currentTarget || evt.target;
evt.preventDefault();
target.click();
}
},
click: function click(evt) {
/* istanbul ignore if: blink/button disabled should handle this */
if (props.disabled && isEvent(evt)) {
evt.stopPropagation();
evt.preventDefault();
} else if (toggle && listeners && listeners['update:pressed']) {
// Send `.sync` updates to any "pressed" prop (if `.sync` listeners)
// `concat()` will normalize the value to an array without
// double wrapping an array value in an array
concat(listeners['update:pressed']).forEach(function (fn) {
if (isFunction(fn)) {
fn(!props.pressed);
}
});
}
}
};
if (toggle) {
on.focusin = handleFocus;
on.focusout = handleFocus;
}
var componentData = {
staticClass: 'btn',
class: computeClass(props),
props: computeLinkProps(props),
attrs: computeAttrs(props, data),
on: on
};
return h(link ? BLink : props.tag, mergeData(data, componentData), children);
}
});