feat(root): new ripple pkg created

This commit is contained in:
Junior Garcia 2023-07-06 00:08:39 -03:00
parent 10ac6ced32
commit 5b5756bb33
81 changed files with 339 additions and 228 deletions

View File

@ -7,7 +7,7 @@ export default function App() {
<Image
alt="nextui logo"
height={40}
radius="lg"
radius="sm"
src="https://avatars.githubusercontent.com/u/86160567?s=200&v=4"
width={40}
/>

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/accordion",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Collapse display a list of high-level options that can expand/collapse to reveal more information.",
"keywords": [
"react",

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/avatar",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "The Avatar component is used to represent a user, and displays the profile picture, initials or fallback icon.",
"keywords": [
"avatar"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/badge",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Badges are used as a small numerical value or status descriptor for UI elements.",
"keywords": [
"badge"

View File

@ -8,7 +8,7 @@ describe("ButtonGroup", () => {
it("should render correctly", () => {
const wrapper = render(
<ButtonGroup>
<Button>action</Button>
<Button disableRipple>action</Button>
</ButtonGroup>,
);
@ -26,7 +26,7 @@ describe("ButtonGroup", () => {
const handler = jest.fn();
const wrapper = render(
<ButtonGroup isDisabled={true}>
<Button data-testid="button-test" onClick={handler}>
<Button disableRipple data-testid="button-test" onClick={handler}>
action
</Button>
</ButtonGroup>,
@ -42,13 +42,13 @@ describe("ButtonGroup", () => {
const wrapper = render(
<ButtonGroup>
<Button variant="flat">button</Button>
<Button color="warning" variant="light">
<Button disableRipple color="warning" variant="light">
light
</Button>
<Button color="success" variant="light">
<Button disableRipple color="success" variant="light">
button
</Button>
<Button color="warning" variant="bordered">
<Button disableRipple color="warning" variant="bordered">
button
</Button>
</ButtonGroup>,

View File

@ -5,7 +5,7 @@ import {Button} from "../src";
describe("Button", () => {
it("should render correctly", () => {
const wrapper = render(<Button />);
const wrapper = render(<Button disableRipple />);
expect(() => wrapper.unmount()).not.toThrow();
});
@ -13,13 +13,13 @@ describe("Button", () => {
it("ref should be forwarded", () => {
const ref = React.createRef<HTMLButtonElement>();
render(<Button ref={ref} />);
render(<Button ref={ref} disableRipple />);
expect(ref.current).not.toBeNull();
});
it("should trigger onPress function", () => {
const onPress = jest.fn();
const {getByRole} = render(<Button onPress={onPress} />);
const {getByRole} = render(<Button disableRipple onPress={onPress} />);
act(() => {
getByRole("button").click();
@ -30,7 +30,7 @@ describe("Button", () => {
it("should ignore events when disabled", () => {
const onPress = jest.fn();
const {getByRole} = render(<Button disabled onPress={onPress} />);
const {getByRole} = render(<Button disableRipple disabled onPress={onPress} />);
act(() => {
getByRole("button").click();
@ -41,7 +41,9 @@ describe("Button", () => {
it("should renders with start icon", () => {
const wrapper = render(
<Button startContent={<span data-testid="start-icon">Icon</span>}>Button</Button>,
<Button disableRipple startContent={<span data-testid="start-icon">Icon</span>}>
Button
</Button>,
);
expect(wrapper.getByTestId("start-icon")).toBeInTheDocument();
@ -49,14 +51,16 @@ describe("Button", () => {
it("should renders with end icon", () => {
const wrapper = render(
<Button endContent={<span data-testid="end-icon">Icon</span>}>Button</Button>,
<Button disableRipple endContent={<span data-testid="end-icon">Icon</span>}>
Button
</Button>,
);
expect(wrapper.getByTestId("end-icon")).toBeInTheDocument();
});
it("should have the proper type attribute", () => {
const wrapper = render(<Button type="submit" />);
const wrapper = render(<Button disableRipple type="submit" />);
expect(wrapper.getByRole("button")).toHaveAttribute("type", "submit");
});

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/button",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Buttons allow users to perform actions and choose with a single tap.",
"keywords": [
"button"
@ -42,7 +42,7 @@
"@nextui-org/react-utils": "workspace:*",
"@nextui-org/use-aria-button": "workspace:*",
"@nextui-org/theme": "workspace:*",
"@nextui-org/drip": "workspace:*",
"@nextui-org/ripple": "workspace:*",
"@nextui-org/spinner": "workspace:*",
"@react-aria/button": "^3.8.0",
"@react-aria/interactions": "^3.16.0",

View File

@ -1,8 +1,9 @@
import {Drip} from "@nextui-org/drip";
import {Spinner} from "@nextui-org/spinner";
import {forwardRef} from "@nextui-org/system";
import {lazy} from "react";
import {UseButtonProps, useButton} from "./use-button";
const Ripple = lazy(() => import("@nextui-org/ripple").then(({Ripple}) => ({default: Ripple})));
export interface ButtonProps extends Omit<UseButtonProps, "ref"> {}
@ -12,7 +13,7 @@ const Button = forwardRef<ButtonProps, "button">((props, ref) => {
domRef,
children,
styles,
drips,
ripples,
spinnerSize,
spinner = <Spinner color="current" size={spinnerSize} />,
spinnerPlacement,
@ -33,7 +34,7 @@ const Button = forwardRef<ButtonProps, "button">((props, ref) => {
{children}
{isLoading && spinnerPlacement === "end" && spinner}
{endContent}
{!disableRipple && <Drip drips={drips} />}
{!disableRipple && <Ripple suspense ripples={ripples} />}
</Component>
);
});

View File

@ -8,13 +8,13 @@ import {ReactRef} from "@nextui-org/react-utils";
import {MouseEventHandler, useCallback} from "react";
import {useFocusRing} from "@react-aria/focus";
import {chain, mergeProps} from "@react-aria/utils";
import {useDrip} from "@nextui-org/drip";
import {useDOMRef} from "@nextui-org/react-utils";
import {button} from "@nextui-org/theme";
import {isValidElement, cloneElement, useMemo} from "react";
import {useAriaButton} from "@nextui-org/use-aria-button";
import {useHover} from "@react-aria/interactions";
import {SpinnerProps} from "@nextui-org/spinner";
import {useRipple} from "@nextui-org/ripple";
import {useButtonGroupContext} from "./button-group-context";
@ -122,11 +122,11 @@ export function useButton(props: UseButtonProps) {
],
);
const {onClick: onDripClickHandler, drips} = useDrip();
const {onClick: onRippleClickHandler, ripples} = useRipple();
const handleDrip = (e: React.MouseEvent<HTMLButtonElement>) => {
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
if (disableRipple || isDisabled || disableAnimation) return;
domRef.current && onDripClickHandler(e);
domRef.current && onRippleClickHandler(e);
};
const {buttonProps: ariaButtonProps, isPressed} = useAriaButton(
@ -134,7 +134,7 @@ export function useButton(props: UseButtonProps) {
elementType: as,
isDisabled,
onPress,
onClick: chain(onClick, handleDrip),
onClick: chain(onClick, handleClick),
...otherProps,
} as AriaButtonProps,
domRef,
@ -192,7 +192,7 @@ export function useButton(props: UseButtonProps) {
Component,
children,
domRef,
drips,
ripples,
spinner,
styles,
startContent,

View File

@ -1,5 +1,6 @@
import * as React from "react";
import {act, render} from "@testing-library/react";
import {render} from "@testing-library/react";
import {act} from "@testing-library/react-hooks";
import {Card} from "../src";
@ -25,10 +26,12 @@ describe("Card", () => {
it("should be clicked when is pressable", () => {
const onPress = jest.fn();
const {getByRole} = render(<Card isPressable onPress={onPress} />);
const {getByRole} = render(<Card disableRipple isPressable onPress={onPress} />);
const button = getByRole("button");
act(() => {
getByRole("button").click();
button.click();
});
expect(onPress).toHaveBeenCalled();
@ -45,7 +48,7 @@ describe("Card", () => {
});
it("should have a button role when is pressable", () => {
const {container} = render(<Card isPressable />);
const {container} = render(<Card disableRipple isPressable />);
expect(container.firstChild).toHaveAttribute("role", "button");
});

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/card",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Card is a container for text, photos, and actions in the context of a single subject.",
"keywords": [
"card"
@ -42,7 +42,7 @@
"@nextui-org/shared-utils": "workspace:*",
"@nextui-org/react-utils": "workspace:*",
"@nextui-org/use-aria-button": "workspace:*",
"@nextui-org/drip": "workspace:*",
"@nextui-org/ripple": "workspace:*",
"@react-aria/focus": "^3.13.0",
"@react-aria/utils": "^3.18.0",
"@react-aria/interactions": "^3.16.0",

View File

@ -1,9 +1,11 @@
import {forwardRef} from "@nextui-org/system";
import {Drip} from "@nextui-org/drip";
import {lazy} from "react";
import {CardProvider} from "./card-context";
import {useCard, UseCardProps} from "./use-card";
const Ripple = lazy(() => import("@nextui-org/ripple").then(({Ripple}) => ({default: Ripple})));
export interface CardProps extends Omit<UseCardProps, "ref"> {}
const Card = forwardRef<CardProps, "div">((props, ref) => {
@ -11,7 +13,7 @@ const Card = forwardRef<CardProps, "div">((props, ref) => {
children,
context,
Component,
drips,
ripples,
isPressable,
disableAnimation,
disableRipple,
@ -24,7 +26,7 @@ const Card = forwardRef<CardProps, "div">((props, ref) => {
return (
<Component {...getCardProps()}>
<CardProvider value={context}>{children}</CardProvider>
{isPressable && !disableAnimation && !disableRipple && <Drip drips={drips} />}
{isPressable && !disableAnimation && !disableRipple && <Ripple suspense ripples={ripples} />}
</Component>
);
});

View File

@ -11,7 +11,7 @@ import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system"
import {callAllHandlers, clsx, dataAttr} from "@nextui-org/shared-utils";
import {ReactRef} from "@nextui-org/react-utils";
import {useDOMRef} from "@nextui-org/react-utils";
import {useDrip} from "@nextui-org/drip";
import {useRipple} from "@nextui-org/ripple";
import {AriaButtonProps} from "@react-aria/button";
export interface Props extends HTMLNextUIProps<"div"> {
@ -80,11 +80,11 @@ export function useCard(originalProps: UseCardProps) {
const baseStyles = clsx(classNames?.base, className);
const {onClick: onDripClickHandler, drips} = useDrip();
const {onClick: onRippleClickHandler, ripples} = useRipple();
const handleDrip = (e: MouseEvent<HTMLDivElement>) => {
const handleClick = (e: MouseEvent<HTMLDivElement>) => {
if (!originalProps.disableAnimation && !disableRipple && domRef.current) {
onDripClickHandler(e);
onRippleClickHandler(e);
}
};
@ -93,7 +93,7 @@ export function useCard(originalProps: UseCardProps) {
onPress,
elementType: as,
isDisabled: !originalProps.isPressable,
onClick: callAllHandlers(onClick, handleDrip),
onClick: callAllHandlers(onClick, handleClick),
allowTextSelectionOnPress,
...otherProps,
} as AriaButtonProps,
@ -178,14 +178,14 @@ export function useCard(originalProps: UseCardProps) {
Component,
classNames,
children,
drips,
ripples,
isHovered,
isPressed,
isPressable: originalProps.isPressable,
isHoverable: originalProps.isHoverable,
disableAnimation: originalProps.disableAnimation,
disableRipple,
onDripClickHandler,
handleClick,
isFocusVisible,
getCardProps,
};

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/checkbox",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Checkboxes allow users to select multiple items from a list of individual items, or to mark one individual item as selected.",
"keywords": [
"checkbox"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/chip",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Chips help people enter information, make selections, filter content, or trigger actions.",
"keywords": [
"chip"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/code",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Code is a component used to display inline code.",
"keywords": [
"code"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/divider",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": ". A separator is a visual divider between two groups of content",
"keywords": [
"divider"

View File

@ -1,30 +0,0 @@
import type {HTMLNextUIProps} from "@nextui-org/system";
import type {DripInstance} from "./use-drip";
import {drip} from "@nextui-org/theme";
export interface DripProps extends HTMLNextUIProps<"span"> {
drips?: DripInstance[];
}
const Drip = (props: DripProps) => {
const {drips, ...otherProps} = props;
const classNames = drip();
if (!drips || !Array.isArray(drips) || drips.length < 1) {
return null;
}
return (
<>
{drips.map(({key, ...dripProps}) => (
<span key={key} className={classNames} {...otherProps} {...dripProps} />
))}
</>
);
};
Drip.displayName = "NextUI.Drip";
export default Drip;

View File

@ -1,8 +0,0 @@
// export hook
export {useDrip} from "./use-drip";
// export types
export type {DripProps} from "./drip";
// export component
export {default as Drip} from "./drip";

View File

@ -1,46 +0,0 @@
import {MouseEvent, CSSProperties, useState} from "react";
import {getUniqueID} from "@nextui-org/shared-utils";
export type DripInstance = {
key: number | string;
style: CSSProperties;
};
export function useDrip() {
const [drips, setDrips] = useState<DripInstance[]>([]);
const onClick = (event: MouseEvent<HTMLElement>) => {
const trigger = event.currentTarget;
const size = Math.max(trigger.clientWidth, trigger.clientHeight);
const rect = trigger.getBoundingClientRect();
const x = event.clientX - rect.x - size / 2;
const y = event.clientY - rect.y - size / 2;
const dripStyle: CSSProperties = {
width: `${size}px`,
height: `${size}px`,
top: `${y}px`,
left: `${x}px`,
};
setDrips((prev) => [
...prev,
{
key: getUniqueID("drip"),
style: dripStyle,
},
]);
setTimeout(() => {
setDrips((prev) => prev.slice(1));
}, 400);
};
return {
drips,
onClick,
};
}
export type UseDripReturn = ReturnType<typeof useDrip>;

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/dropdown",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "A dropdown displays a list of actions or options that a user can choose.",
"keywords": [
"dropdown"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/image",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "A simple image component",
"keywords": [
"image"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/input",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "The input component is designed for capturing user input within a text field.",
"keywords": [
"input"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/kbd",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "The keyboard key components indicates which key or set of keys used to execute a specificv action",
"keywords": [
"kbd"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/link",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Links allow users to click their way from page to page. This component is styled to resemble a hyperlink and semantically renders an &lt;a&gt;",
"keywords": [
"link"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/modal",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Displays a dialog with a custom content that requires attention or provides additional information.",
"keywords": [
"modal"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/navbar",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "A responsive navigation header positioned on top side of your page that includes support for branding, links, navigation, collapse and more.",
"keywords": [
"navbar"

View File

@ -1,19 +1,18 @@
import {TRANSITION_EASINGS} from "@nextui-org/framer-transitions";
import {Variants} from "framer-motion";
export const menuVariants: Variants = {
enter: {
height: "calc(100vh - var(--navbar-height) - 1px)",
transition: {
duration: 0.4,
ease: TRANSITION_EASINGS.ease,
duration: 0.3,
easings: "easeOut",
},
},
exit: {
height: 0,
transition: {
duration: 0.3,
ease: TRANSITION_EASINGS.ease,
duration: 0.25,
easings: "easeIn",
},
},
};

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/pagination",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "The Pagination component allows you to display active page and navigate between multiple pages.",
"keywords": [
"pagination"

View File

@ -102,7 +102,9 @@ describe("Popover", () => {
const wrapper = render(
<Popover onOpenChange={(isOpen) => (!isOpen ? onClose() : undefined)}>
<PopoverTrigger>
<Button data-testid="trigger-test">Open popover</Button>
<Button disableRipple data-testid="trigger-test">
Open popover
</Button>
</PopoverTrigger>
<PopoverContent>
<p>This is the content of the popover.</p>

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/popover",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "A popover is an overlay element positioned relative to a trigger.",
"keywords": [
"popover"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/progress",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Progress bars show either determinate or indeterminate progress of an operation over time.",
"keywords": [
"progress"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/radio",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Radios allow users to select a single option from a list of mutually exclusive options.",
"keywords": [
"radio"

View File

@ -1,4 +1,4 @@
# @nextui-org/drip
# @nextui-org/ripple
A Quick description of the component
@ -7,9 +7,9 @@ A Quick description of the component
## Installation
```sh
yarn add @nextui-org/drip
yarn add @nextui-org/ripple
# or
npm i @nextui-org/drip
npm i @nextui-org/ripple
```
## Contribution

View File

@ -1,9 +1,9 @@
{
"name": "@nextui-org/drip",
"version": "0.0.0-dev-v2-20230705005214",
"description": "A ripple effect for ensuring that the user fells the system is reacting instantaneously",
"name": "@nextui-org/ripple",
"version": "0.0.0-dev-v2-20230706030638",
"description": "A simple implementation to display a ripple animation when the source component is clicked",
"keywords": [
"drip"
"ripple"
],
"author": "Junior Garcia <jrgarciadev@gmail.com>",
"homepage": "https://nextui.org",
@ -19,30 +19,33 @@
"repository": {
"type": "git",
"url": "git+https://github.com/nextui-org/nextui.git",
"directory": "packages/components/drip"
"directory": "packages/components/ripple"
},
"bugs": {
"url": "https://github.com/nextui-org/nextui/issues"
},
"scripts": {
"build": "tsup src --dts",
"build:fast": "tsup src",
"dev": "yarn build:fast -- --watch",
"clean": "rimraf dist .turbo",
"typecheck": "tsc --noEmit",
"build:fast": "tsup src",
"prepack": "clean-package",
"postpack": "clean-package restore"
},
"peerDependencies": {
"react": ">=18"
"react": ">=18",
"framer-motion": ">=4.0.0"
},
"dependencies": {
"@nextui-org/system": "workspace:*",
"@nextui-org/theme": "workspace:*",
"@nextui-org/shared-utils": "workspace:*"
"@nextui-org/shared-utils": "workspace:*",
"@nextui-org/react-utils": "workspace:*"
},
"devDependencies": {
"clean-package": "2.2.0",
"framer-motion": "^10.12.18",
"react": "^18.0.0"
},
"clean-package": "../../../clean-package.config.json"

View File

@ -0,0 +1,10 @@
import Ripple from "./ripple";
// export types
export type {RippleProps} from "./ripple";
// export hooks
export {useRipple} from "./use-ripple";
// export component
export {Ripple};

View File

@ -0,0 +1,67 @@
import {FC, Suspense, Fragment} from "react";
import {AnimatePresence, HTMLMotionProps, motion} from "framer-motion";
import {HTMLNextUIProps} from "@nextui-org/system";
import {RippleType} from "./use-ripple";
export interface RippleProps extends HTMLNextUIProps<"span"> {
ripples: RippleType[];
color?: string;
suspense?: boolean;
motionProps?: HTMLMotionProps<"span">;
style?: React.CSSProperties;
}
const clamp = (value: number, min: number, max: number) => {
return Math.min(Math.max(value, min), max);
};
const Ripple: FC<RippleProps> = ({
ripples = [],
motionProps,
suspense = false,
color = "currentColor",
style,
}) => {
return (
<>
{ripples.map((ripple) => {
const duration = clamp(0.01 * ripple.size, 0.2, ripple.size > 100 ? 0.75 : 0.5);
const Wrapper = suspense ? Suspense : Fragment;
return (
<Wrapper key={ripple.key}>
<AnimatePresence mode="popLayout">
<motion.span
animate={{transform: "scale(2)", opacity: 0}}
className="nextui-ripple"
exit={{opacity: 0}}
initial={{transform: "scale(0)", opacity: 0.35}}
style={{
position: "absolute",
backgroundColor: color,
borderRadius: "100%",
transformOrigin: "center",
pointerEvents: "none",
zIndex: 10,
top: ripple.y,
left: ripple.x,
width: `${ripple.size}px`,
height: `${ripple.size}px`,
...style,
}}
transition={{duration}}
{...motionProps}
/>
</AnimatePresence>
</Wrapper>
);
})}
</>
);
};
Ripple.displayName = "NextUI.Ripple";
export default Ripple;

View File

@ -0,0 +1,57 @@
import {useEffect, useState} from "react";
export type RippleType = {
key: number;
x: number;
y: number;
size: number;
};
export interface UseRippleProps {
/**
/**
* The time to remove the ripples in ms.
* @default 1000
*/
removeAfter?: number;
}
export function useRipple(props: UseRippleProps = {}) {
const {removeAfter = 1000, ...otherProps} = props;
const [ripples, setRipples] = useState<RippleType[]>([]);
useEffect(() => {
const timeoutIds = ripples.map(
(_, i) =>
setTimeout(() => {
setRipples((prevState) => prevState.filter((_, index) => index !== i));
}, removeAfter), // remove after 1s
);
return () => {
timeoutIds.forEach((id) => clearTimeout(id));
};
}, [ripples]);
const onClick = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
const trigger = event.currentTarget;
const size = Math.max(trigger.clientWidth, trigger.clientHeight);
const rect = trigger.getBoundingClientRect();
setRipples((prevRipples) => [
...prevRipples,
{
key: new Date().getTime(),
size,
x: event.clientX - rect.x - size / 2,
y: event.clientY - rect.y - size / 2,
},
]);
};
return {ripples, onClick, ...otherProps};
}
export type UseRippleReturn = ReturnType<typeof useRipple>;

View File

@ -0,0 +1,46 @@
import React from "react";
import {ComponentStory, ComponentMeta} from "@storybook/react";
import {ripple} from "@nextui-org/theme";
import {Ripple, RippleProps} from "../src";
export default {
title: "Components/Ripple",
component: Ripple,
argTypes: {
color: {
control: {
type: "select",
options: ["neutral", "primary", "secondary", "success", "warning", "danger"],
},
},
radius: {
control: {
type: "select",
options: ["none", "sm", "md", "lg", "full"],
},
},
size: {
control: {
type: "select",
options: ["sm", "md", "lg"],
},
},
isDisabled: {
control: {
type: "boolean",
},
},
},
} as ComponentMeta<typeof Ripple>;
const defaultProps = {
...ripple.defaultVariants,
};
const Template: ComponentStory<typeof Ripple> = (args: RippleProps) => <Ripple {...args} />;
export const Default = Template.bind({});
Default.args = {
...defaultProps,
};

View File

@ -4,7 +4,7 @@
"baseUrl": ".",
"paths": {
"tailwind-variants": ["../../../node_modules/tailwind-variants"]
},
}
},
"include": ["src", "index.ts"]
}

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/skeleton",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Skeleton is used to display the loading state of some component.",
"keywords": [
"skeleton"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/snippet",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Display a snippet of copyable code for the command line.",
"keywords": [
"snippet"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/spacer",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "A flexible spacer component designed to create consistent spacing and maintain alignment in your layout.",
"keywords": [
"spacer"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/spinner",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Loaders express an unspecified wait time or display the length of a process.",
"keywords": [
"loading",

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/switch",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "A switch is similar to a checkbox, but represents on/off values as opposed to selection.",
"keywords": [
"switch"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/table",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Tables are used to display tabular data using rows and columns. ",
"keywords": [
"table"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/tabs",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Tabs organize content into multiple sections and allow users to navigate between them.",
"keywords": [
"tabs"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/tooltip",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "A React Component for rendering dynamically positioned Tooltips",
"keywords": [
"tooltip"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/user",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Flexible User Profile Component.",
"keywords": [
"user"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/react",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "🚀 Beautiful and modern React UI library.",
"author": "Junior Garcia <jrgarciadev@gmail.com>",
"homepage": "https://nextui.org",
@ -51,7 +51,6 @@
"@nextui-org/chip": "workspace:*",
"@nextui-org/checkbox": "workspace:*",
"@nextui-org/code": "workspace:*",
"@nextui-org/drip": "workspace:*",
"@nextui-org/link": "workspace:*",
"@nextui-org/pagination": "workspace:*",
"@nextui-org/radio": "workspace:*",

View File

@ -12,7 +12,6 @@ export * from "@nextui-org/card";
export * from "@nextui-org/chip";
export * from "@nextui-org/checkbox";
export * from "@nextui-org/code";
export * from "@nextui-org/drip";
export * from "@nextui-org/link";
export * from "@nextui-org/pagination";
export * from "@nextui-org/radio";

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/system",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "NextUI system primitives",
"keywords": [
"system"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/theme",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "The default theme for NextUI components",
"keywords": [
"theme",

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-aria-accordion-item",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Internal impl for react aria accordion item",
"keywords": [
"use-aria-accordion-item"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-aria-button",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Internal hook to handle button a11y and events, this is based on react-aria button hook but without the onClick warning",
"keywords": [
"use-aria-button"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-aria-label",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Based on react-aria label hook, it provides the accessibility implementation for labels and their associated elements. Labels provide context for user inputs.",
"keywords": [
"use-aria-label"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-aria-modal-overlay",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "A custom implementation of react aria modal overlay, this removes the prevent scroll",
"keywords": [
"use-aria-modal-overlay"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-aria-toggle-button",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Internal hook to handle button a11y and events, this is based on react-aria button hook but without the onClick warning",
"keywords": [
"use-aria-toggle-button"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-callback-ref",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "React hook to persist any value between renders, but keeps it up-to-date if it changes.",
"keywords": [
"use-callback-ref"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-clipboard",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Wrapper around navigator.clipboard with feedback timeout",
"keywords": [
"use-clipboard"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-disclosure",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "The hook in charge of managing modals",
"keywords": [
"use-disclosure"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-image",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "React hook for progressing image loading",
"keywords": [
"use-image"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-infinite-scroll",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "A hook for handling infinity scroll based on the IntersectionObserver API",
"keywords": [
"use-infinite-scroll"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-is-mobile",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "A hook that returns whether the device is mobile or not",
"keywords": [
"use-is-mobile"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-is-mounted",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "This hook can be used to render client-based components or run client logic",
"keywords": [
"use-is-mounted"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-pagination",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "State management hook for Pagination component, it lets you manage pagination with controlled and uncontrolled state",
"keywords": [
"use-pagination"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-real-shape",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Hook that returns the real dimensions of an element",
"keywords": [
"use-real-shape"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-ref-state",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Hook for saving the state in a ref value",
"keywords": [
"use-ref-state"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-resize",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Hook that adds an event listener to the resize window event",
"keywords": [
"use-resize"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-safe-layout-effect",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "",
"keywords": [
"use-safe-layout-effect"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-scroll-position",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Provides the logic to control the scroll over an element",
"keywords": [
"use-scroll-position"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-ssr",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "",
"keywords": [
"use-ssr"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/use-update-effect",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "React effect hook that invokes only on update",
"keywords": [
"use-update-effect"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/aria-utils",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "A package for managing @react-aria nextui utils.",
"keywords": [
"aria-utils"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/framer-transitions",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "A set of framer motion transitions for react",
"keywords": [
"framer-transitions"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/react-utils",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "A set of utilities for react on client side",
"keywords": [
"react-utils"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/shared-icons",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "Internal icons set, commonly used in the components stories",
"keywords": [
"icons-utils"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/shared-utils",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "A set of NextUI utilities",
"keywords": [
"system"

View File

@ -1,6 +1,6 @@
{
"name": "@nextui-org/test-utils",
"version": "0.0.0-dev-v2-20230705005214",
"version": "0.0.0-dev-v2-20230706030638",
"description": "A set of utilities for react testing",
"keywords": [
"test-utils"

59
pnpm-lock.yaml generated
View File

@ -679,12 +679,12 @@ importers:
packages/components/button:
dependencies:
'@nextui-org/drip':
specifier: workspace:*
version: link:../drip
'@nextui-org/react-utils':
specifier: workspace:*
version: link:../../utilities/react-utils
'@nextui-org/ripple':
specifier: workspace:*
version: link:../ripple
'@nextui-org/shared-utils':
specifier: workspace:*
version: link:../../utilities/shared-utils
@ -731,12 +731,12 @@ importers:
packages/components/card:
dependencies:
'@nextui-org/drip':
specifier: workspace:*
version: link:../drip
'@nextui-org/react-utils':
specifier: workspace:*
version: link:../../utilities/react-utils
'@nextui-org/ripple':
specifier: workspace:*
version: link:../ripple
'@nextui-org/shared-utils':
specifier: workspace:*
version: link:../../utilities/shared-utils
@ -938,25 +938,6 @@ importers:
specifier: ^18.2.0
version: 18.2.0
packages/components/drip:
dependencies:
'@nextui-org/shared-utils':
specifier: workspace:*
version: link:../../utilities/shared-utils
'@nextui-org/system':
specifier: workspace:*
version: link:../../core/system
'@nextui-org/theme':
specifier: workspace:*
version: link:../../core/theme
devDependencies:
clean-package:
specifier: 2.2.0
version: 2.2.0
react:
specifier: ^18.2.0
version: 18.2.0
packages/components/dropdown:
dependencies:
'@nextui-org/aria-utils':
@ -1526,6 +1507,31 @@ importers:
specifier: ^18.2.0
version: 18.2.0
packages/components/ripple:
dependencies:
'@nextui-org/react-utils':
specifier: workspace:*
version: link:../../utilities/react-utils
'@nextui-org/shared-utils':
specifier: workspace:*
version: link:../../utilities/shared-utils
'@nextui-org/system':
specifier: workspace:*
version: link:../../core/system
'@nextui-org/theme':
specifier: workspace:*
version: link:../../core/theme
devDependencies:
clean-package:
specifier: 2.2.0
version: 2.2.0
framer-motion:
specifier: ^10.12.18
version: 10.12.18(react-dom@18.2.0)(react@18.2.0)
react:
specifier: ^18.2.0
version: 18.2.0
packages/components/skeleton:
dependencies:
'@nextui-org/react-utils':
@ -1957,9 +1963,6 @@ importers:
'@nextui-org/divider':
specifier: workspace:*
version: link:../../components/divider
'@nextui-org/drip':
specifier: workspace:*
version: link:../../components/drip
'@nextui-org/dropdown':
specifier: workspace:*
version: link:../../components/dropdown