Skip to content

Commit

Permalink
Merge pull request #22 from Atnic/feature/spinner
Browse files Browse the repository at this point in the history
feat: apply banyu design to spinner component
  • Loading branch information
muhamien authored Feb 26, 2024
2 parents 35593c5 + 8eb2024 commit 9f28e23
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 120 deletions.
6 changes: 6 additions & 0 deletions packages/components/spinner/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @jala-banyu/spinner

## 4.1.0

### Minor Changes

- Apply Banyu Design System to Spinner

## 4.0.0

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/components/spinner/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@jala-banyu/spinner",
"version": "4.0.0",
"version": "4.1.0",
"description": "Loaders express an unspecified wait time or display the length of a process.",
"keywords": [
"loading",
Expand Down
29 changes: 26 additions & 3 deletions packages/components/spinner/src/spinner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,36 @@ import {UseSpinnerProps, useSpinner} from "./use-spinner";
export interface SpinnerProps extends UseSpinnerProps {}

const Spinner = forwardRef<"div", SpinnerProps>((props, ref) => {
const {slots, classNames, label, getSpinnerProps} = useSpinner({...props});
const {slots, classNames, label, progress, getSpinnerProps} = useSpinner({...props});

const strokeDashoffset =
progress !== undefined ? `calc(400 - (250 * ${progress > 100 ? 100 : progress}) / 100)` : 200;

return (
<div ref={ref} {...getSpinnerProps()}>
<div className={slots.wrapper({class: classNames?.wrapper})}>
<i className={slots.circle1({class: classNames?.circle1})} />
{/*<i className={slots.circle2({class: classNames?.circle2})} />*/}
<div>
<svg className={"w-full h-full"} viewBox="0 0 100 100">
<circle
className={slots.circleBackground({class: classNames?.circleBackground})}
cx="50"
cy="50"
fill="transparent"
r="40"
strokeWidth="10"
/>
<circle
className={slots.circle({class: classNames?.circle})}
cx="50"
cy="50"
fill="transparent"
r="40"
strokeDashoffset={strokeDashoffset}
strokeLinecap="round"
strokeWidth="10"
/>
</svg>
</div>
</div>
{label && <span className={slots.label()}>{label}</span>}
</div>
Expand Down
21 changes: 16 additions & 5 deletions packages/components/spinner/src/use-spinner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ interface Props extends HTMLBanyuProps<"div"> {
* Spinner label, in case you passed it will be used as `aria-label`.
*/
label?: string;
/**
* If `true` the spinner will act as a progress spinner.
*/
isProgress?: boolean;
/**
* Progress value from 0 to 100.
*/
progress?: number;
/**
* Classname or List of classes to change the classNames of the element.
* if `className` is passed, it will be added to the base slot.
Expand All @@ -24,8 +32,8 @@ interface Props extends HTMLBanyuProps<"div"> {
* <Spinner classNames={{
* base:"base-classes",
* wrapper: "wrapper-classes",
* circle1: "circle1-classes",
* circle2: "circle2-classes",
* circle: "circle-classes",
* circleBackground: "circle-background-classes",
* label: "label-classes"
* }} />
* ```
Expand All @@ -38,9 +46,12 @@ export type UseSpinnerProps = Props & SpinnerVariantProps;
export function useSpinner(originalProps: UseSpinnerProps) {
const [props, variantProps] = mapPropsVariants(originalProps, spinner.variantKeys);

const {children, className, classNames, label: labelProp, ...otherProps} = props;
const {children, className, progress, classNames, label: labelProp, ...otherProps} = props;

const slots = useMemo(() => spinner({...variantProps}), [...Object.values(variantProps)]);
const slots = useMemo(
() => spinner({...variantProps, isProgress: progress !== undefined}),
[...Object.values(variantProps), progress],
);

const baseStyles = clsx(classNames?.base, className);

Expand All @@ -65,7 +76,7 @@ export function useSpinner(originalProps: UseSpinnerProps) {
[ariaLabel, slots, baseStyles, otherProps],
);

return {label, slots, classNames, getSpinnerProps};
return {label, slots, progress, classNames, getSpinnerProps};
}

export type UseSpinnerReturn = ReturnType<typeof useSpinner>;
81 changes: 48 additions & 33 deletions packages/components/spinner/stories/spinner.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,48 @@
import React from "react";
import {Meta} from "@storybook/react";
import {spinner} from "@jala-banyu/theme";

import {Spinner} from "../src";

export default {
title: "Components/Spinner",
component: Spinner,
parameters: {
design: {
type: "figma",
url: "https://www.figma.com/file/T0TUGURgVGElV6MtU2EPYU/%5BJDS%5D-Design-System---Banyu-1.0?node-id=589%3A107692&mode=dev",
},
},
argTypes: {
color: {
control: {
type: "select",
},
options: ["default", "primary", "secondary", "success", "warning", "danger"],
options: ["current", "white", "primary", "success", "warning", "danger"],
},
labelColor: {
size: {
control: {
type: "select",
},
options: ["default", "primary", "secondary", "success", "warning", "danger"],
options: ["xs", "sm", "md", "lg"],
},
size: {
isProgress: {
control: {
type: "select",
type: "boolean",
},
},
label: {
control: {
type: "text",
},
options: ["sm", "md", "lg"],
},
progress: {
control: {
type: "range",
step: 10,
},
min: 0,
max: 100,
},
},
decorators: [
Expand All @@ -35,31 +54,27 @@ export default {
],
} as Meta<typeof Spinner>;

// const defaultProps = {
// ...spinner.defaultVariants,
// };
const defaultProps = {
...spinner.defaultVariants,
};

export const Default = {
args: {
...defaultProps,
},
};

export const WithLabel = {
args: {
...defaultProps,
label: "Loading...",
},
};

// export const Default = {
// parameters: {
// design: {
// type: "figma",
// url: "",
// },
// },
// args: {
// ...defaultProps,
// },
// };
//
// export const WithLabel = {
// parameters: {
// design: {
// type: "figma",
// url: "",
// },
// },
// args: {
// ...defaultProps,
// label: "Loading...",
// },
// };
export const CircularProgress = {
args: {
...defaultProps,
isProgress: true,
progress: 50,
},
};
108 changes: 30 additions & 78 deletions packages/core/theme/src/components/spinner.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type {VariantProps} from "tailwind-variants"
import type {VariantProps} from "tailwind-variants";

import {tv} from "../utils/tv"
import {tv} from "../utils/tv";

/**
* Spinner wrapper **Tailwind Variants** component
Expand All @@ -9,7 +9,7 @@ import {tv} from "../utils/tv"
*
* @example
* <div className={base())}>
* <i className={circle1()}/>
* <i className={circle()}/>
* <i className={circle2()}/>
* <span className={label()}/>
* </div>
Expand All @@ -18,117 +18,69 @@ const spinner = tv({
slots: {
base: "relative inline-flex flex-col gap-2 items-center justify-center",
wrapper: "relative flex",
circle1: [
"absolute",
"w-full",
"h-full",
"rounded-full",
"animate-spinner-ease-spin",
"border-2",
"border-solid",
"border-t-transparent",
"border-l-transparent",
"border-r-transparent",
],
circle2: [
"absolute",
"w-full",
"h-full",
"rounded-full",
"opacity-75",
"animate-spinner-linear-spin",
"border-2",
"border-dotted",
"border-t-transparent",
"border-l-transparent",
"border-r-transparent",
],
label: "text-foreground dark:text-foreground-dark font-regular",
circle: "progress-spinner stroke-current",
circleBackground: "text-neutral-200 stroke-current",
label: "text-neutral-800 font-regular",
},
variants: {
size: {
xs: {
wrapper: "w-8 h-8",
label: "text-xs",
},
sm: {
wrapper: "w-5 h-5",
circle1: "border-2",
circle2: "border-2",
wrapper: "w-10 h-10",
label: "text-sm",
},
md: {
wrapper: "w-8 h-8",
circle1: "border-3",
circle2: "border-3",
wrapper: "w-12 h-12",
label: "text-md",
},
lg: {
wrapper: "w-10 h-10",
circle1: "border-3",
circle2: "border-3",
wrapper: "w-16 h-16",
label: "text-lg",
},
},
color: {
current: {
circle1: "border-b-current",
circle2: "border-b-current",
circle: "text-current",
},
white: {
circle1: "border-b-white",
circle2: "border-b-white",
circle: "text-white",
},
default: {
circle1: "border-b-default",
circle2: "border-b-default",
circle: "text-neutral-800",
},
primary: {
circle1: "border-b-primary",
circle2: "border-b-primary",
},
secondary: {
circle1: "border-b-secondary",
circle2: "border-b-secondary",
circle: "text-brand",
},
success: {
circle1: "border-b-success",
circle2: "border-b-success",
circle: "text-success",
},
warning: {
circle1: "border-b-warning",
circle2: "border-b-warning",
circle: "text-warning",
},
danger: {
circle1: "border-b-danger",
circle2: "border-b-danger",
circle: "text-danger",
},
},
labelColor: {
foreground: {
label: "text-foreground",
},
primary: {
label: "text-primary",
},
secondary: {
label: "text-secondary",
},
success: {
label: "text-success",
isProgress: {
true: {
circleBackground: "hidden",
},
warning: {
label: "text-warning",
},
danger: {
label: "text-danger",
false: {
circle: "animate-spinner-ease-spin",
},
},
},
defaultVariants: {
size: "md",
color: "primary",
labelColor: "foreground",
isProgress: false,
},
})
});

export type SpinnerVariantProps = VariantProps<typeof spinner>
export type SpinnerSlots = keyof ReturnType<typeof spinner>
export type SpinnerVariantProps = VariantProps<typeof spinner>;
export type SpinnerSlots = keyof ReturnType<typeof spinner>;

export {spinner}
export {spinner};
6 changes: 6 additions & 0 deletions packages/core/theme/src/utilities/custom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,10 @@ export default {
".tap-highlight-transparent": {
"-webkit-tap-highlight-color": "transparent",
},
".progress-spinner": {
"stroke-dasharray": "400, 400",
transition: "stroke-dashoffset 0.35s",
transform: "rotate(-90deg)",
"transform-origin": "50% 50%",
},
};

0 comments on commit 9f28e23

Please sign in to comment.