Skip to content

Commit

Permalink
feat: button components
Browse files Browse the repository at this point in the history
  • Loading branch information
mortennordseth committed Sep 29, 2023
1 parent 42562c4 commit 87cc8e2
Show file tree
Hide file tree
Showing 10 changed files with 560 additions and 0 deletions.
243 changes: 243 additions & 0 deletions src/components/button/button.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
/* Button */
.button {
composes: typo-body__primary from '@atb/theme/typography.module.css';
cursor: pointer;
text-align: left;
border: 0;
text-decoration: none;
align-items: center;

display: flex;

flex-wrap: nowrap;
gap: var(--spacings-small);

background: transparent;
color: currentColor;

transition: all 100ms ease-in;
}
.button--display_inline {
display: inline-flex;
}
.button--disabled,
.button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.button--state_loading {
cursor: not-allowed;
}
.button__text {
display: block;
flex: 1;
}

.button--transparent,
.button--transparent:visited {
}
.button--transparent:hover {
color: var(--text-colors-secondary);
}
.button--transparent:active {
background-color: var(--interactive-interactive_0-active-background);
color: var(--interactive-interactive_0-active-text);
}
.button--transparent:disabled,
.button--transparent.button--disabled {
opacity: 0.6;
}
.button--transparent:focus {
outline: 0;
box-shadow: inset 0 0 0 var(--border-width-medium)
var(--interactive-interactive_1-outline-background);
}

.button--transparent--underline,
.button--transparent--underline:visited {
text-decoration: underline;
}
.button--transparent--underline:hover {
color: var(--text-colors-secondary);
}
.button--transparent--underline:active {
background-color: var(--interactive-interactive_0-active-background);
color: var(--interactive-interactive_0-active-text);
}
.button--transparent--underline:disabled,
.button--transparent--underline.button--disabled {
opacity: 0.6;
}
.button--transparent--underline:focus {
outline: 0;
box-shadow: inset 0 0 0 var(--border-width-medium)
var(--interactive-interactive_1-outline-background);
}

/* Interactive button 0 */
.button--interactive_0,
.button--interactive_0:visited {
background-color: var(--interactive-interactive_0-default-background);
color: var(--interactive-interactive_0-default-text);
}
.button--interactive_0:hover {
background-color: var(--interactive-interactive_0-hover-background);
color: var(--interactive-interactive_0-hover-text);
}
.button--interactive_0:active {
background-color: var(--interactive-interactive_0-active-background);
color: var(--interactive-interactive_0-active-text);
}
.button--interactive_0:disabled,
.button--interactive_0.button--disabled {
background-color: var(--interactive-interactive_0-disabled-background);
color: var(--interactive-interactive_0-disabled-text);
}
.button--interactive_0:focus {
outline: 0;
box-shadow: inset 0 0 0 var(--border-width-medium)
var(--interactive-interactive_0-outline-background);
}

/* Interactive button 1 */

.button--interactive_1,
.button--interactive_1:visited {
background-color: var(--interactive-interactive_1-default-background);
color: var(--interactive-interactive_1-default-text);
}
.button--interactive_1:hover {
background-color: var(--interactive-interactive_1-hover-background);
color: var(--interactive-interactive_1-hover-text);
}
.button--interactive_1:active {
background-color: var(--interactive-interactive_1-active-background);
color: var(--interactive-interactive_1-active-text);
}
.button--interactive_1:disabled,
.button--interactive_1.button--disabled {
background-color: var(--interactive-interactive_1-disabled-background);
color: var(--interactive-interactive_1-disabled-text);
}
.button--interactive_1:focus {
outline: 0;
box-shadow: inset 0 0 0 var(--border-width-medium)
var(--interactive-interactive_1-outline-background);
}

/* Interactive button 2 */

.button--interactive_2,
.button--interactive_2:visited {
background-color: var(--interactive-interactive_2-default-background);
color: var(--interactive-interactive_2-default-text);
}
.button--interactive_2:hover {
background-color: var(--interactive-interactive_2-hover-background);
color: var(--interactive-interactive_2-hover-text);
}
.button--interactive_2:active {
background-color: var(--interactive-interactive_2-active-background);
color: var(--interactive-interactive_2-active-text);
}
.button--interactive_2:disabled,
.button--interactive_2.button--disabled {
background-color: var(--interactive-interactive_2-disabled-background);
color: var(--interactive-interactive_2-disabled-text);
}
.button--interactive_2:focus {
outline: 0;
box-shadow: inset 0 0 0 var(--border-width-medium)
var(--interactive-interactive_2-outline-background);
}

/* Interactive button 3 */

.button--interactive_3,
.button--interactive_3:visited {
background-color: var(--interactive-interactive_3-default-background);
color: var(--interactive-interactive_3-default-text);
}
.button--interactive_3:hover {
background-color: var(--interactive-interactive_3-hover-background);
color: var(--interactive-interactive_3-hover-text);
}
.button--interactive_3:active {
background-color: var(--interactive-interactive_3-active-background);
color: var(--interactive-interactive_3-active-text);
}
.button--interactive_3:disabled,
.button--interactive_3.button--disabled {
background-color: var(--interactive-interactive_3-disabled-background);
color: var(--interactive-interactive_3-disabled-text);
}
.button--interactive_3:focus {
outline: 0;
box-shadow: inset 0 0 0 var(--border-width-medium)
var(--interactive-interactive_3-outline-background);
}

/* Interactive button, destructive */

.button--destructive,
.button--destructive:visited {
background-color: var(
--interactive-interactive_destructive-default-background
);
color: var(--interactive-interactive_destructive-default-text);
}
.button--destructive:hover {
background-color: var(--interactive-interactive_destructive-hover-background);
color: var(--interactive-interactive_destructive-hover-text);
}
.button--destructive:active {
background-color: var(
--interactive-interactive_destructive-active-background
);
color: var(--interactive-interactive_destructive-active-text);
}
.button--destructive:disabled,
.button--destructive.button--disabled {
background-color: var(
--interactive-interactive_destructive-disabled-background
);
color: var(--interactive-interactive_destructive-disabled-text);
}
.button--destructive:focus {
outline: 0;
box-shadow: inset 0 0 0 var(--border-width-medium)
var(--interactive-interactive_destructive-outline-background);
}

.button--size_medium {
padding: var(--spacings-xLarge);
}
.button--size_small {
padding: var(--spacings-medium);
}
.button--size_compact {
padding: 0;
}

.button--radius_top-bottom {
border-radius: var(--border-radius-regular);
}
.button--radius_top {
border-top-left-radius: var(--border-radius-regular);
border-top-right-radius: var(--border-radius-regular);
}
.button--radius_bottom {
border-bottom-left-radius: var(--border-radius-regular);
border-bottom-right-radius: var(--border-radius-regular);
}
.button--radius_top-bottom.button--radiusSize_circular {
border-radius: var(--border-radius-circle);
}
.button--radius_top.button--radiusSize_circular {
border-top-left-radius: var(--border-radius-circle);
border-top-right-radius: var(--border-radius-circle);
}
.button--radius_bottom.button--radiusSize_circular {
border-bottom-left-radius: var(--border-radius-circle);
border-bottom-right-radius: var(--border-radius-circle);
}
37 changes: 37 additions & 0 deletions src/components/button/button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, {MouseEventHandler} from 'react';
import {ButtonBase, ButtonBaseProps, getBaseButtonClassName} from './utils';

export type ButtonProps = {
/** Action when clicked */
onClick?: MouseEventHandler<HTMLButtonElement>;
/**
* Specify testID for easier access when using cypress
*/
testID?: string;
/**
* Pass properties to button element directly
*/
buttonProps?: JSX.IntrinsicElements['button'];
} & ButtonBaseProps;

export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
function Button({onClick, testID, buttonProps, ...props}, ref) {
const className = getBaseButtonClassName(props);
return (
<button
ref={ref}
type="button"
onClick={onClick}
className={className}
disabled={props.disabled || props.state === 'loading'}
aria-disabled={props.disabled || props.state === 'loading'}
data-testid={testID}
{...buttonProps}
>
<ButtonBase {...props} />
</button>
);
},
);

export default Button;
5 changes: 5 additions & 0 deletions src/components/button/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export {default as ButtonLink} from './link';
export type {ButtonLinkProps} from './link';

export {default as Button} from './button';
export type {ButtonProps} from './button';
75 changes: 75 additions & 0 deletions src/components/button/link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import Link from 'next/link';
import React from 'react';
import {ButtonBase, ButtonBaseProps, getBaseButtonClassName} from './utils';

import {UrlObject} from 'url';

export type ButtonLinkProps = {
/**
* Link or UrlObject passed to next/link
*/
href: string | UrlObject;
/**
* Optional additional onClick if you want to
* enrich click actions with JavaScript function
*/
onClick?: JSX.IntrinsicElements['a']['onClick'];
/**
* Specify properties to underlying a tag
*/
aProps?: JSX.IntrinsicElements['a'];
/**
* If we should do shallow routing or not.
* Shallow routing will not trigger server side props
* @default false
*/
shallow?: boolean;
} & ButtonBaseProps;

export function ButtonLink({
href,
onClick,
testID,
aProps = {},
shallow = false,
...props
}: ButtonLinkProps) {
const className = getBaseButtonClassName(props);
const extraProps =
props.state == 'active'
? {
'aria-current': true,
}
: {};

if (props.disabled || props.state == 'loading') {
return (
<a
className={className}
role="link"
aria-disabled
data-testid={testID}
{...extraProps}
{...aProps}
>
<ButtonBase {...props} />
</a>
);
}

return (
<Link href={href} shallow={shallow} legacyBehavior>
<a
className={className}
onClick={onClick}
{...extraProps}
{...aProps}
data-testid={testID}
>
<ButtonBase {...props} />
</a>
</Link>
);
}

export default ButtonLink;
Loading

0 comments on commit 87cc8e2

Please sign in to comment.