From 8eb20240a242f615ad749cef789c93302ca8324f Mon Sep 17 00:00:00 2001 From: Dika Mahendra Date: Mon, 26 Feb 2024 01:02:35 +0700 Subject: [PATCH] feat: apply banyu design to spinner component --- packages/components/spinner/CHANGELOG.md | 6 + packages/components/spinner/package.json | 2 +- packages/components/spinner/src/spinner.tsx | 29 ++++- .../components/spinner/src/use-spinner.ts | 21 +++- .../spinner/stories/spinner.stories.tsx | 81 +++++++------ packages/core/theme/src/components/spinner.ts | 108 +++++------------- packages/core/theme/src/utilities/custom.ts | 6 + 7 files changed, 133 insertions(+), 120 deletions(-) diff --git a/packages/components/spinner/CHANGELOG.md b/packages/components/spinner/CHANGELOG.md index f953ea90..96524676 100644 --- a/packages/components/spinner/CHANGELOG.md +++ b/packages/components/spinner/CHANGELOG.md @@ -1,5 +1,11 @@ # @jala-banyu/spinner +## 4.1.0 + +### Minor Changes + +- Apply Banyu Design System to Spinner + ## 4.0.0 ### Patch Changes diff --git a/packages/components/spinner/package.json b/packages/components/spinner/package.json index cf7d6ea0..89912664 100644 --- a/packages/components/spinner/package.json +++ b/packages/components/spinner/package.json @@ -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", diff --git a/packages/components/spinner/src/spinner.tsx b/packages/components/spinner/src/spinner.tsx index ef7a59f1..69d6cdb4 100644 --- a/packages/components/spinner/src/spinner.tsx +++ b/packages/components/spinner/src/spinner.tsx @@ -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 (
- - {/**/} +
+ + + + +
{label && {label}}
diff --git a/packages/components/spinner/src/use-spinner.ts b/packages/components/spinner/src/use-spinner.ts index e46f29b0..a3934f2d 100644 --- a/packages/components/spinner/src/use-spinner.ts +++ b/packages/components/spinner/src/use-spinner.ts @@ -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. @@ -24,8 +32,8 @@ interface Props extends HTMLBanyuProps<"div"> { * * ``` @@ -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); @@ -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; diff --git a/packages/components/spinner/stories/spinner.stories.tsx b/packages/components/spinner/stories/spinner.stories.tsx index f227bc55..ce9249ed 100644 --- a/packages/components/spinner/stories/spinner.stories.tsx +++ b/packages/components/spinner/stories/spinner.stories.tsx @@ -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: [ @@ -35,31 +54,27 @@ export default { ], } as Meta; -// 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, + }, +}; diff --git a/packages/core/theme/src/components/spinner.ts b/packages/core/theme/src/components/spinner.ts index 177b4989..33d701fe 100644 --- a/packages/core/theme/src/components/spinner.ts +++ b/packages/core/theme/src/components/spinner.ts @@ -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 @@ -9,7 +9,7 @@ import {tv} from "../utils/tv" * * @example *
- * + * * * *
@@ -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 -export type SpinnerSlots = keyof ReturnType +export type SpinnerVariantProps = VariantProps; +export type SpinnerSlots = keyof ReturnType; -export {spinner} +export {spinner}; diff --git a/packages/core/theme/src/utilities/custom.ts b/packages/core/theme/src/utilities/custom.ts index 3c5d8d73..deb8e491 100644 --- a/packages/core/theme/src/utilities/custom.ts +++ b/packages/core/theme/src/utilities/custom.ts @@ -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%", + }, };