mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
feat(components): loading component added, button stories improved
This commit is contained in:
parent
47580d1be9
commit
0f07cd0125
@ -50,6 +50,7 @@
|
||||
"devDependencies": {
|
||||
"@nextui-org/spacer": "workspace:*",
|
||||
"@nextui-org/grid": "workspace:*",
|
||||
"@nextui-org/loading": "workspace:*",
|
||||
"@nextui-org/icons-utils": "workspace:*",
|
||||
"@react-types/shared": "^3.14.1",
|
||||
"@react-types/button": "^3.6.2",
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import React from "react";
|
||||
import {Meta} from "@storybook/react";
|
||||
import {Spacer} from "@nextui-org/spacer";
|
||||
import {Grid} from "@nextui-org/grid";
|
||||
import {Loading} from "@nextui-org/loading";
|
||||
import {Lock, Notification, User, Camera, Activity} from "@nextui-org/icons-utils";
|
||||
|
||||
import {Button} from "../src";
|
||||
@ -45,6 +47,36 @@ export const Sizes = () => (
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Loadings = () => (
|
||||
<Grid.Container gap={2}>
|
||||
<Grid>
|
||||
<Button auto disabled color="primary" css={{px: "$13"}}>
|
||||
<Loading color="currentColor" size="sm" />
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Button auto disabled color="secondary" css={{px: "$13"}}>
|
||||
<Loading color="currentColor" size="sm" type="spinner" />
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Button auto disabled color="success" css={{px: "$13"}}>
|
||||
<Loading color="currentColor" size="sm" type="points" />
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Button auto disabled color="warning" css={{px: "$13"}}>
|
||||
<Loading color="currentColor" size="sm" type="points-opacity" />
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Button auto disabled color="error" css={{px: "$13"}}>
|
||||
<Loading color="currentColor" size="sm" type="spinner" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid.Container>
|
||||
);
|
||||
|
||||
export const Colors = () => (
|
||||
<>
|
||||
<Button color="primary">Primary</Button>
|
||||
|
||||
@ -42,7 +42,7 @@ export interface UseImageProps extends Omit<HTMLNextUIProps<"img">, "height" | "
|
||||
*/
|
||||
objectFit?: CSS["objectFit"];
|
||||
/**
|
||||
* Override default Image xontainer styles
|
||||
* Override default Image container styles
|
||||
*/
|
||||
containerCss?: CSS;
|
||||
|
||||
|
||||
24
packages/components/loading/README.md
Normal file
24
packages/components/loading/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# @nextui-org/loading
|
||||
|
||||
A Quick description of the component
|
||||
|
||||
> This is an internal utility, not intended for public usage.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
yarn add @nextui-org/loading
|
||||
# or
|
||||
npm i @nextui-org/loading
|
||||
```
|
||||
|
||||
## Contribution
|
||||
|
||||
Yes please! See the
|
||||
[contributing guidelines](https://github.com/nextui-org/nextui/blob/master/CONTRIBUTING.md)
|
||||
for details.
|
||||
|
||||
## Licence
|
||||
|
||||
This project is licensed under the terms of the
|
||||
[MIT license](https://github.com/nextui-org/nextui/blob/master/LICENSE).
|
||||
49
packages/components/loading/__tests__/loading.test.tsx
Normal file
49
packages/components/loading/__tests__/loading.test.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
import * as React from "react";
|
||||
import {render} from "@testing-library/react";
|
||||
|
||||
import {Loading} from "../src";
|
||||
|
||||
describe("Loading", () => {
|
||||
it("should render correctly", () => {
|
||||
const wrapper = render(<Loading />);
|
||||
|
||||
expect(() => wrapper.unmount()).not.toThrow();
|
||||
});
|
||||
|
||||
it("ref should be forwarded", () => {
|
||||
const ref = React.createRef<HTMLDivElement>();
|
||||
|
||||
render(<Loading ref={ref} />);
|
||||
expect(ref.current).not.toBeNull();
|
||||
});
|
||||
|
||||
it("should render with default aria-label", () => {
|
||||
const {getByLabelText} = render(<Loading />);
|
||||
|
||||
expect(getByLabelText("Loading")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should render with default aria-label for spinner", () => {
|
||||
const {getByLabelText} = render(<Loading type="spinner" />);
|
||||
|
||||
expect(getByLabelText("Loading")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should work with text in spinner type", () => {
|
||||
const {getByText} = render(<Loading type="spinner">Loading</Loading>);
|
||||
|
||||
expect(getByText("Loading")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should replace the default aria-label when a children is passed", () => {
|
||||
const {getByLabelText} = render(<Loading>Custom label</Loading>);
|
||||
|
||||
expect(getByLabelText("Custom label")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should replace the default aria-label if aria-label is passed", () => {
|
||||
const {getByLabelText} = render(<Loading aria-label="Custom label" />);
|
||||
|
||||
expect(getByLabelText("Custom label")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
3
packages/components/loading/clean-package.config.json
Normal file
3
packages/components/loading/clean-package.config.json
Normal file
@ -0,0 +1,3 @@
|
||||
{ "replace": { "main": "dist/index.cjs.js", "module": "dist/index.esm.js",
|
||||
"types": "dist/index.d.ts", "exports": { ".": { "import": "./dist/index.esm.js",
|
||||
"require": "./dist/index.cjs.js" }, "./package.json": "./package.json" } } }
|
||||
50
packages/components/loading/package.json
Normal file
50
packages/components/loading/package.json
Normal file
@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "@nextui-org/loading",
|
||||
"version": "1.0.0-beta.11",
|
||||
"description": "Loaders express an unspecified wait time or display the length of a process.",
|
||||
"keywords": [
|
||||
"loading"
|
||||
],
|
||||
"author": "Junior Garcia <jrgarciadev@gmail.com>",
|
||||
"homepage": "https://nextui.org",
|
||||
"license": "MIT",
|
||||
"main": "src/index.ts",
|
||||
"sideEffects": false,
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/nextui-org/nextui.git",
|
||||
"directory": "packages/components/loading"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextui-org/nextui/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup src/index.ts --format=esm,cjs --dts",
|
||||
"dev": "yarn build:fast -- --watch",
|
||||
"clean": "rimraf dist .turbo",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"build:fast": "tsup src/index.ts --format=esm,cjs",
|
||||
"prepack": "clean-package",
|
||||
"postpack": "clean-package restore"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nextui-org/system": "workspace:*",
|
||||
"@nextui-org/shared-utils": "workspace:*",
|
||||
"@nextui-org/dom-utils": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nextui-org/spacer": "workspace:*",
|
||||
"@nextui-org/grid": "workspace:*",
|
||||
"clean-package": "2.1.1",
|
||||
"react": "^17.0.2"
|
||||
}
|
||||
}
|
||||
5
packages/components/loading/src/index.ts
Normal file
5
packages/components/loading/src/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
// export types
|
||||
export type {LoadingProps} from "./loading";
|
||||
|
||||
// export component
|
||||
export {default as Loading} from "./loading";
|
||||
34
packages/components/loading/src/loading.animations.ts
Normal file
34
packages/components/loading/src/loading.animations.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import {keyframes} from "@nextui-org/system";
|
||||
|
||||
export const blink = keyframes({
|
||||
"0%": {
|
||||
opacity: "0.2",
|
||||
},
|
||||
"20%": {
|
||||
opacity: 1,
|
||||
},
|
||||
"100%": {
|
||||
opacity: "0.2",
|
||||
},
|
||||
});
|
||||
|
||||
export const rotate = keyframes({
|
||||
"0%": {
|
||||
transform: "rotate(0deg)",
|
||||
},
|
||||
"100%": {
|
||||
transform: "rotate(360deg)",
|
||||
},
|
||||
});
|
||||
|
||||
export const points = keyframes({
|
||||
"0%": {
|
||||
transform: "translate(0px, 0px)",
|
||||
},
|
||||
"50%": {
|
||||
transform: "translate(0, calc(-$$loadingSize * 1.4))",
|
||||
},
|
||||
"100%": {
|
||||
transform: "translate(0px, 0px)",
|
||||
},
|
||||
});
|
||||
263
packages/components/loading/src/loading.styles.ts
Normal file
263
packages/components/loading/src/loading.styles.ts
Normal file
@ -0,0 +1,263 @@
|
||||
import {styled} from "@nextui-org/system";
|
||||
|
||||
import {rotate, points, blink} from "./loading.animations";
|
||||
|
||||
export const StyledLoadingContainer = styled("div", {
|
||||
d: "flex",
|
||||
fd: "column",
|
||||
jc: "center",
|
||||
ai: "center",
|
||||
position: "relative",
|
||||
});
|
||||
|
||||
export const StyledLoading = styled("span", {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
size: "100%",
|
||||
dflex: "center",
|
||||
bgColor: "transparent",
|
||||
us: "none",
|
||||
variants: {
|
||||
size: {
|
||||
xs: {
|
||||
$$loadingSize: "$space$8",
|
||||
$$loadingBorder: "$space$1",
|
||||
},
|
||||
sm: {
|
||||
$$loadingSize: "$space$10",
|
||||
$$loadingBorder: "$space$1",
|
||||
},
|
||||
md: {
|
||||
$$loadingSize: "$space$12",
|
||||
$$loadingBorder: "calc($space$1 * 1.5)",
|
||||
},
|
||||
lg: {
|
||||
$$loadingSize: "$space$15",
|
||||
$$loadingBorder: "$space$2",
|
||||
},
|
||||
xl: {
|
||||
$$loadingSize: "$space$18",
|
||||
$$loadingBorder: "$space$3",
|
||||
},
|
||||
},
|
||||
type: {
|
||||
default: {
|
||||
d: "flex",
|
||||
br: "$rounded",
|
||||
position: "relative",
|
||||
size: "$$loadingSize",
|
||||
i: {
|
||||
top: "0px",
|
||||
size: "100%",
|
||||
position: "absolute",
|
||||
br: "inherit",
|
||||
},
|
||||
"._1": {
|
||||
border: "$$loadingBorder solid $$loadingColor",
|
||||
borderTop: "$$loadingBorder solid transparent",
|
||||
borderLeft: "$$loadingBorder solid transparent",
|
||||
borderRight: "$$loadingBorder solid transparent",
|
||||
animation: `${rotate} 0.8s ease infinite`,
|
||||
},
|
||||
"._2": {
|
||||
border: "$$loadingBorder dotted $$loadingColor",
|
||||
borderTop: "$$loadingBorder solid transparent",
|
||||
borderLeft: "$$loadingBorder solid transparent",
|
||||
borderRight: "$$loadingBorder solid transparent",
|
||||
animation: `${rotate} 0.8s linear infinite`,
|
||||
opacity: 0.5,
|
||||
},
|
||||
"._3": {
|
||||
display: "none",
|
||||
},
|
||||
},
|
||||
points: {
|
||||
d: "flex",
|
||||
position: "relative",
|
||||
transform: "translate(0, calc($$loadingSize * 0.6))",
|
||||
i: {
|
||||
size: "$$loadingSize",
|
||||
margin: "0 3px",
|
||||
bg: "$$loadingColor",
|
||||
},
|
||||
"._1": {
|
||||
br: "$rounded",
|
||||
animation: `${points} 0.75s ease infinite`,
|
||||
},
|
||||
"._2": {
|
||||
br: "$rounded",
|
||||
animation: `${points} 0.75s ease infinite 0.25s`,
|
||||
},
|
||||
"._3": {
|
||||
br: "$rounded",
|
||||
animation: `${points} 0.75s ease infinite 0.5s`,
|
||||
},
|
||||
},
|
||||
"points-opacity": {
|
||||
d: "flex",
|
||||
position: "relative",
|
||||
i: {
|
||||
display: "inline-block",
|
||||
size: "$$loadingSize",
|
||||
br: "$rounded",
|
||||
bg: "$$loadingColor",
|
||||
margin: "0 1px",
|
||||
animation: `${blink} 1.4s infinite both`,
|
||||
},
|
||||
"._2": {
|
||||
animationDelay: "0.2s",
|
||||
},
|
||||
"._3": {
|
||||
animationDelay: "0.4s",
|
||||
},
|
||||
},
|
||||
spinner: {},
|
||||
gradient: {
|
||||
display: "flex",
|
||||
position: "relative",
|
||||
size: "$$loadingSize",
|
||||
"._1": {
|
||||
position: "absolute",
|
||||
size: "100%",
|
||||
border: "0px",
|
||||
animation: `${rotate} 1s linear infinite`,
|
||||
top: "0px",
|
||||
br: "$rounded",
|
||||
bg: "linear-gradient(0deg, $background 33%,$$loadingColor 100%)",
|
||||
},
|
||||
"._2": {
|
||||
top: "2px",
|
||||
position: "absolute",
|
||||
size: "calc(100% - 4px)",
|
||||
border: "0px",
|
||||
bg: "$background",
|
||||
br: "$rounded",
|
||||
},
|
||||
"._3": {
|
||||
display: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
compoundVariants: [
|
||||
// points-opacity & xs size
|
||||
{
|
||||
size: "xs",
|
||||
type: "points-opacity",
|
||||
css: {
|
||||
$$loadingSize: "$space$1",
|
||||
},
|
||||
},
|
||||
// points-opacity & sm size
|
||||
{
|
||||
size: "sm",
|
||||
type: "points-opacity",
|
||||
css: {
|
||||
$$loadingSize: "$space$2",
|
||||
},
|
||||
},
|
||||
// points-opacity & md size
|
||||
{
|
||||
size: "md",
|
||||
type: "points-opacity",
|
||||
css: {
|
||||
$$loadingSize: "$space$3",
|
||||
},
|
||||
},
|
||||
// points-opacity & lg size
|
||||
{
|
||||
size: "lg",
|
||||
type: "points-opacity",
|
||||
css: {
|
||||
$$loadingSize: "$space$4",
|
||||
},
|
||||
},
|
||||
// points-opacity & xl size
|
||||
{
|
||||
size: "xl",
|
||||
type: "points-opacity",
|
||||
css: {
|
||||
$$loadingSize: "$space$5",
|
||||
},
|
||||
},
|
||||
// points & xs size
|
||||
{
|
||||
size: "xs",
|
||||
type: "points",
|
||||
css: {
|
||||
$$loadingSize: "$space$1",
|
||||
},
|
||||
},
|
||||
// points & sm size
|
||||
{
|
||||
size: "sm",
|
||||
type: "points",
|
||||
css: {
|
||||
$$loadingSize: "$space$2",
|
||||
},
|
||||
},
|
||||
// points & md size
|
||||
{
|
||||
size: "md",
|
||||
type: "points",
|
||||
css: {
|
||||
$$loadingSize: "$space$3",
|
||||
},
|
||||
},
|
||||
// points & lg size
|
||||
{
|
||||
size: "lg",
|
||||
type: "points",
|
||||
css: {
|
||||
$$loadingSize: "$space$4",
|
||||
},
|
||||
},
|
||||
// points & xl size
|
||||
{
|
||||
size: "xl",
|
||||
type: "points",
|
||||
css: {
|
||||
$$loadingSize: "$space$5",
|
||||
},
|
||||
},
|
||||
],
|
||||
defaultVariants: {
|
||||
type: "default",
|
||||
},
|
||||
});
|
||||
|
||||
export const StyledLoadingLabel = styled("label", {
|
||||
mt: "$1",
|
||||
color: "$$labelColor",
|
||||
fontSize: "$$loadingSize",
|
||||
"*": {
|
||||
margin: 0,
|
||||
},
|
||||
variants: {
|
||||
size: {
|
||||
xs: {
|
||||
fontSize: "$space$5",
|
||||
marginTop: "$2",
|
||||
},
|
||||
sm: {
|
||||
fontSize: "$space$6",
|
||||
marginTop: "$3",
|
||||
},
|
||||
md: {
|
||||
fontSize: "$base",
|
||||
marginTop: "$4",
|
||||
},
|
||||
lg: {
|
||||
fontSize: "$space$10",
|
||||
marginTop: "$4",
|
||||
},
|
||||
xl: {
|
||||
fontSize: "$space$11",
|
||||
marginTop: "$5",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
72
packages/components/loading/src/loading.tsx
Normal file
72
packages/components/loading/src/loading.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import {forwardRef} from "@nextui-org/system";
|
||||
import {useDOMRef} from "@nextui-org/dom-utils";
|
||||
import {clsx, __DEV__} from "@nextui-org/shared-utils";
|
||||
|
||||
import {StyledLoadingContainer, StyledLoading, StyledLoadingLabel} from "./loading.styles";
|
||||
import {UseLoadingProps, useLoading} from "./use-loading";
|
||||
import Spinner from "./variants/spinner";
|
||||
|
||||
export interface LoadingProps extends UseLoadingProps {}
|
||||
|
||||
const Loading = forwardRef<LoadingProps, "div">((props, ref) => {
|
||||
const {
|
||||
css,
|
||||
containerCss,
|
||||
gradientCSS,
|
||||
children,
|
||||
size,
|
||||
type,
|
||||
ariaLabel,
|
||||
loadingColor,
|
||||
labelColor,
|
||||
className,
|
||||
...otherProps
|
||||
} = useLoading(props);
|
||||
|
||||
const domRef = useDOMRef(ref);
|
||||
|
||||
return (
|
||||
<StyledLoadingContainer
|
||||
ref={domRef}
|
||||
className={clsx("nextui-loading-container", className)}
|
||||
css={{
|
||||
$$loadingColor: loadingColor,
|
||||
$$labelColor: labelColor,
|
||||
...containerCss,
|
||||
}}
|
||||
{...otherProps}
|
||||
>
|
||||
{type === "spinner" ? (
|
||||
<Spinner aria-label={ariaLabel} css={css} size={size} />
|
||||
) : (
|
||||
<StyledLoading
|
||||
aria-label={ariaLabel}
|
||||
className={clsx("nextui-loading", `nextui-loading-${type}`)}
|
||||
css={{
|
||||
...css,
|
||||
...gradientCSS,
|
||||
}}
|
||||
size={size}
|
||||
type={type}
|
||||
>
|
||||
<i className="_1" />
|
||||
<i className="_2" />
|
||||
<i className="_3" />
|
||||
</StyledLoading>
|
||||
)}
|
||||
{children && (
|
||||
<StyledLoadingLabel className="nextui-loading-label" size={size}>
|
||||
{children}
|
||||
</StyledLoadingLabel>
|
||||
)}
|
||||
</StyledLoadingContainer>
|
||||
);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
Loading.displayName = "NextUI.Loading";
|
||||
}
|
||||
|
||||
Loading.toString = () => ".nextui-loading";
|
||||
|
||||
export default Loading;
|
||||
71
packages/components/loading/src/use-loading.ts
Normal file
71
packages/components/loading/src/use-loading.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import {useMemo} from "react";
|
||||
import {getCSSColor, NormalSizes} from "@nextui-org/shared-utils";
|
||||
import {CSS, HTMLNextUIProps} from "@nextui-org/system";
|
||||
|
||||
export interface UseLoadingProps extends HTMLNextUIProps<"div"> {
|
||||
/**
|
||||
* Loading size.
|
||||
* @default "md"
|
||||
*/
|
||||
size?: NormalSizes;
|
||||
/**
|
||||
* Loading color.
|
||||
* @default "primary"
|
||||
*/
|
||||
color?: CSS["color"];
|
||||
/**
|
||||
* Loading label color.
|
||||
* @default "default"
|
||||
*/
|
||||
textColor?: CSS["color"];
|
||||
/**
|
||||
* Loading type.
|
||||
* @default "default"
|
||||
*/
|
||||
//TODO: rename to "variant"
|
||||
type?: "default" | "points" | "points-opacity" | "gradient" | "spinner";
|
||||
/**
|
||||
* Sets a background for the "gradient" loading variant.
|
||||
*/
|
||||
gradientBackground?: CSS["color"];
|
||||
/**
|
||||
* Override default container styles
|
||||
*/
|
||||
containerCss?: CSS;
|
||||
}
|
||||
|
||||
export function useLoading(props: UseLoadingProps) {
|
||||
const {
|
||||
children,
|
||||
size = "md",
|
||||
color = "primary",
|
||||
type = "default",
|
||||
textColor = "default",
|
||||
gradientBackground,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
const gradientCSS = useMemo(() => {
|
||||
return type === "gradient" ? {"._2": {bg: gradientBackground}} : {};
|
||||
}, [type, gradientBackground]);
|
||||
|
||||
const ariaLabel = useMemo(() => {
|
||||
if (children && typeof children === "string") {
|
||||
return children;
|
||||
}
|
||||
|
||||
return !otherProps["aria-label"] ? "Loading" : "";
|
||||
}, [children, otherProps["aria-label"]]);
|
||||
|
||||
const loadingColor = useMemo(() => {
|
||||
return getCSSColor(color as string);
|
||||
}, [color]);
|
||||
|
||||
const labelColor = useMemo(() => {
|
||||
return getCSSColor(textColor as string);
|
||||
}, [textColor]);
|
||||
|
||||
return {children, size, type, loadingColor, labelColor, ariaLabel, gradientCSS, ...otherProps};
|
||||
}
|
||||
|
||||
export type UseLoadingReturn = ReturnType<typeof useLoading>;
|
||||
129
packages/components/loading/src/variants/spinner.tsx
Normal file
129
packages/components/loading/src/variants/spinner.tsx
Normal file
@ -0,0 +1,129 @@
|
||||
import {styled, keyframes, forwardRef} from "@nextui-org/system";
|
||||
import {useDOMRef} from "@nextui-org/dom-utils";
|
||||
import {clsx, __DEV__} from "@nextui-org/shared-utils";
|
||||
|
||||
import {UseLoadingProps} from "../use-loading";
|
||||
|
||||
export interface SpinnerProps
|
||||
extends Omit<UseLoadingProps, "type" | "gradientBackground" | "containerCss"> {}
|
||||
|
||||
export const spinnerAnimation = keyframes({
|
||||
"0%": {
|
||||
opacity: 1,
|
||||
},
|
||||
"100%": {
|
||||
opacity: 0.15,
|
||||
},
|
||||
});
|
||||
|
||||
export const StyledSpinner = styled("div", {
|
||||
d: "flex",
|
||||
fd: "column",
|
||||
jc: "center",
|
||||
ai: "center",
|
||||
position: "relative",
|
||||
variants: {
|
||||
size: {
|
||||
xs: {
|
||||
size: "$6",
|
||||
},
|
||||
sm: {
|
||||
size: "$8",
|
||||
},
|
||||
md: {
|
||||
size: "$9",
|
||||
},
|
||||
lg: {
|
||||
size: "$11",
|
||||
},
|
||||
xl: {
|
||||
size: "$12",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const StyledSpinnerSpan = styled("span", {
|
||||
bg: "$$loadingColor",
|
||||
position: "absolute",
|
||||
width: "34%",
|
||||
height: "8%",
|
||||
br: "$lg",
|
||||
animation: `${spinnerAnimation} 1.2s linear 0s infinite normal none running`,
|
||||
"&:nth-child(1)": {
|
||||
animationDelay: "-1.2s",
|
||||
transform: "rotate(0deg) translate(146%)",
|
||||
},
|
||||
"&:nth-child(2)": {
|
||||
animationDelay: "-1.1s",
|
||||
transform: "rotate(30deg) translate(146%)",
|
||||
},
|
||||
"&:nth-child(3)": {
|
||||
animationDelay: "-1s",
|
||||
transform: "rotate(60deg) translate(146%)",
|
||||
},
|
||||
"&:nth-child(4)": {
|
||||
animationDelay: "-0.9s",
|
||||
transform: "rotate(90deg) translate(146%)",
|
||||
},
|
||||
"&:nth-child(5)": {
|
||||
animationDelay: "-0.8s",
|
||||
transform: "rotate(120deg) translate(146%)",
|
||||
},
|
||||
"&:nth-child(6)": {
|
||||
animationDelay: "-0.7s",
|
||||
transform: "rotate(150deg) translate(146%)",
|
||||
},
|
||||
"&:nth-child(7)": {
|
||||
animationDelay: "-0.6s",
|
||||
transform: "rotate(180deg) translate(146%)",
|
||||
},
|
||||
"&:nth-child(8)": {
|
||||
animationDelay: "-0.5s",
|
||||
transform: "rotate(210deg) translate(146%)",
|
||||
},
|
||||
"&:nth-child(9)": {
|
||||
animationDelay: "-0.4s",
|
||||
transform: "rotate(240deg) translate(146%)",
|
||||
},
|
||||
"&:nth-child(10)": {
|
||||
animationDelay: "-0.3s",
|
||||
transform: "rotate(270deg) translate(146%)",
|
||||
},
|
||||
"&:nth-child(11)": {
|
||||
animationDelay: "-0.2s",
|
||||
transform: "rotate(300deg) translate(146%)",
|
||||
},
|
||||
"&:nth-child(12)": {
|
||||
animationDelay: "-0.1s",
|
||||
transform: "rotate(330deg) translate(146%)",
|
||||
},
|
||||
});
|
||||
|
||||
const Spinner = forwardRef<SpinnerProps, "div">((props, ref) => {
|
||||
const {children, size, className, ...otherProps} = props;
|
||||
|
||||
const domRef = useDOMRef(ref);
|
||||
|
||||
return (
|
||||
<StyledSpinner
|
||||
ref={domRef}
|
||||
className={clsx("nextui-spinner", className)}
|
||||
size={size}
|
||||
{...otherProps}
|
||||
>
|
||||
{[...new Array(12)].map((_, index) => (
|
||||
<StyledSpinnerSpan key={`nextui-spinner-${index}`} />
|
||||
))}
|
||||
{children}
|
||||
</StyledSpinner>
|
||||
);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
Spinner.displayName = "NextUI.Spinner";
|
||||
}
|
||||
|
||||
Spinner.toString = () => ".nextui-spinner";
|
||||
|
||||
export default Spinner;
|
||||
99
packages/components/loading/stories/loading.stories.tsx
Normal file
99
packages/components/loading/stories/loading.stories.tsx
Normal file
@ -0,0 +1,99 @@
|
||||
import React from "react";
|
||||
import {Meta} from "@storybook/react";
|
||||
import {Spacer} from "@nextui-org/spacer";
|
||||
import {Grid} from "@nextui-org/grid";
|
||||
|
||||
import {Loading} from "../src";
|
||||
|
||||
export default {
|
||||
title: "Feedback/Loading",
|
||||
component: Loading,
|
||||
} as Meta;
|
||||
|
||||
export const Default = () => <Loading />;
|
||||
|
||||
export const Text = () => (
|
||||
<>
|
||||
<Loading size="xs">Loading</Loading>
|
||||
<Spacer x={1} />
|
||||
<Loading size="sm">Loading</Loading>
|
||||
<Spacer x={1} />
|
||||
<Loading size="md">Loading</Loading>
|
||||
<Spacer x={1} />
|
||||
<Loading size="lg">Loading</Loading>
|
||||
<Spacer x={1} />
|
||||
<Loading size="xl">Loading</Loading>
|
||||
<Spacer x={1} />
|
||||
</>
|
||||
);
|
||||
|
||||
export const Colors = () => (
|
||||
<>
|
||||
<Loading color="primary">Primary</Loading>
|
||||
<Spacer x={1} />
|
||||
<Loading color="secondary">Secondary</Loading>
|
||||
<Spacer x={1} />
|
||||
<Loading color="success">Success</Loading>
|
||||
<Spacer x={1} />
|
||||
<Loading color="warning">Warning</Loading>
|
||||
<Spacer x={1} />
|
||||
<Loading color="error">Error</Loading>
|
||||
<Spacer x={1} />
|
||||
</>
|
||||
);
|
||||
|
||||
export const TextColors = () => (
|
||||
<>
|
||||
<Loading textColor="primary">Primary</Loading>
|
||||
<Spacer x={1} />
|
||||
<Loading textColor="secondary">Secondary</Loading>
|
||||
<Spacer x={1} />
|
||||
<Loading textColor="success">Success</Loading>
|
||||
<Spacer x={1} />
|
||||
<Loading textColor="warning">Warning</Loading>
|
||||
<Spacer x={1} />
|
||||
<Loading textColor="error">Error</Loading>
|
||||
<Spacer x={1} />
|
||||
</>
|
||||
);
|
||||
|
||||
export const Sizes = () => (
|
||||
<>
|
||||
<Loading size="xs">mini</Loading>
|
||||
<Spacer y={2} />
|
||||
<Loading size="sm">small</Loading>
|
||||
<Spacer y={2} />
|
||||
<Loading size="md">medium</Loading>
|
||||
<Spacer y={2} />
|
||||
<Loading size="lg">large</Loading>
|
||||
<Spacer y={2} />
|
||||
<Loading size="xl">xlarge</Loading>
|
||||
<Spacer y={2} />
|
||||
</>
|
||||
);
|
||||
|
||||
export const Types = () => (
|
||||
<Grid.Container gap={4} justify="center">
|
||||
<Grid>
|
||||
<Loading type="default">default</Loading>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Loading type="spinner">spinner</Loading>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Loading style={{marginLeft: "-0.5rem"}} type="points">
|
||||
points
|
||||
</Loading>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Loading style={{marginLeft: "-0.5rem"}} type="points-opacity">
|
||||
points-opacity
|
||||
</Loading>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Loading style={{marginLeft: "-0.5rem"}} type="gradient">
|
||||
gradient
|
||||
</Loading>
|
||||
</Grid>
|
||||
</Grid.Container>
|
||||
);
|
||||
9
packages/components/loading/tsconfig.json
Normal file
9
packages/components/loading/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@stitches/react": ["../../../node_modules/@stitches/react"]
|
||||
}
|
||||
},
|
||||
"include": ["src", "index.ts"]
|
||||
}
|
||||
13
packages/components/loading/tsup.config.ts
Normal file
13
packages/components/loading/tsup.config.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import {defineConfig} from "tsup";
|
||||
import {findUpSync} from "find-up";
|
||||
|
||||
export default defineConfig({
|
||||
clean: true,
|
||||
minify: false,
|
||||
treeshake: true,
|
||||
format: ["cjs", "esm"],
|
||||
outExtension(ctx) {
|
||||
return {js: `.${ctx.format}.js`};
|
||||
},
|
||||
inject: process.env.JSX ? [findUpSync("react-shim.js")!] : undefined,
|
||||
});
|
||||
@ -187,3 +187,32 @@ export const invertHex = (hexProp: string, smooth = true) => {
|
||||
// pad each with zeros and return
|
||||
return "#" + padZero(r.toString(16)) + padZero(g.toString(16)) + padZero(b.toString(16));
|
||||
};
|
||||
|
||||
/**
|
||||
* Function that returns the color token name, if it exists, otherwise returns the color itself
|
||||
* @example getCSSColor("primary") // returns "$primary", getCSSColor("#fff") // returns "#fff"
|
||||
* @param color - string
|
||||
* @param defaultColor - string
|
||||
* @returns string
|
||||
*/
|
||||
export function getCSSColor(color: string, defaultColor: string = "$colors$text") {
|
||||
if (!color) {
|
||||
return defaultColor;
|
||||
}
|
||||
if (isNormalColor(color)) {
|
||||
switch (color) {
|
||||
case "default":
|
||||
return defaultColor;
|
||||
default:
|
||||
return `$colors$${color}`;
|
||||
}
|
||||
}
|
||||
|
||||
if (color?.startsWith("$") && color?.includes("$colors")) {
|
||||
// $colors$<color> e.g. $colors$primary
|
||||
return `$colors$${color}`;
|
||||
}
|
||||
|
||||
// #color || rgb || rgba
|
||||
return color;
|
||||
}
|
||||
|
||||
21
pnpm-lock.yaml
generated
21
pnpm-lock.yaml
generated
@ -348,6 +348,7 @@ importers:
|
||||
'@nextui-org/drip': workspace:*
|
||||
'@nextui-org/grid': workspace:*
|
||||
'@nextui-org/icons-utils': workspace:*
|
||||
'@nextui-org/loading': workspace:*
|
||||
'@nextui-org/shared-css': workspace:*
|
||||
'@nextui-org/shared-utils': workspace:*
|
||||
'@nextui-org/spacer': workspace:*
|
||||
@ -373,6 +374,7 @@ importers:
|
||||
devDependencies:
|
||||
'@nextui-org/grid': link:../grid
|
||||
'@nextui-org/icons-utils': link:../../utilities/icons-utils
|
||||
'@nextui-org/loading': link:../loading
|
||||
'@nextui-org/spacer': link:../spacer
|
||||
'@react-types/button': 3.6.2_react@17.0.2
|
||||
'@react-types/shared': 3.15.0_react@17.0.2
|
||||
@ -602,6 +604,25 @@ importers:
|
||||
clean-package: 2.1.1
|
||||
react: 17.0.2
|
||||
|
||||
packages/components/loading:
|
||||
specifiers:
|
||||
'@nextui-org/dom-utils': workspace:*
|
||||
'@nextui-org/grid': workspace:*
|
||||
'@nextui-org/shared-utils': workspace:*
|
||||
'@nextui-org/spacer': workspace:*
|
||||
'@nextui-org/system': workspace:*
|
||||
clean-package: 2.1.1
|
||||
react: ^17.0.2
|
||||
dependencies:
|
||||
'@nextui-org/dom-utils': link:../../utilities/dom-utils
|
||||
'@nextui-org/shared-utils': link:../../utilities/shared-utils
|
||||
'@nextui-org/system': link:../../core/system
|
||||
devDependencies:
|
||||
'@nextui-org/grid': link:../grid
|
||||
'@nextui-org/spacer': link:../spacer
|
||||
clean-package: 2.1.1
|
||||
react: 17.0.2
|
||||
|
||||
packages/components/row:
|
||||
specifiers:
|
||||
'@nextui-org/dom-utils': workspace:*
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user