Skip to content

Commit

Permalink
Merge pull request #47 from atomicjolt/sc/button-cleanup
Browse files Browse the repository at this point in the history
Button Refactor / Cleanup
  • Loading branch information
seanrcollings authored Dec 2, 2024
2 parents f677a04 + dc2c00f commit 39d5c8a
Show file tree
Hide file tree
Showing 29 changed files with 375 additions and 430 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ docs/build
dist
node_modules
packages/atomic-fuel/libs
.vscode


Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from "../../../types";
import { MaterialIcon } from "../../Icons/MaterialIcon";
import { Banner, BannerVariants } from "../Banner";
import { ButtonVariants } from "../../Buttons/Buttons.types";
import { ButtonVariants } from "../../Buttons/Button";

export interface ActionBannerProps extends HasChildren, HasClassName {
readonly variant?: BannerVariants;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,61 +1,90 @@
import { forwardRef } from "react";
import { AriaButtonOptions } from "@react-aria/button";
import { mergeProps } from "@react-aria/utils";
import { mergeProps, useObjectRef } from "@react-aria/utils";

import { SpinnerLoader } from "../../Loaders/SpinnerLoader";
import {
BaseProps,
HasChildren,
ExtendedSize,
HasVariant,
LoadingProps,
RenderBaseProps,
SuggestStrings,
} from "../../../types";
import { StyledButton } from "./Button.styles";
import { ButtonVariants } from "../Buttons.types";
import useForwardedRef from "../../../hooks/useForwardedRef";
import { useFocusRing } from "../../../hooks/useFocusRing";
import { useFocusRing } from "@hooks/useFocusRing";
import { useRenderProps } from "@hooks/useRenderProps";
import { useButtonLink } from "@hooks/useButtonLink";
import { useContextProps } from "@hooks/useContextProps";
import { useContextPropsV2 } from "@hooks/useContextProps";
import { StyledButton } from "./Button.styles";
import { ButtonContext } from "./Button.context";

export type ButtonProps = AriaButtonOptions<"button"> &
LoadingProps &
BaseProps &
HasChildren &
HasVariant<ButtonVariants> & {
as?: "button" | "a";
};
export type ButtonVariants = SuggestStrings<
| "primary"
| "secondary"
| "link"
| "success"
| "error"
| "inverted"
| "content"
| "border"
| "ghost"
>;

interface ButtonRenderProps {
isLoading: boolean;
isPressed: boolean;
isFocusVisible: boolean;
isFocused: boolean;
}

export interface ButtonProps
extends AriaButtonOptions<"button">,
LoadingProps,
RenderBaseProps<ButtonRenderProps>,
HasVariant<ButtonVariants> {
as?: "button" | "a";
size?: ExtendedSize;
}

/** A button component that can be used to trigger actions or events
*
* @example <Button onPress={() => alert("Hello, world!")}>Click me</Button>
*/
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
(props, ref) => {
function Button(props, forwardedRef) {
[props, forwardedRef] = useContextPropsV2(
ButtonContext,
props,
forwardedRef
);

const ref = useObjectRef(forwardedRef);

const {
children,
size = "auto",
variant = "primary",
isLoading = false,
loadingLabel,
loadingComplete = false,
className,
as = props.href ? "a" : "button",
} = useContextProps(ButtonContext, props);
variant = "primary",
size = "auto",
} = props;

const internalRef = useForwardedRef<HTMLButtonElement>(ref);
const { buttonProps, isPressed } = useButtonLink(
{
...props,
elementType: as,
"aria-label": isLoading ? loadingLabel : props["aria-label"],
},
internalRef
ref
);

const { focusProps } = useFocusRing();
const { focusProps, isFocusVisible, isFocused } = useFocusRing();

const renderProps = useRenderProps({
componentClassName: "aje-btn",
className,
...props,
variant,
size,
values: { isPressed, isLoading, isFocusVisible, isFocused },
selectors: {
"data-pressed": isPressed,
"data-loading": isLoading,
Expand All @@ -65,7 +94,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
return (
<StyledButton
as={as}
ref={internalRef}
ref={ref}
{...mergeProps(buttonProps, focusProps, renderProps)}
>
{isLoading && (
Expand All @@ -74,12 +103,8 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
placement="absolute center"
/>
)}
{children}
{renderProps.children}
</StyledButton>
);
}
);

Button.displayName = "Button";

export default Button;
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from "react";
import { ButtonProps } from ".";
import { IconButtonProps } from "../IconButton";
import { createComponentContext } from "@utils/index";
import { HasIcon } from '../../../types';

export const ButtonContext = createComponentContext<
ButtonProps & IconButtonProps
ButtonProps & HasIcon
>();
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Meta, StoryObj } from "@storybook/react";
import { Button } from ".";
import { PressableArgTypes } from "@sb/helpers";
import { PressableArgTypes, RenderPropsArgTypes } from "@sb/helpers";
import { MaterialIcon } from "@components/Icons/MaterialIcon";
import { getCssProps } from "@sb/cssprops";

Expand All @@ -13,6 +13,7 @@ const meta: Meta<typeof Button> = {
},
argTypes: {
...PressableArgTypes,
...RenderPropsArgTypes,
children: {
control: "text",
},
Expand Down Expand Up @@ -48,11 +49,6 @@ const meta: Meta<typeof Button> = {
description:
"If true, the button will be excluded from the tab order and will not be focusable via keyboard navigation.",
},
// elementType: {
// control: "text",
// description:
// "The type of element to render. By default, it will render a button element.",
// },
},
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,133 @@
import styled from "styled-components";
import { BaseStyledButton } from "../Buttons.styles";
import mixins from "@styles/mixins";

export const StyledButton = styled(BaseStyledButton)`
export const StyledButton = styled.button`
${mixins.SizingX}
${mixins.Bold}
${mixins.FocusVisible(2)}
padding: var(--btn-padding-vert) var(--btn-padding-horiz);
border-radius: var(--btn-border-radius);
font-size: var(--btn-font-size);
min-height: var(--btn-height);
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--btn-icon-gap);
text-decoration: none;
transition:
background 100ms ease,
color 100ms ease,
transform 100ms ease,
box-shadow 100ms ease;
color: var(--btn-text-clr);
background-color: var(--btn-bg-clr);
border: var(--btn-border, none);
box-shadow: var(--btn-shadow, none);
--loader-clr: var(--btn-text-clr);
&:hover {
cursor: pointer;
color: var(--btn-hover-text-clr);
background-color: var(--btn-hover-bg-clr);
box-shadow: var(--btn-hover-shadow);
}
&:disabled {
opacity: 0.5;
pointer-events: none;
}
&[data-pressed] {
transform: var(--btn-pressed-transform);
}
&[data-loading] {
position: relative;
color: transparent;
.aje-spinner,
.aje-three-dot-loader {
--loader-clr: var(--btn-text-clr);
--loader-size: 1em;
}
}
&.aje-btn--primary {
--btn-text-clr: var(--text-clr-inverted);
--btn-bg-clr: var(--accent-clr);
--btn-hover-text-clr: var(--btn-text-clr);
--btn-hover-bg-clr: var(--accent-clr-alt);
}
&.aje-btn--secondary {
--btn-text-clr: var(--text-clr-alt);
--btn-bg-clr: var(--neutral100);
--btn-hover-text-clr: var(--text-clr);
--btn-hover-bg-clr: var(--neutral200);
--btn-border: var(--border);
}
&.aje-btn--link {
--btn-text-clr: var(--primary700);
--btn-bg-clr: var(--neutral50);
--btn-hover-text-clr: var(--text-clr);
--btn-hover-bg-clr: var(--neutral100);
text-decoration: underline;
}
&.aje-btn--error {
--btn-text-clr: var(--text-clr-inverted);
--btn-bg-clr: var(--error700);
--btn-hover-text-clr: var(--btn-text-clr);
--btn-hover-bg-clr: var(--error800);
}
&.aje-btn--success {
--btn-text-clr: var(--text-clr-inverted);
--btn-bg-clr: var(--success700);
--btn-hover-text-clr: var(--btn-text-clr);
--btn-hover-bg-clr: var(--success800);
}
&.aje-btn--inverted {
--btn-text-clr: var(--text-clr);
--btn-bg-clr: var(--neutral50);
--btn-hover-text-clr: var(--btn-text-clr);
--btn-hover-bg-clr: var(--btn-bg-clr);
--btn-hover-shadow: 0 1px 3px hsla(221, 39%, 11%, 0.5);
}
&.aje-btn--content {
--btn-text-clr: var(--text-clr);
--btn-bg-clr: transparent;
--btn-hover-text-clr: var(--btn-text-clr);
--btn-hover-bg-clr: transparent;
--btn-hover-shadow: none;
--btn-padding-horiz: 0px;
--btn-padding-vert: 0px;
--btn-height: auto;
}
&.aje-btn--border {
--btn-text-clr: var(--text-clr-alt);
--btn-bg-clr: var(--neutral50);
--btn-hover-text-clr: var(--text-clr);
--btn-hover-bg-clr: var(--neutral100);
--btn-border: var(--border);
}
&.aje-btn--ghost {
--btn-text-clr: var(--text-clr-alt);
--btn-bg-clr: transparent;
--btn-hover-text-clr: var(--text-clr);
--btn-hover-bg-clr: var(--neutral100);
--btn-border: transparent;
}
& > i {
color: inherit;
font-size: var(--btn-icon-size);
margin-left: calc(var(--btn-padding-horiz) / -2.5);
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
exports[`Button > matches snapshots > changes variant 1`] = `
<DocumentFragment>
<button
class="sc-kLhKbu sc-ixGGxD ccUbiV iksruy aje-btn aje-btn--secondary is-auto"
class="sc-kLhKbu dlRhmD aje-btn aje-btn--secondary is-auto"
type="button"
>
Click Me
Expand All @@ -14,7 +14,7 @@ exports[`Button > matches snapshots > changes variant 1`] = `
exports[`Button > matches snapshots > loading completed state 1`] = `
<DocumentFragment>
<button
class="sc-kLhKbu sc-ixGGxD ccUbiV iksruy aje-btn aje-btn--primary is-auto"
class="sc-kLhKbu dlRhmD aje-btn aje-btn--primary is-auto"
data-loading="true"
type="button"
>
Expand All @@ -35,7 +35,7 @@ exports[`Button > matches snapshots > loading completed state 1`] = `
exports[`Button > matches snapshots > loading state 1`] = `
<DocumentFragment>
<button
class="sc-kLhKbu sc-ixGGxD ccUbiV iksruy aje-btn aje-btn--primary is-auto"
class="sc-kLhKbu dlRhmD aje-btn aje-btn--primary is-auto"
data-loading="true"
type="button"
>
Expand Down Expand Up @@ -74,7 +74,7 @@ exports[`Button > matches snapshots > loading state 1`] = `
exports[`Button > matches snapshots > normal display 1`] = `
<DocumentFragment>
<button
class="sc-kLhKbu sc-ixGGxD ccUbiV iksruy aje-btn aje-btn--primary is-auto"
class="sc-kLhKbu dlRhmD aje-btn aje-btn--primary is-auto"
type="button"
>
Click Me
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { Button } from "./Button.component";
export type { ButtonProps } from "./Button.component";
export type { ButtonProps, ButtonVariants } from "./Button.component";
Loading

0 comments on commit 39d5c8a

Please sign in to comment.