Skip to content

Commit

Permalink
feat: toggle button: adds toggle button and its hooks, updates scss (#43
Browse files Browse the repository at this point in the history
)
  • Loading branch information
dkilgore-eightfold authored Apr 7, 2022
1 parent 56d7ffe commit d009ca3
Show file tree
Hide file tree
Showing 19 changed files with 379 additions and 204 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"@teamsupercell/typings-for-css-modules-loader": "2.1.0",
"@testing-library/jest-dom": "5.16.2",
"@testing-library/react": "12.1.3",
"@testing-library/react-hooks": "7.0.2",
"@testing-library/user-event": "13.5.0",
"@types/dotenv-webpack": "7.0.3",
"@types/enzyme": "3.10.4",
Expand Down
58 changes: 7 additions & 51 deletions src/components/Button/BaseButton.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import React, { FC } from 'react';
import {
ButtonSize,
ButtonTheme,
ButtonType,
InternalButtonProps,
} from './index';
import { ButtonSize, ButtonTheme, InternalButtonProps } from './index';
import { Icon, IconName, IconSize } from '../Icon/index';
import { Breakpoints, useMatchMedia } from '../../shared/hooks';
import { CSSVariables } from '../../shared/variables';
import { classNames, invertForegroundColor } from '../../shared/utilities';
import { classNames } from '../../shared/utilities';

import styles from './button.module.scss';

Expand All @@ -18,18 +12,16 @@ export const BaseButton: FC<InternalButtonProps> = ({
checked = false,
className,
disabled = false,
disruptive = false,
htmlType,
icon,
iconColor,
id,
onClick,
primaryColor,
size = ButtonSize.Flex,
style,
text,
theme,
type = ButtonType.Default,
toggle,
}) => {
const largeScreenActive: boolean = useMatchMedia(Breakpoints.Large);
const mediumScreenActive: boolean = useMatchMedia(Breakpoints.Medium);
Expand Down Expand Up @@ -104,61 +96,25 @@ export const BaseButton: FC<InternalButtonProps> = ({
/>
);

const buttonStyles = (): CSSVariables => {
let buttonStyle: CSSVariables;
if (primaryColor && !disruptive) {
if (type === ButtonType.Default) {
buttonStyle = {
...style,
// TODO: Assign primaryColor to css variables when available
'--css-var-example': primaryColor,
};
} else if (type === ButtonType.Primary) {
buttonStyle = {
...style,
// TODO: Assign primaryColor to css variables when available
'--css-var-example': primaryColor,
};
} else if (type === ButtonType.Secondary) {
buttonStyle = {
...style,
// TODO: Assign primaryColor to css variables when available
'--css-var-example': primaryColor,
};
}
} else {
buttonStyle = style;
}
return buttonStyle;
};

const getButtonText = (
buttonTextClassNames: string,
text: string
): JSX.Element => (
<span
className={buttonTextClassNames}
style={{
color:
primaryColor && type === ButtonType.Primary
? invertForegroundColor(primaryColor)
: 'inherit',
}}
>
{text ? text : 'Button'}
</span>
<span className={buttonTextClassNames}>{text ? text : 'Button'}</span>
);

return (
<button
aria-checked={toggle ? !!checked : undefined}
aria-disabled={allowDisabledFocus}
aria-label={ariaLabel}
aria-pressed={toggle ? !!checked : undefined}
defaultChecked={checked}
disabled={disabled}
className={buttonBaseClassNames}
id={id}
onClick={!allowDisabledFocus ? onClick : null}
style={buttonStyles()}
style={style}
type={htmlType}
>
{iconExists && !textExists && getButtonIcon(icon)}
Expand Down
104 changes: 88 additions & 16 deletions src/components/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import React from 'react';
import React, { FC } from 'react';
import {
ButtonSize,
DefaultButton,
PrimaryButton,
SecondaryButton,
} from './index';
import { IconName } from '../Icon/index';
import { useBoolean } from '../../hooks/useBoolean';

interface ToggleButtonExampleProps {
// These are set based on the toggle shown (not needed in real code)
checked?: boolean;
}

export default {
title: 'Button',
Expand All @@ -14,37 +20,45 @@ export default {

export const Primary = () => (
<>
<h2>Primary</h2>
<p>Default Flex</p>
<h1>Primary</h1>
<h2>Default Flex</h2>
<PrimaryButton
ariaLabel="Primary Button"
icon={IconName.mdiCardsHeart}
onClick={_alertClicked}
text="Primary Button"
/>
<p>Text only</p>
<br />
<br />
<h2>Text only</h2>
<PrimaryButton
ariaLabel="Primary Button"
onClick={_alertClicked}
size={ButtonSize.Large}
text="Primary Button"
/>
<p>Icon only</p>
<br />
<br />
<h2>Icon only</h2>
<PrimaryButton
ariaLabel="Primary Button"
icon={IconName.mdiCardsHeart}
onClick={_alertClicked}
size={ButtonSize.Large}
/>
<p>Text + Icon</p>
<br />
<br />
<h2>Text + Icon</h2>
<PrimaryButton
ariaLabel="Primary Button"
icon={IconName.mdiCardsHeart}
onClick={_alertClicked}
size={ButtonSize.Large}
text="Primary Button"
/>
<p>Disruptive</p>
<br />
<br />
<h2>Disruptive</h2>
<PrimaryButton
ariaLabel="Primary Button"
disruptive
Expand All @@ -57,30 +71,36 @@ export const Primary = () => (

export const Secondary = () => (
<>
<p>Secondary</p>
<p>Text only</p>
<h1>Secondary</h1>
<h2>Text only</h2>
<SecondaryButton
ariaLabel="Secondary Button"
onClick={_alertClicked}
size={ButtonSize.Large}
text="Secondary Button"
/>
<p>Icon only</p>
<br />
<br />
<h2>Icon only</h2>
<SecondaryButton
ariaLabel="Secondary Button"
icon={IconName.mdiCardsHeart}
onClick={_alertClicked}
size={ButtonSize.Large}
/>
<p>Text + Icon</p>
<br />
<br />
<h2>Text + Icon</h2>
<SecondaryButton
ariaLabel="Secondary Button"
icon={IconName.mdiCardsHeart}
onClick={_alertClicked}
size={ButtonSize.Large}
text="Secondary Button"
/>
<p>Disruptive</p>
<br />
<br />
<h2>Disruptive</h2>
<SecondaryButton
ariaLabel="Secondary Button"
disruptive
Expand All @@ -93,22 +113,26 @@ export const Secondary = () => (

export const Default = () => (
<>
<p>Default Button</p>
<p>Text only</p>
<h1>Default Button</h1>
<h2>Text only</h2>
<DefaultButton
ariaLabel="Default Button"
onClick={_alertClicked}
size={ButtonSize.Large}
text="Default Button"
/>
<p>Icon only</p>
<br />
<br />
<h2>Icon only</h2>
<DefaultButton
ariaLabel="Default Button"
icon={IconName.mdiCardsHeart}
onClick={_alertClicked}
size={ButtonSize.Large}
/>
<p>Text + Icon</p>
<br />
<br />
<h2>Text + Icon</h2>
<DefaultButton
ariaLabel="Default Button"
icon={IconName.mdiCardsHeart}
Expand All @@ -119,6 +143,54 @@ export const Default = () => (
</>
);

export const Toggle: FC<ToggleButtonExampleProps> = ({ checked }) => {
const [skill1Added, { toggle: set1Added }] = useBoolean(false);
const [skill2Added, { toggle: set2Added }] = useBoolean(false);
const [skill3Added, { toggle: set3Added }] = useBoolean(false);
return (
<>
<h1>Toggle With Text + Icon</h1>
<h2>
Note: Toggle buttons require the <code>toggle</code> attribute
in addition to <code>checked</code>.
</h2>
<span style={{ marginRight: 16 }}>
<PrimaryButton
ariaLabel="Primary Button"
checked={skill1Added || checked}
icon={skill1Added ? IconName.mdiMinus : IconName.mdiPlus}
onClick={set1Added}
size={ButtonSize.Medium}
text="Primary Button"
toggle
/>
</span>
<span style={{ marginRight: 16 }}>
<SecondaryButton
ariaLabel="Secondary Button"
checked={skill2Added || checked}
icon={skill2Added ? IconName.mdiMinus : IconName.mdiPlus}
onClick={set2Added}
size={ButtonSize.Medium}
text="Secondary Button"
toggle
/>
</span>
<span>
<DefaultButton
ariaLabel="Default Button"
checked={skill3Added || checked}
icon={skill3Added ? IconName.mdiMinus : IconName.mdiPlus}
onClick={set3Added}
size={ButtonSize.Medium}
text="Default Button"
toggle
/>
</span>
</>
);
};

function _alertClicked(): void {
alert('Clicked');
}
10 changes: 7 additions & 3 deletions src/components/Button/Button.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ export interface ButtonProps {
* @default false
*/
disruptive?: boolean;
/**
* The button html type.
*/
htmlType?: 'button' | 'submit' | 'reset';
/**
* The button icon.
*/
Expand Down Expand Up @@ -101,11 +105,11 @@ export interface ButtonProps {
*/
splitButtonMenuProps?: ButtonProps;
/**
* The buton style.
* The button style.
*/
style?: React.CSSProperties;
/**
* The button html type.
* The button is a toggle button with distinct on and off states.
*/
htmlType?: 'button' | 'submit' | 'reset';
toggle?: boolean;
}
4 changes: 2 additions & 2 deletions src/components/Button/DefaultButton/DefaultButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ export const DefaultButton: FC<ButtonProps> = ({
icon,
iconColor,
onClick,
primaryColor,
text,
theme,
size = ButtonSize.Flex,
style,
toggle,
}) => {
const buttonClassNames: string = classNames([
className,
Expand All @@ -37,12 +37,12 @@ export const DefaultButton: FC<ButtonProps> = ({
icon={icon}
iconColor={iconColor}
onClick={onClick}
primaryColor={primaryColor}
size={size}
style={style}
text={text}
theme={theme}
type={ButtonType.Default}
toggle={toggle}
/>
);
};
4 changes: 2 additions & 2 deletions src/components/Button/PrimaryButton/PrimaryButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ export const PrimaryButton: FC<ButtonProps> = ({
icon,
iconColor,
onClick,
primaryColor,
size = ButtonSize.Flex,
style,
text,
theme,
toggle,
}) => {
const buttonClassNames: string = classNames([
className,
Expand All @@ -40,12 +40,12 @@ export const PrimaryButton: FC<ButtonProps> = ({
icon={icon}
iconColor={iconColor}
onClick={onClick}
primaryColor={primaryColor}
size={size}
style={style}
text={text}
theme={theme}
type={ButtonType.Primary}
toggle={toggle}
/>
);
};
Loading

0 comments on commit d009ca3

Please sign in to comment.