refactor: add support for disabling the animation globally (#2929)

* refactor: add support for disabling the animation globally

* chore(docs): disableAnimation removed from global provider

* feat(docs): nextui provider api updated, storybook preview adjusted

* chore(theme): button is scalable when disabled, tooltip animation improved
This commit is contained in:
Junior Garcia 2024-05-12 23:13:54 -03:00 committed by GitHub
parent e34c5e307d
commit 422770cc6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
106 changed files with 633 additions and 286 deletions

View File

@ -0,0 +1,40 @@
---
"@nextui-org/accordion": patch
"@nextui-org/autocomplete": patch
"@nextui-org/avatar": patch
"@nextui-org/badge": patch
"@nextui-org/breadcrumbs": patch
"@nextui-org/button": patch
"@nextui-org/calendar": patch
"@nextui-org/card": patch
"@nextui-org/checkbox": patch
"@nextui-org/date-input": patch
"@nextui-org/date-picker": patch
"@nextui-org/dropdown": patch
"@nextui-org/image": patch
"@nextui-org/input": patch
"@nextui-org/link": patch
"@nextui-org/listbox": patch
"@nextui-org/menu": patch
"@nextui-org/modal": patch
"@nextui-org/navbar": patch
"@nextui-org/pagination": patch
"@nextui-org/popover": patch
"@nextui-org/progress": patch
"@nextui-org/radio": patch
"@nextui-org/ripple": patch
"@nextui-org/select": patch
"@nextui-org/skeleton": patch
"@nextui-org/slider": patch
"@nextui-org/snippet": patch
"@nextui-org/switch": patch
"@nextui-org/table": patch
"@nextui-org/tabs": patch
"@nextui-org/tooltip": patch
"@nextui-org/react": patch
"@nextui-org/system": patch
"@nextui-org/theme": patch
"@nextui-org/framer-utils": patch
---
Add support for disabling the animations globally.

View File

@ -154,7 +154,8 @@
"key": "badge",
"title": "Badge",
"keywords": "badge, markers, status indication, count display",
"path": "/docs/components/badge.mdx"
"path": "/docs/components/badge.mdx",
"updated": true
},
{
"key": "button",
@ -334,7 +335,8 @@
"key": "skeleton",
"title": "Skeleton",
"keywords": "skeleton, loading state, placeholder, content preview",
"path": "/docs/components/skeleton.mdx"
"path": "/docs/components/skeleton.mdx",
"updated": true
},
{
"key": "snippet",

View File

@ -9,7 +9,7 @@ import {badgeContent} from "@/content/components/badge";
Badges are used as a small numerical value or status descriptor for UI elements.
<ComponentLinks component="badge" rscCompatible />
<ComponentLinks component="badge" />
---

View File

@ -9,7 +9,7 @@ import {skeletonContent} from "@/content/components/skeleton";
Skeleton is a placeholder to show a loading state and the expected shape of a component.
<ComponentLinks component="skeleton" rscCompatible />
<ComponentLinks component="skeleton" />
---

View File

@ -42,7 +42,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},

View File

@ -1,4 +1,4 @@
import {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {HTMLNextUIProps, PropGetter, useProviderContext} from "@nextui-org/system";
import {useFocusRing} from "@react-aria/focus";
import {accordionItem} from "@nextui-org/theme";
import {clsx, callAllHandlers, dataAttr, objectToDeps} from "@nextui-org/shared-utils";
@ -39,6 +39,8 @@ export type UseAccordionItemProps<T extends object = {}> = Props<T> &
Omit<AccordionItemBaseProps, "onFocusChange">;
export function useAccordionItem<T extends object = {}>(props: UseAccordionItemProps<T>) {
const globalContext = useProviderContext();
const {ref, as, item, onFocusChange} = props;
const {
@ -55,7 +57,7 @@ export function useAccordionItem<T extends object = {}>(props: UseAccordionItemP
classNames: classNamesProp = {},
isDisabled: isDisabledProp = false,
hideIndicator = false,
disableAnimation = false,
disableAnimation = globalContext?.disableAnimation ?? false,
keepContentMounted = false,
disableIndicatorAnimation = false,
HeadingComponent = as || "h2",

View File

@ -1,8 +1,8 @@
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import type {SelectionBehavior, MultipleSelection} from "@react-types/shared";
import type {AriaAccordionProps} from "@react-types/accordion";
import type {AccordionGroupVariantProps} from "@nextui-org/theme";
import {useProviderContext, type HTMLNextUIProps, type PropGetter} from "@nextui-org/system";
import {ReactRef, filterDOMProps} from "@nextui-org/react-utils";
import React, {Key, useCallback} from "react";
import {TreeState, useTreeState} from "@react-stately/tree";
@ -73,6 +73,8 @@ export type ValuesType<T extends object = {}> = {
};
export function useAccordion<T extends object>(props: UseAccordionProps<T>) {
const globalContext = useProviderContext();
const {
ref,
as,
@ -97,7 +99,7 @@ export function useAccordion<T extends object>(props: UseAccordionProps<T>) {
isDisabled = false,
showDivider = true,
hideIndicator = false,
disableAnimation = false,
disableAnimation = globalContext?.disableAnimation ?? false,
disableIndicatorAnimation = false,
itemClasses,
...otherProps

View File

@ -36,7 +36,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},

View File

@ -1,6 +1,7 @@
import type {AutocompleteVariantProps, SlotsToClasses, AutocompleteSlots} from "@nextui-org/theme";
import type {DOMAttributes, HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {DOMAttributes, HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {mapPropsVariants, useProviderContext} from "@nextui-org/system";
import {useSafeLayoutEffect} from "@nextui-org/use-safe-layout-effect";
import {autocomplete} from "@nextui-org/theme";
import {useFilter} from "@react-aria/i18n";
@ -120,8 +121,11 @@ export type UseAutocompleteProps<T> = Props<T> &
AutocompleteVariantProps;
export function useAutocomplete<T extends object>(originalProps: UseAutocompleteProps<T>) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, autocomplete.variantKeys);
const disableAnimation = originalProps.disableAnimation ?? false;
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
// TODO: Remove disableClearable prop in the next minor release.
const isClearable =

View File

@ -1,7 +1,7 @@
import type {AvatarSlots, AvatarVariantProps, SlotsToClasses} from "@nextui-org/theme";
import {avatar} from "@nextui-org/theme";
import {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {HTMLNextUIProps, PropGetter, useProviderContext} from "@nextui-org/system";
import {mergeProps} from "@react-aria/utils";
import {useDOMRef} from "@nextui-org/react-utils";
import {clsx, safeText, dataAttr} from "@nextui-org/shared-utils";
@ -96,7 +96,8 @@ interface Props extends HTMLNextUIProps<"span"> {
export type UseAvatarProps = Props &
Omit<AvatarVariantProps, "children" | "isInGroup" | "isInGridGroup">;
export function useAvatar(props: UseAvatarProps = {}) {
export function useAvatar(originalProps: UseAvatarProps = {}) {
const globalContext = useProviderContext();
const groupContext = useAvatarGroupContext();
const isInGroup = !!groupContext;
@ -124,7 +125,7 @@ export function useAvatar(props: UseAvatarProps = {}) {
className,
onError,
...otherProps
} = props;
} = originalProps;
const Component = as || "span";
@ -133,6 +134,8 @@ export function useAvatar(props: UseAvatarProps = {}) {
const {isFocusVisible, isFocused, focusProps} = useFocusRing();
const {isHovered, hoverProps} = useHover({isDisabled});
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const imageStatus = useImage({src, onError, ignoreFallback});
@ -156,9 +159,19 @@ export function useAvatar(props: UseAvatarProps = {}) {
isBordered,
isDisabled,
isInGroup,
disableAnimation,
isInGridGroup: groupContext?.isGrid ?? false,
}),
[color, radius, size, isBordered, isDisabled, isInGroup, groupContext?.isGrid],
[
color,
radius,
size,
isBordered,
isDisabled,
disableAnimation,
isInGroup,
groupContext?.isGrid,
],
);
const baseStyles = clsx(classNames?.base, className);
@ -186,11 +199,12 @@ export function useAvatar(props: UseAvatarProps = {}) {
(props = {}) => ({
ref: imgRef,
src: src,
disableAnimation,
"data-loaded": dataAttr(isImgLoaded),
className: slots.img({class: classNames?.img}),
...mergeProps(imgProps, props),
}),
[slots, isImgLoaded, imgProps, src, imgRef],
[slots, isImgLoaded, imgProps, disableAnimation, src, imgRef],
);
return {

View File

@ -36,14 +36,15 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"@nextui-org/theme": ">=2.1.0"
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},
"dependencies": {
"@nextui-org/system-rsc": "workspace:*",
"@nextui-org/shared-utils": "workspace:*",
"@nextui-org/react-utils": "workspace:*"
},
"devDependencies": {
"@nextui-org/system": "workspace:*",
"@nextui-org/theme": "workspace:*",
"@nextui-org/avatar": "workspace:*",
"@nextui-org/shared-icons": "workspace:*",

View File

@ -1,4 +1,4 @@
import {forwardRef} from "@nextui-org/system-rsc";
import {forwardRef} from "@nextui-org/system";
import {UseBadgeProps, useBadge} from "./use-badge";

View File

@ -1,9 +1,9 @@
import type {BadgeSlots, BadgeVariantProps, SlotsToClasses} from "@nextui-org/theme";
import type {ReactNode} from "react";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system-rsc";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {badge} from "@nextui-org/theme";
import {mapPropsVariants} from "@nextui-org/system-rsc";
import {mapPropsVariants, useProviderContext} from "@nextui-org/system";
import {clsx, objectToDeps} from "@nextui-org/shared-utils";
import {ReactRef} from "@nextui-org/react-utils";
import {useMemo} from "react";
@ -45,6 +45,10 @@ interface Props extends HTMLNextUIProps<"span", "content"> {
export type UseBadgeProps = Props & BadgeVariantProps;
export function useBadge(originalProps: UseBadgeProps) {
const globalContext = useProviderContext();
const disableAnimation =
originalProps?.disableAnimation ?? globalContext?.disableAnimation ?? false;
const [props, variantProps] = mapPropsVariants(originalProps, badge.variantKeys);
const {as, children, className, content, classNames, ...otherProps} = props;
@ -87,7 +91,7 @@ export function useBadge(originalProps: UseBadgeProps) {
content,
slots,
classNames,
disableAnimation: originalProps?.disableAnimation,
disableAnimation,
isInvisible: originalProps?.isInvisible,
getBadgeProps,
};

View File

@ -4,4 +4,5 @@ export default defineConfig({
clean: true,
target: "es2019",
format: ["cjs", "esm"],
banner: {js: '"use client";'},
});

View File

@ -2,7 +2,12 @@ import type {BreadcrumbsVariantProps, SlotsToClasses, BreadcrumbsSlots} from "@n
import type {AriaBreadcrumbsProps} from "@react-types/breadcrumbs";
import {Children, ReactNode, Key, ReactElement} from "react";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {breadcrumbs} from "@nextui-org/theme";
import {filterDOMProps, pickChildren, ReactRef, useDOMRef} from "@nextui-org/react-utils";
import {mergeProps} from "@react-aria/utils";
@ -103,6 +108,11 @@ export type UseBreadcrumbsProps = Props &
>;
export function useBreadcrumbs(originalProps: UseBreadcrumbsProps) {
const globalContext = useProviderContext();
const disableAnimation =
originalProps?.disableAnimation ?? globalContext?.disableAnimation ?? false;
const [props, variantProps] = mapPropsVariants(originalProps, breadcrumbs.variantKeys);
const {
@ -117,7 +127,6 @@ export function useBreadcrumbs(originalProps: UseBreadcrumbsProps) {
itemsAfterCollapse = 2,
maxItems = 8,
hideSeparator,
disableAnimation,
renderEllipsis,
className,
classNames,

View File

@ -36,7 +36,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},

View File

@ -3,7 +3,12 @@ import type {ReactRef} from "@nextui-org/react-utils";
import type {ButtonGroupVariantProps} from "@nextui-org/theme";
import {buttonGroup} from "@nextui-org/theme";
import {HTMLNextUIProps, PropGetter, mapPropsVariants} from "@nextui-org/system";
import {
HTMLNextUIProps,
PropGetter,
mapPropsVariants,
useProviderContext,
} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/react-utils";
import {useMemo, useCallback} from "react";
import {objectToDeps} from "@nextui-org/shared-utils";
@ -40,6 +45,7 @@ export type UseButtonGroupProps = Props &
>;
export function useButtonGroup(originalProps: UseButtonGroupProps) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, buttonGroup.variantKeys);
const {
@ -51,9 +57,9 @@ export function useButtonGroup(originalProps: UseButtonGroupProps) {
variant = "solid",
radius,
isDisabled = false,
disableAnimation = false,
disableRipple = false,
isIconOnly = false,
disableRipple = globalContext?.disableRipple ?? false,
disableAnimation = globalContext?.disableAnimation ?? false,
className,
...otherProps
} = props;

View File

@ -1,9 +1,9 @@
import type {ButtonVariantProps} from "@nextui-org/theme";
import type {AriaButtonProps} from "@nextui-org/use-aria-button";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import type {ReactNode} from "react";
import type {RippleProps} from "@nextui-org/ripple";
import {useProviderContext, type HTMLNextUIProps, type PropGetter} from "@nextui-org/system";
import {dataAttr} from "@nextui-org/shared-utils";
import {ReactRef} from "@nextui-org/react-utils";
import {MouseEventHandler, useCallback} from "react";
@ -65,6 +65,7 @@ export type UseButtonProps = Props &
export function useButton(props: UseButtonProps) {
const groupContext = useButtonGroupContext();
const globalContext = useProviderContext();
const isInGroup = !!groupContext;
const {
@ -76,16 +77,16 @@ export function useButton(props: UseButtonProps) {
autoFocus,
className,
spinner,
isLoading = false,
disableRipple: disableRippleProp = false,
fullWidth = groupContext?.fullWidth ?? false,
radius = groupContext?.radius,
size = groupContext?.size ?? "md",
color = groupContext?.color ?? "default",
variant = groupContext?.variant ?? "solid",
disableAnimation = groupContext?.disableAnimation ?? false,
radius = groupContext?.radius,
disableRipple = groupContext?.disableRipple ?? false,
disableAnimation = groupContext?.disableAnimation ?? globalContext?.disableAnimation ?? false,
isDisabled: isDisabledProp = groupContext?.isDisabled ?? false,
isIconOnly = groupContext?.isIconOnly ?? false,
isLoading = false,
spinnerPlacement = "start",
onPress,
onClick,
@ -97,6 +98,8 @@ export function useButton(props: UseButtonProps) {
const domRef = useDOMRef(ref);
const disableRipple = (disableRippleProp || globalContext?.disableRipple) ?? disableAnimation;
const {isFocusVisible, isFocused, focusProps} = useFocusRing({
autoFocus,
});

View File

@ -10,7 +10,7 @@ import type {CalendarState, RangeCalendarState} from "@react-stately/calendar";
import type {RefObject, ReactNode} from "react";
import {Calendar, CalendarDate} from "@internationalized/date";
import {mapPropsVariants} from "@nextui-org/system";
import {mapPropsVariants, useProviderContext} from "@nextui-org/system";
import {useCallback, useMemo} from "react";
import {calendar} from "@nextui-org/theme";
import {useControlledState} from "@react-stately/utils";
@ -18,7 +18,6 @@ import {ReactRef, useDOMRef} from "@nextui-org/react-utils";
import {useLocale} from "@react-aria/i18n";
import {clamp, dataAttr, objectToDeps} from "@nextui-org/shared-utils";
import {mergeProps} from "@react-aria/utils";
import {useProviderContext} from "@nextui-org/system";
type NextUIBaseProps = Omit<HTMLNextUIProps<"div">, keyof AriaCalendarPropsBase | "onChange">;
@ -182,7 +181,7 @@ export type ContextType<T extends CalendarState | RangeCalendarState> = {
export function useCalendarBase(originalProps: UseCalendarBasePropsComplete) {
const [props, variantProps] = mapPropsVariants(originalProps, calendar.variantKeys);
const providerContext = useProviderContext();
const globalContext = useProviderContext();
const {
ref,
@ -199,9 +198,9 @@ export function useCalendarBase(originalProps: UseCalendarBasePropsComplete) {
isHeaderExpanded: isHeaderExpandedProp,
isHeaderDefaultExpanded,
onHeaderExpandedChange = () => {},
minValue = providerContext?.defaultDates?.minDate ?? new CalendarDate(1900, 1, 1),
maxValue = providerContext?.defaultDates?.maxDate ?? new CalendarDate(2099, 12, 31),
createCalendar: createCalendarProp = providerContext?.createCalendar ?? null,
minValue = globalContext?.defaultDates?.minDate ?? new CalendarDate(1900, 1, 1),
maxValue = globalContext?.defaultDates?.maxDate ?? new CalendarDate(2099, 12, 31),
createCalendar: createCalendarProp = globalContext?.createCalendar ?? null,
prevButtonProps: prevButtonPropsProp,
nextButtonProps: nextButtonPropsProp,
errorMessage,
@ -254,7 +253,8 @@ export function useCalendarBase(originalProps: UseCalendarBasePropsComplete) {
[objectToDeps(variantProps), showMonthAndYearPickers, isHeaderExpanded, className],
);
const disableAnimation = originalProps.disableAnimation ?? false;
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const commonButtonProps: ButtonProps = {
size: "sm",
@ -317,6 +317,7 @@ export function useCalendarBase(originalProps: UseCalendarBasePropsComplete) {
shouldFilterDOMProps,
isHeaderExpanded,
showMonthAndYearPickers,
disableAnimation,
createCalendar: createCalendarProp,
getPrevButtonProps,
getNextButtonProps,

View File

@ -39,6 +39,7 @@ export function useCalendar<T extends DateValue>({
weekdayStyle,
visibleDuration,
baseProps,
disableAnimation,
shouldFilterDOMProps,
isHeaderExpanded,
visibleMonths,
@ -73,7 +74,6 @@ export function useCalendar<T extends DateValue>({
useAriaCalendar(originalProps, state);
const baseStyles = clsx(classNames?.base, className);
const disableAnimation = originalProps.disableAnimation ?? false;
const buttonPickerProps: ButtonProps = {
...buttonPickerPropsProp,

View File

@ -39,6 +39,7 @@ export function useRangeCalendar<T extends DateValue>({
shouldFilterDOMProps,
isHeaderExpanded,
visibleMonths,
disableAnimation,
createCalendar: createCalendarProp,
baseProps,
getPrevButtonProps,
@ -70,7 +71,6 @@ export function useRangeCalendar<T extends DateValue>({
useAriaRangeCalendar(originalProps, state, domRef);
const baseStyles = clsx(classNames?.base, className);
const disableAnimation = originalProps.disableAnimation ?? false;
const getBaseCalendarProps = (props = {}): CalendarBaseProps => {
return {

View File

@ -36,7 +36,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},

View File

@ -9,7 +9,12 @@ import {chain, mergeProps} from "@react-aria/utils";
import {useFocusRing} from "@react-aria/focus";
import {useHover} from "@react-aria/interactions";
import {useAriaButton} from "@nextui-org/use-aria-button";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils";
import {ReactRef, filterDOMProps} from "@nextui-org/react-utils";
import {useDOMRef} from "@nextui-org/react-utils";
@ -64,13 +69,14 @@ export type ContextType = {
};
export function useCard(originalProps: UseCardProps) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, card.variantKeys);
const {
ref,
as,
children,
disableRipple = false,
onClick,
onPress,
autoFocus,
@ -84,12 +90,16 @@ export function useCard(originalProps: UseCardProps) {
const Component = as || (originalProps.isPressable ? "button" : "div");
const shouldFilterDOMProps = typeof Component === "string";
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const disableRipple = originalProps.disableRipple ?? globalContext?.disableRipple ?? false;
const baseStyles = clsx(classNames?.base, className);
const {onClick: onRippleClickHandler, onClear: onClearRipple, ripples} = useRipple();
const handleClick = (e: MouseEvent<HTMLDivElement>) => {
if (!originalProps.disableAnimation && !disableRipple && domRef.current) {
if (!disableAnimation && !disableRipple && domRef.current) {
onRippleClickHandler(e);
}
};
@ -119,25 +129,26 @@ export function useCard(originalProps: UseCardProps) {
() =>
card({
...variantProps,
disableAnimation,
}),
[objectToDeps(variantProps)],
[objectToDeps(variantProps), disableAnimation],
);
const context = useMemo<ContextType>(
() => ({
isDisabled: originalProps.isDisabled,
isFooterBlurred: originalProps.isFooterBlurred,
disableAnimation: originalProps.disableAnimation,
fullWidth: originalProps.fullWidth,
slots,
classNames,
disableAnimation,
isDisabled: originalProps.isDisabled,
isFooterBlurred: originalProps.isFooterBlurred,
fullWidth: originalProps.fullWidth,
}),
[
slots,
classNames,
originalProps.isDisabled,
originalProps.isFooterBlurred,
originalProps.disableAnimation,
disableAnimation,
originalProps.fullWidth,
],
);
@ -194,9 +205,9 @@ export function useCard(originalProps: UseCardProps) {
children,
isHovered,
isPressed,
disableAnimation,
isPressable: originalProps.isPressable,
isHoverable: originalProps.isHoverable,
disableAnimation: originalProps.disableAnimation,
disableRipple,
handleClick,
isFocusVisible,

View File

@ -1,10 +1,10 @@
import type {CheckboxGroupSlots, SlotsToClasses} from "@nextui-org/theme";
import type {AriaCheckboxGroupProps} from "@react-types/checkbox";
import type {Orientation} from "@react-types/shared";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import type {ReactRef} from "@nextui-org/react-utils";
import type {CheckboxGroupProps} from "@react-types/checkbox";
import {useProviderContext, type HTMLNextUIProps, type PropGetter} from "@nextui-org/system";
import {useCallback, useMemo} from "react";
import {chain, mergeProps} from "@react-aria/utils";
import {checkboxGroup} from "@nextui-org/theme";
@ -68,6 +68,8 @@ export type ContextType = {
};
export function useCheckboxGroup(props: UseCheckboxGroupProps) {
const globalContext = useProviderContext();
const {
as,
ref,
@ -85,7 +87,7 @@ export function useCheckboxGroup(props: UseCheckboxGroupProps) {
orientation = "vertical",
lineThrough = false,
isDisabled = false,
disableAnimation = false,
disableAnimation = globalContext?.disableAnimation ?? false,
isReadOnly,
isRequired,
onValueChange,

View File

@ -1,7 +1,7 @@
import type {CheckboxVariantProps, CheckboxSlots, SlotsToClasses} from "@nextui-org/theme";
import type {AriaCheckboxProps} from "@react-types/checkbox";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {useProviderContext, type HTMLNextUIProps, type PropGetter} from "@nextui-org/system";
import {ReactNode, Ref, useCallback, useId, useState} from "react";
import {useMemo, useRef} from "react";
import {useToggleState} from "@react-stately/toggle";
@ -72,6 +72,7 @@ export type UseCheckboxProps = Omit<Props, "defaultChecked"> &
CheckboxVariantProps;
export function useCheckbox(props: UseCheckboxProps = {}) {
const globalContext = useProviderContext();
const groupContext = useCheckboxGroupContext();
const isInGroup = !!groupContext;
@ -92,7 +93,7 @@ export function useCheckbox(props: UseCheckboxProps = {}) {
radius = groupContext?.radius,
lineThrough = groupContext?.lineThrough ?? false,
isDisabled: isDisabledProp = groupContext?.isDisabled ?? false,
disableAnimation = groupContext?.disableAnimation ?? false,
disableAnimation = groupContext?.disableAnimation ?? globalContext?.disableAnimation ?? false,
isInvalid = validationState ? validationState === "invalid" : groupContext?.isInvalid ?? false,
isIndeterminate = false,
defaultSelected,
@ -334,9 +335,9 @@ export function useCheckbox(props: UseCheckboxProps = {}) {
const getIconProps = useCallback(
() =>
({
isSelected: isSelected,
isIndeterminate: !!isIndeterminate,
disableAnimation: !!disableAnimation,
isSelected,
isIndeterminate,
disableAnimation,
className: slots.icon({class: classNames?.icon}),
} as CheckboxIconProps),
[slots, classNames?.icon, isSelected, isIndeterminate, disableAnimation],

View File

@ -112,9 +112,9 @@ export type UseDateInputProps<T extends DateValue> = Props<T> &
AriaDateFieldProps<T>;
export function useDateInput<T extends DateValue>(originalProps: UseDateInputProps<T>) {
const [props, variantProps] = mapPropsVariants(originalProps, dateInput.variantKeys);
const globalContext = useProviderContext();
const providerContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, dateInput.variantKeys);
const {
ref,
@ -134,9 +134,9 @@ export function useDateInput<T extends DateValue>(originalProps: UseDateInputPro
descriptionProps: descriptionPropsProp,
validationBehavior,
shouldForceLeadingZeros = true,
minValue = providerContext?.defaultDates?.minDate ?? new CalendarDate(1900, 1, 1),
maxValue = providerContext?.defaultDates?.maxDate ?? new CalendarDate(2099, 12, 31),
createCalendar: createCalendarProp = providerContext?.createCalendar ?? null,
minValue = globalContext?.defaultDates?.minDate ?? new CalendarDate(1900, 1, 1),
maxValue = globalContext?.defaultDates?.maxDate ?? new CalendarDate(2099, 12, 31),
createCalendar: createCalendarProp = globalContext?.createCalendar ?? null,
isInvalid: isInvalidProp = validationState ? validationState === "invalid" : false,
errorMessage,
} = props;
@ -144,6 +144,8 @@ export function useDateInput<T extends DateValue>(originalProps: UseDateInputPro
const domRef = useDOMRef(ref);
const inputRef = useDOMRef(inputRefProp);
const disableAnimation = originalProps.disableAnimation ?? globalContext?.disableAnimation;
const {locale} = useLocale();
const state = useDateFieldState({
@ -193,10 +195,11 @@ export function useDateInput<T extends DateValue>(originalProps: UseDateInputPro
() =>
dateInput({
...variantProps,
disableAnimation,
labelPlacement,
className,
}),
[objectToDeps(variantProps), labelPlacement, className],
[objectToDeps(variantProps), disableAnimation, labelPlacement, className],
);
const getLabelProps: PropGetter = (props) => {

View File

@ -6,7 +6,7 @@ import type {DateInputGroupProps} from "./date-input-group";
import {useLocale} from "@react-aria/i18n";
import {mergeProps} from "@react-aria/utils";
import {PropGetter} from "@nextui-org/system";
import {PropGetter, useProviderContext} from "@nextui-org/system";
import {HTMLNextUIProps, mapPropsVariants} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/react-utils";
import {useTimeField as useAriaTimeField} from "@react-aria/datepicker";
@ -73,6 +73,8 @@ export type UseTimeInputProps<T extends TimeValue> = Props<T> &
Omit<AriaTimeFieldProps<T>, "validationBehavior">;
export function useTimeInput<T extends TimeValue>(originalProps: UseTimeInputProps<T>) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, dateInput.variantKeys);
const {
@ -104,12 +106,15 @@ export function useTimeInput<T extends TimeValue>(originalProps: UseTimeInputPro
const {locale} = useLocale();
const disableAnimation = originalProps.disableAnimation ?? globalContext?.disableAnimation;
const state = useTimeFieldState({
...originalProps,
label,
locale,
minValue,
maxValue,
isInvalid: isInvalidProp,
shouldForceLeadingZeros,
});
@ -150,10 +155,11 @@ export function useTimeInput<T extends TimeValue>(originalProps: UseTimeInputPro
() =>
dateInput({
...variantProps,
disableAnimation,
labelPlacement,
className,
}),
[objectToDeps(variantProps), labelPlacement, className],
[objectToDeps(variantProps), labelPlacement, disableAnimation, className],
);
const getLabelProps: PropGetter = (props) => {

View File

@ -9,7 +9,7 @@ import type {ValueBase} from "@react-types/shared";
import {dateInput, DatePickerVariantProps} from "@nextui-org/theme";
import {useState} from "react";
import {HTMLNextUIProps, mapPropsVariants} from "@nextui-org/system";
import {HTMLNextUIProps, mapPropsVariants, useProviderContext} from "@nextui-org/system";
import {mergeProps} from "@react-aria/utils";
import {useDOMRef} from "@nextui-org/react-utils";
import {dataAttr} from "@nextui-org/shared-utils";
@ -112,6 +112,8 @@ export type UseDatePickerBaseProps<T extends DateValue> = Props<T> &
Omit<AriaDatePickerBaseProps<T>, keyof ValueBase<T> | "validate" | "validationBehavior">;
export function useDatePickerBase<T extends DateValue>(originalProps: UseDatePickerBaseProps<T>) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, dateInput.variantKeys);
const [isCalendarHeaderExpanded, setIsCalendarHeaderExpanded] = useState(false);
@ -145,7 +147,8 @@ export function useDatePickerBase<T extends DateValue>(originalProps: UseDatePic
} = props;
const domRef = useDOMRef(ref);
const disableAnimation = originalProps.disableAnimation ?? false;
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
let stringFormatter = useLocalizedStringFormatter(intlMessages) as any;

View File

@ -36,7 +36,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},

View File

@ -1,8 +1,8 @@
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import type {PopoverProps} from "@nextui-org/popover";
import type {MenuTriggerType} from "@react-types/menu";
import type {Ref} from "react";
import {useProviderContext, type HTMLNextUIProps, type PropGetter} from "@nextui-org/system";
import {useMenuTriggerState} from "@react-stately/menu";
import {useMenuTrigger} from "@react-aria/menu";
import {dropdown} from "@nextui-org/theme";
@ -41,6 +41,8 @@ interface Props extends HTMLNextUIProps<"div"> {
export type UseDropdownProps = Props & Omit<PopoverProps, "children" | "color" | "variant">;
export function useDropdown(props: UseDropdownProps) {
const globalContext = useProviderContext();
const {
as,
triggerRef: triggerRefProp,
@ -54,7 +56,7 @@ export function useDropdown(props: UseDropdownProps) {
closeOnSelect = true,
shouldBlockScroll = true,
classNames: classNamesProp,
disableAnimation = false,
disableAnimation = globalContext?.disableAnimation ?? false,
onClose,
className,
...otherProps

View File

@ -116,7 +116,6 @@ const defaultProps = {
offset: 7,
isDisabled: false,
defaultOpen: false,
disableAnimation: false,
};
const items = [

View File

@ -1,7 +1,12 @@
import type {ImageVariantProps, SlotsToClasses, ImageSlots} from "@nextui-org/theme";
import {ImgHTMLAttributes, useCallback} from "react";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {image} from "@nextui-org/theme";
import {useDOMRef} from "@nextui-org/react-utils";
import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils";
@ -70,6 +75,8 @@ interface Props extends HTMLNextUIProps<"img"> {
export type UseImageProps = Props & ImageVariantProps;
export function useImage(originalProps: UseImageProps) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, image.variantKeys);
const {
@ -103,6 +110,9 @@ export function useImage(originalProps: UseImageProps) {
crossOrigin,
});
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const isImgLoaded = imageStatus === "loaded" && !isLoadingProp;
const isLoading = imageStatus === "loading" || isLoadingProp;
const isZoomed = originalProps.isZoomed;
@ -128,9 +138,10 @@ export function useImage(originalProps: UseImageProps) {
() =>
image({
...variantProps,
disableAnimation,
showSkeleton,
}),
[objectToDeps(variantProps), showSkeleton],
[objectToDeps(variantProps), disableAnimation, showSkeleton],
);
const baseStyles = clsx(className, classNames?.img);

View File

@ -30,6 +30,11 @@ export default {
type: "boolean",
},
},
disableAnimation: {
control: {
type: "boolean",
},
},
showSkeleton: {
control: {
disable: true,

View File

@ -1,7 +1,12 @@
import type {InputVariantProps, SlotsToClasses, InputSlots} from "@nextui-org/theme";
import type {AriaTextFieldOptions} from "@react-aria/textfield";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {useSafeLayoutEffect} from "@nextui-org/use-safe-layout-effect";
import {AriaTextFieldProps} from "@react-types/textfield";
import {useFocusRing} from "@react-aria/focus";
@ -86,6 +91,8 @@ export type UseInputProps<T extends HTMLInputElement | HTMLTextAreaElement = HTM
export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement>(
originalProps: UseInputProps<T>,
) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, input.variantKeys);
const {
@ -120,6 +127,9 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
const Component = as || "div";
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const domRef = useDOMRef<T>(ref);
const baseDomRef = useDOMRef<HTMLDivElement>(baseRef);
const inputWrapperRef = useDOMRef<HTMLDivElement>(wrapperRef);
@ -239,8 +249,16 @@ export function useInput<T extends HTMLInputElement | HTMLTextAreaElement = HTML
isInvalid,
labelPlacement,
isClearable,
disableAnimation,
}),
[objectToDeps(variantProps), isInvalid, labelPlacement, isClearable, hasStartContent],
[
objectToDeps(variantProps),
isInvalid,
labelPlacement,
isClearable,
hasStartContent,
disableAnimation,
],
);
const getBaseProps: PropGetter = useCallback(

View File

@ -3,7 +3,12 @@ import type {LinkVariantProps} from "@nextui-org/theme";
import {link} from "@nextui-org/theme";
import {useAriaLink} from "@nextui-org/use-aria-link";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/react-utils";
import {useFocusRing} from "@react-aria/focus";
import {dataAttr, objectToDeps} from "@nextui-org/shared-utils";
@ -36,6 +41,8 @@ interface Props extends HTMLNextUIProps<"a">, LinkVariantProps {
export type UseLinkProps = Props & AriaLinkProps;
export function useLink(originalProps: UseLinkProps) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, link.variantKeys);
const {
@ -57,6 +64,8 @@ export function useLink(originalProps: UseLinkProps) {
const Component = as || "a";
const domRef = useDOMRef(ref);
const disableAnimation =
originalProps?.disableAnimation ?? globalContext?.disableAnimation ?? false;
const {linkProps} = useAriaLink(
{
@ -85,9 +94,10 @@ export function useLink(originalProps: UseLinkProps) {
() =>
link({
...variantProps,
disableAnimation,
className,
}),
[objectToDeps(variantProps), className],
[objectToDeps(variantProps), disableAnimation, className],
);
const getLinkProps: PropGetter = useCallback(() => {

View File

@ -2,7 +2,12 @@ import type {ListboxItemBaseProps} from "./base/listbox-item-base";
import {useMemo, useRef, useCallback} from "react";
import {listboxItem} from "@nextui-org/theme";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {useFocusRing} from "@react-aria/focus";
import {Node} from "@react-types/shared";
import {filterDOMProps} from "@nextui-org/react-utils";
@ -22,6 +27,8 @@ export type UseListboxItemProps<T extends object> = Props<T> &
Omit<HTMLNextUIProps<"li">, keyof Props<T>>;
export function useListboxItem<T extends object>(originalProps: UseListboxItemProps<T>) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, listboxItem.variantKeys);
const {
@ -44,7 +51,8 @@ export function useListboxItem<T extends object>(originalProps: UseListboxItemPr
...otherProps
} = props;
const disableAnimation = originalProps.disableAnimation;
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const domRef = useRef<HTMLLIElement>(null);

View File

@ -1,7 +1,7 @@
import type {KeyboardDelegate} from "@react-types/shared";
import {AriaListBoxProps, useListBox as useAriaListbox} from "@react-aria/listbox";
import {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {HTMLNextUIProps, PropGetter, useProviderContext} from "@nextui-org/system";
import {listbox, ListboxVariantProps, ListboxSlots, SlotsToClasses} from "@nextui-org/theme";
import {ListState, useListState} from "@react-stately/list";
import {filterDOMProps, ReactRef, useDOMRef} from "@nextui-org/react-utils";
@ -97,6 +97,8 @@ interface Props<T> extends Omit<HTMLNextUIProps<"ul">, "children"> {
export type UseListboxProps<T = object> = Props<T> & AriaListBoxOptions<T> & ListboxVariantProps;
export function useListbox<T extends object>(props: UseListboxProps<T>) {
const globalContext = useProviderContext();
const {
ref,
as,
@ -106,7 +108,7 @@ export function useListbox<T extends object>(props: UseListboxProps<T>) {
onAction,
children,
onSelectionChange,
disableAnimation,
disableAnimation = globalContext?.disableAnimation ?? false,
itemClasses,
className,
topContent,

View File

@ -3,7 +3,12 @@ import type {Node} from "@react-types/shared";
import {useMemo, useRef, useCallback} from "react";
import {menuItem} from "@nextui-org/theme";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {useFocusRing} from "@react-aria/focus";
import {TreeState} from "@react-stately/tree";
import {clsx, dataAttr, objectToDeps, removeEvents} from "@nextui-org/shared-utils";
@ -21,6 +26,8 @@ export type UseMenuItemProps<T extends object> = Props<T> &
Omit<HTMLNextUIProps<"li">, keyof Props<T>>;
export function useMenuItem<T extends object>(originalProps: UseMenuItemProps<T>) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, menuItem.variantKeys);
const {
@ -50,7 +57,8 @@ export function useMenuItem<T extends object>(originalProps: UseMenuItemProps<T>
...otherProps
} = props;
const disableAnimation = originalProps.disableAnimation;
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const domRef = useRef<HTMLLIElement>(null);

View File

@ -1,5 +1,4 @@
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {useProviderContext, type HTMLNextUIProps, type PropGetter} from "@nextui-org/system";
import {AriaMenuProps} from "@react-types/menu";
import {AriaMenuOptions} from "@react-aria/menu";
import {useAriaMenu} from "@nextui-org/use-aria-menu";
@ -90,13 +89,15 @@ export type UseMenuProps<T = object> = Props<T> &
MenuVariantProps;
export function useMenu<T extends object>(props: UseMenuProps<T>) {
const globalContext = useProviderContext();
const {
as,
ref,
variant,
color,
children,
disableAnimation,
disableAnimation = globalContext?.disableAnimation ?? false,
onAction,
closeOnSelect,
itemClasses,

View File

@ -36,7 +36,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},

View File

@ -5,7 +5,12 @@ import {AriaModalOverlayProps} from "@react-aria/overlays";
import {useAriaModalOverlay} from "@nextui-org/use-aria-modal-overlay";
import {useCallback, useId, useRef, useState, useMemo, ReactNode} from "react";
import {modal} from "@nextui-org/theme";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {useAriaButton} from "@nextui-org/use-aria-button";
import {useFocusRing} from "@react-aria/focus";
import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils";
@ -74,6 +79,8 @@ interface Props extends HTMLNextUIProps<"section"> {
export type UseModalProps = Props & OverlayTriggerProps & AriaModalOverlayProps & ModalVariantProps;
export function useModal(originalProps: UseModalProps) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, modal.variantKeys);
const {
@ -81,7 +88,7 @@ export function useModal(originalProps: UseModalProps) {
as,
className,
classNames,
disableAnimation = false,
isOpen,
defaultOpen,
onOpenChange,
@ -104,6 +111,9 @@ export function useModal(originalProps: UseModalProps) {
const [headerMounted, setHeaderMounted] = useState(false);
const [bodyMounted, setBodyMounted] = useState(false);
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const dialogId = useId();
const headerId = useId();
const bodyId = useId();
@ -139,8 +149,9 @@ export function useModal(originalProps: UseModalProps) {
() =>
modal({
...variantProps,
disableAnimation,
}),
[objectToDeps(variantProps)],
[objectToDeps(variantProps), disableAnimation],
);
const getDialogProps: PropGetter = (props = {}, ref = null) => ({

View File

@ -74,7 +74,6 @@ export default {
const defaultProps = {
...modal.defaultVariants,
disableAnimation: false,
isDismissable: true,
isKeyboardDismissDisabled: false,
};

View File

@ -36,7 +36,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},

View File

@ -1,6 +1,11 @@
import type {NavbarVariantProps, SlotsToClasses, NavbarSlots} from "@nextui-org/theme";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {navbar} from "@nextui-org/theme";
import {useDOMRef} from "@nextui-org/react-utils";
import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils";
@ -86,6 +91,8 @@ interface Props extends HTMLNextUIProps<"nav"> {
export type UseNavbarProps = Props & NavbarVariantProps;
export function useNavbar(originalProps: UseNavbarProps) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, navbar.variantKeys);
const {
@ -106,6 +113,8 @@ export function useNavbar(originalProps: UseNavbarProps) {
} = props;
const Component = as || "nav";
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const domRef = useDOMRef(ref);
@ -159,9 +168,10 @@ export function useNavbar(originalProps: UseNavbarProps) {
() =>
navbar({
...variantProps,
disableAnimation,
hideOnScroll: shouldHideOnScroll,
}),
[objectToDeps(variantProps), shouldHideOnScroll],
[objectToDeps(variantProps), disableAnimation, shouldHideOnScroll],
);
const baseStyles = clsx(classNames?.base, className);
@ -206,7 +216,7 @@ export function useNavbar(originalProps: UseNavbarProps) {
domRef,
height,
isHidden,
disableAnimation: originalProps.disableAnimation ?? false,
disableAnimation,
shouldHideOnScroll,
isMenuOpen,
classNames,

View File

@ -10,7 +10,7 @@ import {
PaginationItemType,
} from "@nextui-org/use-pagination";
import {useEffect, useRef, useMemo} from "react";
import {mapPropsVariants} from "@nextui-org/system";
import {mapPropsVariants, useProviderContext} from "@nextui-org/system";
import {usePagination as useBasePagination} from "@nextui-org/use-pagination";
import scrollIntoView from "scroll-into-view-if-needed";
import {pagination} from "@nextui-org/theme";
@ -163,6 +163,8 @@ export type UsePaginationProps = Props & UseBasePaginationProps & PaginationVari
export const CURSOR_TRANSITION_TIMEOUT = 300; // in ms
export function usePagination(originalProps: UsePaginationProps) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, pagination.variantKeys);
const {
@ -196,6 +198,10 @@ export function usePagination(originalProps: UsePaginationProps) {
const isRTL = direction === "rtl";
const disableAnimation =
originalProps?.disableAnimation ?? globalContext?.disableAnimation ?? false;
const disableCursorAnimation = originalProps?.disableCursorAnimation ?? disableAnimation ?? false;
function getItemsRefMap() {
if (!itemsRef.current) {
// Initialize the Map on first usage.
@ -275,14 +281,14 @@ export function usePagination(originalProps: UsePaginationProps) {
const activePageRef = useRef(activePage);
useEffect(() => {
if (activePage && !originalProps.disableAnimation) {
if (activePage && !disableAnimation) {
scrollTo(activePage, activePage === activePageRef.current);
}
activePageRef.current = activePage;
}, [
activePage,
originalProps.disableAnimation,
originalProps.disableCursorAnimation,
disableAnimation,
disableCursorAnimation,
originalProps.dotsJump,
originalProps.isCompact,
originalProps.showControls,
@ -292,10 +298,9 @@ export function usePagination(originalProps: UsePaginationProps) {
() =>
pagination({
...variantProps,
disableCursorAnimation:
originalProps.disableCursorAnimation || originalProps.disableAnimation,
disableCursorAnimation: disableCursorAnimation || disableAnimation,
}),
[objectToDeps(variantProps)],
[objectToDeps(variantProps), disableCursorAnimation, disableAnimation],
);
const baseStyles = clsx(classNames?.base, className);
@ -400,8 +405,8 @@ export function usePagination(originalProps: UsePaginationProps) {
range,
activePage,
getItemRef,
disableCursorAnimation: originalProps.disableCursorAnimation,
disableAnimation: originalProps.disableAnimation,
disableAnimation,
disableCursorAnimation,
setPage,
onPrevious,
onNext,

View File

@ -36,7 +36,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},

View File

@ -8,7 +8,12 @@ import {OverlayTriggerState, useOverlayTriggerState} from "@react-stately/overla
import {useFocusRing} from "@react-aria/focus";
import {ariaHideOutside, useOverlayTrigger} from "@react-aria/overlays";
import {OverlayTriggerProps} from "@react-types/overlays";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {getArrowPlacement, getShouldUseAxisPlacement} from "@nextui-org/aria-utils";
import {popover} from "@nextui-org/theme";
import {mergeProps, mergeRefs} from "@react-aria/utils";
@ -82,6 +87,8 @@ export type UsePopoverProps = Props &
PopoverVariantProps;
export function usePopover(originalProps: UsePopoverProps) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, popover.variantKeys);
const {
@ -127,7 +134,8 @@ export function usePopover(originalProps: UsePopoverProps) {
const dialogRef = useRef(null);
const triggerRef = triggerRefProp || domTriggerRef;
const disableAnimation = originalProps.disableAnimation ?? false;
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const innerState = useOverlayTriggerState({
isOpen: isOpenProp,

View File

@ -106,7 +106,6 @@ const defaultProps = {
placement: "top",
offset: 7,
defaultOpen: false,
disableAnimation: false,
};
const content = (
@ -122,7 +121,7 @@ const Template = (args: PopoverProps) => {
return (
<Popover {...args}>
<PopoverTrigger>
<Button disableAnimation={!!args.disableAnimation}>Open Popover</Button>
<Button>Open Popover</Button>
</PopoverTrigger>
{content}
</Popover>
@ -133,7 +132,7 @@ const WithTitlePropsTemplate = (args: PopoverProps) => {
return (
<Popover {...args}>
<PopoverTrigger>
<Button disableAnimation={!!args.disableAnimation}>Open Popover</Button>
<Button>Open Popover</Button>
</PopoverTrigger>
<PopoverContent>
{(titleProps) => (

View File

@ -6,7 +6,7 @@ import type {
import type {PropGetter} from "@nextui-org/system";
import type {AriaProgressBarProps} from "@react-types/progress";
import {HTMLNextUIProps, mapPropsVariants} from "@nextui-org/system";
import {HTMLNextUIProps, mapPropsVariants, useProviderContext} from "@nextui-org/system";
import {circularProgress} from "@nextui-org/theme";
import {useDOMRef} from "@nextui-org/react-utils";
import {clampPercentage, clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils";
@ -53,6 +53,7 @@ export interface Props extends HTMLNextUIProps<"div"> {
export type UseCircularProgressProps = Props & AriaProgressBarProps & CircularProgressVariantProps;
export function useCircularProgress(originalProps: UseCircularProgressProps) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, circularProgress.variantKeys);
const {
@ -86,6 +87,8 @@ export function useCircularProgress(originalProps: UseCircularProgressProps) {
// default isIndeterminate to true
const isIndeterminate = (originalProps.isIndeterminate ?? true) && value === undefined;
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const {progressBarProps, labelProps} = useAriaProgress({
id,
@ -104,12 +107,13 @@ export function useCircularProgress(originalProps: UseCircularProgressProps) {
() =>
circularProgress({
...variantProps,
disableAnimation,
isIndeterminate,
}),
[objectToDeps(variantProps), isIndeterminate],
[objectToDeps(variantProps), disableAnimation, isIndeterminate],
);
const selfMounted = originalProps.disableAnimation ? true : isMounted;
const selfMounted = disableAnimation ? true : isMounted;
const center = 16;
const strokeWidth = strokeWidthProp || (originalProps.size === "sm" ? 2 : 3);

View File

@ -2,7 +2,7 @@ import type {ProgressVariantProps, SlotsToClasses, ProgressSlots} from "@nextui-
import type {PropGetter} from "@nextui-org/system";
import type {AriaProgressBarProps} from "@react-types/progress";
import {HTMLNextUIProps, mapPropsVariants} from "@nextui-org/system";
import {HTMLNextUIProps, mapPropsVariants, useProviderContext} from "@nextui-org/system";
import {progress} from "@nextui-org/theme";
import {useDOMRef} from "@nextui-org/react-utils";
import {clampPercentage, clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils";
@ -44,6 +44,7 @@ interface Props extends HTMLNextUIProps<"div"> {
export type UseProgressProps = Props & AriaProgressBarProps & ProgressVariantProps;
export function useProgress(originalProps: UseProgressProps) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, progress.variantKeys);
const {
@ -73,8 +74,12 @@ export function useProgress(originalProps: UseProgressProps) {
rerender: true,
delay: 100,
});
const isIndeterminate = originalProps.isIndeterminate;
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const {progressBarProps, labelProps} = useAriaProgress({
id,
label,
@ -92,11 +97,12 @@ export function useProgress(originalProps: UseProgressProps) {
() =>
progress({
...variantProps,
disableAnimation,
}),
[objectToDeps(variantProps)],
[objectToDeps(variantProps), disableAnimation],
);
const selfMounted = originalProps.disableAnimation ? true : isMounted;
const selfMounted = disableAnimation ? true : isMounted;
// Calculate the width of the progress bar as a percentage
const percentage = useMemo(

View File

@ -7,7 +7,7 @@ import {radioGroup} from "@nextui-org/theme";
import {useCallback, useMemo} from "react";
import {RadioGroupState, useRadioGroupState} from "@react-stately/radio";
import {useRadioGroup as useReactAriaRadioGroup} from "@react-aria/radio";
import {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {HTMLNextUIProps, PropGetter, useProviderContext} from "@nextui-org/system";
import {filterDOMProps, useDOMRef} from "@nextui-org/react-utils";
import {clsx, safeAriaLabel} from "@nextui-org/shared-utils";
import {mergeProps} from "@react-aria/utils";
@ -62,6 +62,8 @@ export type ContextType = {
};
export function useRadioGroup(props: UseRadioGroupProps) {
const globalContext = useProviderContext();
const {
as,
ref,
@ -75,7 +77,7 @@ export function useRadioGroup(props: UseRadioGroupProps) {
size = "md",
color = "primary",
isDisabled = false,
disableAnimation = false,
disableAnimation = globalContext?.disableAnimation ?? false,
orientation = "vertical",
isRequired = false,
isReadOnly,

View File

@ -7,7 +7,7 @@ import {useFocusRing} from "@react-aria/focus";
import {useHover, usePress} 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 {HTMLNextUIProps, PropGetter, useProviderContext} from "@nextui-org/system";
import {__DEV__, warn, clsx, dataAttr} from "@nextui-org/shared-utils";
import {useDOMRef} from "@nextui-org/react-utils";
import {chain, mergeProps} from "@react-aria/utils";
@ -51,6 +51,7 @@ export type UseRadioProps = Omit<Props, "defaultChecked"> &
RadioVariantProps;
export function useRadio(props: UseRadioProps) {
const globalContext = useProviderContext();
const groupContext = useRadioGroupContext();
const {
@ -64,7 +65,7 @@ export function useRadio(props: UseRadioProps) {
size = groupContext?.size ?? "md",
color = groupContext?.color ?? "primary",
isDisabled: isDisabledProp = groupContext?.isDisabled ?? false,
disableAnimation = groupContext?.disableAnimation ?? false,
disableAnimation = groupContext?.disableAnimation ?? globalContext?.disableAnimation ?? false,
onChange = groupContext?.onChange,
autoFocus = false,
className,

View File

@ -36,7 +36,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},

View File

@ -1,9 +1,10 @@
import {FC} from "react";
import {AnimatePresence, HTMLMotionProps, m, LazyMotion, domAnimation} from "framer-motion";
import {HTMLNextUIProps} from "@nextui-org/system";
import {clamp} from "@nextui-org/shared-utils";
import type {RippleType} from "./use-ripple";
import type {FC} from "react";
import type {HTMLMotionProps} from "framer-motion";
import type {HTMLNextUIProps} from "@nextui-org/system";
import {RippleType} from "./use-ripple";
import {AnimatePresence, m, LazyMotion, domAnimation} from "framer-motion";
import {clamp} from "@nextui-org/shared-utils";
export interface RippleProps extends HTMLNextUIProps<"span"> {
ripples: RippleType[];
@ -22,38 +23,36 @@ const Ripple: FC<RippleProps> = (props) => {
const duration = clamp(0.01 * ripple.size, 0.2, ripple.size > 100 ? 0.75 : 0.5);
return (
<AnimatePresence key={ripple.key} mode="popLayout">
<>
<LazyMotion features={domAnimation}>
<m.span
animate={{transform: "scale(2)", opacity: 0}}
className="nextui-ripple"
exit={{opacity: 0}}
initial={{transform: "scale(0)", opacity: 0.35}}
style={{
position: "absolute",
backgroundColor: color,
borderRadius: "100%",
transformOrigin: "center",
pointerEvents: "none",
overflow: "hidden",
inset: 0,
zIndex: 0,
top: ripple.y,
left: ripple.x,
width: `${ripple.size}px`,
height: `${ripple.size}px`,
...style,
}}
transition={{duration}}
onAnimationComplete={() => {
onClear(ripple.key);
}}
{...motionProps}
/>
</LazyMotion>
</>
</AnimatePresence>
<LazyMotion key={ripple.key} features={domAnimation}>
<AnimatePresence mode="popLayout">
<m.span
animate={{transform: "scale(2)", opacity: 0}}
className="nextui-ripple"
exit={{opacity: 0}}
initial={{transform: "scale(0)", opacity: 0.35}}
style={{
position: "absolute",
backgroundColor: color,
borderRadius: "100%",
transformOrigin: "center",
pointerEvents: "none",
overflow: "hidden",
inset: 0,
zIndex: 0,
top: ripple.y,
left: ripple.x,
width: `${ripple.size}px`,
height: `${ripple.size}px`,
...style,
}}
transition={{duration}}
onAnimationComplete={() => {
onClear(ripple.key);
}}
{...motionProps}
/>
</AnimatePresence>
</LazyMotion>
);
})}
</>

View File

@ -36,7 +36,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},

View File

@ -1,7 +1,13 @@
import type {SelectSlots, SelectVariantProps, SlotsToClasses} from "@nextui-org/theme";
import type {HiddenSelectProps} from "./hidden-select";
import {DOMAttributes, HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
DOMAttributes,
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {select} from "@nextui-org/theme";
import {ReactRef, useDOMRef, filterDOMProps} from "@nextui-org/react-utils";
import {useMemo, useCallback, useRef, Key, ReactNode, useEffect} from "react";
@ -137,8 +143,12 @@ export type UseSelectProps<T> = Omit<Props<T>, keyof MultiSelectProps<T>> &
SelectVariantProps;
export function useSelect<T extends object>(originalProps: UseSelectProps<T>) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, select.variantKeys);
const disableAnimation = originalProps.disableAnimation ?? false;
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const {
ref,
@ -317,9 +327,10 @@ export function useSelect<T extends object>(originalProps: UseSelectProps<T>) {
...variantProps,
isInvalid,
labelPlacement,
disableAnimation,
className,
}),
[objectToDeps(variantProps), isInvalid, labelPlacement, className],
[objectToDeps(variantProps), isInvalid, labelPlacement, disableAnimation, className],
);
// scroll the listbox to the selected item

View File

@ -36,10 +36,10 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"@nextui-org/theme": ">=2.1.0"
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},
"dependencies": {
"@nextui-org/system-rsc": "workspace:*",
"@nextui-org/shared-utils": "workspace:*",
"@nextui-org/react-utils": "workspace:*"
},
@ -47,6 +47,7 @@
"@nextui-org/theme": "workspace:*",
"@nextui-org/card": "workspace:*",
"@nextui-org/button": "workspace:*",
"@nextui-org/system": "workspace:*",
"clean-package": "2.2.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"

View File

@ -1,4 +1,4 @@
import {forwardRef} from "@nextui-org/system-rsc";
import {forwardRef} from "@nextui-org/system";
import {UseSkeletonProps, useSkeleton} from "./use-skeleton";

View File

@ -1,10 +1,11 @@
import type {SkeletonVariantProps, SkeletonSlots, SlotsToClasses} from "@nextui-org/theme";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system-rsc";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {mapPropsVariants} from "@nextui-org/system-rsc";
import {mapPropsVariants} from "@nextui-org/system";
import {skeleton} from "@nextui-org/theme";
import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils";
import {useMemo, Ref} from "react";
import {useProviderContext} from "@nextui-org/system";
interface Props extends HTMLNextUIProps<"div"> {
/**
@ -34,18 +35,24 @@ interface Props extends HTMLNextUIProps<"div"> {
export type UseSkeletonProps = Props & SkeletonVariantProps;
export function useSkeleton(originalProps: UseSkeletonProps) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, skeleton.variantKeys);
const {as, children, isLoaded = false, className, classNames, ...otherProps} = props;
const Component = as || "div";
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const slots = useMemo(
() =>
skeleton({
...variantProps,
disableAnimation,
}),
[objectToDeps(variantProps), children],
[objectToDeps(variantProps), disableAnimation, children],
);
const baseStyles = clsx(classNames?.base, className);

View File

@ -4,4 +4,5 @@ export default defineConfig({
clean: true,
target: "es2019",
format: ["cjs", "esm"],
banner: {js: '"use client";'},
});

View File

@ -1,6 +1,12 @@
import type {SliderSlots, SliderVariantProps, SlotsToClasses} from "@nextui-org/theme";
import {DOMAttributes, HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
DOMAttributes,
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {slider} from "@nextui-org/theme";
import {ReactRef, useDOMRef, filterDOMProps} from "@nextui-org/react-utils";
import {useSliderState} from "@react-stately/slider";
@ -133,6 +139,8 @@ export type UseSliderProps = Omit<Props, keyof ValueBase<SliderValue>> &
SliderVariantProps;
export function useSlider(originalProps: UseSliderProps) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, slider.variantKeys);
const {
@ -167,6 +175,8 @@ export function useSlider(originalProps: UseSliderProps) {
const Component = as || "div";
const shouldFilterDOMProps = typeof Component === "string";
const disableAnimation =
originalProps?.disableAnimation ?? globalContext?.disableAnimation ?? false;
const domRef = useDOMRef(ref);
const trackRef = useRef<HTMLDivElement>(null);
@ -231,11 +241,12 @@ export function useSlider(originalProps: UseSliderProps) {
slider({
...variantProps,
hasMarks,
disableAnimation,
hasSingleThumb,
isVertical,
className,
}),
[objectToDeps(variantProps), isVertical, hasSingleThumb, hasMarks, className],
[objectToDeps(variantProps), isVertical, disableAnimation, hasSingleThumb, hasMarks, className],
);
const [startOffset, endOffset] = [

View File

@ -36,7 +36,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},

View File

@ -1,7 +1,12 @@
import type {SnippetVariantProps, SnippetSlots, SlotsToClasses} from "@nextui-org/theme";
import {snippet} from "@nextui-org/theme";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {useDOMRef, filterDOMProps} from "@nextui-org/react-utils";
import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils";
import {ReactRef} from "@nextui-org/react-utils";
@ -116,6 +121,8 @@ export interface UseSnippetProps extends Omit<HTMLNextUIProps, "onCopy">, Snippe
}
export function useSnippet(originalProps: UseSnippetProps) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, snippet.variantKeys);
const {
@ -142,6 +149,8 @@ export function useSnippet(originalProps: UseSnippetProps) {
const Component = as || "div";
const shouldFilterDOMProps = typeof Component === "string";
const disableAnimation =
originalProps?.disableAnimation ?? globalContext?.disableAnimation ?? false;
const tooltipProps: Partial<TooltipProps> = {
offset: 15,
@ -167,8 +176,9 @@ export function useSnippet(originalProps: UseSnippetProps) {
() =>
snippet({
...variantProps,
disableAnimation,
}),
[objectToDeps(variantProps)],
[objectToDeps(variantProps), disableAnimation],
);
const symbolBefore = useMemo(() => {

View File

@ -3,7 +3,7 @@ import type {AriaSwitchProps} from "@react-aria/switch";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import {ReactNode, Ref, useCallback, useId, useRef, useState} from "react";
import {mapPropsVariants} from "@nextui-org/system";
import {mapPropsVariants, useProviderContext} from "@nextui-org/system";
import {mergeRefs} from "@nextui-org/react-utils";
import {useSafeLayoutEffect} from "@nextui-org/use-safe-layout-effect";
import {useHover, usePress} from "@react-aria/interactions";
@ -76,6 +76,8 @@ export type UseSwitchProps = Omit<Props, "defaultChecked"> &
ToggleVariantProps;
export function useSwitch(originalProps: UseSwitchProps = {}) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, toggle.variantKeys);
const {
@ -104,6 +106,9 @@ export function useSwitch(originalProps: UseSwitchProps = {}) {
const inputRef = useRef<HTMLInputElement>(null);
const disableAnimation =
originalProps.disableAnimation ?? globalContext?.disableAnimation ?? false;
const labelId = useId();
const ariaSwitchProps = useMemo(() => {
@ -188,8 +193,9 @@ export function useSwitch(originalProps: UseSwitchProps = {}) {
() =>
toggle({
...variantProps,
disableAnimation,
}),
[objectToDeps(variantProps)],
[objectToDeps(variantProps), disableAnimation],
);
const baseStyles = clsx(classNames?.base, className);

View File

@ -12,7 +12,12 @@ import type {TableCollection} from "@react-types/table";
import {ReactNode, Key, useCallback} from "react";
import {useTableState} from "@react-stately/table";
import {AriaTableProps, useTable as useReactAriaTable} from "@react-aria/table";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {table} from "@nextui-org/theme";
import {useDOMRef, filterDOMProps} from "@nextui-org/react-utils";
import {mergeProps} from "@react-aria/utils";
@ -140,6 +145,8 @@ export type ValuesType<T = object> = {
};
export function useTable<T extends object>(originalProps: UseTableProps<T>) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, table.variantKeys);
const {
@ -151,7 +158,7 @@ export function useTable<T extends object>(originalProps: UseTableProps<T>) {
classNames,
layoutNode,
removeWrapper = false,
disableAnimation = false,
disableAnimation = globalContext?.disableAnimation ?? false,
selectionMode = "none",
topContentPlacement = "inside",
bottomContentPlacement = "inside",

View File

@ -36,7 +36,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},

View File

@ -1,6 +1,11 @@
import type {TabsVariantProps, SlotsToClasses, TabsSlots, TabsReturnType} from "@nextui-org/theme";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {tabs} from "@nextui-org/theme";
import {useDOMRef} from "@nextui-org/react-utils";
import {clsx, objectToDeps} from "@nextui-org/shared-utils";
@ -83,6 +88,8 @@ export type ValuesType<T = object> = {
};
export function useTabs<T extends object>(originalProps: UseTabsProps<T>) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, tabs.variantKeys);
const {
@ -104,6 +111,9 @@ export function useTabs<T extends object>(originalProps: UseTabsProps<T>) {
const domRef = useDOMRef(ref);
const disableAnimation =
originalProps?.disableAnimation ?? globalContext?.disableAnimation ?? false;
const state = useTabListState<T>({
children: children as CollectionChildren<T>,
...otherProps,
@ -115,9 +125,10 @@ export function useTabs<T extends object>(originalProps: UseTabsProps<T>) {
tabs({
...variantProps,
className,
disableAnimation,
...(isVertical ? {placement: "start"} : {}),
}),
[objectToDeps(variantProps), className, isVertical],
[objectToDeps(variantProps), className, disableAnimation, isVertical],
);
const baseStyles = clsx(classNames?.base, className);
@ -128,20 +139,20 @@ export function useTabs<T extends object>(originalProps: UseTabsProps<T>) {
slots,
classNames,
motionProps,
disableAnimation,
listRef: domRef,
shouldSelectOnPressUp,
disableCursorAnimation,
isDisabled: originalProps?.isDisabled,
disableAnimation: originalProps?.disableAnimation,
}),
[
state,
slots,
domRef,
motionProps,
disableAnimation,
disableCursorAnimation,
shouldSelectOnPressUp,
originalProps?.disableAnimation,
originalProps?.isDisabled,
classNames,
],

View File

@ -36,7 +36,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0",
"framer-motion": ">=10.17.0",
"@nextui-org/theme": ">=2.1.0",
"@nextui-org/system": ">=2.0.0"
},

View File

@ -9,7 +9,12 @@ import {useTooltipTriggerState} from "@react-stately/tooltip";
import {mergeProps} from "@react-aria/utils";
import {useTooltip as useReactAriaTooltip, useTooltipTrigger} from "@react-aria/tooltip";
import {useOverlayPosition, useOverlay, AriaOverlayProps} from "@react-aria/overlays";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {
HTMLNextUIProps,
mapPropsVariants,
PropGetter,
useProviderContext,
} from "@nextui-org/system";
import {popover} from "@nextui-org/theme";
import {clsx, dataAttr, objectToDeps} from "@nextui-org/shared-utils";
import {ReactRef, mergeRefs} from "@nextui-org/react-utils";
@ -87,6 +92,7 @@ export type UseTooltipProps = Props &
PopoverVariantProps;
export function useTooltip(originalProps: UseTooltipProps) {
const globalContext = useProviderContext();
const [props, variantProps] = mapPropsVariants(originalProps, popover.variantKeys);
const {
@ -122,6 +128,9 @@ export function useTooltip(originalProps: UseTooltipProps) {
const Component = as || "div";
const disableAnimation =
originalProps?.disableAnimation ?? globalContext?.disableAnimation ?? false;
const state = useTooltipTriggerState({
delay,
closeDelay,
@ -203,11 +212,18 @@ export function useTooltip(originalProps: UseTooltipProps) {
() =>
popover({
...variantProps,
disableAnimation,
radius: originalProps?.radius ?? "md",
size: originalProps?.size ?? "md",
shadow: originalProps?.shadow ?? "sm",
}),
[objectToDeps(variantProps), originalProps?.radius, originalProps?.size, originalProps?.shadow],
[
objectToDeps(variantProps),
disableAnimation,
originalProps?.radius,
originalProps?.size,
originalProps?.shadow,
],
);
const getTriggerProps = useCallback<PropGetter>(
@ -269,7 +285,7 @@ export function useTooltip(originalProps: UseTooltipProps) {
showArrow,
portalContainer,
placement: placementProp,
disableAnimation: originalProps?.disableAnimation,
disableAnimation,
isDisabled,
motionProps,
getTooltipContentProps,

View File

@ -104,7 +104,6 @@ const defaultProps = {
offset: 7,
defaultOpen: false,
isDisabled: false,
disableAnimation: false,
content: "I am a tooltip",
children: <Button>Hover me</Button>,
};

View File

@ -89,7 +89,7 @@
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"framer-motion": ">=4.0.0"
"framer-motion": ">=10.17.0"
},
"devDependencies": {
"react": "^18.0.0",

View File

@ -35,12 +35,14 @@
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
"react-dom": ">=18",
"framer-motion": ">=10.17.0"
},
"devDependencies": {
"clean-package": "2.2.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
"react-dom": "^18.0.0",
"clean-package": "2.2.0",
"framer-motion": "^11.0.22"
},
"clean-package": "../../../clean-package.config.json",
"tsup": {

View File

@ -4,6 +4,19 @@ import type {CalendarDate, Calendar} from "@internationalized/date";
import {createContext} from "@nextui-org/react-utils";
export type ProviderContextProps = {
/**
* Whether to disable animations in the whole application.
*
* @default false
*/
disableAnimation?: boolean;
/**
* Whether to disable the ripple effect in the whole application.
* If `disableAnimation` is set to `true`, this prop will be ignored.
*
* @default false
*/
disableRipple?: boolean;
/**
* The default dates range that can be selected in the calendar.
*/

View File

@ -6,6 +6,7 @@ import {RouterProvider} from "@react-aria/utils";
import {OverlayProvider} from "@react-aria/overlays";
import {useMemo} from "react";
import {CalendarDate} from "@internationalized/date";
import {MotionGlobalConfig} from "framer-motion";
import {ProviderContext} from "./provider-context";
@ -13,6 +14,14 @@ export interface NextUIProviderProps
extends Omit<ModalProviderProps, "children">,
ProviderContextProps {
children: React.ReactNode;
/**
* Controls whether `framer-motion` animations are skipped within the application.
* This property is automatically enabled (`true`) when the `disableAnimation` prop is set to `true`,
* effectively skipping all `framer-motion` animations. To retain `framer-motion` animations while
* using the `disableAnimation` prop for other purposes, set this to `false`. However, note that
* animations in NextUI Components are still omitted if the `disableAnimation` prop is `true`.
*/
skipFramerMotionAnimations?: boolean;
/**
* The locale to apply to the children.
* @default "en-US"
@ -28,6 +37,9 @@ export interface NextUIProviderProps
export const NextUIProvider: React.FC<NextUIProviderProps> = ({
children,
navigate,
disableAnimation = false,
disableRipple = false,
skipFramerMotionAnimations = disableAnimation,
locale = "en-US",
defaultDates = {
minDate: new CalendarDate(1900, 1, 1),
@ -42,10 +54,24 @@ export const NextUIProvider: React.FC<NextUIProviderProps> = ({
contents = <RouterProvider navigate={navigate}>{contents}</RouterProvider>;
}
const context = useMemo<ProviderContextProps>(
() => ({createCalendar, defaultDates}),
[createCalendar, defaultDates?.maxDate, defaultDates?.minDate],
);
const context = useMemo<ProviderContextProps>(() => {
if (disableAnimation && skipFramerMotionAnimations) {
MotionGlobalConfig.skipAnimations = true;
}
return {
createCalendar,
defaultDates,
disableAnimation,
disableRipple,
};
}, [
createCalendar,
defaultDates?.maxDate,
defaultDates?.minDate,
disableAnimation,
disableRipple,
]);
return (
<ProviderContext value={context}>

View File

@ -119,7 +119,6 @@ const accordionItem = tv({
radius: "lg",
isDisabled: false,
hideIndicator: false,
disableAnimation: false,
disableIndicatorAnimation: false,
},
});

View File

@ -46,7 +46,6 @@ const autocomplete = tv({
},
},
defaultVariants: {
disableAnimation: false,
isClearable: true,
disableSelectorIconRotation: false,
},

View File

@ -124,6 +124,13 @@ const avatar = tv({
base: "m-0 data-[hover=true]:translate-x-0",
},
},
disableAnimation: {
true: {
base: "transition-none",
img: "transition-none",
},
false: {},
},
},
defaultVariants: {
size: "md",

View File

@ -111,7 +111,6 @@ const badge = tv({
shape: "rectangle",
placement: "top-right",
showOutline: true,
disableAnimation: false,
isInvisible: false,
},
compoundVariants: [

View File

@ -108,7 +108,6 @@ const breadcrumbItem = tv({
color: "foreground",
underline: "hover",
isDisabled: false,
disableAnimation: false,
},
compoundVariants: [
// isCurrent && color

View File

@ -37,6 +37,8 @@ const button = tv({
"subpixel-antialiased",
"overflow-hidden",
"tap-highlight-transparent",
"data-[pressed=true]:scale-[0.97]",
"origin-bottom",
// focus ring
...dataFocusVisibleClasses,
],
@ -85,8 +87,7 @@ const button = tv({
},
disableAnimation: {
true: "!transition-none",
false:
"data-[pressed=true]:scale-[0.97] transition-transform-colors-opacity motion-reduce:transition-none",
false: "transition-transform-colors-opacity motion-reduce:transition-none",
},
},
defaultVariants: {
@ -96,7 +97,6 @@ const button = tv({
fullWidth: false,
isDisabled: false,
isInGroup: false,
disableAnimation: false,
},
compoundVariants: [
// solid / color

View File

@ -154,7 +154,6 @@ const calendar = tv({
showShadow: false,
hideDisabledDates: false,
showMonthAndYearPickers: false,
disableAnimation: false,
},
compoundVariants: [
// !isRange & colors --> Calendar

View File

@ -149,7 +149,6 @@ const card = tv({
compoundVariants: [
{
isPressable: true,
disableAnimation: false,
class: "data-[pressed=true]:scale-[0.97] tap-highlight-transparent",
},
],
@ -160,7 +159,6 @@ const card = tv({
isHoverable: false,
isPressable: false,
isDisabled: false,
disableAnimation: false,
isFooterBlurred: false,
},
});

View File

@ -189,7 +189,6 @@ const checkbox = tv({
size: "md",
isDisabled: false,
lineThrough: false,
disableAnimation: false,
},
});
@ -235,7 +234,6 @@ const checkboxGroup = tv({
defaultVariants: {
isInvalid: false,
isRequired: false,
disableAnimation: false,
},
});

View File

@ -90,7 +90,6 @@ const circularProgress = tv({
color: "primary",
size: "md",
isDisabled: false,
disableAnimation: false,
},
compoundVariants: [
// disableAnimation && !isIndeterminate

View File

@ -218,7 +218,6 @@ const dateInput = tv({
fullWidth: true,
labelPlacement: "inside",
isDisabled: false,
disableAnimation: false,
},
compoundVariants: [
// flat & color

View File

@ -124,7 +124,6 @@ const dropdownItem = tv({
defaultVariants: {
variant: "solid",
color: "default",
disableAnimation: false,
},
compoundVariants: [
// solid / color

View File

@ -71,11 +71,32 @@ const image = tv({
},
showSkeleton: {
true: {
wrapper: ["group", "relative", "overflow-hidden", "bg-content3 dark:bg-content2"],
img: "opacity-0",
},
},
disableAnimation: {
true: {
img: "transition-none",
},
false: {
img: "transition-transform-opacity motion-reduce:transition-none !duration-300",
},
},
},
defaultVariants: {
radius: "lg",
shadow: "none",
isZoomed: false,
isBlurred: false,
showSkeleton: false,
},
compoundVariants: [
{
showSkeleton: true,
disableAnimation: false,
class: {
wrapper: [
"group",
"relative",
"overflow-hidden",
"bg-content3 dark:bg-content2",
// before
"before:opacity-100",
"before:absolute",
@ -97,26 +118,9 @@ const image = tv({
"after:bg-content3",
"dark:after:bg-content2",
],
img: "opacity-0",
},
},
disableAnimation: {
true: {
img: "transition-none",
},
false: {
img: "transition-transform-opacity motion-reduce:transition-none !duration-300",
},
},
},
defaultVariants: {
radius: "lg",
shadow: "none",
isZoomed: false,
isBlurred: false,
showSkeleton: false,
disableAnimation: false,
},
],
compoundSlots: [
{
slots: ["wrapper", "img", "blurredImg", "zoomedWrapper"],

View File

@ -245,7 +245,6 @@ const input = tv({
labelPlacement: "inside",
isDisabled: false,
isMultiline: false,
disableAnimation: false,
},
compoundVariants: [
// flat & color

View File

@ -101,7 +101,6 @@ const link = tv({
isBlock: false,
underline: "none",
isDisabled: false,
disableAnimation: false,
},
});

View File

@ -148,7 +148,6 @@ const menuItem = tv({
defaultVariants: {
variant: "solid",
color: "default",
disableAnimation: false,
showDivider: false,
},
compoundVariants: [

View File

@ -32,16 +32,6 @@ const modal = tv({
"z-50",
"overflow-x-auto",
"justify-center",
// mobile animation vars
"[--scale-enter:100%]",
"[--scale-exit:100%]",
"[--slide-enter:0px]",
"[--slide-exit:80px]",
// tablet/desktop animation vars
"sm:[--scale-enter:100%]",
"sm:[--scale-exit:103%]",
"sm:[--slide-enter:0px]",
"sm:[--slide-exit:0px]",
],
base: [
"flex",
@ -175,6 +165,22 @@ const modal = tv({
base: "my-16",
},
},
disableAnimation: {
false: {
wrapper: [
// mobile animation vars
"[--scale-enter:100%]",
"[--scale-exit:100%]",
"[--slide-enter:0px]",
"[--slide-exit:80px]",
// tablet/desktop animation vars
"sm:[--scale-enter:100%]",
"sm:[--scale-exit:103%]",
"sm:[--slide-enter:0px]",
"sm:[--slide-exit:0px]",
],
},
},
},
defaultVariants: {
size: "md",

View File

@ -154,7 +154,6 @@ const pagination = tv({
isCompact: false,
isDisabled: false,
showShadow: false,
disableAnimation: false,
disableCursorAnimation: false,
},
compoundVariants: [

View File

@ -175,7 +175,6 @@ const popover = tv({
size: "md",
shadow: "md",
backdrop: "transparent",
disableAnimation: false,
triggerScaleOnOpen: true,
},
compoundVariants: [

View File

@ -119,7 +119,6 @@ const progress = tv(
isStriped: false,
isIndeterminate: false,
isDisabled: false,
disableAnimation: false,
},
compoundVariants: [
// disableAnimation && !isIndeterminate

View File

@ -141,7 +141,6 @@ const radio = tv({
size: "md",
isDisabled: false,
isInvalid: false,
disableAnimation: false,
},
});
@ -187,7 +186,6 @@ const radioGroup = tv({
defaultVariants: {
isInvalid: false,
isRequired: false,
disableAnimation: false,
},
});

View File

@ -208,7 +208,6 @@ const select = tv({
fullWidth: true,
isDisabled: false,
isMultiline: false,
disableAnimation: false,
disableSelectorIconRotation: false,
},
compoundVariants: [

View File

@ -59,9 +59,7 @@ const skeleton = tv({
},
},
},
defaultVariants: {
disableAnimation: false,
},
defaultVariants: {},
});
export type SkeletonVariantProps = VariantProps<typeof skeleton>;

View File

@ -418,7 +418,6 @@ const slider = tv({
hideThumb: false,
isDisabled: false,
disableThumbScale: false,
disableAnimation: false,
showOutline: false,
},
});

View File

@ -100,7 +100,6 @@ const snippet = tv({
variant: "flat",
size: "md",
fullWidth: false,
disableAnimation: false,
},
compoundVariants: [
// solid - shadow / color

View File

@ -259,7 +259,6 @@ const table = tv({
hideHeader: false,
isStriped: false,
fullWidth: true,
disableAnimation: false,
},
});

Some files were not shown because too many files have changed in this diff Show More