Repository URL to install this package:
|
Version:
0.0.9 ▾
|
import React from 'react';
import toClassName from 'classnames';
import { Link } from '@skava/link';
import { isFunction, isString } from 'exotic';
import { toCommonState } from '@skava/state';
import { toIdentifier } from '@skava/identifier';
import { Image } from '@skava/packages/ui';
import { classes } from './fixture';
import { StyledButton, StyledDiv, StyledInputButton, StyledButtonText } from './styled';
import { isImage } from './deps';
class Button extends React.Component {
constructor() {
super(...arguments);
this.state = toCommonState(this.props);
/**
* @description handles keydown enter - auto works with isFocused
*/
this.handleKeyDown = (event) => {
if (event.key === 'Enter') {
const baseButtonOnClick = this.props.onClick;
if (!isFunction(baseButtonOnClick)) {
this.handleClick(event);
}
// this.state.activate()
}
else if (event.key === 'Space' || event.key === ' ') {
// ada
if (this.isLink === true) {
this.handleClick(event);
// this.state.activate()
}
}
else {
console.log(event.key);
// @Note this causes errors on Tabbing through modals
// this.state.deactivate()
}
};
this.handleClick = (event) => {
console.log('BUTTON_CLICK');
const baseButtonOnClick = this.props.handleClick || this.props.onClick;
if (isFunction(baseButtonOnClick)) {
baseButtonOnClick(event);
}
};
}
/**
* @todo - state does not have these
*/
get isDisabled() {
// || this.state.isDisabled
return this.props.states === 'disabled' || this.props.isDisabled;
}
get isSelected() {
return this.props.states === 'selected' || this.props.isSelected || this.state.isSelected;
}
get isFocused() {
return this.props.states === 'focused' || this.props.isFocused || this.state.isFocused;
}
get isResting() {
return this.props.states === 'resting' || this.props.isResting || this.state.isResting;
}
get isPushed() {
return this.props.states === 'pushed' || this.props.isPushed || this.state.isPushed;
}
/**
* @alias isSecondary
* ^ (on a secondary button color......)
*
* @description makes it gray but not disabled, or less attention
* @return {Boolean}
*/
get isLowPriority() {
return this.props.isLowPriority;
}
/**
* @todo right, left... ?
*/
get className() {
const extendedClassName = this.extendedClassName || this.props.extendedClassName || '';
const defaultClassName = this.props.defaultClassName || '';
const className = this.props.className || '';
const isSquare = this.props.isSquare;
const squareClass = isSquare ? classes.default : '';
const iconOrder = this.props.iconOrder;
const dynamic = {
[classes.isIconLeft]: iconOrder === 'left' || !!iconOrder,
[classes.isIconRight]: iconOrder === 'right' || !!iconOrder,
[classes.isGhost]: this.props.ghost === true,
[classes.isLowPriority]: this.isLowPriority,
[classes.isSelected]: this.isSelected,
[classes.isDisabled]: this.isDisabled,
[classes.isFocused]: this.isFocused,
[classes.isResting]: this.isResting,
[classes.isPushed]: this.isPushed,
[classes.center]: this.props.center,
};
return toClassName(defaultClassName, squareClass, className, dynamic, extendedClassName);
}
/* eslint-disable brace-style */
get icon() {
const IconComponentOrView = this.props.icon;
// do we have one?
if (IconComponentOrView === undefined) {
return '';
}
// did we already render it?
else if (React.isValidElement(IconComponentOrView)) {
return IconComponentOrView;
}
// is a class/function/component
else if (isFunction(IconComponentOrView)) {
return React.createElement(IconComponentOrView, Object.assign({}, this.props, { key: "icon" }));
}
else if (isImage(IconComponentOrView)) {
return React.createElement(Image, { src: IconComponentOrView });
}
else {
/**
* @todo depending on event system - @see ReactEvents
*/
return '';
}
}
get isLink() {
return this.props.to !== undefined || this.props.isLink === true;
}
get role() {
return isString(this.props.role) ? this.props.role : this.isLink === true ? 'link' : 'button';
}
get target() {
return this.props.target;
}
get type() {
return this.props.type;
}
get identifier() {
return this.props.identifier || this.props.id || toIdentifier(this, 'button');
}
get children() {
return this.props.text || this.props.value || this.props.children;
}
get label() {
// || humanize(this.props.className) || throw new Error()
return this.props['aria-label'] || this.props.label || this.children;
}
// @todo tabindex for -1 inside of expandable divs
//
// @todo aria-flowto for compare & modal
// https://www.w3.org/TR/wai-aria/states_and_properties#aria-flowto
//
// @todo aria-controls
// https://www.w3.org/TR/wai-aria/states_and_properties#aria-controls
//
// @todo aria-busy
// https://www.w3.org/TR/wai-aria/states_and_properties#aria-busy
get accessibleAttributes() {
const accessibleAttributes = {
// @todo isToggle for toggle states
// 'aria-label': this.label,
// can use for controlledby and controls
id: this.identifier,
};
if (isString(this.label)) {
accessibleAttributes['aria-label'] = this.label;
}
if (this.role !== 'link') {
accessibleAttributes['aria-pressed'] = this.state.isActive;
}
if (isString(this.props.qa) || isString(this.props['data-qa'])) {
accessibleAttributes['data-qa'] = this.props.qa || this.props['data-qa'];
}
if (isString(this.props.form)) {
accessibleAttributes.form = this.props.form;
}
return accessibleAttributes;
}
get attributes() {
// should not use this.props.class ever as class is a js reserved word
// and also className is the React convection
const { className, icon, children, target, role } = this;
const { elementType } = this.props;
let text = isString(children) ? React.createElement(StyledButtonText, null, children) : children;
// const accessibleArea = <span className="button-accessible" />
// we may pass in a link element manually
if (this.isLink === true && this.props.to !== undefined) {
// @todo - linkClassName
text = (React.createElement(Link, { to: this.props.to, target: target }, text));
}
// @todo - text select none with just an icon
const hasIconAndText = icon && text;
// add icon if we have one
// to put icon after, either use `order` or we extend this
let value = hasIconAndText
? // both
[icon, text]
: icon
? // just icon
icon
: // just text
text;
if (elementType === 'inputButton') {
value = children;
}
return {
...this.props,
className,
value,
role: this.role,
tabIndex: this.tabIndex,
};
}
get tabIndex() {
if (this.props.tabIndex !== undefined) {
return this.props.tabIndex;
}
else if (this.props.isPresentational === true) {
/**
* @example a list of images like on the carousell,
* you want to tab each image,
* not tab the navigation
*/
return undefined;
}
else {
return '0';
}
}
get attributeProps() {
const { className, style, role, tabIndex } = this.attributes;
const attributes = {
className,
};
if (tabIndex !== undefined) {
attributes.style = style;
attributes.tabIndex = tabIndex;
}
if (this.props.onSubmit !== undefined) {
attributes.onSubmit = this.props.onSubmit;
}
// next will be <link
if (role !== 'button') {
attributes.role = role;
}
return attributes;
}
render() {
const { role, styles, value } = this.attributes;
const { elementType } = this.props;
const attributes = this.attributeProps;
const propsToPass = {
onFocus: this.state.handleFocus,
onBlur: this.state.handleBlur,
onKeyDown: this.handleKeyDown,
onClick: this.handleClick,
};
if (elementType === 'inputButton') {
return (React.createElement(StyledInputButton, Object.assign({ type: this.type, value: value }, propsToPass, attributes, this.accessibleAttributes)));
}
return role === 'button' || role !== 'link' ? (React.createElement(StyledButton, Object.assign({}, propsToPass, attributes, this.accessibleAttributes),
' ',
value,
' ')) : (React.createElement(StyledDiv, Object.assign({}, propsToPass, attributes, this.accessibleAttributes),
' ',
value,
' '));
}
}
Button.defaultProps = {
className: 'button-atom',
defaultClassName: '',
timeout: 60,
shouldAnimate: false,
isActive: false,
target: '',
};
export default Button;
export { Button };
//# sourceMappingURL=BaseButtonAtom.js.map