Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(date-picker): add selectorButtonPlacement property #3248

Merged
merged 5 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
6 changes: 6 additions & 0 deletions .changeset/neat-donkeys-accept.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@nextui-org/date-picker": minor
"@nextui-org/theme": minor
---

Add support for selectorButtonPlacement property (#3015)
2 changes: 1 addition & 1 deletion apps/docs/content/components/date-input/error-message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default function App() {
label={"Birth date"}
defaultValue={parseDate("2024-04-04")}
placeholderValue={new CalendarDate(1995, 11, 6)}
description={"Thiis is my birth date."}
description={"This is my birth date."}
isInvalid
errorMessage="Please enter a valid date."
className="max-w-xs"
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/content/components/date-picker/description.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default function App() {
<DatePicker
label="Birth date"
className="max-w-[284px]"
description={"Thiis is my birth date."}
description={"This is my birth date."}
/>
</div>
);
Expand Down
2 changes: 2 additions & 0 deletions apps/docs/content/components/date-picker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import errorMessage from "./error-message";
import withMonthAndYearPickers from "./with-month-and-year-pickers";
import withTimeField from "./with-time-field";
import selectorIcon from "./selector-icon";
import selectorButtonPlacement from "./selector-button-placement";
import controlled from "./controlled";
import timeZones from "./time-zones";
import granularity from "./granularity";
Expand All @@ -31,6 +32,7 @@ export const datePickerContent = {
withMonthAndYearPickers,
withTimeField,
selectorIcon,
selectorButtonPlacement,
controlled,
timeZones,
granularity,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const App = `import {DatePicker} from "@nextui-org/react";

export default function App() {
return (
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
<DatePicker
label="Placement start"
selectorButtonPlacement="start"
/>
<DatePicker
label="Placement end (default)"
selectorButtonPlacement="end"
/>
</div>
);
}`;

const react = {
"/App.jsx": App,
};

export default {
...react,
};
2 changes: 2 additions & 0 deletions apps/docs/content/components/date-range-picker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import description from "./description";
import errorMessage from "./error-message";
import withTimeField from "./with-time-field";
import selectorIcon from "./selector-icon";
import selectorButtonPlacement from "./selector-button-placement";
import controlled from "./controlled";
import timeZones from "./time-zones";
import granularity from "./granularity";
Expand All @@ -30,6 +31,7 @@ export const dateRangePickerContent = {
errorMessage,
withTimeField,
selectorIcon,
selectorButtonPlacement,
controlled,
timeZones,
granularity,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const App = `import {DateRangePicker} from "@nextui-org/react";

export default function App() {
return (
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
<DateRangePicker
label="Placement start"
selectorButtonPlacement="start"
/>
<DateRangePicker
label="Placement end (default)"
selectorButtonPlacement="end"
/>
</div>
);
}`;

const react = {
"/App.jsx": App,
};

export default {
...react,
};
9 changes: 8 additions & 1 deletion apps/docs/content/docs/components/date-picker.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,13 @@ You can combine the `isInvalid` and `errorMessage` properties to show an invalid

You can use the `selector` to add content to the start and end of the date-picker.

<CodeDemo title="Start and End Content" files={datePickerContent.selectorIcon} />
<CodeDemo title="Selector Icon" files={datePickerContent.selectorIcon} />

### Selector Button Placement

You can change the position of the selector button by setting the `selectorButtonPlacement` property to `start` or `end`.

<CodeDemo title="Selector Button Placement" files={datePickerContent.selectorButtonPlacement} />

### Controlled

Expand Down Expand Up @@ -338,6 +344,7 @@ import {I18nProvider} from "@react-aria/i18n";
| showMonthAndYearPickers | `boolean` \| `undefined` | Whether the calendar should show month and year pickers. | false |
| popoverProps | `PopoverProps` \| `undefined` | Props to be passed to the popover component. | `{ placement: "bottom", triggerScaleOnOpen: false, offset: 13 }` |
| selectorButtonProps | `ButtonProps` \| `undefined` | Props to be passed to the selector button component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` |
| selectorButtonPlacement | `start` \| `end` | The position of the selector button. | `end` |
| calendarProps | `CalendarProps` \| `undefined` | Props to be passed to the selector button component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` |
| timeInputProps | `TimeInputProps` | Props to be passed to the time input component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` |
| disableAnimation | `boolean` | Whether to disable all animations in the date picker. Including the DateInput, Button, Calendar, and Popover. | `false` |
Expand Down
9 changes: 8 additions & 1 deletion apps/docs/content/docs/components/date-range-picker.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,13 @@ DateRangePicker automatically includes time fields when a `CalendarDateTime` or

You can use the `selector` to add content to the start and end of the date-range-picker.

<CodeDemo title="Start and End Content" files={dateRangePickerContent.selectorIcon} />
<CodeDemo title="Selector Icon" files={dateRangePickerContent.selectorIcon} />

### Selector Button Placement

You can change the position of the selector button by setting the `selectorButtonPlacement` property to `start` or `end`.

<CodeDemo title="Selector Button Placement" files={dateRangePickerContent.selectorButtonPlacement} />

### Controlled

Expand Down Expand Up @@ -380,6 +386,7 @@ import {useLocale, useDateFormatter} from "@react-aria/i18n";
| allowsNonContiguousRanges | `boolean` | enables a range to be selected even if there are unavailable dates in the middle | false |
| popoverProps | `PopoverProps` | Props to be passed to the popover component. | `{ placement: "bottom", triggerScaleOnOpen: false, offset: 13 }` |
| selectorButtonProps | `ButtonProps` | Props to be passed to the selector button component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` |
| selectorButtonPlacement | `start` \| `end` | The position of the selector button. | `end` |
jrgarciadev marked this conversation as resolved.
Show resolved Hide resolved
| calendarProps | `CalendarProps` | Props to be passed to the selector button component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` |
| timeInputProps | `TimeInputProps` | Props to be passed to the time input component. | `{ size: "sm", variant: "light", radius: "full", isIconOnly: true }` |
| disableAnimation | `boolean` | Whether to disable all animations in the date picker. Including the DateInput, Button, Calendar, and Popover. | `false` |
Expand Down
37 changes: 37 additions & 0 deletions packages/components/date-picker/__tests__/date-picker.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,43 @@ describe("DatePicker", () => {

expect(getByTestId("foo")).toHaveAttribute("role", "group");
});

it("should work with startContent", () => {
const {getByText} = render(<DatePicker label="Date" startContent={<div>start</div>} />);

expect(getByText("start")).toBeInTheDocument();
});

it("should work with endContent", () => {
const {getByText} = render(<DatePicker endContent={<div>end</div>} label="Date" />);

expect(getByText("end")).toBeInTheDocument();
});

it("should work with startContent and endContent", () => {
const {getByText} = render(
<DatePicker endContent={<div>end</div>} label="Date" startContent={<div>start</div>} />,
);

expect(getByText("start")).toBeInTheDocument();
expect(getByText("end")).toBeInTheDocument();
});

it("should work with selectorButtonPlacement", () => {
const {getByRole} = render(
<DatePicker label="Date" selectorButtonPlacement="start" startContent={<div>start</div>} />,
);

const button = getByRole("button");

expect(button).toHaveTextContent("start");

triggerPress(button);

const dialog = getByRole("dialog");

expect(dialog).toBeInTheDocument();
});
});

describe("Events", () => {
Expand Down
34 changes: 28 additions & 6 deletions packages/components/date-picker/src/date-picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,20 @@ import {CalendarBoldIcon} from "@nextui-org/shared-icons";

import {UseDatePickerProps, useDatePicker} from "./use-date-picker";

export interface Props<T extends DateValue> extends UseDatePickerProps<T> {}
export interface Props<T extends DateValue> extends UseDatePickerProps<T> {
/**
* The placement of the selector button.
* @default "end"
*/
selectorButtonPlacement?: "start" | "end";
}

function DatePicker<T extends DateValue>(props: Props<T>, ref: ForwardedRef<HTMLDivElement>) {
const {selectorButtonPlacement = "end", ...otherProps} = props;

const {
state,
startContent,
endContent,
selectorIcon,
showTimeField,
Expand All @@ -30,7 +39,7 @@ function DatePicker<T extends DateValue>(props: Props<T>, ref: ForwardedRef<HTML
getCalendarProps,
CalendarTopContent,
CalendarBottomContent,
} = useDatePicker<T>({...props, ref});
} = useDatePicker<T>({...otherProps, ref});

const selectorContent = isValidElement(selectorIcon) ? (
cloneElement(selectorIcon, getSelectorIconProps())
Expand Down Expand Up @@ -67,12 +76,25 @@ function DatePicker<T extends DateValue>(props: Props<T>, ref: ForwardedRef<HTML
</FreeSoloPopover>
) : null;

const dateInputProps = {
...getDateInputProps(),
endContent:
selectorButtonPlacement === "end" ? (
<Button {...getSelectorButtonProps()}>{endContent || selectorContent}</Button>
) : (
endContent
),
startContent:
selectorButtonPlacement === "start" ? (
<Button {...getSelectorButtonProps()}>{startContent || selectorContent}</Button>
) : (
startContent
),
};

return (
<>
<DateInput
{...getDateInputProps()}
endContent={<Button {...getSelectorButtonProps()}>{endContent || selectorContent}</Button>}
/>
<DateInput {...dateInputProps} />
{disableAnimation ? popoverContent : <AnimatePresence>{popoverContent}</AnimatePresence>}
</>
);
Expand Down
34 changes: 28 additions & 6 deletions packages/components/date-picker/src/date-range-picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,21 @@ import {CalendarBoldIcon} from "@nextui-org/shared-icons";
import DateRangePickerField from "./date-range-picker-field";
import {UseDateRangePickerProps, useDateRangePicker} from "./use-date-range-picker";

export interface Props<T extends DateValue> extends UseDateRangePickerProps<T> {}
export interface Props<T extends DateValue> extends UseDateRangePickerProps<T> {
/**
* The placement of the selector button.
* @default "end"
*/
selectorButtonPlacement?: "start" | "end";
}

function DateRangePicker<T extends DateValue>(props: Props<T>, ref: ForwardedRef<HTMLDivElement>) {
const {selectorButtonPlacement = "end", ...otherProps} = props;

const {
state,
slots,
startContent,
endContent,
selectorIcon,
showTimeField,
Expand All @@ -37,7 +46,7 @@ function DateRangePicker<T extends DateValue>(props: Props<T>, ref: ForwardedRef
getCalendarProps,
CalendarTopContent,
CalendarBottomContent,
} = useDateRangePicker<T>({...props, ref});
} = useDateRangePicker<T>({...otherProps, ref});

const selectorContent = isValidElement(selectorIcon) ? (
cloneElement(selectorIcon, getSelectorIconProps())
Expand Down Expand Up @@ -77,12 +86,25 @@ function DateRangePicker<T extends DateValue>(props: Props<T>, ref: ForwardedRef
</FreeSoloPopover>
) : null;

const dateInputGroupProps = {
...getDateInputGroupProps(),
endContent:
selectorButtonPlacement === "end" ? (
<Button {...getSelectorButtonProps()}>{endContent || selectorContent}</Button>
) : (
endContent
),
startContent:
selectorButtonPlacement === "start" ? (
<Button {...getSelectorButtonProps()}>{startContent || selectorContent}</Button>
) : (
startContent
),
};

return (
<>
<DateInputGroup
{...getDateInputGroupProps()}
endContent={<Button {...getSelectorButtonProps()}>{endContent || selectorContent}</Button>}
>
<DateInputGroup {...dateInputGroupProps}>
<DateRangePickerField {...getStartDateInputProps()} />
<span {...getSeparatorProps()} aria-hidden="true" role="separator">
jrgarciadev marked this conversation as resolved.
Show resolved Hide resolved
-
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,6 @@ export function useDatePickerBase<T extends DateValue>(originalProps: UseDatePic
ref: domRef,
inputRef,
description,
startContent,
validationState,
shouldForceLeadingZeros,
isInvalid,
Expand Down Expand Up @@ -275,6 +274,7 @@ export function useDatePickerBase<T extends DateValue>(originalProps: UseDatePic

return {
domRef,
startContent,
endContent,
selectorIcon,
createCalendar,
Expand Down
2 changes: 2 additions & 0 deletions packages/components/date-picker/src/use-date-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export function useDatePicker<T extends DateValue>({

const {
domRef,
startContent,
endContent,
selectorIcon,
createCalendar,
Expand Down Expand Up @@ -214,6 +215,7 @@ export function useDatePicker<T extends DateValue>({

return {
state,
startContent,
endContent,
selectorIcon,
showTimeField,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,6 @@ export function useDateRangePicker<T extends DateValue>({
endContent,
errorMessage,
isInvalid,
startContent,
validationDetails,
validationErrors,
shouldLabelBeOutside,
Expand All @@ -418,6 +417,7 @@ export function useDateRangePicker<T extends DateValue>({
label: originalProps.label,
slots,
classNames,
startContent,
endContent,
selectorIcon,
showTimeField,
Expand Down
Loading
Loading