Skip to content
This repository has been archived by the owner on May 24, 2024. It is now read-only.

[terra-button] Create selectable button #3940

Merged
merged 9 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/terra-button/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* Changed
* Added support of selection state for Fusion-Button

## 3.68.2 - (October 3, 2023)

* Fixed
Expand Down
34 changes: 26 additions & 8 deletions packages/terra-button/src/Button.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ const defaultProps = {
class Button extends React.Component {
constructor(props) {
super(props);
this.state = { active: false, focused: false };
this.state = { active: false, focused: false, isSelected: false };
this.handleKeyDown = this.handleKeyDown.bind(this);
this.handleKeyUp = this.handleKeyUp.bind(this);
this.handleOnBlur = this.handleOnBlur.bind(this);
Expand All @@ -144,7 +144,7 @@ class Button extends React.Component {
}
}

handleClick(event) {
handleClick(event, isSelectable) {
// See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Button#Clicking_and_focus
// Button on Firefox, Safari and IE running on OS X does not receive focus when clicked.
// This will put focus on the button when clicked if it is not currently the active element.
Expand All @@ -155,11 +155,15 @@ class Button extends React.Component {
}

if (this.props.onClick) {
this.props.onClick(event);
if (isSelectable) {
this.props.onClick(event, this.state.isSelected);
} else {
this.props.onClick(event);
}
}
}

handleKeyDown(event) {
handleKeyDown(event, isSelectable) {
// Add active state to FF browsers
if (event.nativeEvent.keyCode === KeyCode.KEY_SPACE) {
this.setState({ active: true });
Expand All @@ -175,6 +179,9 @@ class Button extends React.Component {
// Add focus styles for keyboard navigation
if (event.nativeEvent.keyCode === KeyCode.KEY_SPACE || event.nativeEvent.keyCode === KeyCode.KEY_RETURN) {
this.setState({ focused: true });
if (isSelectable) {
this.setState(prevState => ({ isSelected: !prevState.isSelected }));
}
}

if (this.props.onKeyDown) {
Expand Down Expand Up @@ -208,10 +215,13 @@ class Button extends React.Component {
}
}

handleMouseDown(event) {
handleMouseDown(event, isSelectable) {
if (this.props.onMouseDown) {
this.props.onMouseDown(event);
}
if (isSelectable) {
this.setState(prevState => ({ isSelected: !prevState.isSelected }));
}

// See https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/focus#Notes
// If you call HTMLElement.focus() from a mousedown event handler, you must call event.preventDefault() to keep the focus from leaving the HTMLElement.
Expand Down Expand Up @@ -246,6 +256,9 @@ class Button extends React.Component {
const isMac = () => navigator.userAgent.indexOf('Mac') !== -1;
const buttonLabelCx = isMac() ? 'button-label-mac' : 'button-label-win';

// TODO: `isSelectable` prop is used for fusion pass through passivity and should be removed after Fusion Phase2 release.
const { isSelectable } = customProps;

const buttonClasses = classNames(
cx([
'button',
Expand All @@ -255,6 +268,7 @@ class Button extends React.Component {
{ compact: isCompact },
{ 'is-active': this.state.active && !isDisabled },
{ 'is-focused': this.state.focused && !isDisabled },
{ 'is-selected': isSelectable && this.state.isSelected && !isDisabled },
theme.className,
]),
customProps.className,
Expand Down Expand Up @@ -302,6 +316,10 @@ class Button extends React.Component {
ariaLabel = (icon && icon.props.a11yLabel) ? icon.props.a11yLabel : ariaLabel || text;
}

if (isSelectable) {
customProps['aria-pressed'] = this.state.isSelected;
}

let ComponentType = 'button';
if (href) {
ComponentType = 'a';
Expand All @@ -317,12 +335,12 @@ class Button extends React.Component {
tabIndex={isDisabled ? '-1' : customProps.tabIndex}
aria-disabled={isDisabled}
aria-label={ariaLabel}
onKeyDown={this.handleKeyDown}
onKeyDown={(event) => { this.handleKeyDown(event, isSelectable); }}
onKeyUp={this.handleKeyUp}
onBlur={this.handleOnBlur}
title={buttonTitle}
onClick={this.handleClick}
onMouseDown={this.handleMouseDown}
onClick={(event) => { this.handleClick(event, isSelectable); }}
onMouseDown={(event) => { this.handleMouseDown(event, isSelectable); }}
onFocus={this.handleFocus}
href={href}
ref={refCallback}
Expand Down
28 changes: 28 additions & 0 deletions packages/terra-button/src/Button.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,34 @@
opacity: var(--terra-button-disabled-opacity, 0.3);
pointer-events: none; // prevent pointer interaction for anchor elements
}

&.is-selected.is-focused {
background-color: var(--terra-button-selected-and-focus-background-color, #52585b);
border-color: var(--terra-button-selected-and-focus-border-color, #52585b);
box-shadow: var(--terra-button-selected-and-focus-box-shadow, 0 0 1px 3px rgba(76, 178, 233, 0.5), 0 0 7px 4px rgba(76, 178, 233, 0.35));
color: var(--terra-button-selected-and-focus-color, #fff);
}

&.is-selected {
background-color: var(--terra-button-selected-background-color, #52585b);
border-color: var(--terra-button-selected-border-color, #52585b);
box-shadow: var(--terra-button-selected-box-shadow);
color: var(--terra-button-selected-color, #fff);
}
Comment on lines +89 to +94
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe is-Selected is the only class we would need rest other styles should be same as default button ( which might be already added on _mixin.scss of button package.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated along with renaming in cfcc950


&.is-selected:active {
background-color: var(--terra-button-selected-and-active-background-color, #52585b);
border-color: var(--terra-button-selected-and-active-border-color, #52585b);
box-shadow: var(--terra-button-selected-and-active-box-shadow);
color: var(--terra-button-selected-and-active-color, #fff);
}

&.is-selected:hover {
background-color: var(--terra-button-selected-and-hover-background-color, #40474a);
border-color: var(--terra-button-selected-and-hover-border-color, #40474a);
box-shadow: var(--terra-button-selected-and-hover-box-shadow);
color: var(--terra-button-selected-and-hover-color, #fff);
}
}

.button-label-mac {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,5 +190,26 @@
--terra-button-hover-background-color-utility: transparent;
--terra-button-hover-border-color-utility: transparent;
--terra-button-hover-color-utility: #b2b5b6;

// isSelected button
--terra-button-selected-background-color: #1a2023;
--terra-button-selected-border-color: #181b1d;
--terra-button-selected-box-shadow: none;
--terra-button-selected-color: #9b9b9b;

--terra-button-selected-and-focus-background-color: #1a2023;
--terra-button-selected-and-focus-border-color: #181b1d;
--terra-button-selected-and-focus-box-shadow: 0 0 1px 3px rgba(76, 178, 233, 0.5), 0 0 7px 4px rgba(76, 178, 233, 0.35);
--terra-button-selected-and-focus-color: #9b9b9b;

--terra-button-selected-and-active-background-color: #1a2023;
--terra-button-selected-and-active-border-color: #181b1d;
--terra-button-selected-and-active-box-shadow: none;
--terra-button-selected-and-active-color: #9b9b9b;

--terra-button-selected-and-hover-background-color: #121517;
--terra-button-selected-and-hover-border-color: #181b1d;
--terra-button-selected-and-hover-box-shadow: none;
--terra-button-selected-and-hover-color: #9b9b9b;
}
}
21 changes: 21 additions & 0 deletions packages/terra-button/src/orion-fusion-theme/Button.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -190,5 +190,26 @@
--terra-button-hover-background-color-utility: transparent;
--terra-button-hover-border-color-utility: transparent;
--terra-button-hover-color-utility: #004c76;

// isSelected button
--terra-button-selected-and-hover-background-color: #52585b;
--terra-button-selected-and-hover-border-color: #6f7477;
--terra-button-selected-and-hover-box-shadow: none;
--terra-button-selected-and-hover-color: #fff;

--terra-button-selected-and-focus-background-color: #52585b;
--terra-button-selected-and-focus-border-color: #6f7477;
--terra-button-selected-and-focus-box-shadow: 0 0 1px 1px rgba(255, 255, 255, 0.65), 0 0 2px 3px rgba(76, 178, 233, 0.5), 0 0 6px 4px rgba(76, 178, 233, 0.3);
--terra-button-selected-and-focus-color: #fff;

--terra-button-selected-background-color: #52585b;
--terra-button-selected-border-color: #6f7477;
--terra-button-selected-box-shadow: inset 0 3rem 1.5rem -2rem #434a4d;
--terra-button-selected-color: #fff;

--terra-button-selected-and-active-background-color: #52585b;
--terra-button-selected-and-active-border-color: #6f7477;
--terra-button-selected-and-active-box-shadow: inset 0 3rem 1.5rem -2rem #434a4d;
--terra-button-selected-and-active-and-color: #fff;
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions packages/terra-button/tests/wdio/button-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,4 +255,12 @@ Terra.describeViewports('Button', ['tiny'], () => {
Terra.validates.element('programmatic re-enabled -Enabled Button is not focused', { selector: '#root' });
});
});

describe('Selectable button', () => {
it('displays selected button', () => {
browser.url('/raw/tests/cerner-terra-core-docs/button/selectable-button');
$('<button>').click();
Terra.validates.element('selected-button');
});
});
});
3 changes: 3 additions & 0 deletions packages/terra-core-docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
* Updated
* Removed `terra-table` as a dependency as the docs have now moved to `terra-framework-docs`.

* Added
* Added example for selection state of Fusion-Button in `terra-button`.

## 1.45.0 - (October 16, 2023)

* Added
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React, { useState } from 'react';
import Button from 'terra-button';
import classNames from 'classnames/bind';
import styles from './ButtonTestCommon.module.scss';

const cx = classNames.bind(styles);

const SelectableButton = () => {
const [text, setText] = useState('Unselected');

const handleSelection = (event, toggledState) => {
if (toggledState) {
setText('Selected');
} else {
setText('Unselected');
}
};

return (
<div>
<p>
Status:
{' '}
{text}
</p>
<Button text="Click Me" className={cx('button')} isSelectable onClick={handleSelection} />
</div>
);
};

export default SelectableButton;
Loading