Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions packages/components/autocomplete/src/autocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,7 @@ function Autocomplete<T extends object>(props: Props<T>, ref: ForwardedRef<HTMLI
} = useAutocomplete<T>({...props, ref});

const popoverContent = isOpen ? (
<FreeSoloPopover
{...getPopoverProps()}
// avoid popover closing issue in autocomplete with open modal
shouldCloseOnInteractOutside={() => false}
state={state}
>
<FreeSoloPopover {...getPopoverProps()} state={state}>
<ScrollShadow {...getListBoxWrapperProps()}>
<Listbox {...getListBoxProps()} />
</ScrollShadow>
Expand Down
13 changes: 10 additions & 3 deletions packages/components/calendar/src/calendar-base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {useCalendarContext} from "./calendar-context";

export interface CalendarBaseProps extends HTMLNextUIProps<"div"> {
Component?: As;
showHelper?: boolean;
topContent?: ReactNode;
bottomContent?: ReactNode;
calendarProps: HTMLAttributes<HTMLElement>;
Expand All @@ -36,6 +37,7 @@ export interface CalendarBaseProps extends HTMLNextUIProps<"div"> {
export function CalendarBase(props: CalendarBaseProps) {
const {
Component = "div",
showHelper,
topContent,
bottomContent,
calendarProps,
Expand Down Expand Up @@ -143,9 +145,14 @@ export function CalendarBase(props: CalendarBaseProps) {
<h2>{calendarProps["aria-label"]}</h2>
</VisuallyHidden>
{disableAnimation ? (
calendarContent
<div className={slots?.content({class: classNames?.content})} data-slot="content">
{calendarContent}
</div>
) : (
<ResizablePanel>
<ResizablePanel
className={slots?.content({class: classNames?.content})}
data-slot="content"
>
<AnimatePresence custom={direction} initial={false} mode="popLayout">
<>
<MotionConfig transition={transition}>
Expand All @@ -166,7 +173,7 @@ export function CalendarBase(props: CalendarBaseProps) {
onClick={() => state.focusNextPage()}
/>
</VisuallyHidden>
{state.isValueInvalid && (
{state.isValueInvalid && showHelper && (
<div
className={slots?.helperWrapper({class: classNames?.helperWrapper})}
data-slot="helper-wrapper"
Expand Down
2 changes: 1 addition & 1 deletion packages/components/calendar/src/calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {CalendarBase} from "./calendar-base";
interface Props<T extends DateValue> extends Omit<UseCalendarProps<T>, "isHeaderWrapperExpanded"> {}

function Calendar<T extends DateValue>(props: Props<T>, ref: ForwardedRef<HTMLDivElement>) {
const {context, getBaseCalendarProps} = useCalendar({...props, ref});
const {context, getBaseCalendarProps} = useCalendar<T>({...props, ref});

return (
<CalendarProvider value={context}>
Expand Down
2 changes: 1 addition & 1 deletion packages/components/calendar/src/range-calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface Props<T extends DateValue>
> {}

function RangeCalendar<T extends DateValue>(props: Props<T>, ref: ForwardedRef<HTMLDivElement>) {
const {context, getBaseCalendarProps} = useRangeCalendar({...props, ref});
const {context, getBaseCalendarProps} = useRangeCalendar<T>({...props, ref});

return (
<CalendarProvider value={context}>
Expand Down
8 changes: 8 additions & 0 deletions packages/components/calendar/src/use-calendar-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ interface Props extends NextUIBaseProps {
* Props for the next button.
*/
nextButtonProps?: ButtonProps;
/**
* Whether to show the description or error message.
* @default true
*/
showHelper?: boolean;
/**
* Whether the calendar header is expanded. This is only available if the `showMonthAndYearPickers` prop is set to `true`.
* @default false
Expand Down Expand Up @@ -126,6 +131,7 @@ interface Props extends NextUIBaseProps {
* prevButton:"prev-button-classes",
* header:"header-classes",
* title:"title-classes",
* content:"content-classes",
* gridWrapper:"grid-wrapper-classes",
* grid:"grid-classes",
* gridHeader:"grid-header-classes",
Expand Down Expand Up @@ -178,6 +184,7 @@ export function useCalendarBase(originalProps: UseCalendarBasePropsComplete) {
className,
topContent,
bottomContent,
showHelper = true,
visibleMonths: visibleMonthsProp = 1,
weekdayStyle = "narrow",
navButtonProps = {},
Expand Down Expand Up @@ -283,6 +290,7 @@ export function useCalendarBase(originalProps: UseCalendarBasePropsComplete) {
locale,
minValue,
maxValue,
showHelper,
weekdayStyle,
visibleMonths,
visibleDuration,
Expand Down
2 changes: 2 additions & 0 deletions packages/components/calendar/src/use-calendar-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ export function useCalendarPicker(props: CalendarPickerProps) {
nextValue = value + 3;
break;
case "Escape":
case "Enter":
case " ":
setIsHeaderExpanded?.(false);
headerRef?.current?.focus();

Expand Down
2 changes: 2 additions & 0 deletions packages/components/calendar/src/use-calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export function useCalendar<T extends DateValue>({
locale,
minValue,
maxValue,
showHelper,
weekdayStyle,
visibleDuration,
shouldFilterDOMProps,
Expand Down Expand Up @@ -81,6 +82,7 @@ export function useCalendar<T extends DateValue>({
const getBaseCalendarProps = (props = {}): CalendarBaseProps => {
return {
Component,
showHelper,
topContent,
bottomContent,
buttonPickerProps,
Expand Down
2 changes: 2 additions & 0 deletions packages/components/calendar/src/use-range-calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export function useRangeCalendar<T extends DateValue>({
children,
domRef,
locale,
showHelper,
minValue,
maxValue,
weekdayStyle,
Expand Down Expand Up @@ -73,6 +74,7 @@ export function useRangeCalendar<T extends DateValue>({
const getBaseCalendarProps = (props = {}): CalendarBaseProps => {
return {
Component,
showHelper,
topContent,
bottomContent,
calendarRef: domRef,
Expand Down
3 changes: 3 additions & 0 deletions packages/components/calendar/stories/calendar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ const PresetsTemplate = (args: CalendarProps) => {
<CustomRadio value="14_days">14 days</CustomRadio>
</RadioGroup>
}
classNames={{
content: "w-full",
}}
focusedValue={value}
nextButtonProps={{
variant: "bordered",
Expand Down
53 changes: 34 additions & 19 deletions packages/components/date-input/__tests__/date-input.test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
/* eslint-disable jsx-a11y/no-autofocus */
import * as React from "react";
import {act, fireEvent, render} from "@testing-library/react";
import {CalendarDate, CalendarDateTime, ZonedDateTime} from "@internationalized/date";
import {CalendarDate, CalendarDateTime, DateValue, ZonedDateTime} from "@internationalized/date";
import {pointerMap, triggerPress} from "@nextui-org/test-utils";
import userEvent from "@testing-library/user-event";

import {DateInput} from "../src";
import {DateInput as DateInputBase, DateInputProps} from "../src";

/**
* Custom date-input to disable animations and avoid issues with react-motion and jest
*/
const DateInput = React.forwardRef((props: DateInputProps, ref: React.Ref<HTMLDivElement>) => {
return <DateInputBase {...props} ref={ref} disableAnimation />;
});

DateInput.displayName = "DateInput";

describe("DateInput", () => {
let user;
Expand Down Expand Up @@ -57,12 +66,12 @@ describe("DateInput", () => {
/>,
);

await act(() => {
user.tab();
await act(async () => {
await user.tab();
});

await act(() => {
user.keyboard("01011980");
await act(async () => {
await user.keyboard("01011980");
});

expect(tree.getByText("Date unavailable.")).toBeInTheDocument();
Expand Down Expand Up @@ -197,15 +206,17 @@ describe("DateInput", () => {
expect(onBlurSpy).not.toHaveBeenCalled();
expect(onFocusChangeSpy).not.toHaveBeenCalled();
expect(onFocusSpy).not.toHaveBeenCalled();

await user.tab();
await act(async () => {
await user.tab();
});
expect(segments[0]).toHaveFocus();

expect(onBlurSpy).not.toHaveBeenCalled();
expect(onFocusChangeSpy).toHaveBeenCalledTimes(1);
expect(onFocusSpy).toHaveBeenCalledTimes(1);

await user.tab();
await act(async () => {
await user.tab();
});
expect(segments[1]).toHaveFocus();
expect(onBlurSpy).not.toHaveBeenCalled();
expect(onFocusChangeSpy).toHaveBeenCalledTimes(1);
Expand All @@ -226,18 +237,22 @@ describe("DateInput", () => {
expect(onBlurSpy).not.toHaveBeenCalled();
expect(onFocusChangeSpy).not.toHaveBeenCalled();
expect(onFocusSpy).not.toHaveBeenCalled();

await user.tab();
await act(async () => {
await user.tab();
});
expect(segments[0]).toHaveFocus();

await user.tab();
await act(async () => {
await user.tab();
});
expect(segments[1]).toHaveFocus();

await user.tab();
await act(async () => {
await user.tab();
});
expect(segments[2]).toHaveFocus();
expect(onBlurSpy).toHaveBeenCalledTimes(0);

await user.tab();
await act(async () => {
await user.tab();
});
expect(onBlurSpy).toHaveBeenCalledTimes(1);
expect(onFocusChangeSpy).toHaveBeenCalledTimes(2);
expect(onFocusSpy).toHaveBeenCalledTimes(1);
Expand Down Expand Up @@ -296,7 +311,7 @@ describe("DateInput", () => {

it("supports form reset", async () => {
function Test() {
let [value, setValue] = React.useState(new CalendarDate(2020, 2, 3));
let [value, setValue] = React.useState<DateValue>(new CalendarDate(2020, 2, 3));

return (
<form>
Expand Down
13 changes: 8 additions & 5 deletions packages/components/date-input/src/date-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,16 @@ function DateInput<T extends DateValue>(props: Props<T>, ref: ForwardedRef<HTMLD
getFieldProps,
getLabelProps,
getInputWrapperProps,
getInnerWrapperProps,
getDescriptionProps,
getHelperWrapperProps,
getErrorMessageProps,
} = useDateInput({
} = useDateInput<T>({
...props,
ref,
});

const labelContent = label ? <label {...getLabelProps()}>{label}</label> : null;
const labelContent = label ? <span {...getLabelProps()}>{label}</span> : null;

const helperWrapper = useMemo(() => {
if (!hasHelper) return null;
Expand Down Expand Up @@ -81,10 +82,12 @@ function DateInput<T extends DateValue>(props: Props<T>, ref: ForwardedRef<HTMLD
<Component {...getBaseProps()}>
{shouldLabelBeOutside ? labelContent : null}
<div {...getInputWrapperProps()}>
{startContent}
{!shouldLabelBeOutside ? labelContent : null}
{inputContent}
{endContent}
<div {...getInnerWrapperProps()}>
{startContent}
{inputContent}
{endContent}
</div>
{shouldLabelBeOutside ? helperWrapper : null}
</div>
{!shouldLabelBeOutside ? helperWrapper : null}
Expand Down
Loading