mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
feat(progress): component done, needless useId removed, SSR provider exported again
This commit is contained in:
parent
187e8dde83
commit
791b955800
@ -117,14 +117,12 @@ export function useCheckbox(props: UseCheckboxProps) {
|
||||
const domRef = useFocusableRef(ref as FocusableRef<HTMLLabelElement>, inputRef);
|
||||
|
||||
const labelId = useId();
|
||||
const inputId = useId();
|
||||
|
||||
const ariaCheckboxProps = useMemo(() => {
|
||||
const ariaLabel =
|
||||
otherProps["aria-label"] || typeof children === "string" ? (children as string) : undefined;
|
||||
|
||||
return {
|
||||
id: inputId,
|
||||
name,
|
||||
value,
|
||||
children,
|
||||
@ -143,7 +141,6 @@ export function useCheckbox(props: UseCheckboxProps) {
|
||||
}, [
|
||||
value,
|
||||
name,
|
||||
inputId,
|
||||
labelId,
|
||||
children,
|
||||
autoFocus,
|
||||
@ -236,7 +233,6 @@ export function useCheckbox(props: UseCheckboxProps) {
|
||||
const getLabelProps: PropGetter = useCallback(
|
||||
() => ({
|
||||
id: labelId,
|
||||
htmlFor: inputProps.id || inputId,
|
||||
"data-disabled": dataAttr(isDisabled),
|
||||
"data-checked": dataAttr(isSelected),
|
||||
"data-invalid": dataAttr(isInvalid),
|
||||
|
||||
@ -5,7 +5,7 @@ import {Progress} from "../src";
|
||||
|
||||
describe("Progress", () => {
|
||||
it("should render correctly", () => {
|
||||
const wrapper = render(<Progress />);
|
||||
const wrapper = render(<Progress aria-label="progress" />);
|
||||
|
||||
expect(() => wrapper.unmount()).not.toThrow();
|
||||
});
|
||||
@ -13,7 +13,82 @@ describe("Progress", () => {
|
||||
it("ref should be forwarded", () => {
|
||||
const ref = React.createRef<HTMLDivElement>();
|
||||
|
||||
render(<Progress ref={ref} />);
|
||||
render(<Progress ref={ref} aria-label="progress" />);
|
||||
expect(ref.current).not.toBeNull();
|
||||
});
|
||||
|
||||
it("should contain progress aria attributes", () => {
|
||||
const {container} = render(<Progress aria-label="progress" />);
|
||||
const div = container.querySelector("div");
|
||||
|
||||
expect(div).toHaveAttribute("role", "progressbar");
|
||||
|
||||
expect(div).toHaveAttribute("aria-valuemin", "0");
|
||||
expect(div).toHaveAttribute("aria-valuemax", "100");
|
||||
expect(div).toHaveAttribute("aria-valuenow", "0");
|
||||
expect(div).toHaveAttribute("aria-valuetext", "0%");
|
||||
});
|
||||
|
||||
it("should display the correct value", () => {
|
||||
const {container} = render(<Progress aria-label="progress" value={55} />);
|
||||
|
||||
// get the "aria-valuenow" attribute
|
||||
const value = container.querySelector("div")?.getAttribute("aria-valuenow");
|
||||
|
||||
expect(value).toBe("55");
|
||||
});
|
||||
|
||||
it("should support label value formatting", () => {
|
||||
const {container} = render(
|
||||
<Progress
|
||||
aria-label="progress"
|
||||
formatOptions={{style: "currency", currency: "ARS"}}
|
||||
value={55}
|
||||
/>,
|
||||
);
|
||||
|
||||
// get the "aria-valuetext" attribute
|
||||
const value = container.querySelector("div")?.getAttribute("aria-valuetext");
|
||||
|
||||
expect(value).toBe("ARS 55.00");
|
||||
});
|
||||
|
||||
it("should ignore a value under the minimum", () => {
|
||||
const {container} = render(<Progress aria-label="progress" value={-1} />);
|
||||
|
||||
// get the "aria-valuenow" attribute
|
||||
const value = container.querySelector("div")?.getAttribute("aria-valuenow");
|
||||
|
||||
expect(value).toBe("0");
|
||||
});
|
||||
|
||||
it("should ignore a value over the maximum", () => {
|
||||
const {container} = render(<Progress aria-label="progress" value={101} />);
|
||||
|
||||
// get the "aria-valuenow" attribute
|
||||
const value = container.querySelector("div")?.getAttribute("aria-valuenow");
|
||||
|
||||
expect(value).toBe("100");
|
||||
});
|
||||
|
||||
it("should render a label", () => {
|
||||
const {container} = render(<Progress aria-label="progress" label="Loading..." />);
|
||||
|
||||
expect(container.querySelector("span")).not.toBeNull();
|
||||
});
|
||||
|
||||
it("should render a value label", () => {
|
||||
const {container} = render(<Progress showValueLabel aria-label="progress" value={55} />);
|
||||
|
||||
expect(container.querySelector("span")).not.toBeNull();
|
||||
});
|
||||
|
||||
it("the aria-valuenow should not be set if isIndeterminate is true", () => {
|
||||
const {container} = render(<Progress isIndeterminate aria-label="progress" />);
|
||||
|
||||
// get the "aria-valuenow" attribute
|
||||
const value = container.querySelector("div")?.getAttribute("aria-valuenow");
|
||||
|
||||
expect(value).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@ -40,6 +40,7 @@
|
||||
"@nextui-org/aria-utils": "workspace:*",
|
||||
"@nextui-org/dom-utils": "workspace:*",
|
||||
"@nextui-org/shared-utils": "workspace:*",
|
||||
"@nextui-org/use-is-mounted": "workspace:*",
|
||||
"@nextui-org/system": "workspace:*",
|
||||
"@nextui-org/theme": "workspace:*",
|
||||
"@react-aria/i18n": "^3.7.0",
|
||||
|
||||
@ -10,8 +10,8 @@ const Progress = forwardRef<ProgressProps, "div">((props, ref) => {
|
||||
slots,
|
||||
styles,
|
||||
label,
|
||||
percentage,
|
||||
showValueLabel,
|
||||
barWidth,
|
||||
getProgressBarProps,
|
||||
getLabelProps,
|
||||
} = useProgress({ref, ...props});
|
||||
@ -28,11 +28,11 @@ const Progress = forwardRef<ProgressProps, "div">((props, ref) => {
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className={slots.wrapper({class: styles?.wrapper})}>
|
||||
<div className={slots.track({class: styles?.track})}>
|
||||
<div
|
||||
className={slots.filler({class: styles?.filler})}
|
||||
style={{
|
||||
width: barWidth,
|
||||
transform: `translateX(-${100 - (percentage || 0)}%)`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -5,9 +5,10 @@ import type {AriaProgressBarProps} from "@react-types/progress";
|
||||
import {HTMLNextUIProps, mapPropsVariants} from "@nextui-org/system";
|
||||
import {progress} from "@nextui-org/theme";
|
||||
import {useDOMRef} from "@nextui-org/dom-utils";
|
||||
import {clsx, ReactRef} from "@nextui-org/shared-utils";
|
||||
import {clsx, dataAttr, ReactRef} from "@nextui-org/shared-utils";
|
||||
import {mergeProps} from "@react-aria/utils";
|
||||
import {useMemo, useCallback} from "react";
|
||||
import {useIsMounted} from "@nextui-org/use-is-mounted";
|
||||
|
||||
import {useProgressBar as useAriaProgress} from "./use-aria-progress";
|
||||
|
||||
@ -24,11 +25,11 @@ export interface Props extends HTMLNextUIProps<"div"> {
|
||||
* ```ts
|
||||
* <Progress styles={{
|
||||
* base:"base-classes",
|
||||
* wrapper: "wrapper-classes",
|
||||
* filler: "filler-classes",
|
||||
* labelWrapper: "labelWrapper-classes",
|
||||
* label: "label-classes",
|
||||
* value: "value-classes",
|
||||
* track: "track-classes",
|
||||
* filler: "filler-classes",
|
||||
* }} />
|
||||
* ```
|
||||
*/
|
||||
@ -52,7 +53,6 @@ export function useProgress(originalProps: UseProgressProps) {
|
||||
minValue = 0,
|
||||
maxValue = 100,
|
||||
showValueLabel = false,
|
||||
isIndeterminate = false,
|
||||
formatOptions = {
|
||||
style: "percent",
|
||||
},
|
||||
@ -64,6 +64,11 @@ export function useProgress(originalProps: UseProgressProps) {
|
||||
const domRef = useDOMRef(ref);
|
||||
|
||||
const baseStyles = clsx(styles?.base, className);
|
||||
const [, isMounted] = useIsMounted({
|
||||
rerender: true,
|
||||
delay: 100,
|
||||
});
|
||||
const isIndeterminate = originalProps.isIndeterminate;
|
||||
|
||||
const {progressBarProps, labelProps} = useAriaProgress({
|
||||
id,
|
||||
@ -72,8 +77,8 @@ export function useProgress(originalProps: UseProgressProps) {
|
||||
minValue,
|
||||
maxValue,
|
||||
valueLabel,
|
||||
isIndeterminate,
|
||||
formatOptions,
|
||||
isIndeterminate,
|
||||
"aria-labelledby": originalProps["aria-labelledby"],
|
||||
"aria-label": originalProps["aria-label"],
|
||||
});
|
||||
@ -86,21 +91,34 @@ export function useProgress(originalProps: UseProgressProps) {
|
||||
[...Object.values(variantProps)],
|
||||
);
|
||||
|
||||
const selfMounted = originalProps.disableAnimation ? true : isMounted;
|
||||
|
||||
// Calculate the width of the progress bar as a percentage
|
||||
const percentage = useMemo(
|
||||
() => (isIndeterminate ? undefined : ((value - minValue) / (maxValue - minValue)) * 100),
|
||||
[isIndeterminate, value, minValue, maxValue],
|
||||
() =>
|
||||
isIndeterminate || !selfMounted
|
||||
? undefined
|
||||
: ((value - minValue) / (maxValue - minValue)) * 100,
|
||||
[selfMounted, isIndeterminate, value, minValue, maxValue],
|
||||
);
|
||||
|
||||
const barWidth = typeof percentage === "number" ? `${Math.round(percentage)}%` : undefined;
|
||||
|
||||
const getProgressBarProps = useCallback<PropGetter>(
|
||||
(props = {}) => ({
|
||||
ref: domRef,
|
||||
"data-indeterminate": dataAttr(isIndeterminate),
|
||||
"data-disabled": dataAttr(originalProps.isDisabled),
|
||||
className: slots.base({class: baseStyles}),
|
||||
...mergeProps(progressBarProps, otherProps, props),
|
||||
}),
|
||||
[domRef, slots, baseStyles, progressBarProps, otherProps],
|
||||
[
|
||||
domRef,
|
||||
slots,
|
||||
isIndeterminate,
|
||||
originalProps.isDisabled,
|
||||
baseStyles,
|
||||
progressBarProps,
|
||||
otherProps,
|
||||
],
|
||||
);
|
||||
|
||||
const getLabelProps = useCallback<PropGetter>(
|
||||
@ -117,7 +135,6 @@ export function useProgress(originalProps: UseProgressProps) {
|
||||
slots,
|
||||
styles,
|
||||
label,
|
||||
barWidth,
|
||||
percentage,
|
||||
showValueLabel,
|
||||
getProgressBarProps,
|
||||
|
||||
@ -39,11 +39,16 @@ const defaultProps = {
|
||||
value: 55,
|
||||
};
|
||||
|
||||
const Template: ComponentStory<typeof Progress> = (args: ProgressProps) => <Progress {...args} />;
|
||||
const Template: ComponentStory<typeof Progress> = (args: ProgressProps) => (
|
||||
<div className="max-w-[400px]">
|
||||
<Progress {...args} />
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
...defaultProps,
|
||||
"aria-label": "Loading...",
|
||||
};
|
||||
|
||||
export const WithLabel = Template.bind({});
|
||||
@ -58,3 +63,23 @@ WithValueLabel.args = {
|
||||
label: "Loading...",
|
||||
showValueLabel: true,
|
||||
};
|
||||
|
||||
export const WithValueFormatting = Template.bind({});
|
||||
WithValueFormatting.args = {
|
||||
...defaultProps,
|
||||
label: "Loading...",
|
||||
showValueLabel: true,
|
||||
formatOptions: {style: "currency", currency: "ARS"},
|
||||
};
|
||||
|
||||
export const Indeterminate = Template.bind({});
|
||||
Indeterminate.args = {
|
||||
...defaultProps,
|
||||
isIndeterminate: true,
|
||||
};
|
||||
|
||||
export const Striped = Template.bind({});
|
||||
Striped.args = {
|
||||
...defaultProps,
|
||||
isStriped: true,
|
||||
};
|
||||
|
||||
@ -86,9 +86,6 @@ export function useRadio(props: UseRadioProps) {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const labelId = useId();
|
||||
const inputGenId = useId();
|
||||
|
||||
const inputId = id || inputGenId;
|
||||
|
||||
const isDisabled = useMemo(() => !!isDisabledProp, [isDisabledProp]);
|
||||
const isRequired = useMemo(() => groupContext.isRequired ?? false, [groupContext.isRequired]);
|
||||
@ -106,14 +103,14 @@ export function useRadio(props: UseRadioProps) {
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
id: inputId,
|
||||
id,
|
||||
isDisabled,
|
||||
isRequired,
|
||||
"aria-label": ariaLabel,
|
||||
"aria-labelledby": otherProps["aria-labelledby"] || labelId,
|
||||
"aria-describedby": ariaDescribedBy,
|
||||
};
|
||||
}, [labelId, inputId, isDisabled, isRequired]);
|
||||
}, [labelId, id, isDisabled, isRequired]);
|
||||
|
||||
const {inputProps} = useReactAriaRadio(
|
||||
{
|
||||
@ -196,7 +193,6 @@ export function useRadio(props: UseRadioProps) {
|
||||
(props = {}) => ({
|
||||
...props,
|
||||
id: labelId,
|
||||
htmlFor: inputId,
|
||||
"data-disabled": dataAttr(isDisabled),
|
||||
"data-checked": dataAttr(isSelected),
|
||||
"data-invalid": dataAttr(isInvalid),
|
||||
|
||||
@ -98,7 +98,6 @@ export function useSwitch(originalProps: UseSwitchProps) {
|
||||
const domRef = useFocusableRef(ref as FocusableRef<HTMLLabelElement>, inputRef);
|
||||
|
||||
const labelId = useId();
|
||||
const inputId = useId();
|
||||
|
||||
const ariaSwitchProps = useMemo(() => {
|
||||
const ariaLabel =
|
||||
@ -187,7 +186,7 @@ export function useSwitch(originalProps: UseSwitchProps) {
|
||||
const getInputProps: PropGetter = () => {
|
||||
return {
|
||||
ref: inputRef,
|
||||
id: inputProps.id || inputId,
|
||||
id: inputProps.id,
|
||||
...mergeProps(inputProps, focusProps),
|
||||
};
|
||||
};
|
||||
@ -207,7 +206,6 @@ export function useSwitch(originalProps: UseSwitchProps) {
|
||||
const getLabelProps: PropGetter = useCallback(
|
||||
() => ({
|
||||
id: labelId,
|
||||
htmlFor: inputProps.id || inputId,
|
||||
"data-disabled": dataAttr(isDisabled),
|
||||
"data-checked": dataAttr(isSelected),
|
||||
className: slots.label({class: styles?.label}),
|
||||
|
||||
@ -37,8 +37,8 @@
|
||||
"react": ">=18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"react": "^18.0.0",
|
||||
"clean-package": "2.2.0"
|
||||
"clean-package": "2.2.0",
|
||||
"react": "^18.0.0"
|
||||
},
|
||||
"clean-package": "../../../clean-package.config.json",
|
||||
"tsup": {
|
||||
@ -48,5 +48,8 @@
|
||||
"cjs",
|
||||
"esm"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-aria/ssr": "^3.5.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,2 +1,3 @@
|
||||
export * from "./types";
|
||||
export * from "./utils";
|
||||
export * from "./provider";
|
||||
|
||||
3
packages/core/system/src/provider.tsx
Normal file
3
packages/core/system/src/provider.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
import {SSRProvider} from "@react-aria/ssr";
|
||||
|
||||
export const NextUIProvider = SSRProvider;
|
||||
@ -5,6 +5,8 @@ export const animations = {
|
||||
"spinner-linear-spin": "spinner-spin 0.8s linear infinite",
|
||||
"appearance-in": "appearance-in 250ms ease-out normal both",
|
||||
"appearance-out": "appearance-out 60ms ease-in normal both",
|
||||
"indeterminate-bar":
|
||||
"indeterminate-bar 1.5s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite normal none running",
|
||||
},
|
||||
keyframes: {
|
||||
"spinner-spin": {
|
||||
@ -52,5 +54,13 @@ export const animations = {
|
||||
transform: "scale(0.85)",
|
||||
},
|
||||
},
|
||||
"indeterminate-bar": {
|
||||
"0%": {
|
||||
transform: "translateX(-150%)",
|
||||
},
|
||||
"100%": {
|
||||
transform: "translateX(200%)",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -33,36 +33,35 @@ const card = tv({
|
||||
],
|
||||
header: [
|
||||
"flex",
|
||||
"p-3",
|
||||
"z-10",
|
||||
"justify-start",
|
||||
"items-center",
|
||||
"shrink-0",
|
||||
"w-full",
|
||||
"overflow-inherit",
|
||||
"color-inherit",
|
||||
"p-3",
|
||||
"z-10",
|
||||
"subpixel-antialiased",
|
||||
],
|
||||
body: [
|
||||
"relative",
|
||||
"flex",
|
||||
"p-5",
|
||||
"flex-auto",
|
||||
"flex-col",
|
||||
"place-content-inherit",
|
||||
"align-items-inherit",
|
||||
"w-full",
|
||||
"h-auto",
|
||||
"py-5",
|
||||
"px-3",
|
||||
"break-words",
|
||||
"text-left",
|
||||
"overflow-y-auto",
|
||||
"subpixel-antialiased",
|
||||
],
|
||||
footer: [
|
||||
"p-3",
|
||||
"w-full",
|
||||
"h-auto",
|
||||
"p-3",
|
||||
"flex",
|
||||
"items-center",
|
||||
"overflow-hidden",
|
||||
|
||||
@ -5,113 +5,143 @@ import {tv, type VariantProps} from "tailwind-variants";
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* const {base, wrapper, filler, labelWrapper, label, value} = progress({...})
|
||||
* const {base, labelWrapper, label, value, track, filler} = progress({...})
|
||||
*
|
||||
* <div className={base()} aria-label="progress" role="progressbar" aria-valuenow={value} aria-valuemin={min} aria-valuemax={max}>
|
||||
* <div className={labelWrapper()}>
|
||||
* <span className={label()}>{label}</span>
|
||||
* <span className={value()}>{value}</span>
|
||||
* </div>
|
||||
* <div className={wrapper()}>
|
||||
* <div className={track()}>
|
||||
* <div className={filler()} style={{width: `${value}%`}} />
|
||||
* </div>
|
||||
* </div>
|
||||
* ```
|
||||
*/
|
||||
const progress = tv({
|
||||
slots: {
|
||||
base: "flex flex-col gap-2",
|
||||
label: "",
|
||||
labelWrapper: "flex justify-between",
|
||||
value: "",
|
||||
wrapper: "flex flex-1 bg-neutral",
|
||||
filler: "",
|
||||
const progress = tv(
|
||||
{
|
||||
slots: {
|
||||
base: "flex flex-col gap-2",
|
||||
label: "",
|
||||
labelWrapper: "flex justify-between",
|
||||
value: "",
|
||||
track: "z-0 relative bg-neutral-200 overflow-hidden",
|
||||
filler: "h-full",
|
||||
},
|
||||
variants: {
|
||||
color: {
|
||||
neutral: {
|
||||
filler: "bg-neutral-400",
|
||||
},
|
||||
primary: {
|
||||
filler: "bg-primary",
|
||||
},
|
||||
secondary: {
|
||||
filler: "bg-secondary",
|
||||
},
|
||||
success: {
|
||||
filler: "bg-success",
|
||||
},
|
||||
warning: {
|
||||
filler: "bg-warning",
|
||||
},
|
||||
danger: {
|
||||
filler: "bg-danger",
|
||||
},
|
||||
},
|
||||
size: {
|
||||
xs: {
|
||||
track: "h-1",
|
||||
},
|
||||
sm: {
|
||||
track: "h-2",
|
||||
},
|
||||
md: {
|
||||
track: "h-4",
|
||||
},
|
||||
lg: {
|
||||
track: "h-6",
|
||||
},
|
||||
xl: {
|
||||
track: "h-7",
|
||||
},
|
||||
},
|
||||
radius: {
|
||||
none: {
|
||||
track: "rounded-none",
|
||||
filler: "rounded-none",
|
||||
},
|
||||
base: {
|
||||
track: "rounded",
|
||||
filler: "rounded",
|
||||
},
|
||||
sm: {
|
||||
track: "rounded-sm",
|
||||
filler: "rounded-sm",
|
||||
},
|
||||
md: {
|
||||
track: "rounded-md",
|
||||
filler: "rounded-md",
|
||||
},
|
||||
lg: {
|
||||
track: "rounded-lg",
|
||||
filler: "rounded-lg",
|
||||
},
|
||||
xl: {
|
||||
track: "rounded-xl",
|
||||
filler: "rounded-xl",
|
||||
},
|
||||
full: {
|
||||
track: "rounded-full",
|
||||
filler: "rounded-full",
|
||||
},
|
||||
},
|
||||
isStriped: {
|
||||
true: {
|
||||
filler: "bg-stripe-gradient bg-[length:1.25rem_1.25rem]",
|
||||
},
|
||||
},
|
||||
isIndeterminate: {
|
||||
true: {
|
||||
filler: ["absolute", "w-1/2", "animate-indeterminate-bar"],
|
||||
},
|
||||
},
|
||||
isDisabled: {
|
||||
true: {
|
||||
base: "opacity-50 cursor-not-allowed",
|
||||
},
|
||||
},
|
||||
disableAnimation: {
|
||||
true: {},
|
||||
false: {
|
||||
filler: "transition-transform !duration-500",
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
color: "primary",
|
||||
size: "md",
|
||||
radius: "full",
|
||||
isStriped: false,
|
||||
isIndeterminate: false,
|
||||
isDisabled: false,
|
||||
disableAnimation: false,
|
||||
},
|
||||
compoundVariants: [
|
||||
// disableAnimation && !isIndeterminate
|
||||
{
|
||||
disableAnimation: true,
|
||||
isIndeterminate: false,
|
||||
class: {
|
||||
filler: "!transition-none motion-reduce:transition-none",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
variants: {
|
||||
color: {
|
||||
neutral: {
|
||||
filler: "bg-neutral-500",
|
||||
},
|
||||
primary: {
|
||||
filler: "bg-primary",
|
||||
},
|
||||
secondary: {
|
||||
filler: "bg-secondary",
|
||||
},
|
||||
success: {
|
||||
filler: "bg-success",
|
||||
},
|
||||
warning: {
|
||||
filler: "bg-warning",
|
||||
},
|
||||
danger: {
|
||||
filler: "bg-danger",
|
||||
},
|
||||
},
|
||||
size: {
|
||||
xs: {
|
||||
filler: "h-1",
|
||||
},
|
||||
sm: {
|
||||
filler: "h-2",
|
||||
},
|
||||
md: {
|
||||
filler: "h-4",
|
||||
},
|
||||
lg: {
|
||||
filler: "h-6",
|
||||
},
|
||||
xl: {
|
||||
filler: "h-7",
|
||||
},
|
||||
},
|
||||
radius: {
|
||||
none: {
|
||||
wrapper: "rounded-none",
|
||||
filler: "rounded-none",
|
||||
},
|
||||
wrapper: {
|
||||
wrapper: "rounded",
|
||||
filler: "rounded",
|
||||
},
|
||||
sm: {
|
||||
wrapper: "rounded-sm",
|
||||
filler: "rounded-sm",
|
||||
},
|
||||
md: {
|
||||
wrapper: "rounded-md",
|
||||
filler: "rounded-md",
|
||||
},
|
||||
lg: {
|
||||
wrapper: "rounded-lg",
|
||||
filler: "rounded-lg",
|
||||
},
|
||||
xl: {
|
||||
wrapper: "rounded-xl",
|
||||
filler: "rounded-xl",
|
||||
},
|
||||
full: {
|
||||
wrapper: "rounded-full",
|
||||
filler: "rounded-full",
|
||||
},
|
||||
},
|
||||
isDisabled: {
|
||||
true: {
|
||||
base: "opacity-50 cursor-not-allowed",
|
||||
},
|
||||
},
|
||||
disableAnimation: {
|
||||
true: {},
|
||||
},
|
||||
{
|
||||
twMerge: false,
|
||||
},
|
||||
defaultVariants: {
|
||||
color: "primary",
|
||||
size: "md",
|
||||
radius: "full",
|
||||
isDisabled: false,
|
||||
disableAnimation: false,
|
||||
},
|
||||
});
|
||||
);
|
||||
|
||||
export type ProgressVariantProps = VariantProps<typeof progress>;
|
||||
export type ProgressSlots = keyof ReturnType<typeof progress>;
|
||||
|
||||
@ -198,6 +198,10 @@ const corePlugin = (config: ConfigObject | ConfigFunction = {}, defaultTheme: De
|
||||
3: "3px",
|
||||
5: "5px",
|
||||
},
|
||||
backgroundImage: {
|
||||
"stripe-gradient":
|
||||
"linear-gradient(45deg, rgba(0, 0, 0, 0.1) 25%, transparent 25%, transparent 50%, rgba(0, 0, 0, 0.1) 50%, rgba(0, 0, 0, 0.1) 75%, transparent 75%, transparent)",
|
||||
},
|
||||
transitionDuration: {
|
||||
0: "0ms",
|
||||
250: "250ms",
|
||||
|
||||
@ -51,6 +51,11 @@ export const utilities = {
|
||||
"transition-timing-function": "ease",
|
||||
"transition-duration": DEFAULT_TRANSITION_DURATION,
|
||||
},
|
||||
".transition-left": {
|
||||
"transition-property": "left",
|
||||
"transition-timing-function": "ease",
|
||||
"transition-duration": DEFAULT_TRANSITION_DURATION,
|
||||
},
|
||||
".transition-shadow": {
|
||||
"transition-property": "box-shadow",
|
||||
"transition-timing-function": "ease",
|
||||
|
||||
@ -2,10 +2,11 @@ import {useCallback, useEffect, useRef, useState} from "react";
|
||||
|
||||
export type UseIsMountedProps = {
|
||||
rerender?: boolean;
|
||||
delay?: number;
|
||||
};
|
||||
|
||||
export function useIsMounted(props: UseIsMountedProps = {}) {
|
||||
const {rerender = false} = props;
|
||||
const {rerender = false, delay = 0} = props;
|
||||
|
||||
const isMountedRef = useRef(false);
|
||||
const [isMounted, setIsMounted] = useState(false);
|
||||
@ -13,9 +14,16 @@ export function useIsMounted(props: UseIsMountedProps = {}) {
|
||||
// Update the ref when the component mounts
|
||||
useEffect(() => {
|
||||
isMountedRef.current = true;
|
||||
let timer: any = null;
|
||||
|
||||
if (rerender) {
|
||||
setIsMounted(true);
|
||||
if (delay > 0) {
|
||||
timer = setTimeout(() => {
|
||||
setIsMounted(true);
|
||||
}, delay);
|
||||
} else {
|
||||
setIsMounted(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the ref when the component unmounts
|
||||
@ -24,6 +32,9 @@ export function useIsMounted(props: UseIsMountedProps = {}) {
|
||||
if (rerender) {
|
||||
setIsMounted(false);
|
||||
}
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
};
|
||||
}, [rerender]);
|
||||
|
||||
|
||||
5
pnpm-lock.yaml
generated
5
pnpm-lock.yaml
generated
@ -629,6 +629,7 @@ importers:
|
||||
'@nextui-org/shared-utils': workspace:*
|
||||
'@nextui-org/system': workspace:*
|
||||
'@nextui-org/theme': workspace:*
|
||||
'@nextui-org/use-is-mounted': workspace:*
|
||||
'@react-aria/i18n': ^3.7.0
|
||||
'@react-aria/progress': ^3.4.0
|
||||
'@react-aria/utils': ^3.15.0
|
||||
@ -641,6 +642,7 @@ importers:
|
||||
'@nextui-org/shared-utils': link:../../utilities/shared-utils
|
||||
'@nextui-org/system': link:../../core/system
|
||||
'@nextui-org/theme': link:../../core/theme
|
||||
'@nextui-org/use-is-mounted': link:../../hooks/use-is-mounted
|
||||
'@react-aria/i18n': 3.7.0_react@18.2.0
|
||||
'@react-aria/progress': 3.4.0_react@18.2.0
|
||||
'@react-aria/utils': 3.15.0_react@18.2.0
|
||||
@ -874,8 +876,11 @@ importers:
|
||||
|
||||
packages/core/system:
|
||||
specifiers:
|
||||
'@react-aria/ssr': ^3.5.0
|
||||
clean-package: 2.2.0
|
||||
react: ^18.2.0
|
||||
dependencies:
|
||||
'@react-aria/ssr': 3.5.0_react@18.2.0
|
||||
devDependencies:
|
||||
clean-package: 2.2.0
|
||||
react: 18.2.0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user