feat(components): card & related components added
2
next-env.d.ts
vendored
@ -1,2 +0,0 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/types/global" />
|
||||
24
packages/components/card/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# @nextui-org/card
|
||||
|
||||
A Quick description of the component
|
||||
|
||||
> This is an internal utility, not intended for public usage.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
yarn add @nextui-org/card
|
||||
# or
|
||||
npm i @nextui-org/card
|
||||
```
|
||||
|
||||
## 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).
|
||||
50
packages/components/card/__tests__/card.test.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import * as React from "react";
|
||||
import {render} from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
|
||||
import {Card} from "../src";
|
||||
|
||||
describe("Card", () => {
|
||||
it("should render correctly", () => {
|
||||
const wrapper = render(<Card />);
|
||||
|
||||
expect(() => wrapper.unmount()).not.toThrow();
|
||||
});
|
||||
|
||||
it("ref should be forwarded", () => {
|
||||
const ref = React.createRef<HTMLDivElement>();
|
||||
|
||||
render(<Card ref={ref} />);
|
||||
expect(ref.current).not.toBeNull();
|
||||
});
|
||||
|
||||
it("should support hoverable", () => {
|
||||
const wrapper = render(<Card isHoverable />);
|
||||
|
||||
expect(() => wrapper.unmount()).not.toThrow();
|
||||
});
|
||||
|
||||
it("should be clicked when is pressable", () => {
|
||||
const onPress = jest.fn();
|
||||
const {container} = render(<Card isPressable onPress={onPress} />);
|
||||
|
||||
userEvent.click(container.firstChild as HTMLElement);
|
||||
expect(onPress).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should render correctly when nested", () => {
|
||||
const wrapper = render(
|
||||
<Card>
|
||||
<Card />
|
||||
</Card>,
|
||||
);
|
||||
|
||||
expect(() => wrapper.unmount()).not.toThrow();
|
||||
});
|
||||
|
||||
it("should have a button role when is pressable", () => {
|
||||
const {container} = render(<Card isPressable />);
|
||||
|
||||
expect(container.firstChild).toHaveAttribute("role", "button");
|
||||
});
|
||||
});
|
||||
3
packages/components/card/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" } } }
|
||||
62
packages/components/card/package.json
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
"name": "@nextui-org/card",
|
||||
"version": "1.0.0-beta.11",
|
||||
"description": "Card is a container for text, photos, and actions in the context of a single subject.",
|
||||
"keywords": [
|
||||
"card"
|
||||
],
|
||||
"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/card"
|
||||
},
|
||||
"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:*",
|
||||
"@nextui-org/divider": "workspace:*",
|
||||
"@nextui-org/image": "workspace:*",
|
||||
"@react-aria/focus": "^3.9.0",
|
||||
"@react-aria/utils": "^3.14.0",
|
||||
"@react-aria/interactions": "^3.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-types/shared": "^3.14.1",
|
||||
"@nextui-org/text": "workspace:*",
|
||||
"@nextui-org/grid": "workspace:*",
|
||||
"@nextui-org/col": "workspace:*",
|
||||
"@nextui-org/row": "workspace:*",
|
||||
"@nextui-org/code": "workspace:*",
|
||||
"@nextui-org/link": "workspace:*",
|
||||
"clean-package": "2.1.1",
|
||||
"react": "^17.0.2"
|
||||
}
|
||||
}
|
||||
177
packages/components/card/src/card.styles.ts
Normal file
@ -0,0 +1,177 @@
|
||||
import {styled} from "@nextui-org/system";
|
||||
import {cssFocusVisible, cssNoBlurriness} from "@nextui-org/shared-css";
|
||||
|
||||
export const StyledCardBody = styled("div", {
|
||||
d: "flex",
|
||||
w: "100%",
|
||||
h: "auto",
|
||||
flex: "1 1 auto",
|
||||
fd: "column",
|
||||
jc: "inherit",
|
||||
ai: "inherit",
|
||||
ac: "inherit",
|
||||
py: "$lg",
|
||||
px: "$sm",
|
||||
oy: "auto",
|
||||
position: "relative",
|
||||
ta: "left",
|
||||
});
|
||||
|
||||
export const StyledCard = styled(
|
||||
"div",
|
||||
{
|
||||
$$cardColor: "$colors$backgroundContrast",
|
||||
$$cardTextColor: "$colors$text",
|
||||
m: 0,
|
||||
p: 0,
|
||||
br: "$lg",
|
||||
bg: "$$cardColor",
|
||||
color: "$$cardTextColor",
|
||||
position: "relative",
|
||||
display: "flex",
|
||||
overflow: "hidden",
|
||||
fd: "column",
|
||||
width: "100%",
|
||||
height: "auto",
|
||||
boxSizing: "border-box",
|
||||
"@motion": {
|
||||
transition: "none",
|
||||
},
|
||||
".nextui-image": {
|
||||
width: "100%",
|
||||
},
|
||||
".nextui-drip": {
|
||||
zIndex: "$1",
|
||||
".nextui-drip-filler": {
|
||||
opacity: 0.25,
|
||||
fill: "$accents6",
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
variant: {
|
||||
flat: {
|
||||
bg: "$accents0",
|
||||
},
|
||||
shadow: {
|
||||
dropShadow: "$lg",
|
||||
"@safari": {
|
||||
boxShadow: "$lg",
|
||||
dropShadow: "none",
|
||||
},
|
||||
},
|
||||
bordered: {
|
||||
borderStyle: "solid",
|
||||
borderColor: "$border",
|
||||
},
|
||||
},
|
||||
borderWeight: {
|
||||
light: {
|
||||
bw: "$light",
|
||||
},
|
||||
normal: {
|
||||
bw: "$normal",
|
||||
},
|
||||
bold: {
|
||||
bw: "$bold",
|
||||
},
|
||||
extrabold: {
|
||||
bw: "$extrabold",
|
||||
},
|
||||
black: {
|
||||
bw: "$black",
|
||||
},
|
||||
},
|
||||
disableAnimation: {
|
||||
true: {
|
||||
transition: "none",
|
||||
},
|
||||
false: {
|
||||
transition: "$card",
|
||||
},
|
||||
},
|
||||
isPressable: {
|
||||
true: {
|
||||
cursor: "pointer",
|
||||
us: "none",
|
||||
WebkitTapHighlightColor: "transparent",
|
||||
},
|
||||
},
|
||||
isPressed: {
|
||||
true: {},
|
||||
},
|
||||
isHovered: {
|
||||
true: {
|
||||
dropShadow: "$lg",
|
||||
"@safari": {
|
||||
boxShadow: "$lg",
|
||||
dropShadow: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
compoundVariants: [
|
||||
// isPreseed && !disableAnimation
|
||||
{
|
||||
isPressed: true,
|
||||
disableAnimation: false,
|
||||
css: {
|
||||
transform: "scale(0.97)",
|
||||
},
|
||||
},
|
||||
// isHovered && !disableAnimation
|
||||
{
|
||||
isHovered: true,
|
||||
disableAnimation: false,
|
||||
css: {
|
||||
transform: "translateY(-2px)",
|
||||
},
|
||||
},
|
||||
// isHovered && variant === 'shadow'
|
||||
{
|
||||
isHovered: true,
|
||||
variant: "shadow",
|
||||
css: {
|
||||
dropShadow: "$xl",
|
||||
"@safari": {
|
||||
boxShadow: "$xl",
|
||||
dropShadow: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
cssNoBlurriness,
|
||||
cssFocusVisible,
|
||||
);
|
||||
|
||||
export const StyledCardHeader = styled("div", {
|
||||
w: "100%",
|
||||
display: "flex",
|
||||
flexShrink: 0,
|
||||
zIndex: "$1",
|
||||
jc: "flex-start",
|
||||
ai: "center",
|
||||
overflow: "hidden",
|
||||
color: "inherit",
|
||||
p: "$sm",
|
||||
});
|
||||
|
||||
export const StyledCardFooter = styled("div", {
|
||||
w: "100%",
|
||||
h: "auto",
|
||||
p: "$sm",
|
||||
d: "flex",
|
||||
ai: "center",
|
||||
overflow: "hidden",
|
||||
color: "inherit",
|
||||
bblr: "$lg",
|
||||
bbrr: "$lg",
|
||||
variants: {
|
||||
isBlurred: {
|
||||
true: {
|
||||
bf: "saturate(180%) blur(10px)",
|
||||
bg: "$$cardColor",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
75
packages/components/card/src/card.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
import {forwardRef} from "@nextui-org/system";
|
||||
import {clsx, __DEV__} from "@nextui-org/shared-utils";
|
||||
import {Divider} from "@nextui-org/divider";
|
||||
import {Image} from "@nextui-org/image";
|
||||
import {Drip} from "@nextui-org/drip";
|
||||
|
||||
import {
|
||||
StyledCard,
|
||||
StyledCardHeader as CardHeader,
|
||||
StyledCardFooter as CardFooter,
|
||||
StyledCardBody as CardBody,
|
||||
} from "./card.styles";
|
||||
import {UseCardProps, useCard} from "./use-card";
|
||||
|
||||
export interface CardProps extends Omit<UseCardProps, "ref"> {}
|
||||
|
||||
type CompoundCard = {
|
||||
Header: typeof CardHeader;
|
||||
Body: typeof CardBody;
|
||||
Footer: typeof CardFooter;
|
||||
Image: typeof Image;
|
||||
Divider: typeof Divider;
|
||||
};
|
||||
|
||||
const Card = forwardRef<CardProps, "div", CompoundCard>((props, ref) => {
|
||||
const {
|
||||
cardRef,
|
||||
children,
|
||||
className,
|
||||
variant,
|
||||
isFocusVisible,
|
||||
isPressable,
|
||||
isPressed,
|
||||
disableAnimation,
|
||||
disableRipple,
|
||||
borderWeight,
|
||||
isHovered,
|
||||
dripBindings,
|
||||
getCardProps,
|
||||
} = useCard({ref, ...props});
|
||||
|
||||
return (
|
||||
<StyledCard
|
||||
ref={cardRef}
|
||||
borderWeight={borderWeight}
|
||||
className={clsx("nextui-card", className)}
|
||||
disableAnimation={disableAnimation}
|
||||
isFocusVisible={isFocusVisible}
|
||||
isHovered={isHovered}
|
||||
isPressable={isPressable}
|
||||
isPressed={isPressed}
|
||||
role={isPressable ? "button" : "section"}
|
||||
tabIndex={isPressable ? 0 : -1}
|
||||
variant={variant}
|
||||
{...getCardProps()}
|
||||
>
|
||||
{isPressable && !disableAnimation && !disableRipple && <Drip {...dripBindings} />}
|
||||
{children}
|
||||
</StyledCard>
|
||||
);
|
||||
});
|
||||
|
||||
Card.Header = CardHeader;
|
||||
Card.Body = CardBody;
|
||||
Card.Footer = CardFooter;
|
||||
Card.Image = Image;
|
||||
Card.Divider = Divider;
|
||||
|
||||
if (__DEV__) {
|
||||
Card.displayName = "NextUI.Card";
|
||||
}
|
||||
|
||||
Card.toString = () => ".nextui-card";
|
||||
|
||||
export default Card;
|
||||
5
packages/components/card/src/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
// export types
|
||||
export type {CardProps} from "./card";
|
||||
|
||||
// export component
|
||||
export {default as Card} from "./card";
|
||||
145
packages/components/card/src/use-card.ts
Normal file
@ -0,0 +1,145 @@
|
||||
import type {PressEvents, PressEvent, FocusableProps} from "@react-types/shared";
|
||||
|
||||
import {MouseEvent, useCallback} from "react";
|
||||
import {mergeProps} from "@react-aria/utils";
|
||||
import {useFocusRing} from "@react-aria/focus";
|
||||
import {usePress, useHover} from "@react-aria/interactions";
|
||||
import {HTMLNextUIProps} from "@nextui-org/system";
|
||||
import {NormalWeights, ReactRef} from "@nextui-org/shared-utils";
|
||||
import {useDOMRef, IFocusRingAria} from "@nextui-org/dom-utils";
|
||||
import {useDrip} from "@nextui-org/drip";
|
||||
|
||||
export interface UseCardProps extends HTMLNextUIProps<"div", PressEvents & FocusableProps> {
|
||||
/**
|
||||
* The card ref.
|
||||
*/
|
||||
ref: ReactRef<HTMLDivElement | null>;
|
||||
/**
|
||||
* The card variant style.
|
||||
* @default "shadow"
|
||||
*/
|
||||
variant?: "shadow" | "flat" | "bordered";
|
||||
/**
|
||||
* The border weight of the `bordered` variant card.
|
||||
* @default "normal"
|
||||
*/
|
||||
borderWeight?: NormalWeights;
|
||||
/**
|
||||
* Whether the card should allow users to interact with the card.
|
||||
* @default false
|
||||
*/
|
||||
isPressable?: boolean;
|
||||
/**
|
||||
* Whether the card can be hovered by the user.
|
||||
* @default false
|
||||
*/
|
||||
isHoverable?: boolean;
|
||||
/**
|
||||
* Whether the card should show a ripple animation on press
|
||||
* @default false
|
||||
*/
|
||||
disableRipple?: boolean;
|
||||
// @deprecated - use `onPress` instead
|
||||
onClick?: React.MouseEventHandler<HTMLDivElement>;
|
||||
/**
|
||||
* Whether the card is animated.
|
||||
* @default false
|
||||
*/
|
||||
disableAnimation?: boolean;
|
||||
/**
|
||||
* Whether the card should allow text selection on press. (only for pressable cards)
|
||||
* @default true
|
||||
*/
|
||||
allowTextSelectionOnPress?: boolean;
|
||||
}
|
||||
|
||||
export function useCard(props: UseCardProps) {
|
||||
const {
|
||||
ref,
|
||||
children,
|
||||
disableAnimation = false,
|
||||
disableRipple = false,
|
||||
variant = "shadow",
|
||||
isHoverable = false,
|
||||
borderWeight = "light",
|
||||
isPressable = false,
|
||||
onClick: deprecatedOnClick,
|
||||
onPress,
|
||||
autoFocus,
|
||||
className,
|
||||
allowTextSelectionOnPress = true,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
const cardRef = useDOMRef<HTMLDivElement>(ref);
|
||||
|
||||
const {onClick: onDripClickHandler, ...dripBindings} = useDrip(false, cardRef);
|
||||
|
||||
const handleDrip = (e: MouseEvent<HTMLDivElement> | PressEvent | Event) => {
|
||||
if (!disableAnimation && !disableRipple && cardRef.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 {isPressed, pressProps} = usePress({
|
||||
isDisabled: !isPressable,
|
||||
onPress: handlePress,
|
||||
allowTextSelectionOnPress,
|
||||
...otherProps,
|
||||
});
|
||||
|
||||
const {hoverProps, isHovered} = useHover({
|
||||
isDisabled: !isHoverable,
|
||||
...otherProps,
|
||||
});
|
||||
|
||||
const {isFocusVisible, focusProps}: IFocusRingAria<Pick<UseCardProps, "css">> = useFocusRing({
|
||||
autoFocus,
|
||||
});
|
||||
|
||||
const getCardProps = useCallback(
|
||||
(props = {}) => {
|
||||
return {
|
||||
...mergeProps(
|
||||
isPressable ? {...pressProps, ...focusProps} : {},
|
||||
isHoverable ? hoverProps : {},
|
||||
otherProps,
|
||||
props,
|
||||
),
|
||||
};
|
||||
},
|
||||
[isPressable, isHoverable, pressProps, focusProps, hoverProps, otherProps],
|
||||
);
|
||||
|
||||
return {
|
||||
cardRef,
|
||||
variant,
|
||||
children,
|
||||
borderWeight,
|
||||
isPressable,
|
||||
isHovered,
|
||||
isPressed,
|
||||
disableAnimation,
|
||||
disableRipple,
|
||||
dripBindings,
|
||||
onDripClickHandler,
|
||||
isFocusVisible,
|
||||
className,
|
||||
getCardProps,
|
||||
};
|
||||
}
|
||||
|
||||
export type UseCardReturn = ReturnType<typeof useCard>;
|
||||
BIN
packages/components/card/stories/assets/accessories.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
packages/components/card/stories/assets/airpods.jpeg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
packages/components/card/stories/assets/airpods.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
packages/components/card/stories/assets/airtag.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
packages/components/card/stories/assets/apple-event.jpeg
Normal file
|
After Width: | Height: | Size: 668 KiB |
BIN
packages/components/card/stories/assets/apple-watch.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
packages/components/card/stories/assets/appletv.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
packages/components/card/stories/assets/bicycle.jpeg
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
packages/components/card/stories/assets/breathing-app-icon.jpeg
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
packages/components/card/stories/assets/cup.jpeg
Normal file
|
After Width: | Height: | Size: 451 KiB |
BIN
packages/components/card/stories/assets/headphones.jpg
Normal file
|
After Width: | Height: | Size: 283 KiB |
BIN
packages/components/card/stories/assets/homepod-mini.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
packages/components/card/stories/assets/homepod.jpeg
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
packages/components/card/stories/assets/ipad.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
packages/components/card/stories/assets/iphone.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
packages/components/card/stories/assets/items.jpeg
Normal file
|
After Width: | Height: | Size: 3.6 MiB |
BIN
packages/components/card/stories/assets/mac.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
packages/components/card/stories/assets/relaxing.jpeg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
packages/components/card/stories/assets/watch.jpeg
Normal file
|
After Width: | Height: | Size: 147 KiB |
668
packages/components/card/stories/card.stories.tsx
Normal file
@ -0,0 +1,668 @@
|
||||
import React from "react";
|
||||
import {styled} from "@nextui-org/system";
|
||||
import {Meta} from "@storybook/react";
|
||||
import {Text} from "@nextui-org/text";
|
||||
import {Grid} from "@nextui-org/grid";
|
||||
import {Link} from "@nextui-org/link";
|
||||
import {Col} from "@nextui-org/col";
|
||||
import {Row} from "@nextui-org/row";
|
||||
import {Code} from "@nextui-org/code";
|
||||
|
||||
import {Card} from "../src";
|
||||
|
||||
export default {
|
||||
title: "General/Card",
|
||||
component: Card,
|
||||
} as Meta;
|
||||
|
||||
export const Default = () => (
|
||||
<Card css={{w: "400px"}}>
|
||||
<Card.Body css={{py: "$lg"}}>
|
||||
<Text>A basic card</Text>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
);
|
||||
|
||||
export const Hoverable = () => (
|
||||
<Card isHoverable css={{w: "400px"}} variant="bordered">
|
||||
<Card.Body css={{py: "$lg"}}>
|
||||
<Text>A basic card</Text>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
);
|
||||
|
||||
export const Variants = () => (
|
||||
<Grid.Container gap={2}>
|
||||
<Grid xs={4}>
|
||||
<Card>
|
||||
<Card.Body>
|
||||
<Text>Default card. (shadow)</Text>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid xs={4}>
|
||||
<Card variant="flat">
|
||||
<Card.Body>
|
||||
<Text>Flat card.</Text>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid xs={4}>
|
||||
<Card variant="bordered">
|
||||
<Card.Body>
|
||||
<Text>Bordered card.</Text>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid.Container>
|
||||
);
|
||||
|
||||
export const WithFooter = () => (
|
||||
<Grid.Container gap={2}>
|
||||
<Grid xs={4}>
|
||||
<Card css={{p: "$6"}}>
|
||||
<Card.Header>
|
||||
<img
|
||||
alt="nextui logo"
|
||||
height="34px"
|
||||
src="https://avatars.githubusercontent.com/u/86160567?s=200&v=4"
|
||||
width="34px"
|
||||
/>
|
||||
<Grid.Container css={{pl: "$6"}}>
|
||||
<Grid xs={12}>
|
||||
<Text h4 css={{lineHeight: "$xs"}}>
|
||||
Next UI
|
||||
</Text>
|
||||
</Grid>
|
||||
<Grid xs={12}>
|
||||
<Text css={{color: "$accents8"}}>nextui.org</Text>
|
||||
</Grid>
|
||||
</Grid.Container>
|
||||
</Card.Header>
|
||||
<Card.Body css={{py: "$2"}}>
|
||||
<Text>Make beautiful websites regardless of your design experience.</Text>
|
||||
</Card.Body>
|
||||
<Card.Footer>
|
||||
<Link
|
||||
isExternal
|
||||
color="primary"
|
||||
href="https://github.com/nextui-org/nextui"
|
||||
target="_blank"
|
||||
>
|
||||
Visit source code on GitHub.
|
||||
</Link>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid.Container>
|
||||
);
|
||||
|
||||
export const AbsImageWithHeader = () => {
|
||||
return (
|
||||
<Grid.Container gap={1} justify="center">
|
||||
<Grid>
|
||||
<Card css={{w: "330px"}}>
|
||||
<Card.Header css={{position: "absolute", top: 5, zIndex: 1}}>
|
||||
<Col>
|
||||
<Text color="#ffffffAA" size={12} transform="uppercase" weight="bold">
|
||||
What to watch
|
||||
</Text>
|
||||
<Text h3 color="white">
|
||||
Stream the Apple event
|
||||
</Text>
|
||||
</Col>
|
||||
</Card.Header>
|
||||
<Card.Image
|
||||
alt="Apple event background"
|
||||
autoResize={false}
|
||||
height={440}
|
||||
src={require("./assets/apple-event.jpeg")}
|
||||
style={{objectFit: "cover"}}
|
||||
width="100%"
|
||||
/>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid.Container>
|
||||
);
|
||||
};
|
||||
|
||||
export const AbsImgWithHeaderFooter = () => {
|
||||
return (
|
||||
<Grid.Container gap={2} justify="center">
|
||||
<Grid>
|
||||
<Card css={{w: "330px", bg: "$gray50"}}>
|
||||
<Card.Header css={{position: "absolute", top: 5, zIndex: 1}}>
|
||||
<Col>
|
||||
<Text color="#9E9E9E" size={12} transform="uppercase" weight="bold">
|
||||
New
|
||||
</Text>
|
||||
<Text h2 color="black">
|
||||
HomePod mini
|
||||
</Text>
|
||||
<Text size={14} style={{paddingRight: "10px"}}>
|
||||
Room-filling sound, Intelligent assistant. Smart home control. Works seamlessly with
|
||||
iPhone. Check it out
|
||||
</Text>
|
||||
</Col>
|
||||
</Card.Header>
|
||||
<Card.Image
|
||||
alt="Apple homedpods background"
|
||||
autoResize={false}
|
||||
height={440}
|
||||
src={require("./assets/homepod.jpeg")}
|
||||
style={{objectFit: "cover", paddingTop: "100px"}}
|
||||
width="100%"
|
||||
/>
|
||||
<Card.Footer css={{m: 0}}>
|
||||
<Row>
|
||||
<Col>
|
||||
<Text size={12}>Available soon.</Text>
|
||||
<Text size={12}>Get notified.</Text>
|
||||
</Col>
|
||||
<Col>
|
||||
<Row justify="flex-end">
|
||||
<Text size={12} transform="uppercase" weight="bold">
|
||||
Notify Me
|
||||
</Text>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Card css={{w: "630px"}}>
|
||||
<Card.Header css={{position: "absolute", top: 5, zIndex: 1}}>
|
||||
<Col>
|
||||
<Text color="#9E9E9E" size={12} transform="uppercase" weight="bold">
|
||||
Your day your way
|
||||
</Text>
|
||||
<Text h3 color="white">
|
||||
Your checklist for better sleep
|
||||
</Text>
|
||||
</Col>
|
||||
</Card.Header>
|
||||
<Card.Image
|
||||
alt="Apple homedpods background"
|
||||
autoResize={false}
|
||||
height={440}
|
||||
src={require("./assets/relaxing.jpeg")}
|
||||
style={{objectFit: "cover"}}
|
||||
width="100%"
|
||||
/>
|
||||
<Card.Footer
|
||||
isBlurred
|
||||
css={{
|
||||
position: "absolute",
|
||||
bgBlur: "#0f111466",
|
||||
borderTop: "$borderWeights$light solid $gray500",
|
||||
bottom: 0,
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
<Row>
|
||||
<Col>
|
||||
<Row>
|
||||
<Col span={3}>
|
||||
<Card.Image
|
||||
alt="Breathing app icon"
|
||||
autoResize={false}
|
||||
height={40}
|
||||
src={require("./assets/breathing-app-icon.jpeg")}
|
||||
style={{background: "black"}}
|
||||
width={40}
|
||||
/>
|
||||
</Col>
|
||||
<Col>
|
||||
<Text color="#d1d1d1" size={12}>
|
||||
Breathing App
|
||||
</Text>
|
||||
<Text color="#d1d1d1" size={12}>
|
||||
Get a good night's sleep.
|
||||
</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
<Col>
|
||||
<Row justify="flex-end">
|
||||
<Text size={12} transform="uppercase" weight="bold">
|
||||
Get App
|
||||
</Text>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid.Container>
|
||||
);
|
||||
};
|
||||
|
||||
export const CoverImage = () => (
|
||||
<Grid.Container gap={2} justify="center">
|
||||
<Grid sm={4} xs={12}>
|
||||
<Card>
|
||||
<Card.Header css={{position: "absolute", zIndex: 1, top: 5}}>
|
||||
<Col>
|
||||
<Text color="#ffffffAA" size={12} transform="uppercase" weight="bold">
|
||||
What to watch
|
||||
</Text>
|
||||
<Text h4 color="white">
|
||||
Stream the Acme event
|
||||
</Text>
|
||||
</Col>
|
||||
</Card.Header>
|
||||
<Card.Image
|
||||
alt="Card image background"
|
||||
height={340}
|
||||
objectFit="cover"
|
||||
src="https://nextui.org/images/card-example-4.jpeg"
|
||||
width="100%"
|
||||
/>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid sm={4} xs={12}>
|
||||
<Card css={{w: "100%"}}>
|
||||
<Card.Header css={{position: "absolute", zIndex: 1, top: 5}}>
|
||||
<Col>
|
||||
<Text color="#ffffffAA" size={12} transform="uppercase" weight="bold">
|
||||
Plant a tree
|
||||
</Text>
|
||||
<Text h4 color="white">
|
||||
Contribute to the planet
|
||||
</Text>
|
||||
</Col>
|
||||
</Card.Header>
|
||||
<Card.Image
|
||||
alt="Card image background"
|
||||
height={340}
|
||||
objectFit="cover"
|
||||
src="https://nextui.org/images/card-example-3.jpeg"
|
||||
width="100%"
|
||||
/>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid sm={4} xs={12}>
|
||||
<Card css={{bg: "$black", w: "100%"}}>
|
||||
<Card.Header css={{position: "absolute", zIndex: 1, top: 5}}>
|
||||
<Col>
|
||||
<Text color="#ffffffAA" size={12} transform="uppercase" weight="bold">
|
||||
Supercharged
|
||||
</Text>
|
||||
<Text h4 color="white">
|
||||
Creates beauty like a beast
|
||||
</Text>
|
||||
</Col>
|
||||
</Card.Header>
|
||||
<Card.Image
|
||||
alt="Card image background"
|
||||
height={340}
|
||||
objectFit="cover"
|
||||
src="https://nextui.org/images/card-example-2.jpeg"
|
||||
width="100%"
|
||||
/>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid sm={5} xs={12}>
|
||||
<Card css={{w: "100%", h: "400px"}}>
|
||||
<Card.Header css={{position: "absolute", zIndex: 1, top: 5}}>
|
||||
<Col>
|
||||
<Text color="#ffffffAA" size={12} transform="uppercase" weight="bold">
|
||||
New
|
||||
</Text>
|
||||
<Text h3 color="black">
|
||||
Acme camera
|
||||
</Text>
|
||||
</Col>
|
||||
</Card.Header>
|
||||
<Card.Body css={{p: 0}}>
|
||||
<Card.Image
|
||||
alt="Card example background"
|
||||
height="100%"
|
||||
objectFit="cover"
|
||||
src="https://nextui.org/images/card-example-6.jpeg"
|
||||
width="100%"
|
||||
/>
|
||||
</Card.Body>
|
||||
<Card.Footer
|
||||
isBlurred
|
||||
css={{
|
||||
position: "absolute",
|
||||
bgBlur: "#ffffff66",
|
||||
borderTop: "$borderWeights$light solid rgba(255, 255, 255, 0.2)",
|
||||
bottom: 0,
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
<Row>
|
||||
<Col>
|
||||
<Text color="#000" size={12}>
|
||||
Available soon.
|
||||
</Text>
|
||||
<Text color="#000" size={12}>
|
||||
Get notified.
|
||||
</Text>
|
||||
</Col>
|
||||
<Col>
|
||||
<Row justify="flex-end">
|
||||
<Text css={{color: "inherit"}} size={12} transform="uppercase" weight="bold">
|
||||
Notify Me
|
||||
</Text>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid sm={7} xs={12}>
|
||||
<Card css={{w: "100%", h: "400px"}}>
|
||||
<Card.Header css={{position: "absolute", zIndex: 1, top: 5}}>
|
||||
<Col>
|
||||
<Text color="#9E9E9E" size={12} transform="uppercase" weight="bold">
|
||||
Your day your way
|
||||
</Text>
|
||||
<Text h3 color="white">
|
||||
Your checklist for better sleep
|
||||
</Text>
|
||||
</Col>
|
||||
</Card.Header>
|
||||
<Card.Body css={{p: 0}}>
|
||||
<Card.Image
|
||||
alt="Relaxing app background"
|
||||
height="100%"
|
||||
objectFit="cover"
|
||||
src="https://nextui.org/images/card-example-5.jpeg"
|
||||
width="100%"
|
||||
/>
|
||||
</Card.Body>
|
||||
<Card.Footer
|
||||
isBlurred
|
||||
css={{
|
||||
position: "absolute",
|
||||
bgBlur: "#0f111466",
|
||||
borderTop: "$borderWeights$light solid $gray700",
|
||||
bottom: 0,
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
<Row>
|
||||
<Col>
|
||||
<Row>
|
||||
<Col span={3}>
|
||||
<Card.Image
|
||||
alt="Breathing app icon"
|
||||
css={{bg: "black", br: "50%"}}
|
||||
height={40}
|
||||
src="https://nextui.org/images/breathing-app-icon.jpeg"
|
||||
width={40}
|
||||
/>
|
||||
</Col>
|
||||
<Col>
|
||||
<Text color="#d1d1d1" size={12}>
|
||||
Breathing App
|
||||
</Text>
|
||||
<Text color="#d1d1d1" size={12}>
|
||||
Get a good night's sleep.
|
||||
</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
<Col>
|
||||
<Row justify="flex-end">
|
||||
<Text css={{color: "inherit"}} size={12} transform="uppercase" weight="bold">
|
||||
Get App
|
||||
</Text>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid.Container>
|
||||
);
|
||||
|
||||
export const PrimaryAction = () => {
|
||||
const list = [
|
||||
{
|
||||
title: "Orange",
|
||||
img: "/images/fruit-1.jpeg",
|
||||
price: "$5.50",
|
||||
},
|
||||
{
|
||||
title: "Tangerine",
|
||||
img: "/images/fruit-2.jpeg",
|
||||
price: "$3.00",
|
||||
},
|
||||
{
|
||||
title: "Raspberry",
|
||||
img: "/images/fruit-3.jpeg",
|
||||
price: "$10.00",
|
||||
},
|
||||
{
|
||||
title: "Lemon",
|
||||
img: "/images/fruit-4.jpeg",
|
||||
price: "$5.30",
|
||||
},
|
||||
{
|
||||
title: "Advocato",
|
||||
img: "/images/fruit-5.jpeg",
|
||||
price: "$15.70",
|
||||
},
|
||||
{
|
||||
title: "Lemon 2",
|
||||
img: "/images/fruit-6.jpeg",
|
||||
price: "$8.00",
|
||||
},
|
||||
{
|
||||
title: "Banana",
|
||||
img: "/images/fruit-7.jpeg",
|
||||
price: "$7.50",
|
||||
},
|
||||
{
|
||||
title: "Watermelon",
|
||||
img: "/images/fruit-8.jpeg",
|
||||
price: "$12.20",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Grid.Container gap={2} justify="flex-start">
|
||||
{list.map((item, index) => (
|
||||
<Grid key={index} sm={3} xs={6}>
|
||||
<Card isPressable onPress={() => console.log("item pressed", item)}>
|
||||
<Card.Body css={{p: 0}}>
|
||||
<Card.Image
|
||||
alt={item.title}
|
||||
height={140}
|
||||
objectFit="cover"
|
||||
src={"https://nextui.org" + item.img}
|
||||
width="100%"
|
||||
/>
|
||||
</Card.Body>
|
||||
<Card.Footer css={{justifyItems: "flex-start"}}>
|
||||
<Row justify="space-between" wrap="wrap">
|
||||
<Text b>{item.title}</Text>
|
||||
<Text css={{color: "$accents7", fontWeight: "$semibold"}}>{item.price}</Text>
|
||||
</Row>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid.Container>
|
||||
);
|
||||
};
|
||||
|
||||
export const CenterImgWithHeader = () => {
|
||||
const list = [
|
||||
{
|
||||
title: "Mac",
|
||||
img: require("./assets/mac.png"),
|
||||
},
|
||||
{
|
||||
title: "iPhone",
|
||||
img: require("./assets/iphone.png"),
|
||||
},
|
||||
{
|
||||
title: "iPad",
|
||||
img: require("./assets/ipad.png"),
|
||||
},
|
||||
{
|
||||
title: "Apple Watch",
|
||||
img: require("./assets/apple-watch.png"),
|
||||
},
|
||||
{
|
||||
title: "AirPods",
|
||||
img: require("./assets/airpods.png"),
|
||||
},
|
||||
{
|
||||
title: "AirTag",
|
||||
img: require("./assets/airtag.png"),
|
||||
},
|
||||
{
|
||||
title: "Apple TV",
|
||||
img: require("./assets/appletv.png"),
|
||||
},
|
||||
{
|
||||
title: "HomePod mini",
|
||||
img: require("./assets/homepod-mini.png"),
|
||||
},
|
||||
{
|
||||
title: "Accessories",
|
||||
img: require("./assets/accessories.png"),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Grid.Container gap={2} justify="center">
|
||||
{list.map((item, index) => (
|
||||
<Grid key={index}>
|
||||
<Card isHoverable isPressable css={{w: "200px", h: "220px"}}>
|
||||
<Card.Header css={{p: 0}}>
|
||||
<Text h5 style={{paddingLeft: "24px", paddingTop: "10px"}}>
|
||||
{item.title}
|
||||
</Text>
|
||||
</Card.Header>
|
||||
<Card.Body css={{h: "100%", jc: "center"}}>
|
||||
<Card.Image alt={item.title} autoResize={false} src={item.img} width={180} />
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid.Container>
|
||||
);
|
||||
};
|
||||
|
||||
export const WithDivider = () => (
|
||||
<Card css={{w: "400px"}}>
|
||||
<Card.Header>
|
||||
<Text b>Description</Text>
|
||||
</Card.Header>
|
||||
<Card.Divider />
|
||||
<Card.Body>
|
||||
<Text>The Object constructor creates an object wrapper for the given value.</Text>
|
||||
</Card.Body>
|
||||
<Card.Divider />
|
||||
<Card.Footer>
|
||||
<Text>
|
||||
When called in a non-constructor context, Object behaves identically to{" "}
|
||||
<Code>new Object()</Code>.
|
||||
</Text>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
);
|
||||
|
||||
export const Shadows = () => {
|
||||
const Box = styled("div", {
|
||||
size: "120px",
|
||||
dflex: "center",
|
||||
bg: "$backgroundContrast",
|
||||
br: "$md",
|
||||
});
|
||||
|
||||
const shadows = ["$xs", "$sm", "$md", "$lg", "$xl"];
|
||||
|
||||
return (
|
||||
<Grid.Container gap={3} justify="center">
|
||||
<Grid justify="center" xs={12}>
|
||||
<Text b>Drop shadows</Text>
|
||||
</Grid>
|
||||
{shadows.map((shadow, index) => (
|
||||
<Grid key={`${shadow}_${index}`} sm={2} xs={6}>
|
||||
<Box css={{dropShadow: shadow}}>
|
||||
<Text>Shadow: {shadow}</Text>
|
||||
</Box>
|
||||
</Grid>
|
||||
))}
|
||||
<Grid justify="center" xs={12}>
|
||||
<Text b>Box shadows</Text>
|
||||
</Grid>
|
||||
{shadows.map((shadow, index) => (
|
||||
<Grid key={`${shadow}_${index}`} sm={2} xs={6}>
|
||||
<Box css={{boxShadow: shadow}}>
|
||||
<Text>Shadow: {shadow}</Text>
|
||||
</Box>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid.Container>
|
||||
);
|
||||
};
|
||||
|
||||
//TODO: Input & Button still missing
|
||||
// export const withForm = () => {
|
||||
// return (
|
||||
// <Card css={{mw: "400px"}}>
|
||||
// <Card.Header css={{justifyContent: "center"}}>
|
||||
// <Text size={18}>
|
||||
// Welcome to
|
||||
// <Text b size={18}>
|
||||
// NextUI
|
||||
// </Text>
|
||||
// </Text>
|
||||
// </Card.Header>
|
||||
// <Card.Body css={{px: "$10", pt: "$1", ov: "visible"}}>
|
||||
// <Input
|
||||
// bordered
|
||||
// clearable
|
||||
// fullWidth
|
||||
// color="primary"
|
||||
// contentLeft={<Mail fill="currentColor" />}
|
||||
// placeholder="Email"
|
||||
// size="lg"
|
||||
// />
|
||||
// <Spacer y={0.5} />
|
||||
// <Input
|
||||
// bordered
|
||||
// clearable
|
||||
// fullWidth
|
||||
// color="primary"
|
||||
// contentLeft={<Password />}
|
||||
// placeholder="Password"
|
||||
// size="lg"
|
||||
// />
|
||||
// <Spacer y={0.5} />
|
||||
// <Row align="center" justify="space-between">
|
||||
// <Checkbox>
|
||||
// <Text css={{color: "$accents8"}} size={14}>
|
||||
// Remember me
|
||||
// </Text>
|
||||
// </Checkbox>
|
||||
// <Link css={{color: "$link", fontSize: "$sm"}} href="#">
|
||||
// Forgot password?
|
||||
// </Link>
|
||||
// </Row>
|
||||
// </Card.Body>
|
||||
// <Card.Footer css={{pt: 0}}>
|
||||
// <Grid.Container gap={1} justify="flex-end">
|
||||
// <Grid>
|
||||
// <Button auto flat>
|
||||
// Sign Up
|
||||
// </Button>
|
||||
// </Grid>
|
||||
// <Grid>
|
||||
// <Button auto>Login</Button>
|
||||
// </Grid>
|
||||
// </Grid.Container>
|
||||
// </Card.Footer>
|
||||
// </Card>
|
||||
// );
|
||||
// };
|
||||
9
packages/components/card/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/card/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,
|
||||
});
|
||||
24
packages/components/drip/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# @nextui-org/drip
|
||||
|
||||
A Quick description of the component
|
||||
|
||||
> This is an internal utility, not intended for public usage.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
yarn add @nextui-org/drip
|
||||
# or
|
||||
npm i @nextui-org/drip
|
||||
```
|
||||
|
||||
## 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).
|
||||
19
packages/components/drip/__tests__/drip.test.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import * as React from "react";
|
||||
import {render} from "@testing-library/react";
|
||||
|
||||
import { Drip } from "../src";
|
||||
|
||||
describe("Drip", () => {
|
||||
it("should render correctly", () => {
|
||||
const wrapper = render(<Drip />);
|
||||
|
||||
expect(() => wrapper.unmount()).not.toThrow();
|
||||
});
|
||||
|
||||
it("ref should be forwarded", () => {
|
||||
const ref = React.createRef<HTMLDivElement>();
|
||||
|
||||
render(<Drip ref={ref} />);
|
||||
expect(ref.current).not.toBeNull();
|
||||
});
|
||||
});
|
||||
3
packages/components/drip/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" } } }
|
||||
48
packages/components/drip/package.json
Normal file
@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "@nextui-org/drip",
|
||||
"version": "1.0.0-beta.11",
|
||||
"description": "A ripple effect for ensuring that the user fells the system is reacting instantaneously",
|
||||
"keywords": [
|
||||
"drip"
|
||||
],
|
||||
"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/drip"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextui-org/nextui/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup src/index.ts --format=esm,cjs --dts",
|
||||
"dev": "yarn build:fast -- --watch",
|
||||
"clean": "rimraf dist .turbo",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"build:fast": "tsup src/index.ts --format=esm,cjs",
|
||||
"prepack": "clean-package",
|
||||
"postpack": "clean-package restore"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nextui-org/system": "workspace:*",
|
||||
"@nextui-org/shared-utils": "workspace:*",
|
||||
"@nextui-org/dom-utils": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"clean-package": "2.1.1",
|
||||
"react": "^17.0.2"
|
||||
}
|
||||
}
|
||||
18
packages/components/drip/src/drip.animations.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import {keyframes} from "@nextui-org/system";
|
||||
|
||||
export const expand = keyframes({
|
||||
"0%": {
|
||||
opacity: 0,
|
||||
transform: "scale(0.25)",
|
||||
},
|
||||
"30%": {
|
||||
opacity: 1,
|
||||
},
|
||||
"80%": {
|
||||
opacity: 0.5,
|
||||
},
|
||||
"100%": {
|
||||
transform: "scale(28)",
|
||||
opacity: 0,
|
||||
},
|
||||
});
|
||||
18
packages/components/drip/src/drip.styles.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import {styled} from "@nextui-org/system";
|
||||
|
||||
import {expand} from "./drip.animations";
|
||||
|
||||
export const StyledDrip = styled("div", {
|
||||
position: "absolute",
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
"& svg": {
|
||||
position: "absolute",
|
||||
animation: `350ms linear ${expand}`,
|
||||
animationFillMode: "forwards",
|
||||
width: "$md",
|
||||
height: "$md",
|
||||
},
|
||||
});
|
||||
57
packages/components/drip/src/drip.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import {useEffect} from "react";
|
||||
import {NextUI, forwardRef, HTMLNextUIProps} from "@nextui-org/system";
|
||||
import {useDOMRef} from "@nextui-org/dom-utils";
|
||||
import {clsx, __DEV__} from "@nextui-org/shared-utils";
|
||||
|
||||
import {StyledDrip} from "./drip.styles";
|
||||
|
||||
export interface DripProps extends HTMLNextUIProps<"div"> {
|
||||
isVisible?: boolean;
|
||||
x: number;
|
||||
y: number;
|
||||
color?: string;
|
||||
onCompleted: () => void;
|
||||
}
|
||||
|
||||
const Drip = forwardRef<DripProps, "div">((props, ref) => {
|
||||
const {isVisible, x, y, color, onCompleted, className, ...otherProps} = props;
|
||||
|
||||
const domRef = useDOMRef(ref);
|
||||
|
||||
const top = Number.isNaN(+y) ? 0 : y - 10;
|
||||
const left = Number.isNaN(+x) ? 0 : x - 10;
|
||||
|
||||
useEffect(() => {
|
||||
let drip = domRef.current;
|
||||
|
||||
if (!drip) return;
|
||||
drip.addEventListener("animationend", onCompleted);
|
||||
|
||||
return () => {
|
||||
if (!drip) return;
|
||||
drip.removeEventListener("animationend", onCompleted);
|
||||
};
|
||||
});
|
||||
|
||||
if (!isVisible) return null;
|
||||
|
||||
return (
|
||||
<StyledDrip ref={domRef} className={clsx("nextui-drip", className)} {...otherProps}>
|
||||
<NextUI.Svg css={{top, left}} height="20" viewBox="0 0 20 20" width="20">
|
||||
<g fill="none" fillRule="evenodd" stroke="none" strokeWidth="1">
|
||||
<g className="nextui-drip-filler" fill={color}>
|
||||
<rect height="100%" rx="10" width="100%" />
|
||||
</g>
|
||||
</g>
|
||||
</NextUI.Svg>
|
||||
</StyledDrip>
|
||||
);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
Drip.displayName = "NextUI.Drip";
|
||||
}
|
||||
|
||||
Drip.toString = () => ".nextui-drip";
|
||||
|
||||
export default Drip;
|
||||
8
packages/components/drip/src/index.ts
Normal file
@ -0,0 +1,8 @@
|
||||
// export hook
|
||||
export {useDrip} from "./use-drip";
|
||||
|
||||
// export types
|
||||
export type {DripProps} from "./drip";
|
||||
|
||||
// export component
|
||||
export {default as Drip} from "./drip";
|
||||
37
packages/components/drip/src/use-drip.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import {PressEvent} from "@react-types/shared";
|
||||
import {MouseEvent, RefObject, useState} from "react";
|
||||
|
||||
export function useDrip(initialValue = false, ref: RefObject<HTMLElement>) {
|
||||
const [isVisible, setIsVisible] = useState(initialValue);
|
||||
const [dripX, setDripX] = useState(0);
|
||||
const [dripY, setDripY] = useState(0);
|
||||
|
||||
const onCompleted = () => {
|
||||
setIsVisible(false);
|
||||
setDripX(0);
|
||||
setDripY(0);
|
||||
};
|
||||
|
||||
const onClick = (event: MouseEvent<HTMLElement> | PressEvent | Event) => {
|
||||
if (!ref?.current) return;
|
||||
const rect = ref.current.getBoundingClientRect?.();
|
||||
|
||||
if (!rect) return;
|
||||
|
||||
setIsVisible(true);
|
||||
if (typeof event === "object" && "clientX" in event) {
|
||||
setDripX(event.clientX - rect.left);
|
||||
setDripY(event.clientY - rect.top);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
isVisible,
|
||||
x: dripX,
|
||||
y: dripY,
|
||||
onClick,
|
||||
onCompleted,
|
||||
};
|
||||
}
|
||||
|
||||
export type UseDripReturn = ReturnType<typeof useDrip>;
|
||||
12
packages/components/drip/stories/drip.stories.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
import {Meta} from "@storybook/react";
|
||||
|
||||
import { Drip } from "../src";
|
||||
|
||||
export default {
|
||||
title: "Drip",
|
||||
component: Drip,
|
||||
} as Meta;
|
||||
|
||||
|
||||
export const Default = () => <Drip />;
|
||||
9
packages/components/drip/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/drip/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,
|
||||
});
|
||||
24
packages/components/image/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# @nextui-org/image
|
||||
|
||||
A Quick description of the component
|
||||
|
||||
> This is an internal utility, not intended for public usage.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
yarn add @nextui-org/image
|
||||
# or
|
||||
npm i @nextui-org/image
|
||||
```
|
||||
|
||||
## 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).
|
||||
51
packages/components/image/__tests__/image.test.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import * as React from "react";
|
||||
import {act, render, waitFor} from "@testing-library/react";
|
||||
|
||||
import {Image} from "../src";
|
||||
|
||||
const url =
|
||||
"data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAUA" +
|
||||
"AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO" +
|
||||
"9TXL0Y4OHwAAAABJRU5ErkJggg==";
|
||||
|
||||
describe("Image", () => {
|
||||
it("should render correctly", () => {
|
||||
const wrapper = render(<Image src={url} />);
|
||||
|
||||
expect(() => wrapper.unmount()).not.toThrow();
|
||||
});
|
||||
|
||||
it("ref should be forwarded", () => {
|
||||
const ref = React.createRef<HTMLImageElement>();
|
||||
|
||||
render(<Image ref={ref} src={url} />);
|
||||
expect(ref.current).not.toBeNull();
|
||||
});
|
||||
|
||||
it("should work correctly with skeleton", async () => {
|
||||
const {container} = render(<Image showSkeleton src={url} />);
|
||||
|
||||
expect(container.querySelector(".nextui-image-skeleton")).not.toBeNull();
|
||||
});
|
||||
|
||||
it("should remove skeleton when timeout", async () => {
|
||||
Object.defineProperty((global as any).Image.prototype, "complete", {
|
||||
get() {
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
const {container} = render(<Image maxDelay={100} src={url} />);
|
||||
|
||||
const img = container.querySelector("img");
|
||||
|
||||
// simulate img load
|
||||
act(() => {
|
||||
img?.dispatchEvent(new Event("load"));
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(container.querySelector(".nextui-image-skeleton")).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
3
packages/components/image/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" } } }
|
||||
52
packages/components/image/package.json
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "@nextui-org/image",
|
||||
"version": "1.0.0-beta.11",
|
||||
"description": "The Image component is used to display images with support for fallback.",
|
||||
"keywords": [
|
||||
"image"
|
||||
],
|
||||
"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/image"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextui-org/nextui/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup src/index.ts --format=esm,cjs --dts",
|
||||
"dev": "yarn build:fast -- --watch",
|
||||
"clean": "rimraf dist .turbo",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"build:fast": "tsup src/index.ts --format=esm,cjs",
|
||||
"prepack": "clean-package",
|
||||
"postpack": "clean-package restore"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nextui-org/system": "workspace:*",
|
||||
"@nextui-org/shared-utils": "workspace:*",
|
||||
"@nextui-org/dom-utils": "workspace:*",
|
||||
"@nextui-org/use-ref-state": "workspace:*",
|
||||
"@nextui-org/use-real-shape": "workspace:*",
|
||||
"@nextui-org/use-resize": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nextui-org/grid": "workspace:*",
|
||||
"clean-package": "2.1.1",
|
||||
"react": "^17.0.2"
|
||||
}
|
||||
}
|
||||
39
packages/components/image/src/image-skeleton.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import {forwardRef, HTMLNextUIProps} from "@nextui-org/system";
|
||||
import {useDOMRef} from "@nextui-org/dom-utils";
|
||||
import {clsx, __DEV__} from "@nextui-org/shared-utils";
|
||||
|
||||
import {StyledImageSkeleton} from "./image.styles";
|
||||
|
||||
export interface ImageSkeletonProps extends HTMLNextUIProps<"div"> {
|
||||
/**
|
||||
* The skeleton opacity - between 0 and 1.
|
||||
* @default 0.5
|
||||
*/
|
||||
opacity?: number;
|
||||
}
|
||||
|
||||
const ImageSkeleton = forwardRef<ImageSkeletonProps, "div">((props, ref) => {
|
||||
const {opacity, css, className, ...otherProps} = props;
|
||||
|
||||
const domRef = useDOMRef(ref);
|
||||
|
||||
return (
|
||||
<StyledImageSkeleton
|
||||
ref={domRef}
|
||||
className={clsx("nextui-image-skeleton", className)}
|
||||
css={{
|
||||
opacity,
|
||||
...css,
|
||||
}}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
ImageSkeleton.displayName = "NextUI.ImageSkeleton";
|
||||
}
|
||||
|
||||
ImageSkeleton.toString = () => ".nextui-image-skeleton";
|
||||
|
||||
export default ImageSkeleton;
|
||||
10
packages/components/image/src/image.animations.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import {keyframes} from "@nextui-org/system";
|
||||
|
||||
export const loading = keyframes({
|
||||
"0%": {
|
||||
backgroundPosition: "200% 0",
|
||||
},
|
||||
to: {
|
||||
backgroundPosition: "-200% 0",
|
||||
},
|
||||
});
|
||||
45
packages/components/image/src/image.styles.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import {styled} from "@nextui-org/system";
|
||||
|
||||
import {loading} from "./image.animations";
|
||||
|
||||
export const StyledImage = styled("img", {
|
||||
size: "100%",
|
||||
display: "block",
|
||||
});
|
||||
|
||||
export const StyledImageContainer = styled("div", {
|
||||
opacity: 0,
|
||||
margin: "0 auto",
|
||||
position: "relative",
|
||||
overflow: "hidden",
|
||||
maxWidth: "100%",
|
||||
transition: "transform 250ms ease 0ms, opacity 200ms ease-in 0ms",
|
||||
"@motion": {
|
||||
transition: "none",
|
||||
},
|
||||
variants: {
|
||||
isLoaded: {
|
||||
true: {
|
||||
opacity: 1,
|
||||
},
|
||||
false: {
|
||||
opacity: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const StyledImageSkeleton = styled("div", {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
size: "100%",
|
||||
borderRadius: "inherit",
|
||||
backgroundImage:
|
||||
"linear-gradient(270deg, $colors$accents1, $colors$accents2, $colors$accents2, $colors$accents1)",
|
||||
backgroundSize: "400% 100%",
|
||||
animation: `${loading} 5s ease-in-out infinite`,
|
||||
transition: "opacity 300ms ease-out",
|
||||
});
|
||||
69
packages/components/image/src/image.tsx
Normal file
@ -0,0 +1,69 @@
|
||||
import {forwardRef} from "@nextui-org/system";
|
||||
import {clsx, __DEV__} from "@nextui-org/shared-utils";
|
||||
|
||||
import ImageSkeleton from "./image-skeleton";
|
||||
import {StyledImage, StyledImageContainer} from "./image.styles";
|
||||
import {UseImageProps, useImage} from "./use-image";
|
||||
|
||||
export interface ImageProps extends Omit<UseImageProps, "ref"> {}
|
||||
|
||||
const Image = forwardRef<ImageProps, "img">((props, ref) => {
|
||||
const {
|
||||
w,
|
||||
css,
|
||||
src,
|
||||
width,
|
||||
height,
|
||||
imageRef,
|
||||
objectFit,
|
||||
isLoading,
|
||||
showSkeleton,
|
||||
zoomHeight,
|
||||
state,
|
||||
className,
|
||||
containerCss,
|
||||
onLoad,
|
||||
...otherProps
|
||||
} = useImage({
|
||||
ref,
|
||||
...props,
|
||||
});
|
||||
|
||||
return (
|
||||
<StyledImageContainer
|
||||
className={clsx("nextui-image-container", className)}
|
||||
css={{
|
||||
width: w,
|
||||
height: zoomHeight,
|
||||
...containerCss,
|
||||
}}
|
||||
data-state={state}
|
||||
isLoaded={!isLoading || showSkeleton}
|
||||
>
|
||||
{showSkeleton && <ImageSkeleton opacity={1} />}
|
||||
<StyledImage
|
||||
ref={imageRef}
|
||||
alt={props.alt || ""}
|
||||
className="nextui-image"
|
||||
css={{
|
||||
objectFit,
|
||||
...css,
|
||||
}}
|
||||
data-state={state}
|
||||
height={height}
|
||||
src={src}
|
||||
width={width}
|
||||
onLoad={onLoad}
|
||||
{...otherProps}
|
||||
/>
|
||||
</StyledImageContainer>
|
||||
);
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
Image.displayName = "NextUI.Image";
|
||||
}
|
||||
|
||||
Image.toString = () => ".nextui-image";
|
||||
|
||||
export default Image;
|
||||
5
packages/components/image/src/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
// export types
|
||||
export type {ImageProps} from "./image";
|
||||
|
||||
// export component
|
||||
export {default as Image} from "./image";
|
||||
153
packages/components/image/src/use-image.ts
Normal file
@ -0,0 +1,153 @@
|
||||
import {useState, useEffect, useMemo} from "react";
|
||||
import {HTMLNextUIProps, CSS} from "@nextui-org/system";
|
||||
import {useDOMRef} from "@nextui-org/dom-utils";
|
||||
import {useRefState} from "@nextui-org/use-ref-state";
|
||||
import {useRealShape} from "@nextui-org/use-real-shape";
|
||||
import {useResize} from "@nextui-org/use-resize";
|
||||
|
||||
export interface UseImageProps extends Omit<HTMLNextUIProps<"img">, "height" | "width"> {
|
||||
/**
|
||||
* The image ref.
|
||||
*/
|
||||
ref?: React.Ref<HTMLImageElement>;
|
||||
/**
|
||||
* The image source (local or remote)
|
||||
*/
|
||||
src: string;
|
||||
/**
|
||||
* Resize Image to fits screen width
|
||||
* @default false
|
||||
*/
|
||||
autoResize?: boolean;
|
||||
/**
|
||||
* Shows loading Skeleton while image is loading
|
||||
* @default true
|
||||
*/
|
||||
showSkeleton?: boolean;
|
||||
/**
|
||||
* Specifies Image width
|
||||
*/
|
||||
width?: number | string;
|
||||
/**
|
||||
* Specifies Image height
|
||||
*/
|
||||
height?: number | string;
|
||||
/**
|
||||
* Specifies how long Image Skeleton Renders Animation
|
||||
* @default 3000
|
||||
*/
|
||||
maxDelay?: number;
|
||||
/**
|
||||
* Property tells the content to fill the container
|
||||
*/
|
||||
objectFit?: CSS["objectFit"];
|
||||
/**
|
||||
* Override default Image xontainer styles
|
||||
*/
|
||||
containerCss?: CSS;
|
||||
|
||||
/**
|
||||
* Function to be called when the image is loaded
|
||||
*/
|
||||
onLoad?: () => void;
|
||||
}
|
||||
|
||||
export function useImage(props: UseImageProps) {
|
||||
const {
|
||||
ref,
|
||||
width,
|
||||
height,
|
||||
showSkeleton: showSkeletonProp = true,
|
||||
maxDelay = 3000,
|
||||
autoResize = false,
|
||||
objectFit = "scale-down",
|
||||
onLoad: onLoadProp,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
const imageRef = useDOMRef(ref);
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [showSkeleton, setShowSkeleton] = useState(showSkeletonProp);
|
||||
|
||||
const {w, h} = useMemo(() => {
|
||||
return {
|
||||
w: width ? (typeof width === "number" ? `${width}px` : width) : "auto",
|
||||
h: height ? (typeof height === "number" ? `${height}px` : height) : "auto",
|
||||
};
|
||||
}, [width, height]);
|
||||
|
||||
const [zoomHeight, setZoomHeight, zoomHeightRef] = useRefState<string>(h);
|
||||
const [shape, updateShape] = useRealShape(imageRef);
|
||||
|
||||
const showAnimation = showSkeletonProp && !!width && !!height;
|
||||
|
||||
const onLoad = () => {
|
||||
setIsLoading(false);
|
||||
onLoadProp?.();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!imageRef.current) return;
|
||||
if (imageRef.current.complete) {
|
||||
setIsLoading(false);
|
||||
setShowSkeleton(false);
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
if (showAnimation) {
|
||||
setShowSkeleton(false);
|
||||
}
|
||||
clearTimeout(timer);
|
||||
}, maxDelay);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [isLoading]);
|
||||
|
||||
/**
|
||||
* On mobile devices, the render witdth may be less than CSS width value.
|
||||
* If the image is scaled, set the height manually.
|
||||
* This is to ensure the aspect ratio of the image.
|
||||
*
|
||||
* If the image is auto width, ignore all.
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (!autoResize) return;
|
||||
const notLoaded = shape.width === 0;
|
||||
const isAutoZoom = zoomHeightRef.current === "auto";
|
||||
|
||||
if (notLoaded || !width || !height) return;
|
||||
if (shape.width < width) {
|
||||
!isAutoZoom && setZoomHeight("auto");
|
||||
} else {
|
||||
isAutoZoom && setZoomHeight(h);
|
||||
}
|
||||
}, [shape, width]);
|
||||
|
||||
useResize(() => {
|
||||
if (!autoResize) return;
|
||||
updateShape();
|
||||
});
|
||||
|
||||
const state = useMemo(() => {
|
||||
return isLoading ? "loading" : "loaded";
|
||||
}, [isLoading]);
|
||||
|
||||
return {
|
||||
w,
|
||||
state,
|
||||
width,
|
||||
height,
|
||||
imageRef,
|
||||
objectFit,
|
||||
zoomHeight,
|
||||
isLoading,
|
||||
showSkeleton,
|
||||
onLoad,
|
||||
...otherProps,
|
||||
};
|
||||
}
|
||||
|
||||
export type UseImageReturn = ReturnType<typeof useImage>;
|
||||
68
packages/components/image/stories/image.stories.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
import React from "react";
|
||||
import {Meta} from "@storybook/react";
|
||||
import {Grid} from "@nextui-org/grid";
|
||||
|
||||
import {Image} from "../src";
|
||||
|
||||
export default {
|
||||
title: "Display/Image",
|
||||
component: Image,
|
||||
} as Meta;
|
||||
|
||||
export const Default = () => (
|
||||
<Image
|
||||
alt="Default Image"
|
||||
height={180}
|
||||
objectFit="cover"
|
||||
src="https://github.com/nextui-org/nextui/blob/next/apps/docs/public/nextui-banner.jpeg?raw=true"
|
||||
width={320}
|
||||
/>
|
||||
);
|
||||
|
||||
export const Sizes = () => (
|
||||
<Grid.Container gap={2}>
|
||||
<Grid>
|
||||
<Image alt="Default Image" height={50} src="http://placehold.jp/50x50.png" width={50} />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Image alt="Default Image" height={100} src="http://placehold.jp/100x100.png" width={100} />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Image alt="Default Image" height={150} src="http://placehold.jp/150x150.png" width={150} />
|
||||
</Grid>
|
||||
</Grid.Container>
|
||||
);
|
||||
|
||||
export const Skeleton = () => (
|
||||
<Image
|
||||
showSkeleton
|
||||
alt="Default Image"
|
||||
height={180}
|
||||
maxDelay={5000}
|
||||
src="http://www.deelay.me/5000/https://github.com/nextui-org/nextui/blob/next/apps/docs/public/nextui-banner.jpeg?raw=true"
|
||||
width={320}
|
||||
/>
|
||||
);
|
||||
|
||||
export const ObjectFit = () => (
|
||||
<Grid.Container gap={2}>
|
||||
<Grid>
|
||||
<Image
|
||||
alt="Default Image"
|
||||
height={180}
|
||||
objectFit="contain"
|
||||
src="https://github.com/nextui-org/nextui/blob/next/apps/docs/public/nextui-banner.jpeg?raw=true"
|
||||
width={320}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Image
|
||||
alt="Default Image"
|
||||
height={180}
|
||||
objectFit="cover"
|
||||
src="https://github.com/nextui-org/nextui/blob/next/apps/docs/public/nextui-banner.jpeg?raw=true"
|
||||
width={320}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid.Container>
|
||||
);
|
||||
9
packages/components/image/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/image/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,
|
||||
});
|
||||
24
packages/hooks/use-real-shape/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# @nextui-org/use-real-shape
|
||||
|
||||
A Quick description of the component
|
||||
|
||||
> This is an internal utility, not intended for public usage.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
yarn add @nextui-org/use-real-shape
|
||||
# or
|
||||
npm i @nextui-org/use-real-shape
|
||||
```
|
||||
|
||||
## 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).
|
||||
3
packages/hooks/use-real-shape/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" } } }
|
||||
46
packages/hooks/use-real-shape/package.json
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "@nextui-org/use-real-shape",
|
||||
"version": "1.0.0-beta.11",
|
||||
"description": "Hook that returns the real dimensions of an element",
|
||||
"keywords": [
|
||||
"use-real-shape"
|
||||
],
|
||||
"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/hooks/use-real-shape"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nextui-org/dom-utils": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"clean-package": "2.1.1",
|
||||
"react": "^17.0.2"
|
||||
}
|
||||
}
|
||||
24
packages/hooks/use-real-shape/src/index.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import {RefObject, useState, useEffect} from "react";
|
||||
import {ShapeType, getRealShape} from "@nextui-org/dom-utils";
|
||||
|
||||
export type ShapeResult = [ShapeType, () => void];
|
||||
|
||||
export function useRealShape<T extends HTMLElement>(ref: RefObject<T | null>) {
|
||||
const [shape, setState] = useState<ShapeType>({
|
||||
width: 0,
|
||||
height: 0,
|
||||
});
|
||||
const updateShape = () => {
|
||||
if (!ref?.current) return;
|
||||
|
||||
const {width, height} = getRealShape(ref.current);
|
||||
|
||||
setState({width, height});
|
||||
};
|
||||
|
||||
useEffect(() => updateShape(), [ref.current]);
|
||||
|
||||
return [shape, updateShape] as ShapeResult;
|
||||
}
|
||||
|
||||
export type UseRealShapeReturn = ReturnType<typeof useRealShape>;
|
||||
4
packages/hooks/use-real-shape/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"include": ["src", "index.ts"]
|
||||
}
|
||||
13
packages/hooks/use-real-shape/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,
|
||||
});
|
||||
24
packages/hooks/use-ref-state/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# @nextui-org/use-ref-state
|
||||
|
||||
A Quick description of the component
|
||||
|
||||
> This is an internal utility, not intended for public usage.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
yarn add @nextui-org/use-ref-state
|
||||
# or
|
||||
npm i @nextui-org/use-ref-state
|
||||
```
|
||||
|
||||
## 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).
|
||||
@ -0,0 +1,61 @@
|
||||
import * as React from "react";
|
||||
import {renderHook, act} from "@testing-library/react-hooks";
|
||||
import {render} from "@testing-library/react";
|
||||
|
||||
import {useRefState} from "../src";
|
||||
|
||||
describe("useRefState", () => {
|
||||
it("should work correctly", () => {
|
||||
const {result} = renderHook(() => useRefState(""));
|
||||
|
||||
expect(result.current[0]).toEqual("");
|
||||
|
||||
act(() => result.current[1]("test"));
|
||||
|
||||
expect(result.current[0]).toEqual("test");
|
||||
expect(result.current[2].current).toEqual("test");
|
||||
});
|
||||
|
||||
it("functional initial mode should be supported", () => {
|
||||
const {result} = renderHook(() => useRefState(() => "test"));
|
||||
|
||||
expect(result.current[0]).toEqual("test");
|
||||
expect(result.current[2].current).toEqual("test");
|
||||
});
|
||||
|
||||
it("functional update mode should be supported", () => {
|
||||
const {result} = renderHook(() => useRefState(""));
|
||||
|
||||
expect(result.current[0]).toEqual("");
|
||||
|
||||
act(() => result.current[1]((value) => value + "test"));
|
||||
|
||||
expect(result.current[0]).toEqual("test");
|
||||
expect(result.current[2].current).toEqual("test");
|
||||
});
|
||||
|
||||
it("only the ref should track latest value", () => {
|
||||
const Mock: React.FC<unknown> = () => {
|
||||
const [state, setState, stateRef] = useRefState("");
|
||||
|
||||
React.useEffect(() => {
|
||||
return () => {
|
||||
setTimeout(() => {
|
||||
expect(state).not.toEqual("test2");
|
||||
expect(stateRef.current).toEqual("test2");
|
||||
}, 0);
|
||||
};
|
||||
}, []);
|
||||
React.useEffect(() => {
|
||||
setState("test");
|
||||
setState("test2");
|
||||
}, []);
|
||||
|
||||
return <span />;
|
||||
};
|
||||
|
||||
const wrapper = render(<Mock />);
|
||||
|
||||
expect(() => wrapper.unmount()).not.toThrow();
|
||||
});
|
||||
});
|
||||
3
packages/hooks/use-ref-state/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" } } }
|
||||
43
packages/hooks/use-ref-state/package.json
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "@nextui-org/use-ref-state",
|
||||
"version": "1.0.0-beta.11",
|
||||
"description": "Hook for saving the state in a ref value",
|
||||
"keywords": [
|
||||
"use-ref-state"
|
||||
],
|
||||
"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/hooks/use-ref-state"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"devDependencies": {
|
||||
"clean-package": "2.1.1",
|
||||
"react": "^17.0.2"
|
||||
}
|
||||
}
|
||||
28
packages/hooks/use-ref-state/src/index.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import {Dispatch, MutableRefObject, SetStateAction, useEffect, useRef, useState} from "react";
|
||||
|
||||
export type CurrentStateType<S> = [S, Dispatch<SetStateAction<S>>, MutableRefObject<S>];
|
||||
|
||||
export interface UseUseRefStateProps {}
|
||||
|
||||
export function useRefState<S>(initialState: S | (() => S)) {
|
||||
const [state, setState] = useState<S>(() => {
|
||||
return typeof initialState === "function" ? (initialState as () => S)() : initialState;
|
||||
});
|
||||
|
||||
const ref = useRef<S>(initialState as S);
|
||||
|
||||
useEffect(() => {
|
||||
ref.current = state;
|
||||
}, [state]);
|
||||
|
||||
const setValue = (val: SetStateAction<S>) => {
|
||||
const result = typeof val === "function" ? (val as (prevState: S) => S)(ref.current) : val;
|
||||
|
||||
ref.current = result;
|
||||
setState(result);
|
||||
};
|
||||
|
||||
return [state, setValue, ref] as CurrentStateType<S>;
|
||||
}
|
||||
|
||||
export type UseRefStateReturn = ReturnType<typeof useRefState>;
|
||||
4
packages/hooks/use-ref-state/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"include": ["src", "index.ts"]
|
||||
}
|
||||
13
packages/hooks/use-ref-state/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,
|
||||
});
|
||||
24
packages/hooks/use-resize/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# @nextui-org/use-resize
|
||||
|
||||
A Quick description of the component
|
||||
|
||||
> This is an internal utility, not intended for public usage.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
yarn add @nextui-org/use-resize
|
||||
# or
|
||||
npm i @nextui-org/use-resize
|
||||
```
|
||||
|
||||
## 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).
|
||||
3
packages/hooks/use-resize/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" } } }
|
||||
43
packages/hooks/use-resize/package.json
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "@nextui-org/use-resize",
|
||||
"version": "1.0.0-beta.11",
|
||||
"description": "Hook that adds an event listener to the resize window event",
|
||||
"keywords": [
|
||||
"use-resize"
|
||||
],
|
||||
"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/hooks/use-resize"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"devDependencies": {
|
||||
"clean-package": "2.1.1",
|
||||
"react": "^17.0.2"
|
||||
}
|
||||
}
|
||||
14
packages/hooks/use-resize/src/index.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import {useEffect} from "react";
|
||||
|
||||
export function useResize(callback: Function, immediatelyInvoke: boolean = true) {
|
||||
useEffect(() => {
|
||||
const fn = () => callback();
|
||||
|
||||
if (immediatelyInvoke) {
|
||||
fn();
|
||||
}
|
||||
window.addEventListener("resize", fn);
|
||||
|
||||
return () => window.removeEventListener("resize", fn);
|
||||
}, []);
|
||||
}
|
||||
4
packages/hooks/use-resize/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"include": ["src", "index.ts"]
|
||||
}
|
||||
13
packages/hooks/use-resize/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,
|
||||
});
|
||||
29
packages/utilities/dom-utils/src/dimensions.ts
Normal file
@ -0,0 +1,29 @@
|
||||
export type ShapeType = {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
|
||||
export const getCSSStyleVal = (str: string, parentNum: number) => {
|
||||
if (!str) return 0;
|
||||
const strVal = str.includes("px")
|
||||
? +str.split("px")[0]
|
||||
: str.includes("%")
|
||||
? +str.split("%")[0] * parentNum * 0.01
|
||||
: str;
|
||||
|
||||
return Number.isNaN(+strVal) ? 0 : +strVal;
|
||||
};
|
||||
|
||||
export const getRealShape = (el: HTMLElement | null): ShapeType => {
|
||||
const defaultShape: ShapeType = {width: 0, height: 0};
|
||||
|
||||
if (!el || typeof window === "undefined") return defaultShape;
|
||||
|
||||
const rect = el.getBoundingClientRect();
|
||||
const {width, height} = window.getComputedStyle(el);
|
||||
|
||||
return {
|
||||
width: getCSSStyleVal(`${width}`, rect.width),
|
||||
height: getCSSStyleVal(`${height}`, rect.height),
|
||||
};
|
||||
};
|
||||
@ -1,2 +1,3 @@
|
||||
export * from "./dom";
|
||||
export * from "./aria";
|
||||
export * from "./dimensions";
|
||||
|
||||
@ -2,7 +2,7 @@ import * as React from "react";
|
||||
|
||||
import {isFunction} from "./assertion";
|
||||
|
||||
export type ReactRef<T> = React.Ref<T> | React.RefObject<T> | React.MutableRefObject<T>;
|
||||
export type ReactRef<T> = React.RefObject<T> | React.MutableRefObject<T> | React.Ref<T>;
|
||||
|
||||
/**
|
||||
* Assigns a value to a ref function or object
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {renderHook} from "@testing-library/react";
|
||||
import {renderHook} from "@testing-library/react-hooks";
|
||||
|
||||
import { {{camelCase hookName}} } from "../src";
|
||||
|
||||
|
||||
@ -7,5 +7,5 @@ export function {{camelCase hookName}}(props: Use{{capitalize hookName}}Props =
|
||||
return {...otherProps};
|
||||
}
|
||||
|
||||
export type Use{{capitalize hookName}}Return = ReturnType<typeof {{camelCase hookName}}>;
|
||||
export type {{capitalize hookName}}Return = ReturnType<typeof {{camelCase hookName}}>;
|
||||
|
||||
108
pnpm-lock.yaml
generated
@ -342,6 +342,49 @@ importers:
|
||||
clean-package: 2.1.1
|
||||
react: 17.0.2
|
||||
|
||||
packages/components/card:
|
||||
specifiers:
|
||||
'@nextui-org/code': workspace:*
|
||||
'@nextui-org/col': workspace:*
|
||||
'@nextui-org/divider': workspace:*
|
||||
'@nextui-org/dom-utils': workspace:*
|
||||
'@nextui-org/drip': workspace:*
|
||||
'@nextui-org/grid': workspace:*
|
||||
'@nextui-org/image': workspace:*
|
||||
'@nextui-org/link': workspace:*
|
||||
'@nextui-org/row': workspace:*
|
||||
'@nextui-org/shared-css': workspace:*
|
||||
'@nextui-org/shared-utils': workspace:*
|
||||
'@nextui-org/system': workspace:*
|
||||
'@nextui-org/text': workspace:*
|
||||
'@react-aria/focus': ^3.9.0
|
||||
'@react-aria/interactions': ^3.12.0
|
||||
'@react-aria/utils': ^3.14.0
|
||||
'@react-types/shared': ^3.14.1
|
||||
clean-package: 2.1.1
|
||||
react: ^17.0.2
|
||||
dependencies:
|
||||
'@nextui-org/divider': link:../divider
|
||||
'@nextui-org/dom-utils': link:../../utilities/dom-utils
|
||||
'@nextui-org/drip': link:../drip
|
||||
'@nextui-org/image': link:../image
|
||||
'@nextui-org/shared-css': link:../../utilities/shared-css
|
||||
'@nextui-org/shared-utils': link:../../utilities/shared-utils
|
||||
'@nextui-org/system': link:../../core/system
|
||||
'@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/code': link:../code
|
||||
'@nextui-org/col': link:../col
|
||||
'@nextui-org/grid': link:../grid
|
||||
'@nextui-org/link': link:../link
|
||||
'@nextui-org/row': link:../row
|
||||
'@nextui-org/text': link:../text
|
||||
'@react-types/shared': 3.15.0_react@17.0.2
|
||||
clean-package: 2.1.1
|
||||
react: 17.0.2
|
||||
|
||||
packages/components/checkbox:
|
||||
specifiers:
|
||||
'@nextui-org/dom-utils': workspace:*
|
||||
@ -438,6 +481,21 @@ importers:
|
||||
clean-package: 2.1.1
|
||||
react: 17.0.2
|
||||
|
||||
packages/components/drip:
|
||||
specifiers:
|
||||
'@nextui-org/dom-utils': workspace:*
|
||||
'@nextui-org/shared-utils': workspace:*
|
||||
'@nextui-org/system': workspace:*
|
||||
clean-package: 2.1.1
|
||||
react: ^17.0.2
|
||||
dependencies:
|
||||
'@nextui-org/dom-utils': link:../../utilities/dom-utils
|
||||
'@nextui-org/shared-utils': link:../../utilities/shared-utils
|
||||
'@nextui-org/system': link:../../core/system
|
||||
devDependencies:
|
||||
clean-package: 2.1.1
|
||||
react: 17.0.2
|
||||
|
||||
packages/components/grid:
|
||||
specifiers:
|
||||
'@nextui-org/dom-utils': workspace:*
|
||||
@ -453,6 +511,29 @@ importers:
|
||||
clean-package: 2.1.1
|
||||
react: 17.0.2
|
||||
|
||||
packages/components/image:
|
||||
specifiers:
|
||||
'@nextui-org/dom-utils': workspace:*
|
||||
'@nextui-org/grid': workspace:*
|
||||
'@nextui-org/shared-utils': workspace:*
|
||||
'@nextui-org/system': workspace:*
|
||||
'@nextui-org/use-real-shape': workspace:*
|
||||
'@nextui-org/use-ref-state': workspace:*
|
||||
'@nextui-org/use-resize': workspace:*
|
||||
clean-package: 2.1.1
|
||||
react: ^17.0.2
|
||||
dependencies:
|
||||
'@nextui-org/dom-utils': link:../../utilities/dom-utils
|
||||
'@nextui-org/shared-utils': link:../../utilities/shared-utils
|
||||
'@nextui-org/system': link:../../core/system
|
||||
'@nextui-org/use-real-shape': link:../../hooks/use-real-shape
|
||||
'@nextui-org/use-ref-state': link:../../hooks/use-ref-state
|
||||
'@nextui-org/use-resize': link:../../hooks/use-resize
|
||||
devDependencies:
|
||||
'@nextui-org/grid': link:../grid
|
||||
clean-package: 2.1.1
|
||||
react: 17.0.2
|
||||
|
||||
packages/components/link:
|
||||
specifiers:
|
||||
'@nextui-org/dom-utils': workspace:*
|
||||
@ -633,6 +714,33 @@ importers:
|
||||
clean-package: 2.1.1
|
||||
react: 17.0.2
|
||||
|
||||
packages/hooks/use-real-shape:
|
||||
specifiers:
|
||||
'@nextui-org/dom-utils': workspace:*
|
||||
clean-package: 2.1.1
|
||||
react: ^17.0.2
|
||||
dependencies:
|
||||
'@nextui-org/dom-utils': link:../../utilities/dom-utils
|
||||
devDependencies:
|
||||
clean-package: 2.1.1
|
||||
react: 17.0.2
|
||||
|
||||
packages/hooks/use-ref-state:
|
||||
specifiers:
|
||||
clean-package: 2.1.1
|
||||
react: ^17.0.2
|
||||
devDependencies:
|
||||
clean-package: 2.1.1
|
||||
react: 17.0.2
|
||||
|
||||
packages/hooks/use-resize:
|
||||
specifiers:
|
||||
clean-package: 2.1.1
|
||||
react: ^17.0.2
|
||||
devDependencies:
|
||||
clean-package: 2.1.1
|
||||
react: 17.0.2
|
||||
|
||||
packages/hooks/use-ssr:
|
||||
specifiers:
|
||||
clean-package: 2.1.1
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"downlevelIteration": true
|
||||
"downlevelIteration": true,
|
||||
},
|
||||
"include": ["packages", "react-shim.js"],
|
||||
"exclude": ["**/node_modules"]
|
||||
|
||||
5
typings/mdx.d.ts
vendored
@ -1,5 +0,0 @@
|
||||
declare module '*.mdx' {
|
||||
let MDXComponent: (props: any) => JSX.Element
|
||||
export default MDXComponent
|
||||
}
|
||||
|
||||
7
typings/meta.d.ts
vendored
@ -1,7 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
declare module 'react' {
|
||||
interface MetaHTMLAttributes<T> extends React.MetaHTMLAttributes<T> {
|
||||
itemprop?: string
|
||||
}
|
||||
}
|
||||
8
typings/styled.d.ts
vendored
@ -1,8 +0,0 @@
|
||||
declare global {
|
||||
declare module "react" {
|
||||
interface StyleHTMLAttributes<T> extends React.HTMLAttributes<T> {
|
||||
jsx?: boolean;
|
||||
global?: boolean;
|
||||
}
|
||||
}
|
||||
}
|
||||