Repository URL to install this package:
Version:
0.14.1 ▾
|
import React from 'react'
import {
isFunction,
isString,
isReal,
isStringOrNumber,
EMPTY_OBJ,
NO_OP,
} from 'exotic'
import {
BaseButtonProps as Props,
ButtonState as State,
ButtonRole,
BaseButtonStandardProps,
AccessibleButtonAttributes,
PassThroughAttributes,
} from './typings'
import { classes } from './fixture'
export function toIconOrderClassName(props: Props) {
const { iconOrder } = props
switch (iconOrder) {
case 'left':
return -1
case 'right':
return 10
default:
return iconOrder
}
}
export function makeButtonState(props: Props): State {
// const state = {
// isFocused: !!props.isFocused,
// isDisabled: !!props.is
// }
// handleBlur = event => {
// }
// handleFocus = event => {
// }
}
/**
* ========= group 1 =========
*/
// this.hasSnackbar === true
export function isAnimated(props: Props): boolean {
return props.isAnimated === true || props.hasAnimation === true || props.shouldAnimate === true
}
export function isDisabled(props: Props): boolean {
return props.states === 'disabled' || props.isDisabled
}
export function isSelected(props: Props, state?: State): boolean {
return props.states === 'selected' || props.isSelected || state.isSelected
}
export function isFocused(props: Props, state?: State): boolean {
return props.states === 'focused' || props.isFocused || state.isFocused
}
export function isResting(props: Props, state?: State): boolean {
return props.states === 'resting' || props.isResting || state.isResting
}
export function isPushed(props: Props, state?: State): boolean {
return props.states === 'pushed' || props.isPushed || state.isPushed
}
export function isCenter(props: Props): boolean {
return Boolean(props.center || props.isCenter)
}
export function isLink(props: Props): boolean {
return props.to !== undefined || props.isLink === true
}
export function isGhost(props: Props): boolean {
return props.ghost || props.isGhost
}
export function isIconLeft(props: Props): boolean {
return props.iconOrder === 'left' || !!props.iconOrder
}
export function isIconRight(props: Props): boolean {
return props.iconOrder === 'right' || !!props.iconOrder
}
/**
* @alias isSecondary
* ^ (on a secondary button color......)
*
* @description makes it gray but not disabled, or less attention
*/
export function isLowPriority(props: Props): boolean {
return props.isLowPriority
}
export function hasSnackbar(props: Props): boolean {
return Boolean(
props.snackbarText !== undefined ||
props.snackbar !== undefined ||
props.onSnackbarClose !== undefined ||
props.onSnacbkarUndo !== undefined ||
props.snackbarTimeout !== undefined
)
}
export function toRemappedProps(props: Props, state: State = EMPTY_OBJ): BaseButtonStandardProps {
return {
isAnimated: isAnimated(props),
isDisabled: isDisabled(props),
isSelected: isSelected(props, state),
isFocused: isFocused(props, state),
isResting: isResting(props, state),
isPushed: isPushed(props, state),
isLowPriority: isLowPriority(props),
isLink: isLink(props),
isCenter: isCenter(props),
isGhost: isGhost(props),
hasSnackbar: hasSnackbar(props),
// yagni icon top bottom center - but it's used in mobile menu
isIconLeft: isIconLeft(props),
isIconRight: isIconRight(props),
// @todo this one is from the component...
eventHandlers: props.eventHandlers,
renderSnackbar: props.renderSnackbar,
renderIconAndText: props.renderIconAndText,
render: props.render,
}
}
/**
* @todo right, left... ?
*/
export function toButtonClassName(props: Props) {
// const extendedClassName = this.extendedClassName || this.props.extendedClassName || ''
const defaultClassName = props.defaultClassName || ''
const className = props.className || ''
const isSquare = props.isSquare
const squareClass = isSquare ? classes.default : ''
const states = props.states
const iconOrder = props.iconOrder
const dynamic = {
// ...priority 1-3?
// [classes.isHighPriority]: this.isHighPriority,
[classes.isIconLeft]: iconOrder === 'left' || !!iconOrder,
[classes.isIconRight]: iconOrder === 'right' || !!iconOrder,
[classes.isGhost]: isGhost,
[classes.isLowPriority]: isLowPriority,
[classes.isSelected]: isSelected,
[classes.isDisabled]: isDisabled,
[classes.isFocused]: isFocused,
[classes.isResting]: isResting,
[classes.isPushed]: isPushed,
[classes.center]: isCenter,
}
// 'button' - messes a lot
// return toClassName(defaultClassName, squareClass, className, dynamic, extendedClassName)
// return classnames(defaultClassName, className, this.props.class || '')
}
/**
* ========= group 2 =========
*/
export function toRole(props: Props): ButtonRole {
return isString(props.role) ? props.role : isLink(props) === true ? 'link' : 'button'
}
/**
* @todo toIdentifier(this, 'button')
*/
export function toIdentifier(props: Props): string {
return props.identifier || props.id
}
export function toChildren(props: Props): string {
return props.text || props.value || props.children
}
export function toLabel(props: Props): string | any {
// || humanize(props.className) || throw new Error()
return props['aria-label'] || props.label || toChildren(props)
}
export function toTabIndex(props: Props): string | number {
if (props.tabIndex !== undefined) {
return props.tabIndex
} else if (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'
}
// return '-1' ?
}
/**
* @alias toFinalProps
* @alias toPassThroughProps
* @alias attributeProps
*/
function toPassThroughProps(props: Props): PassThroughAttributes {
// style
const { className, role, tabIndex } = toAttributes(props)
const attributes: PassThroughAttributes = {
className,
}
if (tabIndex !== undefined) {
// attributes.style = style
}
if (tabIndex !== undefined) {
attributes.tabIndex = tabIndex
}
if (props.onSubmit !== undefined) {
attributes.onSubmit = props.onSubmit
}
// next will be <link
if (role !== 'button') {
attributes.role = role
}
return attributes
}
// unused
export function toStyles(props: Props) {
if (isReal(props.styled)) {
return props.styled
} else if (isString(props.height) || isString(props.width)) {
return {
height: props.height,
width: props.width,
}
} else {
return {}
}
}
// eslint-disable-next-line
export function toAttributes(props: Props, state: State) {
// const text = renderText(props, state)
// @todo !!!!!! but may not want to do it here
// const value = renderIconAndText(props, state)
return {
...props,
...toRemappedProps(props),
// value,
identifier: toIdentifier(props),
children: toChildren(props),
label: toLabel(props),
hasSnackbar: hasSnackbar(props),
tabIndex: toTabIndex(props),
role: toRole(props),
// className: toButtonClassName(props),
// styles: toStyles(props, state),
}
}
/**
* @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
*/
export function toAccessibleAttributes(props: Props, state: State): AccessibleButtonAttributes {
const label = toLabel(props)
const role = toRole(props)
const accessibleAttributes = {
// @todo isToggle for toggle states
// 'aria-label': this.label,
// can use for controlledby and controls
id: toIdentifier(props),
// ignoring this because button type button...
// 'role': this.role,
// 'aria-active'
}
if (isString(label)) {
accessibleAttributes['aria-label'] = label
}
if (role !== 'link') {
accessibleAttributes['aria-pressed'] = state.isActive
}
// should be `qa`?
if (isString(props.dataQa)) {
accessibleAttributes['data-qa'] = props.dataQa
}
return accessibleAttributes
}