Commit 884fc5ca authored by Lyza Danger Gardner's avatar Lyza Danger Gardner Committed by Lyza Gardner

Remove unused `Button` component

parent 0b6b7606
import { SvgIcon } from '@hypothesis/frontend-shared';
/**
* @typedef ButtonProps
* @prop {string} [buttonText] -
* The presence of this property indicates that the button will have a visibly-rendered
* label (with this prop's value). For brevity, when providing `buttonText`, the `title`
* prop is optional—if `title` is not present, the value of `buttonText` will be used for
* the button's `title` attribute, as they are typically identical. When this prop is
* missing, an icon-only button will be rendered.
* @prop {string} [className] -
* When present, this will be used as the base class name and will override all styling.
* See `buttons` SCSS mixins module for more details.
* @prop {string} [icon] -
* The name of the SVGIcon to render. This is optional if a `buttonText` is provided.
* @prop {'left'|'right'} [iconPosition] - Whether icon should render to the left or
* to the right of label text
* @prop {boolean} [isExpanded] -
* Is the expandable element controlled by this button currently expanded?
* @prop {boolean} [isPressed] -
* Indicate that this is a toggle button (if `isPressed` is a boolean) and whether it
* is pressed. If omitted, the button is a non-toggle button.
* @prop {(e: Event) => any} [onClick] - callback for button clicks
* @prop {boolean} [disabled] - disables the button when true
* @prop {Object} [style] - optional inline styling
* @prop {string} [title] -
* `title`, used for button `title`, is required unless `buttonText` is present
*/
/**
* A button.
*
* By default, styling will be applied for the button based on its general
* "type" (e.g. an icon-only button, a labeled button). The presence of a
* `className` prop will disable all default styling.
*
* @param {ButtonProps} props
*/
export default function Button({
buttonText = '',
className = '',
disabled = false,
icon = '',
iconPosition = 'left',
isExpanded,
isPressed,
onClick = () => {},
style = {},
title,
}) {
// If `buttonText` is provided, the `title` prop is optional and the `button`'s
// `title` attribute will be set from the `buttonText`
title = title || buttonText;
const buttonModifier = buttonText ? 'labeled' : 'icon-only';
// `className` overrides default class naming when present
const baseClassName = className || `Button--${buttonModifier}`;
const extraProps = {};
// If there is no displayed text in the button, or if the provided `title`
// differs from the displayed text, add `aria-label` and `title` attributes
if (!buttonText || title !== buttonText) {
extraProps.title = title;
extraProps['aria-label'] = title;
}
if (typeof isPressed === 'boolean') {
// Indicate that this is a toggle button.
extraProps['aria-pressed'] = isPressed;
}
if (typeof isExpanded === 'boolean') {
extraProps['aria-expanded'] = isExpanded;
}
return (
<button
className={baseClassName}
onClick={onClick}
style={style}
disabled={disabled}
{...extraProps}
>
{icon && iconPosition === 'left' && <SvgIcon name={icon} />}
{buttonText}
{icon && iconPosition === 'right' && <SvgIcon name={icon} />}
</button>
);
}
import { mount } from 'enzyme';
import Button from '../Button';
import { $imports } from '../Button';
import { checkAccessibility } from '../../../test-util/accessibility';
import mockImportedComponents from '../../../test-util/mock-imported-components';
describe('Button', () => {
let fakeOnClick;
function createComponent(props = {}) {
return mount(
<Button
icon="fakeIcon"
title="My Action"
onClick={fakeOnClick}
{...props}
/>
);
}
beforeEach(() => {
fakeOnClick = sinon.stub();
$imports.$mock(mockImportedComponents());
});
afterEach(() => {
$imports.$restore();
});
it('renders `SvgIcon` for associated icon', () => {
const wrapper = createComponent();
assert.equal(wrapper.find('SvgIcon').prop('name'), 'fakeIcon');
});
it('positions `SvgIcon` left (first) by default', () => {
const wrapper = createComponent({ buttonText: 'My Button' });
assert.isTrue(wrapper.find('button').childAt(0).is('SvgIcon'));
assert.equal(wrapper.find('button').childAt(1).text(), 'My Button');
});
it('positions `SvgIcon` right (second) with `iconPosition` prop', () => {
const wrapper = createComponent({
buttonText: 'My Button',
iconPosition: 'right',
});
assert.equal(wrapper.find('button').childAt(0).text(), 'My Button');
assert.isTrue(wrapper.find('button').childAt(1).is('SvgIcon'));
});
[true, false].forEach(isExpanded => {
it('sets `aria-expanded` attribute if `isExpanded` is a boolean', () => {
const wrapper = createComponent({ isExpanded });
assert.equal(wrapper.find('button').prop('aria-expanded'), isExpanded);
});
});
it('does not set `aria-expanded` attribute if `isExpanded` is omitted', () => {
const wrapper = createComponent();
assert.notProperty(wrapper.find('button').props(), 'aria-expanded');
});
[true, false].forEach(isPressed => {
it('sets `aria-pressed` attribute if `isPressed` is a boolean', () => {
const wrapper = createComponent({ isPressed });
assert.equal(wrapper.find('button').prop('aria-pressed'), isPressed);
});
});
it('does not set `aria-pressed` attribute if `isPressed` is omitted', () => {
const wrapper = createComponent();
assert.notProperty(wrapper.find('button').props(), 'aria-pressed');
});
describe('`title` and `aria-label` attributes', () => {
it('sets attrs to provided `title` prop', () => {
const wrapper = createComponent({});
assert.equal(wrapper.find('button').prop('title'), 'My Action');
assert.equal(wrapper.find('button').prop('aria-label'), 'My Action');
});
it('sets attrs if `title` is different than `buttonText`', () => {
const wrapper = createComponent({
buttonText: 'My Label',
title: 'Click here to do something',
});
assert.equal(
wrapper.find('button').prop('title'),
'Click here to do something'
);
assert.equal(
wrapper.find('button').prop('aria-label'),
'Click here to do something'
);
});
it('does not set attrs if no `title` provided and `buttonText` present', () => {
const wrapper = createComponent({
buttonText: 'My Label',
title: undefined,
});
assert.notProperty(wrapper.find('button').props(), 'title');
assert.notProperty(wrapper.find('button').props(), 'aria-label');
});
it('does not set attrs if `title` is the same as `buttonText`', () => {
const wrapper = createComponent({
buttonText: 'My Label',
title: 'My Label',
});
assert.notProperty(wrapper.find('button').props(), 'title');
assert.notProperty(wrapper.find('button').props(), 'aria-label');
});
});
it('invokes `onClick` callback when pressed', () => {
const wrapper = createComponent();
wrapper.find('button').simulate('click');
assert.calledOnce(fakeOnClick);
});
it('applies icon-only class if no visible label present', () => {
const wrapper = createComponent();
assert.isTrue(wrapper.find('button').hasClass('Button--icon-only'));
assert.isFalse(wrapper.find('button').hasClass('Button--labeled'));
});
it('applies labeled class if any visible label present', () => {
const wrapper = createComponent({ buttonText: 'Some text' });
assert.isTrue(wrapper.find('button').hasClass('Button--labeled'));
assert.isFalse(wrapper.find('button').hasClass('Button--icon-only'));
});
it('applies class passed in `className` prop', () => {
const wrapper = createComponent({ className: 'my-class' });
assert.isTrue(wrapper.find('button').hasClass('my-class'));
assert.isFalse(wrapper.find('button').hasClass('Button--icon-only'));
assert.isFalse(wrapper.find('button').hasClass('Button--labeled'));
});
it('disables the button when `disabled` prop is true', () => {
const wrapper = createComponent({ disabled: true });
assert.isTrue(wrapper.find('button[disabled=true]').exists());
});
it('shall not disable the button by default', () => {
const wrapper = createComponent();
assert.isTrue(wrapper.find('button[disabled=false]').exists());
});
it(
'should pass a11y checks',
checkAccessibility({
content: () => createComponent(),
})
);
});
@use "../../mixins/buttons";
@use "../../variables" as var;
/**
* Button markup structure as generated by the `<Button>` component when
* default styles are not overridden:
*
* <button class="<button--icon-only|button--labeled>">
* [<SvgIcon />]
* [<span>label</span>]
* </button>
*/
.Button {
@include buttons.button;
}
.Button--icon-only {
@include buttons.button--icon-only;
}
.Button--labeled {
@include buttons.button--labeled;
}
.Button--primary {
@include buttons.button--primary;
}
......@@ -31,7 +31,6 @@
@use './components/AnnotationTimestamps';
@use './components/AnnotationUser';
@use './components/AutocompleteList';
@use './components/Button';
@use './components/Excerpt';
@use './components/FilterSelect';
@use './components/FilterStatus';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment