mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
feat(components): button component added
This commit is contained in:
parent
6991692525
commit
54d26fed91
24
packages/components/button/README.md
Normal file
24
packages/components/button/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# @nextui-org/button
|
||||
|
||||
A Quick description of the component
|
||||
|
||||
> This is an internal utility, not intended for public usage.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
yarn add @nextui-org/button
|
||||
# or
|
||||
npm i @nextui-org/button
|
||||
```
|
||||
|
||||
## 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).
|
||||
72
packages/components/button/__tests__/button.test.tsx
Normal file
72
packages/components/button/__tests__/button.test.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import * as React from "react";
|
||||
import {render} from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
|
||||
import {Button} from "../src";
|
||||
|
||||
describe("Button", () => {
|
||||
it("should render correctly", () => {
|
||||
const wrapper = render(<Button />);
|
||||
|
||||
expect(() => wrapper.unmount()).not.toThrow();
|
||||
});
|
||||
|
||||
it("ref should be forwarded", () => {
|
||||
const ref = React.createRef<HTMLButtonElement>();
|
||||
|
||||
render(<Button ref={ref} />);
|
||||
expect(ref.current).not.toBeNull();
|
||||
});
|
||||
|
||||
it("should trigger onPress function", () => {
|
||||
const onPress = jest.fn();
|
||||
const {getByRole} = render(<Button onPress={onPress} />);
|
||||
|
||||
getByRole("button").click();
|
||||
expect(onPress).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should show warning message when onClick is being used", () => {
|
||||
const onClick = jest.fn();
|
||||
const spy = jest.spyOn(console, "warn").mockImplementation(() => {});
|
||||
|
||||
const wrapper = render(<Button onClick={onClick} />);
|
||||
|
||||
let button = wrapper.getByRole("button");
|
||||
|
||||
userEvent.click(button);
|
||||
|
||||
expect(spy).toHaveBeenCalled();
|
||||
spy.mockRestore();
|
||||
});
|
||||
|
||||
it("should ignore events when disabled", () => {
|
||||
const onPress = jest.fn();
|
||||
const {getByRole} = render(<Button disabled onPress={onPress} />);
|
||||
|
||||
getByRole("button").click();
|
||||
expect(onPress).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should renders with left icon", () => {
|
||||
const wrapper = render(
|
||||
<Button icon={<span data-testid="left-icon">Icon</span>}>Button</Button>,
|
||||
);
|
||||
|
||||
expect(wrapper.getByTestId("left-icon")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should renders with right icon", () => {
|
||||
const wrapper = render(
|
||||
<Button iconRight={<span data-testid="right-icon">Icon</span>}>Button</Button>,
|
||||
);
|
||||
|
||||
expect(wrapper.getByTestId("right-icon")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should have the proper type attribute", () => {
|
||||
const wrapper = render(<Button type="submit" />);
|
||||
|
||||
expect(wrapper.getByRole("button")).toHaveAttribute("type", "submit");
|
||||
});
|
||||
});
|
||||
75
packages/components/button/__tests__/group.test.tsx
Normal file
75
packages/components/button/__tests__/group.test.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
import React from "react";
|
||||
import {render} from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
|
||||
import {Button} from "../src";
|
||||
|
||||
describe("ButtonGroup", () => {
|
||||
it("should render correctly", () => {
|
||||
const wrapper = render(
|
||||
<Button.Group>
|
||||
<Button>action</Button>
|
||||
</Button.Group>,
|
||||
);
|
||||
|
||||
expect(() => wrapper.unmount()).not.toThrow();
|
||||
});
|
||||
|
||||
it("ref should be forwarded", () => {
|
||||
const ref = React.createRef<HTMLDivElement>();
|
||||
|
||||
render(<Button.Group ref={ref} />);
|
||||
expect(ref.current).not.toBeNull();
|
||||
});
|
||||
|
||||
it("should ignore events when group disabled", () => {
|
||||
const handler = jest.fn();
|
||||
const wrapper = render(
|
||||
<Button.Group disabled>
|
||||
<Button data-testid="button-test" onClick={handler}>
|
||||
action
|
||||
</Button>
|
||||
</Button.Group>,
|
||||
);
|
||||
|
||||
let button = wrapper.getByTestId("button-test");
|
||||
|
||||
userEvent.click(button);
|
||||
expect(handler).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
it("buttons should be displayed vertically", () => {
|
||||
const wrapper = render(
|
||||
<Button.Group vertical>
|
||||
<Button>action1</Button>
|
||||
<Button>action2</Button>
|
||||
</Button.Group>,
|
||||
);
|
||||
|
||||
expect(() => wrapper.unmount()).not.toThrow();
|
||||
});
|
||||
|
||||
it("should render different variants", () => {
|
||||
const wrapper = render(
|
||||
<Button.Group>
|
||||
<Button flat>button</Button>
|
||||
<Button light color="warning">
|
||||
light
|
||||
</Button>
|
||||
<Button flat color="success">
|
||||
button
|
||||
</Button>
|
||||
<Button flat color="warning">
|
||||
button
|
||||
</Button>
|
||||
<Button rounded>button</Button>
|
||||
<Button flat>button</Button>
|
||||
<Button shadow>button</Button>
|
||||
<Button auto>button</Button>
|
||||
<Button animated={false}>button</Button>
|
||||
</Button.Group>,
|
||||
);
|
||||
|
||||
expect(() => wrapper.unmount()).not.toThrow();
|
||||
});
|
||||
});
|
||||
3
packages/components/button/clean-package.config.json
Normal file
3
packages/components/button/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" } } }
|
||||
58
packages/components/button/package.json
Normal file
58
packages/components/button/package.json
Normal file
@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "@nextui-org/button",
|
||||
"version": "1.0.0-beta.11",
|
||||
"description": "Buttons allow users to perform actions and choose with a single tap.",
|
||||
"keywords": [
|
||||
"button"
|
||||
],
|
||||
"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/button"
|
||||
},
|
||||
"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/shared-css": "workspace:*",
|
||||
"@nextui-org/dom-utils": "workspace:*",
|
||||
"@nextui-org/drip": "workspace:*",
|
||||
"@react-aria/button": "^3.6.2",
|
||||
"@react-aria/interactions": "^3.12.0",
|
||||
"@react-aria/utils": "^3.14.0",
|
||||
"@react-aria/focus": "^3.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nextui-org/spacer": "workspace:*",
|
||||
"@nextui-org/icons-utils": "workspace:*",
|
||||
"@react-types/shared": "^3.14.1",
|
||||
"@react-types/button": "^3.6.2",
|
||||
"clean-package": "2.1.1",
|
||||
"react": "^17.0.2"
|
||||
}
|
||||
}
|
||||
8
packages/components/button/src/button-group-context.ts
Normal file
8
packages/components/button/src/button-group-context.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import {createContext} from "@nextui-org/shared-utils";
|
||||
|
||||
import {UseButtonProps} from "./use-button";
|
||||
|
||||
export const [ButtonGroupProvider, useButtonGroupContext] = createContext<UseButtonProps>({
|
||||
name: "ButtonGroupContext",
|
||||
strict: false,
|
||||
});
|
||||
120
packages/components/button/src/button-group.styles.ts
Normal file
120
packages/components/button/src/button-group.styles.ts
Normal file
@ -0,0 +1,120 @@
|
||||
import {styled} from "@nextui-org/system";
|
||||
|
||||
import {StyledButton} from "./button.styles";
|
||||
|
||||
export const StyledButtonGroup = styled("div", {
|
||||
display: "inline-flex",
|
||||
margin: "$3",
|
||||
backgroundColor: "transparent",
|
||||
height: "min-content",
|
||||
[`& ${StyledButton}`]: {
|
||||
".nextui-button-text": {
|
||||
top: 0,
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
size: {
|
||||
xs: {
|
||||
br: "$xs",
|
||||
},
|
||||
sm: {
|
||||
br: "$sm",
|
||||
},
|
||||
md: {
|
||||
br: "$md",
|
||||
},
|
||||
lg: {
|
||||
br: "$base",
|
||||
},
|
||||
xl: {
|
||||
br: "$xl",
|
||||
},
|
||||
},
|
||||
isVertical: {
|
||||
true: {
|
||||
fd: "column",
|
||||
[`& ${StyledButton}`]: {
|
||||
"&:not(:first-child)": {
|
||||
btlr: 0, // top-left
|
||||
btrr: 0, // top-right
|
||||
},
|
||||
"&:not(:last-child)": {
|
||||
bblr: 0,
|
||||
bbrr: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
false: {
|
||||
fd: "row",
|
||||
[`& ${StyledButton}`]: {
|
||||
"&:not(:first-child)": {
|
||||
btlr: 0, // top-left
|
||||
bblr: 0, // bottom-left
|
||||
},
|
||||
"&:not(:last-child)": {
|
||||
btrr: 0, // top-right
|
||||
bbrr: 0, // bottom-right
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
isRounded: {
|
||||
true: {
|
||||
br: "$pill",
|
||||
},
|
||||
},
|
||||
isBordered: {
|
||||
true: {
|
||||
bg: "transparent",
|
||||
},
|
||||
},
|
||||
isGradient: {
|
||||
true: {
|
||||
pl: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
compoundVariants: [
|
||||
// isBordered / isVertical:true
|
||||
{
|
||||
isBordered: true,
|
||||
isVertical: true,
|
||||
css: {
|
||||
[`& ${StyledButton}`]: {
|
||||
"&:not(:last-child)": {
|
||||
borderBottom: "none",
|
||||
paddingBottom: "0",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// isBordered / isVertical:false
|
||||
{
|
||||
isBordered: true,
|
||||
isVertical: false,
|
||||
css: {
|
||||
[`& ${StyledButton}`]: {
|
||||
"&:not(:first-child)": {
|
||||
borderLeft: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// isBordered & isVertical:false & isGradient
|
||||
{
|
||||
isBordered: true,
|
||||
isVertical: false,
|
||||
isGradient: true,
|
||||
css: {
|
||||
[`& ${StyledButton}`]: {
|
||||
"&:not(:last-child)&:not(:first-child)": {
|
||||
pl: 0,
|
||||
},
|
||||
"&:last-child": {
|
||||
pl: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
35
packages/components/button/src/button-group.tsx
Normal file
35
packages/components/button/src/button-group.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import {forwardRef} from "@nextui-org/system";
|
||||
import {useDOMRef} from "@nextui-org/dom-utils";
|
||||
import {clsx, __DEV__} from "@nextui-org/shared-utils";
|
||||
|
||||
import {ButtonGroupProvider} from "./button-group-context";
|
||||
import {UseButtonGroupProps, useButtonGroup} from "./use-button-group";
|
||||
import {StyledButtonGroup} from "./button-group.styles";
|
||||
|
||||
export interface ButtonGroupProps extends UseButtonGroupProps {}
|
||||
|
||||
const ButtonGroup = forwardRef<ButtonGroupProps, "div">((props, ref) => {
|
||||
const {context, children, className, ...otherProps} = useButtonGroup(props);
|
||||
|
||||
const domRef = useDOMRef(ref);
|
||||
|
||||
return (
|
||||
<ButtonGroupProvider value={context}>
|
||||
<StyledButtonGroup
|
||||
ref={domRef}
|
||||
className={clsx("nextui-button-group", className)}
|
||||
{...otherProps}
|
||||
>
|
||||
{children}
|
||||
</StyledButtonGroup>
|
||||
</ButtonGroupProvider>
|
||||
);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
ButtonGroup.displayName = "NextUI.ButtonGroup";
|
||||
}
|
||||
|
||||
ButtonGroup.toString = () => ".nextui-button-group";
|
||||
|
||||
export default ButtonGroup;
|
||||
130
packages/components/button/src/button-icon.tsx
Normal file
130
packages/components/button/src/button-icon.tsx
Normal file
@ -0,0 +1,130 @@
|
||||
import {styled, forwardRef, HTMLNextUIProps} from "@nextui-org/system";
|
||||
import {useDOMRef} from "@nextui-org/dom-utils";
|
||||
import {clsx, __DEV__} from "@nextui-org/shared-utils";
|
||||
|
||||
export interface ButtonIconProps extends HTMLNextUIProps<"span"> {
|
||||
isAuto?: boolean;
|
||||
isRight?: boolean;
|
||||
isSingle?: boolean;
|
||||
isGradientButtonBorder?: boolean;
|
||||
}
|
||||
|
||||
const StyledButtonIcon = styled("span", {
|
||||
dflex: "center",
|
||||
position: "absolute",
|
||||
left: "$$buttonPadding",
|
||||
right: "auto",
|
||||
top: "50%",
|
||||
transform: "translateY(-50%)",
|
||||
color: "inherit",
|
||||
zIndex: "$1",
|
||||
"& svg": {
|
||||
background: "transparent",
|
||||
},
|
||||
variants: {
|
||||
isAuto: {
|
||||
true: {
|
||||
position: "relative",
|
||||
transform: "none",
|
||||
top: "0%",
|
||||
},
|
||||
},
|
||||
isRight: {
|
||||
true: {
|
||||
right: "$$buttonPadding",
|
||||
left: "auto",
|
||||
},
|
||||
},
|
||||
isSingle: {
|
||||
true: {
|
||||
position: "static",
|
||||
transform: "none",
|
||||
},
|
||||
},
|
||||
isGradientButtonBorder: {
|
||||
true: {},
|
||||
},
|
||||
},
|
||||
compoundVariants: [
|
||||
// isAuto && isRight
|
||||
{
|
||||
isAuto: true,
|
||||
isRight: true,
|
||||
isSingle: false,
|
||||
css: {
|
||||
order: 2,
|
||||
ml: "calc($$buttonPadding / 2)",
|
||||
right: "0%",
|
||||
left: "0%",
|
||||
},
|
||||
},
|
||||
// isAuto && !isRight
|
||||
{
|
||||
isAuto: true,
|
||||
isRight: false,
|
||||
isSingle: false,
|
||||
css: {
|
||||
order: 0,
|
||||
mr: "calc($$buttonPadding / 2)",
|
||||
right: "0%",
|
||||
left: "0%",
|
||||
},
|
||||
},
|
||||
// isSingle && isRight
|
||||
{
|
||||
isSingle: true,
|
||||
isRight: false,
|
||||
css: {
|
||||
ml: 0,
|
||||
},
|
||||
},
|
||||
// isSingle && !isRight
|
||||
{
|
||||
isSingle: true,
|
||||
isRight: true,
|
||||
css: {
|
||||
mr: 0,
|
||||
},
|
||||
},
|
||||
// isSingle && !isRight && hasButttonBorder
|
||||
{
|
||||
isSingle: true,
|
||||
isRight: false,
|
||||
isGradientButtonBorder: true,
|
||||
css: {
|
||||
mr: "calc($$buttonPadding / 2)",
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const ButtonIcon = forwardRef<ButtonIconProps, "span">((props, ref) => {
|
||||
const {children, className, ...otherProps} = props;
|
||||
|
||||
const domRef = useDOMRef(ref);
|
||||
|
||||
return (
|
||||
<StyledButtonIcon
|
||||
ref={domRef}
|
||||
className={clsx(
|
||||
"nextui-button-icon",
|
||||
{
|
||||
"nextui-button-icon-right": props.isRight,
|
||||
"nextui-button-icon-single": props.isSingle,
|
||||
},
|
||||
className,
|
||||
)}
|
||||
{...otherProps}
|
||||
>
|
||||
{children}
|
||||
</StyledButtonIcon>
|
||||
);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
ButtonIcon.displayName = "NextUI.ButtonIcon";
|
||||
}
|
||||
|
||||
ButtonIcon.toString = () => ".nextui-button-icon";
|
||||
|
||||
export default ButtonIcon;
|
||||
52
packages/components/button/src/button-utils.ts
Normal file
52
packages/components/button/src/button-utils.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import type {UseButtonProps} from "./use-button";
|
||||
|
||||
export const getColors = (props: UseButtonProps) => {
|
||||
if (!props.disabled) {
|
||||
if (props.auto && props.color === "gradient" && (props.bordered || props.ghost)) {
|
||||
return {
|
||||
px: "$$buttonBorderWeight",
|
||||
py: "$$buttonBorderWeight",
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
const defaultDisabledCss = {
|
||||
bg: "$accents1",
|
||||
color: "$accents7",
|
||||
transform: "none",
|
||||
boxShadow: "none",
|
||||
pe: "none",
|
||||
};
|
||||
|
||||
if (!props.bordered && !props.flat && !props.ghost && !props.light) {
|
||||
return defaultDisabledCss;
|
||||
}
|
||||
if (props.color === "gradient" && (props.bordered || props.ghost)) {
|
||||
return {
|
||||
color: "$accents4",
|
||||
backgroundImage:
|
||||
"linear-gradient($background, $background), linear-gradient($accents2, $accents2)",
|
||||
transform: "none",
|
||||
boxShadow: "none",
|
||||
pe: "none",
|
||||
pl: "$$buttonBorderWeight",
|
||||
pr: "$$buttonBorderWeight",
|
||||
};
|
||||
}
|
||||
if (props.bordered || props.ghost || props.light) {
|
||||
return {
|
||||
...defaultDisabledCss,
|
||||
bg: "transparent",
|
||||
borderColor: "$accents4",
|
||||
};
|
||||
}
|
||||
if (props.flat) {
|
||||
return {
|
||||
...defaultDisabledCss,
|
||||
bg: "$accents1",
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
||||
815
packages/components/button/src/button.styles.ts
Normal file
815
packages/components/button/src/button.styles.ts
Normal file
@ -0,0 +1,815 @@
|
||||
import {styled} from "@nextui-org/system";
|
||||
import {cssFocusVisible} from "@nextui-org/shared-css";
|
||||
|
||||
export const StyledButton = styled(
|
||||
"button",
|
||||
{
|
||||
$$buttonBorderRadius: "$radii$md",
|
||||
$$buttonPressedScale: 0.97,
|
||||
dflex: "center",
|
||||
appearance: "none",
|
||||
boxSizing: "border-box",
|
||||
fontWeight: "$medium",
|
||||
us: "none",
|
||||
lineHeight: "$sm",
|
||||
ta: "center",
|
||||
whiteSpace: "nowrap",
|
||||
transition: "$button",
|
||||
position: "relative",
|
||||
overflow: "hidden",
|
||||
border: "none",
|
||||
cursor: "pointer",
|
||||
pe: "auto",
|
||||
p: 0,
|
||||
br: "$$buttonBorderRadius",
|
||||
"@motion": {
|
||||
transition: "none",
|
||||
},
|
||||
".nextui-button-text": {
|
||||
dflex: "center",
|
||||
zIndex: "$2",
|
||||
"p, pre, div": {
|
||||
margin: 0,
|
||||
},
|
||||
},
|
||||
".nextui-drip": {
|
||||
zIndex: "$1",
|
||||
".nextui-drip-filler": {
|
||||
opacity: 0.25,
|
||||
fill: "$accents2",
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
bordered: {
|
||||
true: {
|
||||
bg: "transparent",
|
||||
borderStyle: "solid",
|
||||
color: "$text",
|
||||
},
|
||||
},
|
||||
ghost: {
|
||||
true: {},
|
||||
},
|
||||
color: {
|
||||
default: {
|
||||
bg: "$primary",
|
||||
color: "$primarySolidContrast",
|
||||
},
|
||||
primary: {
|
||||
bg: "$primary",
|
||||
color: "$primarySolidContrast",
|
||||
},
|
||||
secondary: {
|
||||
bg: "$secondary",
|
||||
color: "$secondarySolidContrast",
|
||||
},
|
||||
success: {
|
||||
bg: "$success",
|
||||
color: "$successSolidContrast",
|
||||
},
|
||||
warning: {
|
||||
bg: "$warning",
|
||||
color: "$warningSolidContrast",
|
||||
},
|
||||
error: {
|
||||
bg: "$error",
|
||||
color: "$errorSolidContrast",
|
||||
},
|
||||
gradient: {
|
||||
bg: "$gradient",
|
||||
color: "$primarySolidContrast",
|
||||
},
|
||||
},
|
||||
size: {
|
||||
xs: {
|
||||
$$buttonPadding: "$space$3",
|
||||
$$buttonBorderRadius: "$radii$xs",
|
||||
$$buttonHeight: "$space$10",
|
||||
px: "$3",
|
||||
height: "$$buttonHeight",
|
||||
lh: "$space$10",
|
||||
width: "auto",
|
||||
minWidth: "$20",
|
||||
fontSize: "$xs",
|
||||
},
|
||||
sm: {
|
||||
$$buttonPadding: "$space$5",
|
||||
$$buttonBorderRadius: "$radii$sm",
|
||||
$$buttonHeight: "$space$12",
|
||||
px: "$5",
|
||||
height: "$$buttonHeight",
|
||||
lh: "$space$14",
|
||||
width: "auto",
|
||||
minWidth: "$36",
|
||||
fontSize: "$sm",
|
||||
},
|
||||
md: {
|
||||
$$buttonPadding: "$space$7",
|
||||
$$buttonBorderRadius: "$radii$md",
|
||||
$$buttonHeight: "$space$14",
|
||||
px: "$7",
|
||||
height: "$$buttonHeight",
|
||||
lh: "$space$14",
|
||||
width: "auto",
|
||||
minWidth: "$48",
|
||||
fontSize: "$sm",
|
||||
},
|
||||
lg: {
|
||||
$$buttonPadding: "$space$9",
|
||||
$$buttonBorderRadius: "$radii$base",
|
||||
$$buttonHeight: "$space$16",
|
||||
px: "$9",
|
||||
height: "$$buttonHeight",
|
||||
lh: "$space$15",
|
||||
width: "auto",
|
||||
minWidth: "$60",
|
||||
fontSize: "$md",
|
||||
},
|
||||
xl: {
|
||||
$$buttonPadding: "$space$10",
|
||||
$$buttonBorderRadius: "$radii$xl",
|
||||
$$buttonHeight: "$space$18",
|
||||
px: "$10",
|
||||
height: "$$buttonHeight",
|
||||
lh: "$space$17",
|
||||
width: "auto",
|
||||
minWidth: "$72",
|
||||
fontSize: "$lg",
|
||||
},
|
||||
},
|
||||
borderWeight: {
|
||||
light: {
|
||||
bw: "$light",
|
||||
$$buttonBorderWeight: "$borderWeights$light",
|
||||
},
|
||||
normal: {
|
||||
bw: "$normal",
|
||||
$$buttonBorderWeight: "$borderWeights$normal",
|
||||
},
|
||||
bold: {
|
||||
bw: "$bold",
|
||||
$$buttonBorderWeight: "$borderWeights$bold",
|
||||
},
|
||||
extrabold: {
|
||||
bw: "$extrabold",
|
||||
$$buttonBorderWeight: "$borderWeights$extrabold",
|
||||
},
|
||||
black: {
|
||||
bw: "$black",
|
||||
$$buttonBorderWeight: "$borderWeights$black",
|
||||
},
|
||||
},
|
||||
flat: {
|
||||
true: {
|
||||
color: "$text",
|
||||
},
|
||||
},
|
||||
light: {
|
||||
true: {
|
||||
bg: "transparent",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
opacity: 0.8,
|
||||
fill: "$accents2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
shadow: {
|
||||
true: {
|
||||
bs: "$sm",
|
||||
},
|
||||
},
|
||||
animated: {
|
||||
false: {
|
||||
transition: "none",
|
||||
},
|
||||
},
|
||||
auto: {
|
||||
true: {
|
||||
width: "auto",
|
||||
minWidth: "min-content",
|
||||
},
|
||||
},
|
||||
rounded: {
|
||||
true: {
|
||||
$$buttonBorderRadius: "$radii$pill",
|
||||
},
|
||||
},
|
||||
isPressed: {
|
||||
true: {},
|
||||
},
|
||||
isHovered: {
|
||||
true: {},
|
||||
},
|
||||
isChildLess: {
|
||||
true: {
|
||||
p: 0,
|
||||
width: "$$buttonHeight",
|
||||
height: "$$buttonHeight",
|
||||
},
|
||||
},
|
||||
},
|
||||
compoundVariants: [
|
||||
// isPressed && animated
|
||||
{
|
||||
isPressed: true,
|
||||
animated: true,
|
||||
css: {
|
||||
transform: "scale($$buttonPressedScale)",
|
||||
},
|
||||
},
|
||||
// size / auto / isChildLess
|
||||
{
|
||||
auto: true,
|
||||
isChildLess: false,
|
||||
size: "xs",
|
||||
css: {
|
||||
px: "$5",
|
||||
minWidth: "min-content",
|
||||
},
|
||||
},
|
||||
{
|
||||
auto: true,
|
||||
isChildLess: false,
|
||||
size: "sm",
|
||||
css: {
|
||||
px: "$8",
|
||||
minWidth: "min-content",
|
||||
},
|
||||
},
|
||||
{
|
||||
auto: true,
|
||||
isChildLess: false,
|
||||
size: "md",
|
||||
css: {
|
||||
px: "$9",
|
||||
minWidth: "min-content",
|
||||
},
|
||||
},
|
||||
{
|
||||
auto: true,
|
||||
isChildLess: false,
|
||||
size: "lg",
|
||||
css: {
|
||||
px: "$10",
|
||||
minWidth: "min-content",
|
||||
},
|
||||
},
|
||||
{
|
||||
auto: true,
|
||||
isChildLess: false,
|
||||
size: "xl",
|
||||
css: {
|
||||
px: "$11",
|
||||
minWidth: "min-content",
|
||||
},
|
||||
},
|
||||
// shadow / color
|
||||
{
|
||||
shadow: true,
|
||||
color: "default",
|
||||
css: {
|
||||
normalShadow: "$primaryShadow",
|
||||
},
|
||||
},
|
||||
{
|
||||
shadow: true,
|
||||
color: "primary",
|
||||
css: {
|
||||
normalShadow: "$primaryShadow",
|
||||
},
|
||||
},
|
||||
{
|
||||
shadow: true,
|
||||
color: "secondary",
|
||||
css: {
|
||||
normalShadow: "$secondaryShadow",
|
||||
},
|
||||
},
|
||||
{
|
||||
shadow: true,
|
||||
color: "warning",
|
||||
css: {
|
||||
normalShadow: "$warningShadow",
|
||||
},
|
||||
},
|
||||
{
|
||||
shadow: true,
|
||||
color: "success",
|
||||
css: {
|
||||
normalShadow: "$successShadow",
|
||||
},
|
||||
},
|
||||
{
|
||||
shadow: true,
|
||||
color: "error",
|
||||
css: {
|
||||
normalShadow: "$errorShadow",
|
||||
},
|
||||
},
|
||||
{
|
||||
shadow: true,
|
||||
color: "gradient",
|
||||
css: {
|
||||
normalShadow: "$primaryShadow",
|
||||
},
|
||||
},
|
||||
// light / color
|
||||
{
|
||||
light: true,
|
||||
color: "default",
|
||||
css: {
|
||||
bg: "transparent",
|
||||
color: "$text",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
opacity: 0.8,
|
||||
fill: "$primaryLightActive",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
light: true,
|
||||
color: "primary",
|
||||
css: {
|
||||
bg: "transparent",
|
||||
color: "$primary",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
opacity: 0.8,
|
||||
fill: "$primaryLightActive",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
light: true,
|
||||
color: "secondary",
|
||||
css: {
|
||||
bg: "transparent",
|
||||
color: "$secondary",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
opacity: 0.8,
|
||||
fill: "$secondaryLightActive",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
light: true,
|
||||
color: "warning",
|
||||
css: {
|
||||
bg: "transparent",
|
||||
color: "$warning",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
opacity: 0.8,
|
||||
fill: "$warningLightActive",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
light: true,
|
||||
color: "success",
|
||||
css: {
|
||||
bg: "transparent",
|
||||
color: "$success",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
opacity: 0.8,
|
||||
fill: "$successLightActive",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
light: true,
|
||||
color: "error",
|
||||
css: {
|
||||
bg: "transparent",
|
||||
color: "$error",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
opacity: 0.8,
|
||||
fill: "$errorLightActive",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// bordered / color
|
||||
{
|
||||
bordered: true,
|
||||
color: "default",
|
||||
css: {
|
||||
bg: "transparent",
|
||||
borderColor: "$primary",
|
||||
color: "$primary",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
fill: "$primary",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
bordered: true,
|
||||
color: "primary",
|
||||
css: {
|
||||
bg: "transparent",
|
||||
borderColor: "$primary",
|
||||
color: "$primary",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
fill: "$primary",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
bordered: true,
|
||||
color: "secondary",
|
||||
css: {
|
||||
bg: "transparent",
|
||||
borderColor: "$secondary",
|
||||
color: "$secondary",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
fill: "$secondary",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
bordered: true,
|
||||
color: "success",
|
||||
css: {
|
||||
bg: "transparent",
|
||||
borderColor: "$success",
|
||||
color: "$success",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
fill: "$success",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
bordered: true,
|
||||
color: "warning",
|
||||
css: {
|
||||
bg: "transparent",
|
||||
borderColor: "$warning",
|
||||
color: "$warning",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
fill: "$warning",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
bordered: true,
|
||||
color: "error",
|
||||
css: {
|
||||
bg: "transparent",
|
||||
borderColor: "$error",
|
||||
color: "$error",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
fill: "$error",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
bordered: true,
|
||||
color: "gradient",
|
||||
css: {
|
||||
bg: "transparent",
|
||||
color: "$text",
|
||||
padding: "$$buttonBorderWeight",
|
||||
bgClip: "content-box, border-box",
|
||||
borderColor: "$primary",
|
||||
backgroundImage: "linear-gradient($background, $background), $gradient",
|
||||
border: "none",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
fill: "$secondary",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// ghost / color && isHovered
|
||||
{
|
||||
ghost: true,
|
||||
isHovered: true,
|
||||
color: "default",
|
||||
css: {
|
||||
bg: "$primary",
|
||||
color: "$primarySolidContrast",
|
||||
},
|
||||
},
|
||||
{
|
||||
ghost: true,
|
||||
isHovered: true,
|
||||
color: "primary",
|
||||
css: {
|
||||
bg: "$primary",
|
||||
color: "$primarySolidContrast",
|
||||
},
|
||||
},
|
||||
{
|
||||
ghost: true,
|
||||
isHovered: true,
|
||||
color: "secondary",
|
||||
css: {
|
||||
bg: "$secondary",
|
||||
color: "$secondarySolidContrast",
|
||||
},
|
||||
},
|
||||
{
|
||||
ghost: true,
|
||||
isHovered: true,
|
||||
color: "success",
|
||||
css: {
|
||||
bg: "$success",
|
||||
color: "$successSolidContrast",
|
||||
},
|
||||
},
|
||||
{
|
||||
ghost: true,
|
||||
isHovered: true,
|
||||
color: "warning",
|
||||
css: {
|
||||
bg: "$warning",
|
||||
color: "$warningSolidContrast",
|
||||
},
|
||||
},
|
||||
{
|
||||
ghost: true,
|
||||
isHovered: true,
|
||||
color: "error",
|
||||
css: {
|
||||
bg: "$error",
|
||||
color: "$errorSolidContrast",
|
||||
},
|
||||
},
|
||||
{
|
||||
ghost: true,
|
||||
color: "gradient",
|
||||
isHovered: true,
|
||||
css: {
|
||||
bg: "$gradient",
|
||||
color: "$white",
|
||||
},
|
||||
},
|
||||
// flat / color
|
||||
{
|
||||
flat: true,
|
||||
color: "default",
|
||||
css: {
|
||||
bg: "$primaryLight",
|
||||
color: "$primaryLightContrast",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
opacity: 0.4,
|
||||
fill: "$primary",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
flat: true,
|
||||
color: "primary",
|
||||
css: {
|
||||
bg: "$primaryLight",
|
||||
color: "$primaryLightContrast",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
opacity: 0.4,
|
||||
fill: "$primary",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
flat: true,
|
||||
color: "secondary",
|
||||
css: {
|
||||
bg: "$secondaryLight",
|
||||
color: "$secondaryLightContrast",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
opacity: 0.4,
|
||||
fill: "$secondary",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
flat: true,
|
||||
color: "success",
|
||||
css: {
|
||||
bg: "$successLight",
|
||||
color: "$successLightContrast",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
opacity: 0.4,
|
||||
fill: "$success",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
flat: true,
|
||||
color: "warning",
|
||||
css: {
|
||||
bg: "$warningLight",
|
||||
color: "$warningLightContrast",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
opacity: 0.4,
|
||||
fill: "$warning",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
flat: true,
|
||||
color: "error",
|
||||
css: {
|
||||
bg: "$errorLight",
|
||||
color: "$errorLightContrast",
|
||||
".nextui-drip": {
|
||||
".nextui-drip-filler": {
|
||||
opacity: 0.4,
|
||||
fill: "$error",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// flat / isHovered / color
|
||||
{
|
||||
flat: true,
|
||||
isHovered: true,
|
||||
color: "default",
|
||||
css: {
|
||||
bg: "$primaryLightHover",
|
||||
},
|
||||
},
|
||||
{
|
||||
flat: true,
|
||||
isHovered: true,
|
||||
color: "primary",
|
||||
css: {
|
||||
bg: "$primaryLightHover",
|
||||
},
|
||||
},
|
||||
{
|
||||
flat: true,
|
||||
isHovered: true,
|
||||
color: "secondary",
|
||||
css: {
|
||||
bg: "$secondaryLightHover",
|
||||
},
|
||||
},
|
||||
{
|
||||
flat: true,
|
||||
isHovered: true,
|
||||
color: "success",
|
||||
css: {
|
||||
bg: "$successLightHover",
|
||||
},
|
||||
},
|
||||
{
|
||||
flat: true,
|
||||
isHovered: true,
|
||||
color: "warning",
|
||||
css: {
|
||||
bg: "$warningLightHover",
|
||||
},
|
||||
},
|
||||
{
|
||||
flat: true,
|
||||
isHovered: true,
|
||||
color: "error",
|
||||
css: {
|
||||
bg: "$errorLightHover",
|
||||
},
|
||||
},
|
||||
// flat / isPressed / color
|
||||
{
|
||||
flat: true,
|
||||
isPressed: true,
|
||||
color: "default",
|
||||
css: {
|
||||
bg: "$primaryLightActive",
|
||||
},
|
||||
},
|
||||
{
|
||||
flat: true,
|
||||
isPressed: true,
|
||||
color: "primary",
|
||||
css: {
|
||||
bg: "$primaryLightActive",
|
||||
},
|
||||
},
|
||||
{
|
||||
flat: true,
|
||||
isPressed: true,
|
||||
color: "secondary",
|
||||
css: {
|
||||
bg: "$secondaryLightActive",
|
||||
},
|
||||
},
|
||||
{
|
||||
flat: true,
|
||||
isPressed: true,
|
||||
color: "success",
|
||||
css: {
|
||||
bg: "$successLightActive",
|
||||
},
|
||||
},
|
||||
{
|
||||
flat: true,
|
||||
isPressed: true,
|
||||
color: "warning",
|
||||
css: {
|
||||
bg: "$warningLightActive",
|
||||
},
|
||||
},
|
||||
{
|
||||
flat: true,
|
||||
isPressed: true,
|
||||
color: "error",
|
||||
css: {
|
||||
bg: "$errorLightActive",
|
||||
},
|
||||
},
|
||||
// auto / gradient-color / bordered
|
||||
{
|
||||
auto: true,
|
||||
color: "gradient",
|
||||
bordered: true,
|
||||
css: {
|
||||
".nextui-button-text": {
|
||||
px: "$$buttonPadding",
|
||||
},
|
||||
".nextui-button-icon": {
|
||||
ml: "$$buttonPadding",
|
||||
},
|
||||
".nextui-button-icon-right": {
|
||||
mr: "$$buttonPadding",
|
||||
},
|
||||
".nextui-button-text-left": {
|
||||
pl: 0,
|
||||
},
|
||||
".nextui-button-text-right": {
|
||||
pr: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
// rounded && size
|
||||
{
|
||||
rounded: true,
|
||||
size: "xs",
|
||||
css: {
|
||||
br: "$pill",
|
||||
},
|
||||
},
|
||||
{
|
||||
rounded: true,
|
||||
size: "sm",
|
||||
css: {
|
||||
br: "$pill",
|
||||
},
|
||||
},
|
||||
{
|
||||
rounded: true,
|
||||
size: "md",
|
||||
css: {
|
||||
br: "$pill",
|
||||
},
|
||||
},
|
||||
{
|
||||
rounded: true,
|
||||
size: "lg",
|
||||
css: {
|
||||
br: "$pill",
|
||||
},
|
||||
},
|
||||
{
|
||||
rounded: true,
|
||||
size: "xl",
|
||||
css: {
|
||||
br: "$pill",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
cssFocusVisible,
|
||||
);
|
||||
97
packages/components/button/src/button.tsx
Normal file
97
packages/components/button/src/button.tsx
Normal file
@ -0,0 +1,97 @@
|
||||
import {forwardRef} from "@nextui-org/system";
|
||||
import {clsx, __DEV__} from "@nextui-org/shared-utils";
|
||||
import {Drip} from "@nextui-org/drip";
|
||||
import {Children, useMemo} from "react";
|
||||
|
||||
import ButtonGroup from "./button-group";
|
||||
import ButtonIcon from "./button-icon";
|
||||
import {StyledButton} from "./button.styles";
|
||||
import {UseButtonProps, useButton} from "./use-button";
|
||||
|
||||
export interface ButtonProps extends Omit<UseButtonProps, "ref"> {}
|
||||
|
||||
type CompoundButton = {
|
||||
Group: typeof ButtonGroup;
|
||||
};
|
||||
|
||||
const Button = forwardRef<ButtonProps, "button", CompoundButton>((props, ref) => {
|
||||
const {
|
||||
buttonRef,
|
||||
children,
|
||||
state,
|
||||
as,
|
||||
css,
|
||||
hasIcon,
|
||||
dripBindings,
|
||||
isRightIcon,
|
||||
cssColors,
|
||||
getIconCss,
|
||||
className,
|
||||
isGradientButtonBorder,
|
||||
getButtonProps,
|
||||
} = useButton({
|
||||
ref,
|
||||
...props,
|
||||
});
|
||||
|
||||
const buttonProps = useMemo(() => getButtonProps(), [getButtonProps]);
|
||||
|
||||
return (
|
||||
<StyledButton
|
||||
ref={buttonRef}
|
||||
as={as}
|
||||
className={clsx("nextui-button", className)}
|
||||
css={{
|
||||
...cssColors,
|
||||
...css,
|
||||
}}
|
||||
data-state={state}
|
||||
{...buttonProps}
|
||||
>
|
||||
{Children.count(children) === 0 ? (
|
||||
<ButtonIcon
|
||||
isSingle
|
||||
css={getIconCss}
|
||||
isAuto={buttonProps.auto}
|
||||
isGradientButtonBorder={isGradientButtonBorder}
|
||||
isRight={isRightIcon}
|
||||
>
|
||||
{hasIcon}
|
||||
</ButtonIcon>
|
||||
) : hasIcon ? (
|
||||
<>
|
||||
<ButtonIcon
|
||||
css={getIconCss}
|
||||
isAuto={buttonProps.auto}
|
||||
isGradientButtonBorder={isGradientButtonBorder}
|
||||
isRight={isRightIcon}
|
||||
isSingle={false}
|
||||
>
|
||||
{hasIcon}
|
||||
</ButtonIcon>
|
||||
<div
|
||||
className={clsx("nextui-button-text", {
|
||||
"nextui-button-text-right": isRightIcon,
|
||||
"nextui-button-text-left": !isRightIcon,
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<span className="nextui-button-text">{children}</span>
|
||||
)}
|
||||
<Drip color="white" {...dripBindings} />
|
||||
</StyledButton>
|
||||
);
|
||||
});
|
||||
|
||||
Button.Group = ButtonGroup;
|
||||
|
||||
if (__DEV__) {
|
||||
Button.displayName = "NextUI.Button";
|
||||
}
|
||||
|
||||
Button.toString = () => ".nextui-button";
|
||||
|
||||
export default Button;
|
||||
5
packages/components/button/src/index.ts
Normal file
5
packages/components/button/src/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
// export types
|
||||
export type {ButtonProps} from "./button";
|
||||
|
||||
// export component
|
||||
export {default as Button} from "./button";
|
||||
67
packages/components/button/src/use-button-group.ts
Normal file
67
packages/components/button/src/use-button-group.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import type {UseButtonProps} from "./use-button";
|
||||
|
||||
import {useMemo} from "react";
|
||||
import {HTMLNextUIProps} from "@nextui-org/system";
|
||||
|
||||
export interface UseButtonGroupProps extends HTMLNextUIProps<"div", Omit<UseButtonProps, "ref">> {
|
||||
/**
|
||||
* Whether the buttons should be stacked vertically.
|
||||
* @default false
|
||||
*/
|
||||
vertical?: boolean;
|
||||
}
|
||||
|
||||
export function useButtonGroup(props: UseButtonGroupProps) {
|
||||
const {
|
||||
color = "default",
|
||||
size = "md",
|
||||
borderWeight = "normal",
|
||||
disabled = false,
|
||||
bordered = false,
|
||||
light = false,
|
||||
ghost = false,
|
||||
flat = false,
|
||||
shadow = false,
|
||||
auto = true,
|
||||
animated = true,
|
||||
rounded = false,
|
||||
ripple = true,
|
||||
vertical = false,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
const context = useMemo<UseButtonProps>(
|
||||
() => ({
|
||||
disabled,
|
||||
size,
|
||||
color,
|
||||
bordered,
|
||||
light,
|
||||
ghost,
|
||||
flat,
|
||||
shadow,
|
||||
auto,
|
||||
borderWeight,
|
||||
animated,
|
||||
rounded,
|
||||
ripple,
|
||||
isButtonGroup: true,
|
||||
}),
|
||||
[disabled, animated, size, ripple, color, bordered, light, ghost, flat, borderWeight],
|
||||
);
|
||||
|
||||
const isGradient = color === "gradient";
|
||||
|
||||
// TODO: the idea is to migrate the boolean names from "disable" to "isDisabled" (v12)
|
||||
return {
|
||||
context,
|
||||
size,
|
||||
isRounded: rounded,
|
||||
isBordered: bordered || ghost,
|
||||
isVertical: vertical,
|
||||
isGradient,
|
||||
...otherProps,
|
||||
};
|
||||
}
|
||||
|
||||
export type UseButtonGroupReturn = ReturnType<typeof useButtonGroup>;
|
||||
276
packages/components/button/src/use-button.ts
Normal file
276
packages/components/button/src/use-button.ts
Normal file
@ -0,0 +1,276 @@
|
||||
import type {AriaButtonProps} from "@react-types/button";
|
||||
import type {PressEvent} from "@react-types/shared";
|
||||
import type {ReactRef, NormalColors, NormalSizes, NormalWeights} from "@nextui-org/shared-utils";
|
||||
import type {HTMLNextUIProps, CSS} from "@nextui-org/system";
|
||||
|
||||
import {MouseEventHandler, ReactNode, useCallback, useMemo, Children} from "react";
|
||||
import {useButton as useAriaButton} from "@react-aria/button";
|
||||
import {useFocusRing} from "@react-aria/focus";
|
||||
import {mergeProps} from "@react-aria/utils";
|
||||
import {useDrip} from "@nextui-org/drip";
|
||||
import {useHover} from "@react-aria/interactions";
|
||||
import {IFocusRingAria, useDOMRef} from "@nextui-org/dom-utils";
|
||||
import {__DEV__} from "@nextui-org/shared-utils";
|
||||
|
||||
import {getColors} from "./button-utils";
|
||||
import {useButtonGroupContext} from "./button-group-context";
|
||||
|
||||
export interface UseButtonProps extends HTMLNextUIProps<"button", AriaButtonProps> {
|
||||
/**
|
||||
* the button ref.
|
||||
*/
|
||||
ref?: ReactRef<HTMLButtonElement | null>;
|
||||
/**
|
||||
* The button color.
|
||||
* @default "default"
|
||||
*/
|
||||
color?: NormalColors;
|
||||
/**
|
||||
* The button size.
|
||||
* @default "md"
|
||||
*/
|
||||
size?: NormalSizes;
|
||||
/**
|
||||
* The border weight of the border button.
|
||||
* @default "normal"
|
||||
*/
|
||||
borderWeight?: NormalWeights;
|
||||
/**
|
||||
* Whether the button should autoscale its width to fit its content.
|
||||
* @default false
|
||||
*/
|
||||
auto?: boolean;
|
||||
/**
|
||||
* Whether the button is disabled.
|
||||
* @default false
|
||||
*/
|
||||
disabled?: boolean;
|
||||
/**
|
||||
* Whether the button should be rounded.
|
||||
* @default false
|
||||
*/
|
||||
bordered?: boolean;
|
||||
/**
|
||||
* Whether the button should be light.
|
||||
* @default false
|
||||
*/
|
||||
light?: boolean;
|
||||
/**
|
||||
* Whether the button should be flat.
|
||||
* @default false
|
||||
*/
|
||||
flat?: boolean;
|
||||
/**
|
||||
* Whether the button should display a shadow.
|
||||
* @default false
|
||||
*/
|
||||
shadow?: boolean;
|
||||
/**
|
||||
* Whether the button should be rounded.
|
||||
* @default false
|
||||
*/
|
||||
rounded?: boolean;
|
||||
/**
|
||||
* Whether the button should have a ghost look.
|
||||
* @default false
|
||||
*/
|
||||
ghost?: boolean;
|
||||
/**
|
||||
* Whether the button have animations.
|
||||
* @default true
|
||||
*/
|
||||
animated?: boolean;
|
||||
/**
|
||||
* Whether the button should display a ripple effect on press.
|
||||
* @default true
|
||||
*/
|
||||
ripple?: boolean;
|
||||
|
||||
/**
|
||||
* The button left content.
|
||||
*/
|
||||
icon?: ReactNode;
|
||||
/**
|
||||
* The button right content.
|
||||
*/
|
||||
iconRight?: ReactNode;
|
||||
/**
|
||||
* The button left content css object.
|
||||
*/
|
||||
iconLeftCss?: CSS;
|
||||
/**
|
||||
* The button right content css object.
|
||||
*/
|
||||
iconRightCss?: CSS;
|
||||
/**
|
||||
* The native button click event handler.
|
||||
* @deprecated - use `onPress` instead.
|
||||
*/
|
||||
onClick?: MouseEventHandler<HTMLButtonElement>;
|
||||
}
|
||||
|
||||
export function useButton(props: UseButtonProps) {
|
||||
const groupContext = useButtonGroupContext();
|
||||
|
||||
const {
|
||||
ref,
|
||||
as,
|
||||
css,
|
||||
children,
|
||||
iconLeftCss,
|
||||
iconRightCss,
|
||||
autoFocus,
|
||||
icon,
|
||||
iconRight,
|
||||
className,
|
||||
auto = groupContext?.auto ?? false,
|
||||
size = groupContext?.size ?? "md",
|
||||
color = groupContext?.color ?? "default",
|
||||
shadow = groupContext?.shadow ?? false,
|
||||
flat = groupContext?.flat ?? false,
|
||||
ghost = groupContext?.ghost ?? false,
|
||||
light = groupContext?.light ?? false,
|
||||
bordered = groupContext?.bordered ?? false,
|
||||
borderWeight = groupContext?.borderWeight ?? "normal",
|
||||
animated = groupContext?.animated ?? true,
|
||||
rounded = groupContext?.rounded ?? false,
|
||||
ripple = groupContext?.ripple ?? true,
|
||||
disabled = groupContext?.disabled ?? false,
|
||||
onClick: deprecatedOnClick,
|
||||
onPress,
|
||||
onPressStart,
|
||||
onPressEnd,
|
||||
onPressChange,
|
||||
onPressUp,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
const buttonRef = useDOMRef(ref);
|
||||
|
||||
const hasIcon = icon || iconRight;
|
||||
const isChildLess = Children.count(children) === 0;
|
||||
const isRightIcon = Boolean(iconRight);
|
||||
const isGradientButtonBorder = useMemo(
|
||||
() => color === "gradient" && (bordered || ghost),
|
||||
[color, bordered, ghost],
|
||||
);
|
||||
|
||||
/* eslint-enable @typescript-eslint/no-unused-vars */
|
||||
if (__DEV__ && color === "gradient" && (flat || light)) {
|
||||
console.warn("Using the gradient color on flat and light buttons will have no effect.");
|
||||
}
|
||||
|
||||
const buttonProps = {
|
||||
auto,
|
||||
size,
|
||||
color,
|
||||
shadow,
|
||||
flat,
|
||||
ghost,
|
||||
light,
|
||||
bordered,
|
||||
borderWeight,
|
||||
animated,
|
||||
rounded,
|
||||
disabled,
|
||||
};
|
||||
|
||||
const cssColors = getColors(buttonProps) as CSS;
|
||||
|
||||
const {onClick: onDripClickHandler, ...dripBindings} = useDrip(false, buttonRef);
|
||||
|
||||
const handleDrip = (e: React.MouseEvent<HTMLButtonElement> | PressEvent | Event) => {
|
||||
if (animated && ripple && buttonRef.current) {
|
||||
onDripClickHandler(e);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePress = (e: PressEvent) => {
|
||||
if (e.pointerType === "keyboard" || e.pointerType === "virtual") {
|
||||
handleDrip(e);
|
||||
} else if (typeof window !== "undefined" && window.event) {
|
||||
handleDrip(window.event);
|
||||
}
|
||||
if (deprecatedOnClick) {
|
||||
deprecatedOnClick(e as any);
|
||||
console.warn("onClick is deprecated, please use onPress");
|
||||
}
|
||||
onPress?.(e);
|
||||
};
|
||||
|
||||
const {buttonProps: buttonAriaProps, isPressed} = useAriaButton(
|
||||
{
|
||||
...otherProps,
|
||||
elementType: as,
|
||||
onPress: handlePress,
|
||||
onPressStart,
|
||||
onPressEnd,
|
||||
onPressChange,
|
||||
onPressUp,
|
||||
} as AriaButtonProps,
|
||||
buttonRef,
|
||||
);
|
||||
|
||||
const {hoverProps, isHovered} = useHover({isDisabled: disabled});
|
||||
|
||||
const {isFocused, isFocusVisible, focusProps}: IFocusRingAria<UseButtonProps> = useFocusRing({
|
||||
autoFocus,
|
||||
});
|
||||
|
||||
const getButtonProps = useCallback(() => {
|
||||
return mergeProps(buttonAriaProps, hoverProps, focusProps, otherProps, {
|
||||
...buttonProps,
|
||||
bordered: buttonProps.bordered || buttonProps.ghost,
|
||||
isFocusVisible: isFocusVisible && !buttonProps.disabled,
|
||||
isHovered: isHovered || (buttonProps.ghost && isFocused),
|
||||
isChildLess,
|
||||
isPressed,
|
||||
});
|
||||
}, [
|
||||
buttonProps,
|
||||
buttonAriaProps,
|
||||
hoverProps,
|
||||
focusProps,
|
||||
isFocusVisible,
|
||||
isHovered,
|
||||
isFocused,
|
||||
isPressed,
|
||||
isChildLess,
|
||||
otherProps,
|
||||
]);
|
||||
|
||||
const state = useMemo(() => {
|
||||
if (isPressed) return "pressed";
|
||||
if (isHovered) return "hovered";
|
||||
|
||||
return disabled ? "disabled" : "ready";
|
||||
}, [disabled, isHovered, isPressed]);
|
||||
|
||||
const getIconCss = useMemo<any>(() => {
|
||||
if (isRightIcon) return iconRightCss;
|
||||
|
||||
return iconLeftCss;
|
||||
}, [isRightIcon, iconRightCss, iconLeftCss]);
|
||||
|
||||
return {
|
||||
as,
|
||||
css,
|
||||
state,
|
||||
icon,
|
||||
children,
|
||||
buttonRef,
|
||||
className,
|
||||
cssColors,
|
||||
hasIcon,
|
||||
iconRight,
|
||||
isFocused,
|
||||
isRightIcon,
|
||||
isFocusVisible,
|
||||
isGradientButtonBorder,
|
||||
dripBindings,
|
||||
getIconCss,
|
||||
getButtonProps,
|
||||
};
|
||||
}
|
||||
|
||||
export type UseButtonReturn = ReturnType<typeof useButton>;
|
||||
260
packages/components/button/stories/button.stories.tsx
Normal file
260
packages/components/button/stories/button.stories.tsx
Normal file
@ -0,0 +1,260 @@
|
||||
import React from "react";
|
||||
import {Meta} from "@storybook/react";
|
||||
import {Spacer} from "@nextui-org/spacer";
|
||||
import {Lock, Notification, User, Camera, Activity} from "@nextui-org/icons-utils";
|
||||
|
||||
import {Button} from "../src";
|
||||
|
||||
export default {
|
||||
title: "General/Button",
|
||||
component: Button,
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<div style={{}}>
|
||||
<Story />
|
||||
</div>
|
||||
),
|
||||
],
|
||||
} as Meta;
|
||||
|
||||
export const Default = () => <Button>Action</Button>;
|
||||
|
||||
export const Sizes = () => (
|
||||
<div>
|
||||
<Button size="xs">Mini</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button color="secondary" size="sm">
|
||||
Small
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button color="success" size="md">
|
||||
Medium
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button color="warning" size="lg">
|
||||
Large
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button color="error" size="xl">
|
||||
Extra Large
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button auto color="gradient">
|
||||
Auto width
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Colors = () => (
|
||||
<>
|
||||
<Button color="primary">Primary</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button color="secondary">Secondary</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button color="success">Success</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button color="warning">Warning</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button color="error">Error</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button color="gradient">Gradient</Button>
|
||||
<Spacer y={0.5} />
|
||||
</>
|
||||
);
|
||||
|
||||
export const Ghost = () => (
|
||||
<>
|
||||
<Button ghost color="primary">
|
||||
Primary
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button ghost color="secondary">
|
||||
Secondary
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button ghost color="success">
|
||||
Success
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button ghost color="warning">
|
||||
Warning
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button ghost color="error">
|
||||
Error
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button ghost color="gradient">
|
||||
Gradient
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
</>
|
||||
);
|
||||
|
||||
export const Disabled = () => <Button disabled>Action</Button>;
|
||||
|
||||
export const Shadow = () => (
|
||||
<>
|
||||
<Button shadow color="primary">
|
||||
Primary
|
||||
</Button>
|
||||
<Spacer y={1} />
|
||||
<Button shadow color="secondary">
|
||||
Secondary
|
||||
</Button>
|
||||
<Spacer y={1} />
|
||||
<Button shadow color="success">
|
||||
Success
|
||||
</Button>
|
||||
<Spacer y={1} />
|
||||
<Button shadow color="warning">
|
||||
Warning
|
||||
</Button>
|
||||
<Spacer y={1} />
|
||||
<Button shadow color="error">
|
||||
Error
|
||||
</Button>
|
||||
<Spacer y={1} />
|
||||
<Button shadow color="gradient">
|
||||
Gradient
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
|
||||
export const Bordered = () => (
|
||||
<>
|
||||
<Button bordered color="primary">
|
||||
Primary
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button bordered color="secondary">
|
||||
Secondary
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button bordered color="success">
|
||||
Success
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button bordered color="warning">
|
||||
Warning
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button bordered color="error">
|
||||
Error
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button bordered color="gradient">
|
||||
Gradient
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
|
||||
export const Flat = () => (
|
||||
<>
|
||||
<Button flat color="primary">
|
||||
Primary
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button flat color="secondary">
|
||||
Secondary
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button flat color="success">
|
||||
Success
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button flat color="warning">
|
||||
Warning
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button flat color="error">
|
||||
Error
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
|
||||
export const Rounded = () => (
|
||||
<>
|
||||
<Button rounded color="primary">
|
||||
Primary
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button rounded color="secondary">
|
||||
Secondary
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button rounded color="success">
|
||||
Success
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button rounded color="warning">
|
||||
Warning
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button rounded color="error">
|
||||
Error
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button rounded color="gradient">
|
||||
Action
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
|
||||
export const Light = () => (
|
||||
<>
|
||||
<Button light>Default</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button light color="primary">
|
||||
Primary
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button light color="secondary">
|
||||
Secondary
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button light color="success">
|
||||
Success
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button light color="warning">
|
||||
Warning
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button light color="error">
|
||||
Error
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
|
||||
export const Icons = () => {
|
||||
return (
|
||||
<>
|
||||
<Button auto color="secondary" icon={<Activity fill="currentColor" />} />
|
||||
<Spacer y={0.5} />
|
||||
<Button auto iconRight={<Camera fill="currentColor" />}>
|
||||
Right Icon
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button auto bordered color="gradient" icon={<Camera fill="currentColor" />}>
|
||||
Left Icon
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button color="success" icon={<Lock fill="currentColor" />}>
|
||||
Lock
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button color="secondary" icon={<Notification fill="currentColor" />}>
|
||||
Notifications
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button flat color="error" icon={<User fill="currentColor" />}>
|
||||
Delete User
|
||||
</Button>
|
||||
<Spacer y={0.5} />
|
||||
<Button disabled icon={<User fill="currentColor" />}>
|
||||
Delete User
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
9
packages/components/button/tsconfig.json
Normal file
9
packages/components/button/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/button/tsup.config.ts
Normal file
13
packages/components/button/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,
|
||||
});
|
||||
@ -3,7 +3,7 @@ import {useDOMRef} from "@nextui-org/dom-utils";
|
||||
import {clsx, __DEV__} from "@nextui-org/shared-utils";
|
||||
import {mergeProps} from "@react-aria/utils";
|
||||
|
||||
import {CheckboxGroupProvider} from "./checkbox-context";
|
||||
import {CheckboxGroupProvider} from "./checkbox-group-context";
|
||||
import {StyledCheckboxGroup, StyledCheckboxGroupContainer} from "./checkbox-group.styles";
|
||||
import {UseCheckboxGroupProps, useCheckboxGroup} from "./use-checkbox-group";
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ import {
|
||||
useCheckboxGroupItem as useReactAriaCheckboxGroupItem,
|
||||
} from "@react-aria/checkbox";
|
||||
|
||||
import {useCheckboxGroupContext} from "./checkbox-context";
|
||||
import {useCheckboxGroupContext} from "./checkbox-group-context";
|
||||
|
||||
export interface UseCheckboxProps extends HTMLNextUIProps<"label", AriaCheckboxProps> {
|
||||
/**
|
||||
|
||||
51
pnpm-lock.yaml
generated
51
pnpm-lock.yaml
generated
@ -342,6 +342,41 @@ importers:
|
||||
clean-package: 2.1.1
|
||||
react: 17.0.2
|
||||
|
||||
packages/components/button:
|
||||
specifiers:
|
||||
'@nextui-org/dom-utils': workspace:*
|
||||
'@nextui-org/drip': workspace:*
|
||||
'@nextui-org/icons-utils': workspace:*
|
||||
'@nextui-org/shared-css': workspace:*
|
||||
'@nextui-org/shared-utils': workspace:*
|
||||
'@nextui-org/spacer': workspace:*
|
||||
'@nextui-org/system': workspace:*
|
||||
'@react-aria/button': ^3.6.2
|
||||
'@react-aria/focus': ^3.9.0
|
||||
'@react-aria/interactions': ^3.12.0
|
||||
'@react-aria/utils': ^3.14.0
|
||||
'@react-types/button': ^3.6.2
|
||||
'@react-types/shared': ^3.14.1
|
||||
clean-package: 2.1.1
|
||||
react: ^17.0.2
|
||||
dependencies:
|
||||
'@nextui-org/dom-utils': link:../../utilities/dom-utils
|
||||
'@nextui-org/drip': link:../drip
|
||||
'@nextui-org/shared-css': link:../../utilities/shared-css
|
||||
'@nextui-org/shared-utils': link:../../utilities/shared-utils
|
||||
'@nextui-org/system': link:../../core/system
|
||||
'@react-aria/button': 3.6.2_react@17.0.2
|
||||
'@react-aria/focus': 3.9.0_react@17.0.2
|
||||
'@react-aria/interactions': 3.12.0_react@17.0.2
|
||||
'@react-aria/utils': 3.14.0_react@17.0.2
|
||||
devDependencies:
|
||||
'@nextui-org/icons-utils': link:../../utilities/icons-utils
|
||||
'@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
|
||||
clean-package: 2.1.1
|
||||
react: 17.0.2
|
||||
|
||||
packages/components/card:
|
||||
specifiers:
|
||||
'@nextui-org/code': workspace:*
|
||||
@ -4653,6 +4688,21 @@ packages:
|
||||
tslib: 2.4.0
|
||||
dev: false
|
||||
|
||||
/@react-aria/button/3.6.2_react@17.0.2:
|
||||
resolution: {integrity: sha512-8XRcPR5qXKNmnBO6u9FSY8vYa7P1FIgVix07EHBCTZiJYHYxcUsFYRWG9qf2aShGotJs4957unqGH1L1ncRYKQ==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
|
||||
dependencies:
|
||||
'@babel/runtime': 7.19.0
|
||||
'@react-aria/focus': 3.9.0_react@17.0.2
|
||||
'@react-aria/interactions': 3.12.0_react@17.0.2
|
||||
'@react-aria/utils': 3.14.0_react@17.0.2
|
||||
'@react-stately/toggle': 3.4.2_react@17.0.2
|
||||
'@react-types/button': 3.6.2_react@17.0.2
|
||||
'@react-types/shared': 3.15.0_react@17.0.2
|
||||
react: 17.0.2
|
||||
dev: false
|
||||
|
||||
/@react-aria/checkbox/3.6.0_react@17.0.2:
|
||||
resolution: {integrity: sha512-E2MZoMZhtHtlS1mYjxTI29JRq4s3Y6d92KHj7tzvcC308d4Bzz0IHJd0bMz/8whoNteU02pQyZ3rDAcGf92bHQ==}
|
||||
peerDependencies:
|
||||
@ -4891,7 +4941,6 @@ packages:
|
||||
dependencies:
|
||||
'@react-types/shared': 3.15.0_react@17.0.2
|
||||
react: 17.0.2
|
||||
dev: false
|
||||
|
||||
/@react-types/checkbox/3.4.0_react@17.0.2:
|
||||
resolution: {integrity: sha512-ZDqbtAYWWSGPjL4ydinaWHrD65Qft9yEGA6BCKQTxdJCgxiXxgGkA3pI7Sxwk+OulR+O0CYJ1JROExM9cSJyyQ==}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user