feat(root): stories improved, welcome page added, pagination migration started

This commit is contained in:
Junior Garcia 2023-03-07 23:03:03 -03:00
parent aba2e459d6
commit d12ee9e768
60 changed files with 1339 additions and 818 deletions

View File

@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
import {__DEV__} from "@nextui-org/shared-utils";
import {AvatarGroupProvider} from "./avatar-group-context";
import {useAvatarGroup, UseAvatarGroupProps} from "./use-avatar-group";
@ -30,8 +29,6 @@ const AvatarGroup = forwardRef<AvatarGroupProps, "div">((props, ref) => {
);
});
if (__DEV__) {
AvatarGroup.displayName = "NextUI.AvatarGroup";
}
AvatarGroup.displayName = "NextUI.AvatarGroup";
export default AvatarGroup;

View File

@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
import {__DEV__} from "@nextui-org/shared-utils";
import {useMemo} from "react";
import {AvatarIcon} from "./avatar-icon";
@ -73,8 +72,6 @@ const Avatar = forwardRef<AvatarProps, "span">((props, ref) => {
);
});
if (__DEV__) {
Avatar.displayName = "NextUI.Avatar";
}
Avatar.displayName = "NextUI.Avatar";
export default Avatar;

View File

@ -1,7 +1,7 @@
import type {AvatarVariantProps, AvatarSlots, SlotsToClasses} from "@nextui-org/theme";
import {avatar} from "@nextui-org/theme";
import {HTMLNextUIProps} from "@nextui-org/system";
import {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {mergeProps} from "@react-aria/utils";
import {useDOMRef} from "@nextui-org/dom-utils";
import {ReactRef, clsx, safeText} from "@nextui-org/shared-utils";
@ -166,7 +166,7 @@ export function useAvatar(props: UseAvatarProps) {
return isFocusable || as === "button";
}, [isFocusable, as]);
const getAvatarProps = useCallback(
const getAvatarProps = useCallback<PropGetter>(
() => ({
tabIndex: canBeFocused ? 0 : -1,
className: slots.base({

View File

@ -4,7 +4,7 @@ import {ComponentStory, ComponentMeta} from "@storybook/react";
import {Avatar, AvatarGroup, AvatarGroupProps} from "../src";
export default {
title: "Display/AvatarGroup",
title: "Components/AvatarGroup",
component: AvatarGroup,
argTypes: {
color: {

View File

@ -6,7 +6,7 @@ import {avatar} from "@nextui-org/theme";
import {Avatar, AvatarProps} from "../src";
export default {
title: "Display/Avatar",
title: "Components/Avatar",
component: Avatar,
argTypes: {
color: {

View File

@ -1,7 +1,6 @@
import type {ReactNode} from "react";
import {forwardRef} from "@nextui-org/system";
import {__DEV__} from "@nextui-org/shared-utils";
import {UseBadgeProps, useBadge} from "./use-badge";
@ -20,10 +19,6 @@ const Badge = forwardRef<BadgeProps, "span">((props, ref) => {
);
});
if (__DEV__) {
Badge.displayName = "NextUI.Badge";
}
Badge.toString = () => ".nextui-badge";
Badge.displayName = "NextUI.Badge";
export default Badge;

View File

@ -7,7 +7,7 @@ import {CheckIcon} from "@nextui-org/shared-icons";
import {Badge, BadgeProps} from "../src";
export default {
title: "Display/Badge",
title: "Components/Badge",
component: Badge,
argTypes: {
content: {

View File

@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
import {__DEV__} from "@nextui-org/shared-utils";
import {ButtonGroupProvider} from "./button-group-context";
import {UseButtonGroupProps, useButtonGroup} from "./use-button-group";
@ -21,8 +20,6 @@ const ButtonGroup = forwardRef<ButtonGroupProps, "div">((props, ref) => {
);
});
if (__DEV__) {
ButtonGroup.displayName = "NextUI.ButtonGroup";
}
ButtonGroup.displayName = "NextUI.ButtonGroup";
export default ButtonGroup;

View File

@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
import {__DEV__} from "@nextui-org/shared-utils";
import {Drip} from "@nextui-org/drip";
import {UseButtonProps, useButton} from "./use-button";
@ -40,8 +39,6 @@ const Button = forwardRef<ButtonProps, "button">((props, ref) => {
);
});
if (__DEV__) {
Button.displayName = "NextUI.Button";
}
Button.displayName = "NextUI.Button";
export default Button;

View File

@ -5,7 +5,7 @@ import {button, buttonGroup} from "@nextui-org/theme";
import {Button, ButtonGroup, ButtonGroupProps} from "../src";
export default {
title: "Actions/ButtonGroup",
title: "Components/ButtonGroup",
component: ButtonGroup,
argTypes: {
variant: {

View File

@ -7,7 +7,7 @@ import {Spinner} from "@nextui-org/spinner";
import {Button, ButtonProps} from "../src";
export default {
title: "Actions/Button",
title: "Components/Button",
component: Button,
argTypes: {
variant: {
@ -83,6 +83,12 @@ WithIcons.args = {
rightIcon: <Camera />,
};
export const IconButton = Template.bind({});
IconButton.args = {
...defaultProps,
children: <Notification fill="currentColor" />,
};
export const IsLoading = Template.bind({});
IsLoading.args = {
...defaultProps,

View File

@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
import {__DEV__} from "@nextui-org/shared-utils";
import {CheckboxGroupProvider} from "./checkbox-group-context";
import {UseCheckboxGroupProps, useCheckboxGroup} from "./use-checkbox-group";
@ -20,8 +19,6 @@ const CheckboxGroup = forwardRef<CheckboxGroupProps, "div">((props, ref) => {
);
});
if (__DEV__) {
CheckboxGroup.displayName = "NextUI.CheckboxGroup";
}
CheckboxGroup.displayName = "NextUI.CheckboxGroup";
export default CheckboxGroup;

View File

@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
import {__DEV__} from "@nextui-org/shared-utils";
import {VisuallyHidden} from "@react-aria/visually-hidden";
import {cloneElement, ReactElement} from "react";
@ -39,8 +38,6 @@ const Checkbox = forwardRef<CheckboxProps, "label">((props, ref) => {
);
});
if (__DEV__) {
Checkbox.displayName = "NextUI.Checkbox";
}
Checkbox.displayName = "NextUI.Checkbox";
export default Checkbox;

View File

@ -250,6 +250,9 @@ export function useCheckbox(props: UseCheckboxProps) {
isSelected,
isDisabled,
isInvalid,
isFocused,
isHovered,
isFocusVisible,
getBaseProps,
getWrapperProps,
getInputProps,

View File

@ -10,7 +10,7 @@ import {
} from "./checkbox.stories";
export default {
title: "Inputs/CheckboxGroup",
title: "Components/CheckboxGroup",
component: CheckboxGroup,
argTypes: {
color: {
@ -170,14 +170,25 @@ export const CustomWithStyles = () => {
};
export const CustomWithHooks = () => {
const [groupSelected, setGroupSelected] = React.useState<string[]>([]);
return (
<CheckboxGroup className="gap-1" label="Select ammenities" orientation="horizontal">
<CheckboxItemWithHooks value="wifi">Wifi</CheckboxItemWithHooks>
<CheckboxItemWithHooks value="tv">TV</CheckboxItemWithHooks>
<CheckboxItemWithHooks value="kitchen">Kitchen</CheckboxItemWithHooks>
<CheckboxItemWithHooks value="parking">Parking</CheckboxItemWithHooks>
<CheckboxItemWithHooks value="pool">Pool</CheckboxItemWithHooks>
<CheckboxItemWithHooks value="gym">Gym</CheckboxItemWithHooks>
</CheckboxGroup>
<>
<CheckboxGroup
className="gap-1"
label="Select ammenities"
orientation="horizontal"
value={groupSelected}
onChange={setGroupSelected}
>
<CheckboxItemWithHooks value="wifi">Wifi</CheckboxItemWithHooks>
<CheckboxItemWithHooks value="tv">TV</CheckboxItemWithHooks>
<CheckboxItemWithHooks value="kitchen">Kitchen</CheckboxItemWithHooks>
<CheckboxItemWithHooks value="parking">Parking</CheckboxItemWithHooks>
<CheckboxItemWithHooks value="pool">Pool</CheckboxItemWithHooks>
<CheckboxItemWithHooks value="gym">Gym</CheckboxItemWithHooks>
</CheckboxGroup>
<p className="mt-4 ml-1 text-neutral-500">Selected: {groupSelected.join(", ")}</p>
</>
);
};

View File

@ -17,7 +17,7 @@ import {
} from "../src";
export default {
title: "Inputs/Checkbox",
title: "Components/Checkbox",
component: Checkbox,
argTypes: {
color: {
@ -175,7 +175,7 @@ export const CustomWithStyles = (props: CustomCheckboxProps) => {
aria-label={userName}
styles={{
base: clsx(
"inline-flex w-full max-w-md bg-content1 hover:bg-content2 items-center justify-start cursor-pointer rounded-lg gap-2 p-4 border-2 border-transparent",
"inline-flex w-full max-w-md bg-content1 hover:bg-content2 items-center justify-start cursor-pointer rounded-lg gap-2 p-4 border-1.5 border-transparent",
{
"border-primary": isChecked,
},
@ -207,10 +207,11 @@ export const CustomWithStyles = (props: CustomCheckboxProps) => {
};
export const CustomWithHooks = (props: CheckboxProps) => {
const {children, isSelected, getBaseProps, getLabelProps, getInputProps} = useCheckbox({
"aria-label": props["aria-label"] || "Toggle status",
...props,
});
const {children, isSelected, isFocusVisible, getBaseProps, getLabelProps, getInputProps} =
useCheckbox({
"aria-label": props["aria-label"] || "Toggle status",
...props,
});
return (
<label {...getBaseProps()}>
@ -223,6 +224,8 @@ export const CustomWithHooks = (props: CheckboxProps) => {
styles={{
base: clsx("border-neutral hover:bg-neutral-200", {
"border-primary bg-primary hover:bg-primary-600 hover:border-primary-600": isSelected,
"outline-none ring-2 !ring-primary ring-offset-2 ring-offset-background dark:ring-offset-background-dark":
isFocusVisible,
}),
content: clsx("text-primary", {
"text-primary-contrastText pl-1": isSelected,

View File

@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
import {__DEV__} from "@nextui-org/shared-utils";
import {CloseFilledIcon} from "@nextui-org/shared-icons";
import {useMemo} from "react";
@ -52,8 +51,6 @@ const Chip = forwardRef<ChipProps, "div">((props, ref) => {
);
});
if (__DEV__) {
Chip.displayName = "NextUI.Chip";
}
Chip.displayName = "NextUI.Chip";
export default Chip;

View File

@ -9,6 +9,7 @@ import {chip} from "@nextui-org/theme";
import {useDOMRef} from "@nextui-org/dom-utils";
import {clsx, ReactRef} from "@nextui-org/shared-utils";
import {useMemo, isValidElement, cloneElement} from "react";
import {PressEvent} from "@react-types/shared";
export interface UseChipProps extends HTMLNextUIProps<"div">, ChipVariantProps {
/**
@ -47,8 +48,9 @@ export interface UseChipProps extends HTMLNextUIProps<"div">, ChipVariantProps {
/**
* Callback fired when the chip is closed. if you pass this prop,
* the chip will display a close button (rightContent).
* @param e PressEvent
*/
onClose?: () => void;
onClose?: (e: PressEvent) => void;
}
export function useChip(originalProps: UseChipProps) {
@ -83,14 +85,25 @@ export function useChip(originalProps: UseChipProps) {
[children],
);
const hasLeftContent = useMemo(() => !!avatar || !!leftContent, [avatar, leftContent]);
const hasRightContent = useMemo(() => !!rightContent || isCloseable, [rightContent, isCloseable]);
const slots = useMemo(
() =>
chip({
...variantProps,
hasLeftContent,
hasRightContent,
isOneChar,
isCloseButtonFocusVisible,
}),
[...Object.values(variantProps), isCloseButtonFocusVisible, isOneChar],
[
...Object.values(variantProps),
isCloseButtonFocusVisible,
hasLeftContent,
hasRightContent,
isOneChar,
],
);
const {pressProps: closePressProps} = usePress({

View File

@ -7,7 +7,7 @@ import {CheckIcon} from "@nextui-org/shared-icons";
import {Chip, ChipProps} from "../src";
export default {
title: "Display/Chip",
title: "Components/Chip",
component: Chip,
argTypes: {
variant: {
@ -54,6 +54,18 @@ Default.args = {
...defaultProps,
};
export const LeftContent = Template.bind({});
LeftContent.args = {
...defaultProps,
leftContent: <span className="ml-1">🎉</span>,
};
export const RightContent = Template.bind({});
RightContent.args = {
...defaultProps,
rightContent: <span className="mr-1">🚀</span>,
};
export const Closeable = Template.bind({});
Closeable.args = {
...defaultProps,

View File

@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
import {__DEV__} from "@nextui-org/shared-utils";
import {useCode, UseCodeProps} from "./use-code";
@ -11,8 +10,6 @@ const Code = forwardRef<CodeProps, "code">((props, ref) => {
return <Component {...getCodeProps()}>{children}</Component>;
});
if (__DEV__) {
Code.displayName = "NextUI.Code";
}
Code.displayName = "NextUI.Code";
export default Code;

View File

@ -5,7 +5,7 @@ import {code} from "@nextui-org/theme";
import {Code, CodeProps} from "../src";
export default {
title: "Display/Code",
title: "Components/Code",
component: Code,
argTypes: {
color: {

View File

@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
import {__DEV__} from "@nextui-org/shared-utils";
import {UseLinkProps, useLink} from "./use-link";
import {LinkIcon} from "./link-icon";
@ -25,8 +24,6 @@ const Link = forwardRef<LinkProps, "a">((props, ref) => {
);
});
if (__DEV__) {
Link.displayName = "NextUI.Link";
}
Link.displayName = "NextUI.Link";
export default Link;

View File

@ -6,7 +6,7 @@ import {link} from "@nextui-org/theme";
import {Link, LinkProps} from "../src";
export default {
title: "Navigation/Link",
title: "Components/Link",
component: Link,
argTypes: {
color: {

View File

@ -39,9 +39,11 @@
"dependencies": {
"@nextui-org/system": "workspace:*",
"@nextui-org/shared-utils": "workspace:*",
"@nextui-org/shared-css": "workspace:*",
"@nextui-org/theme": "workspace:*",
"@nextui-org/dom-utils": "workspace:*",
"@nextui-org/use-pagination": "workspace:*",
"@react-aria/focus": "^3.11.0",
"@react-aria/interactions": "^3.14.0",
"@react-aria/utils": "^3.15.0"
},
"devDependencies": {

View File

@ -1,5 +1,15 @@
import Pagination from "./pagination";
import PaginationItem from "./pagination-item";
// export types
export type {PaginationProps} from "./pagination";
export type {PaginationItemRenderProps} from "./use-pagination";
export type {PaginationItemProps} from "./pagination-item";
export type {DOTS as PAGINATION_DOTS} from "@nextui-org/use-pagination";
// export hooks
export {usePagination} from "./use-pagination";
export {usePaginationItem} from "./use-pagination-item";
// export component
export {default as Pagination} from "./pagination";
export {Pagination, PaginationItem};

View File

@ -1,7 +1,7 @@
import {forwardRef, HTMLNextUIProps} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/dom-utils";
import {useState, MouseEvent} from "react";
import {clsx, __DEV__} from "@nextui-org/shared-utils";
import {clsx} from "@nextui-org/shared-utils";
import PaginationItem from "./pagination-item";
import {StyledPaginationEllipsis} from "./pagination.styles";
@ -72,10 +72,6 @@ const PaginationEllipsis = forwardRef<PaginationEllipsisProps, "svg">((props, re
);
});
if (__DEV__) {
PaginationEllipsis.displayName = "NextUI.PaginationEllipsis";
}
PaginationEllipsis.toString = () => ".nextui-pagination-ellipsis";
PaginationEllipsis.displayName = "NextUI.PaginationEllipsis";
export default PaginationEllipsis;

View File

@ -2,7 +2,7 @@ import {useState, useEffect, useMemo} from "react";
import {mergeProps} from "@react-aria/utils";
import {forwardRef, HTMLNextUIProps} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/dom-utils";
import {clsx, __DEV__} from "@nextui-org/shared-utils";
import {clsx} from "@nextui-org/shared-utils";
import {StyledPaginationHighlight} from "./pagination.styles";
@ -58,10 +58,6 @@ const PaginationHighlight = forwardRef<PaginationHighlightProps, "div">((props,
);
});
if (__DEV__) {
PaginationHighlight.displayName = "NextUI.PaginationHighlight";
}
PaginationHighlight.toString = () => ".nextui-pagination-highlight";
PaginationHighlight.displayName = "NextUI.PaginationHighlight";
export default PaginationHighlight;

View File

@ -1,7 +1,7 @@
import {MouseEvent} from "react";
import {forwardRef, HTMLNextUIProps} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/dom-utils";
import {clsx, __DEV__} from "@nextui-org/shared-utils";
import {clsx} from "@nextui-org/shared-utils";
import PaginationItem from "./pagination-item";
import {StyledPaginationIcon} from "./pagination.styles";
@ -53,10 +53,6 @@ const PaginationIcon = forwardRef<PaginationIconProps, "svg">((props, ref) => {
);
});
if (__DEV__) {
PaginationIcon.displayName = "NextUI.PaginationIcon";
}
PaginationIcon.toString = () => ".nextui-pagination-icon";
PaginationIcon.displayName = "NextUI.PaginationIcon";
export default PaginationIcon;

View File

@ -1,93 +1,15 @@
import {useMemo, MouseEvent} from "react";
import {forwardRef, HTMLNextUIProps} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/dom-utils";
import {clsx, __DEV__} from "@nextui-org/shared-utils";
import {DOTS} from "@nextui-org/use-pagination";
import {forwardRef} from "@nextui-org/system";
import {StyledPaginationItem, StyledPaginationItemContent} from "./pagination.styles";
import {usePaginationItem, UsePaginationItemProps} from "./use-pagination-item";
export interface PaginationItemProps extends HTMLNextUIProps<"button"> {
active?: boolean;
value?: string | number;
onlyDots?: boolean;
disabled?: boolean;
bordered?: boolean;
animated?: boolean;
preserveContent?: boolean;
onClick?: (e: MouseEvent) => void;
}
export interface PaginationItemProps extends Omit<UsePaginationItemProps, "ref"> {}
const getItemAriaLabel = (page?: string | number) => {
if (!page) return;
switch (page) {
case DOTS:
return "dots element";
case "<":
return "previous page button";
case ">":
return "next page button";
case "first":
return "first page button";
case "last":
return "last page button";
default:
return `${page} item`;
}
};
const PaginationItem = forwardRef<PaginationItemProps, "li">((props, ref) => {
const {Component, children, getItemProps} = usePaginationItem({ref, ...props});
const PaginationItem = forwardRef<PaginationItemProps, "button">((props, ref) => {
const {
children,
className,
active,
value,
animated,
bordered,
disabled,
onlyDots,
preserveContent = false,
onClick,
...otherProps
} = props;
const domRef = useDOMRef(ref);
const ariaLabel = useMemo(
() => (active ? `${getItemAriaLabel(value)} active` : getItemAriaLabel(value)),
[value, active],
);
const clickHandler = (event: React.MouseEvent) => {
if (disabled) return;
onClick?.(event);
};
return (
<StyledPaginationItem
ref={domRef}
active={active}
animated={animated}
aria-label={ariaLabel}
bordered={bordered}
className={clsx("nextui-pagination-item", className)}
disabled={disabled}
onlyDots={onlyDots}
preserveContent={preserveContent}
tabIndex={disabled ? -1 : 0}
onClick={clickHandler}
{...otherProps}
>
<StyledPaginationItemContent className="nextui-pagination-item-count">
{children}
</StyledPaginationItemContent>
</StyledPaginationItem>
);
return <Component {...getItemProps()}>{children}</Component>;
});
if (__DEV__) {
PaginationItem.displayName = "NextUI.PaginationItem";
}
PaginationItem.toString = () => ".nextui-pagination-item";
PaginationItem.displayName = "NextUI.PaginationItem";
export default PaginationItem;

View File

@ -1,93 +1,90 @@
import type {PaginationItemParam} from "@nextui-org/use-pagination";
import {useCallback} from "react";
import {forwardRef} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/dom-utils";
import {PaginationItemParam} from "@nextui-org/use-pagination";
import {useCallback} from "react";
import {DOTS} from "@nextui-org/use-pagination";
import {clsx, __DEV__} from "@nextui-org/shared-utils";
import PaginationItem from "./pagination-item";
import PaginationEllipsis from "./pagination-ellipsis";
import PaginationHighlight from "./pagination-highlight";
import PaginationIcon from "./pagination-icon";
import {StyledPagination} from "./pagination.styles";
import {UsePaginationProps, usePagination} from "./use-pagination";
import PaginationItem from "./pagination-item";
export interface PaginationProps extends UsePaginationProps {}
const Pagination = forwardRef<PaginationProps, "nav">((props, ref) => {
const Pagination = forwardRef<PaginationProps, "ul">((props, ref) => {
const {
className,
controls,
animated,
rounded,
bordered,
shadow,
onlyDots,
Component,
// showControls,
dotsJump,
noMargin,
loop,
slots,
styles,
total,
range,
active,
setPage,
onPrevious,
onNext,
...otherProps
} = usePagination(props);
const domRef = useDOMRef(ref);
// onPrevious,
// onNext,
renderItem: renderItemProp,
getBaseProps,
} = usePagination({ref, ...props});
const renderItem = useCallback(
(value: PaginationItemParam, index: number) => {
if (value === DOTS) {
const isBefore = index < range.indexOf(active);
const isBefore = index < range.indexOf(active);
return (
<PaginationEllipsis
key={`nextui-pagination-item-${value}-${index}`}
animated={animated}
bordered={bordered}
isBefore={isBefore}
onlyDots={onlyDots}
value={value}
onClick={() =>
isBefore
? setPage(active - dotsJump >= 1 ? active - dotsJump : 1)
: setPage(active + dotsJump <= total ? active + dotsJump : total)
}
/>
);
if (renderItemProp && typeof renderItemProp === "function") {
return renderItemProp({
value,
index,
dotsJump,
isDots: value === DOTS,
isBefore,
isActive: value === active,
isPrevious: value === active - 1,
isNext: value === active + 1,
isFirst: value === 1,
isLast: value === total,
className: slots.item({class: styles?.item}),
});
}
if (value === DOTS) {
return <li>...</li>;
// return (
// <PaginationEllipsis
// key={`nextui-pagination-item-${value}-${index}`}
// animated={animated}
// bordered={bordered}
// isBefore={isBefore}
// onlyDots={onlyDots}
// value={value}
// onClick={() =>
// isBefore
// ? setPage(active - dotsJump >= 1 ? active - dotsJump : 1)
// : setPage(active + dotsJump <= total ? active + dotsJump : total)
// }
// />
// );
}
return (
<PaginationItem
key={`nextui-pagination-item-${value}-${index}`}
active={value === active}
animated={animated}
bordered={bordered}
onlyDots={onlyDots}
key={`${value}-${index}`}
className={slots.item({class: styles?.item})}
isActive={value === active}
value={value}
onClick={() => value !== active && setPage(value)}
onPress={() => value !== active && setPage(value)}
>
{value}
</PaginationItem>
);
},
[total, onlyDots, active, bordered, animated],
[active, dotsJump, loop, range, renderItemProp, setPage, slots.item, styles?.item, total],
);
return (
<StyledPagination
ref={domRef}
bordered={bordered}
className={clsx("nextui-pagination", className)}
noMargin={noMargin}
onlyDots={onlyDots}
rounded={rounded}
{...otherProps}
>
{controls && (
<Component {...getBaseProps()}>
{range.map(renderItem)}
{/* {controls && (
<PaginationIcon
isPrev
animated={animated}
@ -113,15 +110,11 @@ const Pagination = forwardRef<PaginationProps, "nav">((props, ref) => {
onlyDots={onlyDots}
onClick={onNext}
/>
)}
</StyledPagination>
)} */}
</Component>
);
});
if (__DEV__) {
Pagination.displayName = "NextUI.Pagination";
}
Pagination.toString = () => ".nextui-pagination";
Pagination.displayName = "NextUI.Pagination";
export default Pagination;

View File

@ -0,0 +1,129 @@
import type {Ref} from "react";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import type {PressEvent} from "@react-types/shared";
import {useMemo} from "react";
import {DOTS} from "@nextui-org/use-pagination";
import {dataAttr} from "@nextui-org/shared-utils";
import {mergeProps} from "@react-aria/utils";
import {useDOMRef} from "@nextui-org/dom-utils";
import {usePress} from "@react-aria/interactions";
import {useFocusRing} from "@react-aria/focus";
export interface UsePaginationItemProps extends Omit<HTMLNextUIProps<"li">, "onClick"> {
/**
* Ref to the DOM node.
*/
ref?: Ref<HTMLElement>;
/**
* Value of the item.
*/
value?: string | number;
/**
* Whether the item is active.
* @default false
*/
isActive?: boolean;
/**
* Whether the item is disabled.
* @default false
*/
isDisabled?: boolean;
/**
* Callback fired when the item is clicked.
* @param e MouseEvent
* @deprecated Use `onPress` instead.
*/
onClick?: () => void;
/**
* Callback fired when the item is clicked.
* @param e PressEvent
*/
onPress?: (e: PressEvent) => void;
/**
* Function to get the aria-label of the item.
* @param page string | number
* @returns string
*/
getAriaLabel?: (page?: string | number) => string;
}
const getItemAriaLabel = (page?: string | number) => {
if (!page) return;
switch (page) {
case DOTS:
return "dots element";
case "<":
return "previous page button";
case ">":
return "next page button";
case "first":
return "first page button";
case "last":
return "last page button";
default:
return `${page} item`;
}
};
export function usePaginationItem(props: UsePaginationItemProps) {
const {
as,
ref,
value,
children,
isActive,
isDisabled,
onPress,
onClick,
getAriaLabel = getItemAriaLabel,
...otherProps
} = props;
const Component = as || "li";
const domRef = useDOMRef(ref);
const ariaLabel = useMemo(
() => (isActive ? `${getAriaLabel(value)} active` : getAriaLabel(value)),
[value, isActive],
);
const handlePress = (e: PressEvent) => {
onClick?.();
onPress?.(e);
};
const {pressProps} = usePress({
isDisabled,
onPress: handlePress,
});
const {focusProps, isFocused, isFocusVisible} = useFocusRing();
const getItemProps: PropGetter = (props = {}) => {
return {
ref: domRef,
role: "button",
tabIndex: isDisabled ? -1 : 0,
"aria-label": ariaLabel,
"aria-current": dataAttr(isActive),
"aria-disabled": dataAttr(isDisabled),
"data-active": dataAttr(isActive),
"data-focus-visible": dataAttr(isFocusVisible),
"data-focused": dataAttr(isFocused),
...mergeProps(props, pressProps, focusProps, otherProps),
};
};
return {
Component,
children,
ariaLabel,
isFocused,
isFocusVisible,
getItemProps,
};
}
export type UsePaginationItemReturn = ReturnType<typeof usePaginationItem>;

View File

@ -1,86 +1,84 @@
import type {NormalColors, NormalSizes, NormalWeights} from "@nextui-org/shared-utils";
import type {HTMLNextUIProps} from "@nextui-org/system";
import type {ReactNode, Ref} from "react";
import type {PaginationSlots, PaginationVariantProps, SlotsToClasses} from "@nextui-org/theme";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
PaginationItemParam,
usePagination as useBasePagination,
UsePaginationProps as UseBasePaginationProps,
} from "@nextui-org/use-pagination";
import {useMemo} from "react";
import {pagination} from "@nextui-org/theme";
import {useDOMRef} from "@nextui-org/dom-utils";
import {clsx, dataAttr} from "@nextui-org/shared-utils";
export interface UsePaginationProps extends HTMLNextUIProps<"nav", UseBasePaginationProps> {
export type PaginationItemRenderProps = {
value: PaginationItemParam;
index: number;
dotsJump: number;
isActive: boolean;
isNext: boolean;
isPrevious: boolean;
isFirst: boolean;
isLast: boolean;
isDots: boolean;
isBefore: boolean;
className: string;
};
interface Props extends HTMLNextUIProps<"ul"> {
/**
* The pagination color.
* @default "default"
* Ref to the DOM node.
*/
color?: NormalColors;
/**
* The pagination size.
* @default "md"
*/
size?: NormalSizes;
/**
* The border weight of the bordered pagination.
* @default "normal"
*/
borderWeight?: NormalWeights;
/**
* Show only dots as pagination elements
* @default false
*/
onlyDots?: boolean;
ref?: Ref<HTMLElement>;
/**
* Number of pages that are added or subtracted on the '...' button.
* @default 5
*/
dotsJump?: number;
/**
* Whether the pagination is bordered.
* @default false
*/
bordered?: boolean;
/**
* Whether the pagination is rounded.
* @default false
*/
rounded?: boolean;
/**
* Whether to show a shadow effect.
* @default false
*/
shadow?: boolean;
/**
* Whether the pagination should have animations.
* @default true
*/
animated?: boolean;
/**
* Non disable next/previous controls
* @default false
*/
loop?: boolean;
/**
* Whether the pagination should have a margin.
* @default false
*/
noMargin?: boolean;
/**
* Whether the pagination should display controls (left/right arrows).
* @default true
*/
controls?: boolean;
showControls?: boolean;
/**
* Render a custom pagination item.
* @param props Pagination item props
* @returns ReactNode
*/
renderItem?: (props: PaginationItemRenderProps) => ReactNode;
/**
* Classname or List of classes to change the styles of the element.
* if `className` is passed, it will be added to the base slot.
*
* @example
* ```ts
* <Pagination styles={{
* base:"base-classes",
* wrapper: "wrapper-classes",
* item: "item-classes",
* cursor: "cursor-classes", // this is the one that moves when an item is selected
* }} />
* ```
*/
styles?: SlotsToClasses<PaginationSlots>;
}
export function usePagination(props: UsePaginationProps) {
export type UsePaginationProps = Props & UseBasePaginationProps & PaginationVariantProps;
export function usePagination(originalProps: UsePaginationProps) {
const [props, variantProps] = mapPropsVariants(originalProps, pagination.variantKeys);
const {
color = "default",
size = "md",
borderWeight = "normal",
rounded = false,
noMargin = false,
bordered = false,
animated = true,
shadow = false,
onlyDots = false,
controls = true,
as,
ref,
styles,
showControls = true,
dotsJump = 5,
loop = false,
total = 1,
@ -89,19 +87,34 @@ export function usePagination(props: UsePaginationProps) {
siblings,
boundaries,
onChange,
className,
renderItem,
...otherProps
} = props;
const Component = as || "ul";
const domRef = useDOMRef(ref);
const {range, active, setPage, previous, next, first, last} = useBasePagination({
page,
initialPage,
siblings: onlyDots ? 10 : siblings,
boundaries: onlyDots ? 10 : boundaries,
siblings,
boundaries,
total,
onChange,
});
const slots = useMemo(
() =>
pagination({
...variantProps,
}),
[...Object.values(variantProps)],
);
const baseStyles = clsx(styles?.base, className);
const onNext = () => {
if (loop && active === total) {
return first();
@ -118,26 +131,35 @@ export function usePagination(props: UsePaginationProps) {
return previous();
};
const getBaseProps: PropGetter = (props = {}) => {
return {
...props,
ref: domRef,
"data-controls": dataAttr(showControls),
"data-loop": dataAttr(loop),
"data-dots-jump": dotsJump,
"data-total": total,
"data-active": active,
className: slots.base({class: baseStyles}),
...otherProps,
};
};
return {
color,
size,
bordered,
shadow,
onlyDots,
controls,
Component,
showControls,
dotsJump,
animated,
noMargin,
borderWeight,
slots,
styles,
loop,
total,
active,
rounded,
range,
active,
setPage,
onNext,
onPrevious,
...otherProps,
onNext,
renderItem,
getBaseProps,
};
}

View File

@ -1,161 +1,216 @@
import React from "react";
import {Meta} from "@storybook/react";
import {Grid} from "@nextui-org/grid";
import {ComponentStory, ComponentMeta} from "@storybook/react";
import {pagination} from "@nextui-org/theme";
import {Pagination} from "../src";
import {Pagination, PaginationProps} from "../src";
export default {
title: "Navigation/Pagination",
title: "Components/Pagination",
component: Pagination,
} as Meta;
argTypes: {
variant: {
control: {
type: "select",
options: ["solid", "bordered", "light", "flat", "faded", "shadow", "dot"],
},
},
color: {
control: {
type: "select",
options: ["neutral", "primary", "secondary", "success", "warning", "danger"],
},
},
radius: {
control: {
type: "select",
options: ["none", "base", "sm", "md", "lg", "xl", "full"],
},
},
size: {
control: {
type: "select",
options: ["xs", "sm", "md", "lg", "xl"],
},
},
isDisabled: {
control: {
type: "boolean",
},
},
},
} as ComponentMeta<typeof Pagination>;
export const Default = () => <Pagination initialPage={1} total={20} />;
const defaultProps = {
...pagination.defaultVariants,
total: 10,
initialPage: 1,
};
export const Colors = () => (
<>
<Grid xs={12}>
<Pagination color="primary" total={10} />
</Grid>
<Grid xs={12}>
<Pagination color="secondary" total={10} />
</Grid>
<Grid xs={12}>
<Pagination color="success" total={10} />
</Grid>
<Grid xs={12}>
<Pagination color="warning" total={10} />
</Grid>
<Grid xs={12}>
<Pagination color="error" total={10} />
</Grid>
<Grid xs={12}>
<Pagination color="gradient" total={10} />
</Grid>
</>
const Template: ComponentStory<typeof Pagination> = (args: PaginationProps) => (
<Pagination {...args} />
);
export const Sizes = () => (
<>
<Grid xs={12}>
<Pagination size="xs" total={10} />
</Grid>
<Grid xs={12}>
<Pagination size="sm" total={5} />
</Grid>
<Grid xs={12}>
<Pagination initialPage={6} size="md" total={10} />
</Grid>
<Grid xs={12}>
<Pagination initialPage={6} size="lg" total={10} />
</Grid>
<Grid xs={12}>
<Pagination initialPage={6} size="xl" total={30} />
</Grid>
</>
);
export const Default = Template.bind({});
Default.args = {
...defaultProps,
};
export const Rounded = () => (
<>
<Grid xs={12}>
<Pagination rounded size="xs" total={10} />
</Grid>
<Grid xs={12}>
<Pagination rounded size="sm" total={5} />
</Grid>
<Grid xs={12}>
<Pagination rounded initialPage={6} size="md" total={10} />
</Grid>
<Grid xs={12}>
<Pagination rounded initialPage={6} size="lg" total={10} />
</Grid>
<Grid xs={12}>
<Pagination rounded initialPage={6} size="xl" total={30} />
</Grid>
</>
);
// import {Grid} from "@nextui-org/grid";
export const Bordered = () => (
<>
<Grid xs={12}>
<Pagination bordered initialPage={1} total={20} />
</Grid>
<Grid xs={12}>
<Pagination bordered rounded initialPage={1} total={20} />
</Grid>
</>
);
// import {Pagination} from "../src";
export const Shadow = () => (
<>
<Grid xs={12}>
<Pagination shadow color="primary" total={10} />
</Grid>
<Grid xs={12}>
<Pagination rounded shadow color="secondary" total={10} />
</Grid>
<Grid xs={12}>
<Pagination shadow color="success" total={10} />
</Grid>
<Grid xs={12}>
<Pagination rounded shadow color="warning" total={10} />
</Grid>
<Grid xs={12}>
<Pagination shadow color="error" total={10} />
</Grid>
<Grid xs={12}>
<Pagination rounded shadow color="gradient" total={10} />
</Grid>
</>
);
// export default {
// title: "Navigation/Pagination",
// component: Pagination,
// } as Meta;
export const OnlyDots = () => (
<>
<Grid xs={12}>
<Pagination onlyDots color="primary" size="xs" total={10} />
</Grid>
<Grid xs={12}>
<Pagination onlyDots shadow color="secondary" size="sm" total={10} />
</Grid>
<Grid xs={12}>
<Pagination onlyDots color="success" size="md" total={10} />
</Grid>
<Grid xs={12}>
<Pagination onlyDots shadow color="warning" size="lg" total={10} />
</Grid>
<Grid xs={12}>
<Pagination onlyDots color="error" size="xl" total={10} />
</Grid>
</>
);
// export const Default = () => <Pagination initialPage={1} total={20} />;
export const Loop = () => (
<>
<Grid xs={12}>
<Pagination loop initialPage={1} total={6} />
</Grid>
</>
);
// export const Colors = () => (
// <>
// <Grid xs={12}>
// <Pagination color="primary" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination color="secondary" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination color="success" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination color="warning" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination color="error" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination color="gradient" total={10} />
// </Grid>
// </>
// );
export const NoMargin = () => (
<>
<Grid xs={12}>
<Pagination noMargin shadow color="secondary" initialPage={1} total={6} />
</Grid>
</>
);
// export const Sizes = () => (
// <>
// <Grid xs={12}>
// <Pagination size="xs" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination size="sm" total={5} />
// </Grid>
// <Grid xs={12}>
// <Pagination initialPage={6} size="md" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination initialPage={6} size="lg" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination initialPage={6} size="xl" total={30} />
// </Grid>
// </>
// );
export const NoControls = () => (
<>
<Grid xs={12}>
<Pagination shadow color="success" controls={false} initialPage={1} total={20} />
</Grid>
</>
);
// export const Rounded = () => (
// <>
// <Grid xs={12}>
// <Pagination rounded size="xs" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination rounded size="sm" total={5} />
// </Grid>
// <Grid xs={12}>
// <Pagination rounded initialPage={6} size="md" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination rounded initialPage={6} size="lg" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination rounded initialPage={6} size="xl" total={30} />
// </Grid>
// </>
// );
export const NoAnimated = () => (
<>
<Grid xs={12}>
<Pagination animated={false} initialPage={1} total={6} />
</Grid>
</>
);
// export const Bordered = () => (
// <>
// <Grid xs={12}>
// <Pagination bordered initialPage={1} total={20} />
// </Grid>
// <Grid xs={12}>
// <Pagination bordered rounded initialPage={1} total={20} />
// </Grid>
// </>
// );
// export const Shadow = () => (
// <>
// <Grid xs={12}>
// <Pagination shadow color="primary" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination rounded shadow color="secondary" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination shadow color="success" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination rounded shadow color="warning" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination shadow color="error" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination rounded shadow color="gradient" total={10} />
// </Grid>
// </>
// );
// export const OnlyDots = () => (
// <>
// <Grid xs={12}>
// <Pagination onlyDots color="primary" size="xs" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination onlyDots shadow color="secondary" size="sm" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination onlyDots color="success" size="md" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination onlyDots shadow color="warning" size="lg" total={10} />
// </Grid>
// <Grid xs={12}>
// <Pagination onlyDots color="error" size="xl" total={10} />
// </Grid>
// </>
// );
// export const Loop = () => (
// <>
// <Grid xs={12}>
// <Pagination loop initialPage={1} total={6} />
// </Grid>
// </>
// );
// export const NoMargin = () => (
// <>
// <Grid xs={12}>
// <Pagination noMargin shadow color="secondary" initialPage={1} total={6} />
// </Grid>
// </>
// );
// export const NoControls = () => (
// <>
// <Grid xs={12}>
// <Pagination shadow color="success" controls={false} initialPage={1} total={20} />
// </Grid>
// </>
// );
// export const NoAnimated = () => (
// <>
// <Grid xs={12}>
// <Pagination animated={false} initialPage={1} total={6} />
// </Grid>
// </>
// );

View File

@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
import {__DEV__} from "@nextui-org/shared-utils";
import {RadioGroupProvider} from "./radio-group-context";
import {UseRadioGroupProps, useRadioGroup} from "./use-radio-group";
@ -20,8 +19,6 @@ const RadioGroup = forwardRef<RadioGroupProps, "div">((props, ref) => {
);
});
if (__DEV__) {
RadioGroup.displayName = "NextUI.RadioGroup";
}
RadioGroup.displayName = "NextUI.RadioGroup";
export default RadioGroup;

View File

@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
import {__DEV__} from "@nextui-org/shared-utils";
import {VisuallyHidden} from "@react-aria/visually-hidden";
import {UseRadioProps, useRadio} from "./use-radio";
@ -39,8 +38,6 @@ const Radio = forwardRef<RadioProps, "label">((props, ref) => {
);
});
if (__DEV__) {
Radio.displayName = "NextUI.Radio";
}
Radio.displayName = "NextUI.Radio";
export default Radio;

View File

@ -1,10 +1,11 @@
import type {AriaRadioProps} from "@react-types/radio";
import type {RadioVariantProps, RadioSlots, SlotsToClasses} from "@nextui-org/theme";
import {RadioVariantProps, RadioSlots, SlotsToClasses, radio} from "@nextui-org/theme";
import {Ref, ReactNode, useCallback} from "react";
import {useMemo, useRef} from "react";
import {useFocusRing} from "@react-aria/focus";
import {useHover} from "@react-aria/interactions";
import {radio} from "@nextui-org/theme";
import {useRadio as useReactAriaRadio} from "@react-aria/radio";
import {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {__DEV__, warn, clsx, dataAttr} from "@nextui-org/shared-utils";

View File

@ -14,7 +14,7 @@ import {
} from "../src";
export default {
title: "Inputs/RadioGroup",
title: "Components/RadioGroup",
component: RadioGroup,
onChange: {action: "changed"},
argTypes: {

View File

@ -1,5 +1,5 @@
import {forwardRef} from "@nextui-org/system";
import {clsx, __DEV__} from "@nextui-org/shared-utils";
import {clsx} from "@nextui-org/shared-utils";
import {Tooltip} from "@nextui-org/tooltip";
import {ReactNode, useCallback, useMemo} from "react";
@ -101,8 +101,6 @@ const Snippet = forwardRef<SnippetProps, "div">((props, ref) => {
);
});
if (__DEV__) {
Snippet.displayName = "NextUI.Snippet";
}
Snippet.displayName = "NextUI.Snippet";
export default Snippet;

View File

@ -5,7 +5,7 @@ import {snippet} from "@nextui-org/theme";
import {Snippet, SnippetProps} from "../src";
export default {
title: "Display/Snippet",
title: "Components/Snippet",
component: Snippet,
argTypes: {
variant: {

View File

@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
import {__DEV__} from "@nextui-org/shared-utils";
// import {StyledLoadingContainer, StyledLoading, StyledLoadingLabel} from "./loading.styles";
import {UseSpinnerProps, useSpinner} from "./use-spinner";
@ -18,8 +17,6 @@ const Spinner = forwardRef<SpinnerProps, "div">((props, ref) => {
);
});
if (__DEV__) {
Spinner.displayName = "NextUI.Loading";
}
Spinner.displayName = "NextUI.Loading";
export default Spinner;

View File

@ -5,7 +5,7 @@ import {spinner} from "@nextui-org/theme";
import {Spinner, SpinnerProps} from "../src";
export default {
title: "Feedback/Spinner",
title: "Components/Spinner",
component: Spinner,
argTypes: {
color: {

View File

@ -1,5 +1,5 @@
import {forwardRef} from "@nextui-org/system";
import {warn, __DEV__} from "@nextui-org/shared-utils";
import {warn} from "@nextui-org/shared-utils";
import {cloneElement, Children} from "react";
import {OverlayContainer} from "@react-aria/overlays";
import {CSSTransition} from "@nextui-org/react-utils";
@ -52,8 +52,6 @@ const Tooltip = forwardRef<TooltipProps, "div">((props, ref) => {
);
});
if (__DEV__) {
Tooltip.displayName = "NextUI.Tooltip";
}
Tooltip.displayName = "NextUI.Tooltip";
export default Tooltip;

View File

@ -6,7 +6,7 @@ import {Button} from "@nextui-org/button";
import {Tooltip, TooltipProps} from "../src";
export default {
title: "Display/Tooltip",
title: "Components/Tooltip",
component: Tooltip,
argTypes: {
variant: {

View File

@ -1,5 +1,4 @@
import {forwardRef} from "@nextui-org/system";
import {__DEV__} from "@nextui-org/shared-utils";
import {Avatar} from "@nextui-org/avatar";
import {UseUserProps, useUser} from "./use-user";
@ -23,8 +22,6 @@ const User = forwardRef<UserProps, "div">((props, ref) => {
);
});
if (__DEV__) {
User.displayName = "NextUI.User";
}
User.displayName = "NextUI.User";
export default User;

View File

@ -5,7 +5,7 @@ import {Link} from "@nextui-org/link";
import {User, UserProps} from "../src";
export default {
title: "Display/User",
title: "Components/User",
component: User,
} as ComponentMeta<typeof User>;

View File

@ -53,7 +53,7 @@
"lodash.foreach": "^4.5.0",
"lodash.get": "^4.4.2",
"lodash.isempty": "^4.4.0",
"tailwind-variants": "^0.0.30",
"tailwind-variants": "^0.0.31",
"tailwindcss": "^3.2.7"
},
"peerDependencies": {

View File

@ -1,16 +1,11 @@
import {commonColors} from "./common";
import {semanticColorsLight, semanticColorsDark} from "./semantic";
import {semanticColors} from "./semantic";
export * from "./types";
const colors = {
...commonColors,
light: {
...semanticColorsLight,
},
dark: {
...semanticColorsDark,
},
...semanticColors,
};
export {colors, commonColors, semanticColorsLight, semanticColorsDark};
export {colors, commonColors, semanticColors};

View File

@ -21,7 +21,7 @@ const chip = tv({
slots: {
base: ["relative", "max-w-fit", "inline-flex", "items-center", "justify-between", "box-border"],
content: "flex-1 text-inherit select-none font-regular",
dot: ["w-2", "h-2", "mx-1", "rounded-full"],
dot: ["w-2", "h-2", "ml-1", "rounded-full"],
avatar: "flex-shrink-0",
closeButton: [
"z-10",
@ -115,6 +115,12 @@ const chip = tv({
"3xl": {base: "rounded-3xl"},
full: {base: "rounded-full"},
},
hasLeftContent: {
true: {},
},
hasRightContent: {
true: {},
},
isOneChar: {
true: {
base: "px-0 justify-center",
@ -432,6 +438,36 @@ const chip = tv({
base: "w-8 h-8",
},
},
// hasLeftContent / size
{
hasLeftContent: true,
size: ["xs", "sm"],
class: {
content: "pl-0.5",
},
},
{
hasLeftContent: true,
size: ["md", "lg", "xl"],
class: {
content: "pl-1",
},
},
// hasRightContent / size
{
hasRightContent: true,
size: ["xs", "sm"],
class: {
content: "pr-0.5",
},
},
{
hasRightContent: true,
size: ["md", "lg", "xl"],
class: {
content: "pr-1",
},
},
],
});

View File

@ -15,3 +15,4 @@ export * from "./checkbox";
export * from "./checkbox-group";
export * from "./radio";
export * from "./radio-group";
export * from "./pagination";

View File

@ -0,0 +1,138 @@
import {tv, type VariantProps} from "tailwind-variants";
import {ringClasses} from "../utils";
/**
* Pagination wrapper **Tailwind Variants** component
*
* const {base, item, cursor} = pagination({...})
*
* @example
* <ul className={base()} aria-label="pagination navigation">
* <li className={cursor()} aria-hidden="true"/> // this marks the active page
* <li role="button" className={item()} aria-label="Go to previous page" data-disabled="true">Prev</li>
* <li role="button" className={item()} aria-label="page 1" data-active="true">1</li>
* <li role="button" className={item()} aria-label="page 2">2</li>
* <li role="button" className={item()} aria-hidden="true">...</li>
* <li role="button" className={item()} aria-label="page 10">10</li>
* <li role="button" className={item()} aria-label="Go to next page">Next</li>
* </ul>
*/
const pagination = tv({
slots: {
base: "flex gap-1",
item: [
"flex",
"items-center",
"justify-center",
"bg-neutral-100",
"hover:bg-neutral-200",
"text-neutral-contrastText",
],
cursor: "",
},
variants: {
variant: {
solid: {},
bordered: {
item: "border-1.5 !bg-transparent",
},
light: {
item: "!bg-transparent",
},
flat: {},
faded: {
item: "border-1.5",
},
shadow: {},
},
color: {
neutral: {},
primary: {},
secondary: {},
success: {},
warning: {},
danger: {},
},
size: {
xs: {
item: "w-7 h-7 text-xs",
},
sm: {
item: "w-8 h-8 text-sm",
},
md: {
item: "w-9 h-9 text-sm",
},
lg: {
item: "w-10 h-10 text-base",
},
xl: {
item: "w-11 h-11 text-lg",
},
},
radius: {
none: {
item: "rounded-none",
},
base: {
item: "rounded",
},
sm: {
item: "rounded-sm",
},
md: {
item: "rounded-md",
},
lg: {
item: "rounded-lg",
},
xl: {
item: "rounded-xl",
},
full: {
item: "rounded-full",
},
},
isEven: {
true: {
base: "gap-0",
item: [
"first:rounded-r-none",
"last:rounded-l-none",
"[&:not(:first-child):not(:last-child)]:rounded-none",
],
},
},
isDisabled: {
true: {
base: "opacity-50 pointer-events-none",
},
},
isFocusVisible: {
true: {
wrapper: [...ringClasses],
},
},
disableAnimation: {
true: {},
false: {
item: "transition-background",
},
},
},
defaultVariants: {
variant: "solid",
color: "primary",
size: "md",
radius: "xl",
isEven: false,
isDisabled: false,
disableAnimation: false,
},
});
export type PaginationVariantProps = VariantProps<typeof pagination>;
export type PaginationSlots = keyof ReturnType<typeof pagination>;
export {pagination};

View File

@ -2,5 +2,5 @@ export * from "./components";
export * from "./utils";
export * from "./colors";
export {tv} from "tailwind-variants";
export {tv, cx as tvCx, cxBase as cx} from "tailwind-variants";
export type {VariantProps} from "tailwind-variants";

View File

@ -1,4 +1,4 @@
import {ClassValue} from "tailwind-variants/utils";
import {ClassValue} from "tailwind-variants";
/**
* This Typescript utility transform a list of slots into a list of {slot: classes}

1
packages/storybook/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.vercel

View File

@ -1,5 +1,6 @@
module.exports = {
stories: [
'./welcome.stories.mdx', // default page
"../../core/theme/stories/*.stories.@(js|jsx|ts|tsx)",
"../../components/link/stories/*.stories.@(js|jsx|ts|tsx)",
"../../components/avatar/stories/*.stories.@(js|jsx|ts|tsx)",
@ -13,6 +14,7 @@ module.exports = {
"../../components/badge/stories/*.stories.@(js|jsx|ts|tsx)",
"../../components/checkbox/stories/*.stories.@(js|jsx|ts|tsx)",
"../../components/radio/stories/*.stories.@(js|jsx|ts|tsx)",
"../../components/pagination/stories/*.stories.@(js|jsx|ts|tsx)",
],
staticDirs: ["../public"],
addons: [

View File

@ -1,4 +1,6 @@
import {themes} from "@storybook/theming";
import React from 'react';
import addons from '@storybook/addons';
import { themes } from '@storybook/theming';
import Style from "./style";
export const decorators = [
@ -11,6 +13,7 @@ export const decorators = [
];
export const parameters = {
viewMode: 'docs',
actions: {argTypesRegex: "^on[A-Z].*"},
controls: {
matchers: {

View File

@ -1,3 +1,73 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
h1 {
@apply text-4xl font-bold !text-foreground;
}
h2 {
@apply text-2xl font-bold !text-foreground !border-none;
}
h3 {
@apply text-xl font-bold !text-neutral-600;
}
.dark .sbdocs-wrapper, .dark .sbdocs-preview {
background-color: #000000;
color: #fff;
}
.dark .sbdocs-preview {
border: 1px solid #292929;
}
.dark .docblock-code-toggle {
background: transparent;
color: #d4d4d4;
}
.dark div:has(.docblock-code-toggle) {
background: transparent;
}
.dark .os-theme-dark {
background: #161616;
color: #fff;
}
.dark .sbdocs-title {
color: #fff;
}
.dark .docblock-argstable-head {
background: #161616;
}
.dark .docblock-argstable-head th {
color: #bcbcbc;
border-bottom: 1px solid #292929 !important;
}
.dark .docblock-argstable-head th span {
color: #bcbcbc;
}
.dark tbody td {
background: #161616 !important;
color: #bcbcbc !important;
}
.dark tbody tr:first-child td:first-child {
border-top-left-radius: 0 !important;
}
.dark tbody tr:first-child td:last-child {
border-top-right-radius: 0 !important;
}
.dark tbody tr:not(:first-child) {
border-top: 1px solid #292929 !important;
}

View File

@ -0,0 +1,141 @@
import {Meta, Story} from "@storybook/addon-docs";
import {link, button} from "@nextui-org/theme";
<Meta title="Welcome" />
<br />
# Welcome 👋🏼
<br />
## NextUI Version 2 - Design system
<br />
<p className="text-md text-neutral-600 max-w-xl">
Here you can find the guidelines, components APIs and examples to help you build your next project
with NextUI. This version is still in development, so some components are not yet available. You
can follow the progress in the{" "}
<a
href="https://github.com/orgs/nextui-org/projects/2/views/1?pane=issue&itemId=20037976"
target="_blank"
className={link()}
>
project board
</a>
.
</p>
<div className="flex flex-row justify-start items-center mt-8 gap-4">
<a
href="https://nextui.org"
target="_blank"
className={button({
color: "primary",
variant: "flat",
className: "gap-1",
})}
>
Website (v1)
<svg
aria-hidden="true"
className="flex text-current self-center"
fill="none"
height="1em"
shapeRendering="geometricPrecision"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
viewBox="0 0 24 24"
width="1em"
>
<path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" />
<path d="M15 3h6v6" />
<path d="M10 14L21 3" />
</svg>
</a>
<a
href="https://github.com/nextui-org/nextui"
target="_blank"
className={button({
color: "neutral",
variant: "bordered",
className: "gap-1",
})}
>
Github
<svg
aria-hidden="true"
className="flex text-current self-center"
fill="none"
height="1em"
shapeRendering="geometricPrecision"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
viewBox="0 0 24 24"
width="1em"
>
<path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" />
<path d="M15 3h6v6" />
<path d="M10 14L21 3" />
</svg>
</a>
<a
href="https://discord.gg/9b6yyZKmH4"
target="_blank"
className={button({
color: "neutral",
variant: "bordered",
className: "gap-1",
})}
>
Discord
<svg
aria-hidden="true"
className="flex text-current self-center"
fill="none"
height="1em"
shapeRendering="geometricPrecision"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
viewBox="0 0 24 24"
width="1em"
>
<path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" />
<path d="M15 3h6v6" />
<path d="M10 14L21 3" />
</svg>
</a>
</div>
<div className="mt-8 flex items-center gap-2">
<svg width="30" height="30" viewBox="0 0 374 374" >
<g transform="translate(-773 -353)">
<rect width="374" height="374" rx="99" transform="translate(773 353)" fill="currentColor"/>
<path d="M127.309-159.273h14.543V-53.817a55.656,55.656,0,0,1-7.621,29.047A54.131,54.131,0,0,1,113.039-4.627Q99.468,2.722,81.5,2.722q-17.887,0-31.5-7.388A54.429,54.429,0,0,1,28.775-24.809a55.451,55.451,0,0,1-7.621-29.008V-159.273H35.7V-54.828a44.65,44.65,0,0,0,5.677,22.592A40.568,40.568,0,0,0,57.355-16.643q10.3,5.677,24.148,5.677t24.186-5.677a40.232,40.232,0,0,0,15.982-15.593,44.893,44.893,0,0,0,5.638-22.592Zm71.393,0V0H184.159V-159.273Z" transform="translate(851 620)" fill="currentColor" className="text-background"/>
</g>
</svg>
<svg
height="24.48"
viewBox="0 0 100 24.48"
width="100"
>
<path fill="currentColor" d="M18.745 0v24.069h-2.139L2.386 3.914h-.188v20.155H0V0h2.127l14.267 20.179h.188V0zm13.256 24.445a7.934 7.934 0 01-4.371-1.181 7.79 7.79 0 01-2.85-3.279 11.069 11.069 0 01-1-4.836 11.2 11.2 0 011-4.848 8.1 8.1 0 012.785-3.326 7.175 7.175 0 014.119-1.2 7.689 7.689 0 012.832.535 7.042 7.042 0 012.45 1.634 7.836 7.836 0 011.722 2.756 11.015 11.015 0 01.635 3.931v1.034h-12.1V13.82h9.963a6.882 6.882 0 00-.7-3.132 5.55 5.55 0 00-1.939-2.2 5.11 5.11 0 00-2.862-.811 5.121 5.121 0 00-3.02.917 6.251 6.251 0 00-2.039 2.421 7.513 7.513 0 00-.746 3.291v1.1a8.822 8.822 0 00.746 3.755 5.751 5.751 0 002.124 2.487 5.9 5.9 0 003.255.881 5.873 5.873 0 002.251-.4 4.843 4.843 0 001.634-1.075 4.729 4.729 0 001-1.487l1.986.646a5.885 5.885 0 01-1.346 2.1 6.889 6.889 0 01-2.327 1.545 8.251 8.251 0 01-3.202.587zm12.74-18.428l4.654 7.7 4.654-7.7h2.433l-5.806 9.026 5.806 9.026H54.05l-4.654-7.451-4.655 7.451H42.32l5.735-9.026-5.735-9.026zm23.246 0v1.822h-8.615V6.017zm-5.923-4.325h2.1v17.664a3.414 3.414 0 00.388 1.769 2.159 2.159 0 001.011.9 3.363 3.363 0 001.328.264 4.045 4.045 0 00.705-.053q.294-.053.517-.112l.447 1.892a5.433 5.433 0 01-.752.217 5.162 5.162 0 01-1.1.1 5.1 5.1 0 01-2.215-.505 4.337 4.337 0 01-1.743-1.499 4.3 4.3 0 01-.682-2.48zM89.211 0h2.2v15.936a8.411 8.411 0 01-1.152 4.389 8.18 8.18 0 01-3.2 3.044 9.854 9.854 0 01-4.77 1.111 9.82 9.82 0 01-4.76-1.116 8.225 8.225 0 01-3.208-3.044 8.379 8.379 0 01-1.152-4.384V0h2.2v15.783a6.747 6.747 0 00.858 3.414 6.13 6.13 0 002.415 2.356 7.444 7.444 0 003.649.858 7.478 7.478 0 003.655-.858 6.08 6.08 0 002.413-2.353 6.784 6.784 0 00.852-3.414zM100 0v24.069h-2.2V0z" />
</svg>
</div>
<br/>
<div class="block text-xs text-neutral-400">
Last updated on <time datetime="2023-03-07">March 7, 2023</time>
</div>

View File

@ -31,7 +31,7 @@
"build:storybook": "build-storybook build",
"watch:css": "npx tailwindcss -i ./.storybook/style.css -o ./public/tailwind.css --watch",
"watch:storybook": "start-storybook dev -p 6006",
"start:storybook": "pnpx serve storybook-static"
"start:storybook": "pnpx http-server storybook-static"
},
"dependencies": {
"@nextui-org/theme": "workspace:*"

View File

@ -3,6 +3,7 @@ const {nextui} = require("@nextui-org/theme/plugin");
// /** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./.storybook/welcome.stories.mdx",
"../components/**/src/**/*.{js,jsx,ts,tsx}",
"../components/**/stories/**/*.{js,jsx,ts,tsx}",
"../core/theme/src/components/**/*.{js,jsx,ts,tsx}",

643
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff