diff --git a/.changeset/old-penguins-judge.md b/.changeset/old-penguins-judge.md new file mode 100644 index 000000000..649d1dd30 --- /dev/null +++ b/.changeset/old-penguins-judge.md @@ -0,0 +1,6 @@ +--- +'@saas-ui/date-picker': minor +'website': minor +--- + +Added new portal prop to DateInput and DateRangePicker components to conditionally open the dialog in a portal. diff --git a/apps/website/src/docs/components/mdx-components/codeblock/react-live-scope.tsx b/apps/website/src/docs/components/mdx-components/codeblock/react-live-scope.tsx index 64af03459..bd85685e7 100644 --- a/apps/website/src/docs/components/mdx-components/codeblock/react-live-scope.tsx +++ b/apps/website/src/docs/components/mdx-components/codeblock/react-live-scope.tsx @@ -111,6 +111,8 @@ const reactIcons = { import { KanbanItems } from '@saas-ui-pro/kanban' import * as SaasUIKanban from '@saas-ui-pro/kanban' +import { now, getLocalTimeZone } from '@internationalized/date' + const StarIcon = (props) => ( @@ -190,6 +192,7 @@ const ReactLiveScope = { 'react-icons/fi': reactIcons, '@hookform/resolvers/yup': { yupResolver }, '@hookform/resolvers/zod': { zodResolver }, + '@internationalized/date': { now, getLocalTimeZone }, zod: z, yup: yup, }, diff --git a/apps/website/src/pages/docs/components/date-time/date-input/usage.mdx b/apps/website/src/pages/docs/components/date-time/date-input/usage.mdx index 7597d39d2..4033b6f0b 100644 --- a/apps/website/src/pages/docs/components/date-time/date-input/usage.mdx +++ b/apps/website/src/pages/docs/components/date-time/date-input/usage.mdx @@ -12,17 +12,33 @@ description: Allow users to enter or select a Date and Time value. /> - The DateInput is currently in beta, we'd love to hear your feedback while we + The DatePicker is currently in beta, we'd love to hear your feedback while we finalize the API. ## Import -- `DateInput`: A date form input. -- `DateTimeInput`: A date time form input. +- `DatePicker`: The container component that manages state and context. +- `DatePickerInput`: A date form input. +- `DatePickerDialog`: A dialog that contains a calendar and time picker. +- `DatePickerCalendar`: A calendar that allows users to select a date. +- `DatePickerTimeField`: A time picker that allows users to select a time. + +# + +- `DateInput`: A composite component that contains a date form input and a + calendar dialog. +- `DateTimeInput`: A composite component that contains a date form input and a + calendar and time picker dialog. ```ts -import { DateInput, DateTimeInput } from '@saas-ui/date-picker' +import { + DatePicker, + DatePickerInput, + DatePickerDialog, + DatePickerCalendar, + DatePickerTimeField, +} from '@saas-ui/date-picker' ``` ## Usage @@ -38,65 +54,292 @@ import { DateInput, DateTimeInput } from '@saas-ui/date-picker' ### Basic ```jsx center=true - - Date - - +import { FormControl, FormLabel } from '@chakra-ui/react' +import { DateInput } from '@saas-ui/date-picker' + +export default function Basic() { + return ( + + Date + + + ) +} ``` -### DateTime +### Basic with time ```jsx center=true - - Date and time - - +import { FormControl, FormLabel } from '@chakra-ui/react' +import { DateTimeInput } from '@saas-ui/date-picker' + +export default function BasicWithTime() { + return ( + + Date + + + ) +} ``` -### With 24 hour time +### Composed + +Composing the `DatePicker` components gives you more control over the layout and +props of the child components. ```jsx center=true - - Date and time - - +import { FormControl, FormLabel } from '@chakra-ui/react' +import { + DatePicker, + DatePickerInput, + DatePickerDialog, + DatePickerCalendar, +} from '@saas-ui/date-picker' + +export default function Composed() { + return ( + + Date + + + + + + + + ) +} +``` + +### Custom calendar icon + +```jsx center=true +import { FormControl, FormLabel } from '@chakra-ui/react' +import { + DatePicker, + DatePickerInput, + DatePickerDialog, + DatePickerCalendar, +} from '@saas-ui/date-picker' +import { CalendarIcon } from '@chakra-ui/icons' + +export default function CustomCalendarIcon() { + return ( + + Date + + } /> + + + + + + ) +} +``` + +### Using Portal + +When the `DatePicker` is rendered inside an overflow container, you can use the +`Portal` to render the dialog in a portal outside of the overflow +container. + +```jsx center=true +import { FormControl, FormLabel, Portal } from '@chakra-ui/react' +import { + DatePicker, + DatePickerInput, + DatePickerDialog, + DatePickerCalendar, +} from '@saas-ui/date-picker' +import { CalendarIcon } from '@chakra-ui/icons' + +export default function UsingPortal() { + return ( + + Date + + } /> + + + + + + + + ) +} +``` + +### DateTime + +Changing the granularity to `minute` and adding a `DatePickerTimeField` will +allow users to select a time as well. + +```jsx center=true +import { FormControl, FormLabel } from '@chakra-ui/react' +import { + DatePicker, + DatePickerInput, + DatePickerDialog, + DatePickerCalendar, + DatePickerTimeField, +} from '@saas-ui/date-picker' + +export default function DateTime() { + return ( + + Date and time + + + + + + + + + ) +} ``` ### Controlled ```jsx center=true -function ControlledPicker() { +import { FormControl, FormLabel } from '@chakra-ui/react' +import { + DatePicker, + DatePickerInput, + DatePickerDialog, + DatePickerCalendar, +} from '@saas-ui/date-picker' + +export default function ControlledPicker() { const [value, setValue] = React.useState(today(getLocalTimeZone())) - return + return ( + + Date + + + + + + + + ) +} +``` + +### With 24 hour time + +To use 24 hour time, set the `hourCycle` prop to `24`. + +```jsx center=true +import { FormControl, FormLabel } from '@chakra-ui/react' +import { + DatePicker, + DatePickerInput, + DatePickerDialog, + DatePickerCalendar, + DatePickerTimeField, +} from '@saas-ui/date-picker' + +export default function HourCycle() { + return ( + + Date and time + + + + + + + + + ) } ``` ### Time zone +When using a local date, the `DatePicker` will show the time zone of the user's +browser. + ```jsx center=true -function ControlledPicker() { +import { FormControl, FormLabel } from '@chakra-ui/react' +import { + DatePicker, + DatePickerInput, + DatePickerDialog, + DatePickerCalendar, + DatePickerTimeField, +} from '@saas-ui/date-picker' +import { now, getLocalTimeZone } from '@internationalized/date' + +export default function TimeZone() { const [value, setValue] = React.useState(now(getLocalTimeZone())) return ( - + + Date and time + + + + + + + + ) } ``` ### Hide time zone +To hide the time zone, add the `hideTimeZone` prop. + ```jsx center=true -function ControlledPicker() { +import { FormControl, FormLabel } from '@chakra-ui/react' +import { + DatePicker, + DatePickerInput, + DatePickerDialog, + DatePickerCalendar, + DatePickerTimeField, +} from '@saas-ui/date-picker' +import { now, getLocalTimeZone } from '@internationalized/date' + +export default function HideTimeZone() { const [value, setValue] = React.useState(now(getLocalTimeZone())) return ( - + + Date and time + + + + + + + + ) } ``` diff --git a/apps/website/src/pages/docs/components/date-time/date-range-input/usage.mdx b/apps/website/src/pages/docs/components/date-time/date-range-input/usage.mdx index 3d7428eef..33df05286 100644 --- a/apps/website/src/pages/docs/components/date-time/date-range-input/usage.mdx +++ b/apps/website/src/pages/docs/components/date-time/date-range-input/usage.mdx @@ -18,10 +18,23 @@ description: Allow users to enter or select a Date and Time range. ## Import -- `DateRangeInput`: A date range form input. +- `DateRangePicker`: The container component that manages state and context. +- `DateRangePickerInput`: A date range form input. +- `DateRangePickerDialog`: A dialog that contains a calendar and time picker. +- `DateRangePickerCalendar`: A calendar that allows users to select a date range. + +# + +- `DateRangeInput`: A composite component that composes the above components. ```ts -import { DateRangeInput, DateRangeTimeInput } from '@saas-ui/date-picker' +import { + DateRangePicker + DateRangePickerInput, + DateRangePickerDialog, + DateRangePickerCalendar, + DateRangeInput + } from '@saas-ui/date-picker' ``` ## Usage @@ -37,34 +50,58 @@ import { DateRangeInput, DateRangeTimeInput } from '@saas-ui/date-picker' ### Basic ```jsx center=true - - Dates - - +import { FormControl, FormLabel } from '@chakra-ui/react' +import { DateRangeInput } from '@saas-ui/date-picker' + +export default function Basic() { + return ( + + Dates + + + ) +} ``` ### DateTime ```jsx center=true - - Dates and time - - +import { FormControl, FormLabel } from '@chakra-ui/react' +import { DateRangeInput } from '@saas-ui/date-picker' + +export default function DateTime() { + return ( + + Dates + + + ) +} ``` ### With 24 hour time ```jsx center=true - - Dates and time - - +import { FormControl, FormLabel } from '@chakra-ui/react' +import { DateRangeInput } from '@saas-ui/date-picker' + +export default function HourCycle() { + return ( + + Dates and time + + + ) +} ``` ### Controlled ```jsx -function ControlledPicker() { +import { FormControl, FormLabel } from '@chakra-ui/react' +import { DateRangeInput } from '@saas-ui/date-picker' + +export default function ControlledPicker() { const [value, setValue] = React.useState({ start: today(getLocalTimeZone()), end: null, @@ -77,7 +114,10 @@ function ControlledPicker() { ### Time zone ```jsx -function ControlledPicker() { +import { FormControl, FormLabel } from '@chakra-ui/react' +import { DateRangeInput } from '@saas-ui/date-picker' + +export default function ControlledPicker() { const [value, setValue] = React.useState({ start: now(getLocalTimeZone()), end: null, @@ -92,7 +132,10 @@ function ControlledPicker() { ### Hide time zone ```jsx -function ControlledPicker() { +import { FormControl, FormLabel } from '@chakra-ui/react' +import { DateRangeInput } from '@saas-ui/date-picker' + +export default function ControlledPicker() { const [value, setValue] = React.useState({ start: now(getLocalTimeZone()), end: null, @@ -108,3 +151,57 @@ function ControlledPicker() { ) } ``` + +### Composed + +```jsx +import { FormControl, FormLabel } from '@chakra-ui/react' +import { + DateRangePicker, + DateRangeInput, + DateRangePickerDialog, + DateRangePickerCalendar, +} from '@saas-ui/date-picker' + +export default function Composed() { + return ( + + Dates + + + + + + + + ) +} +``` + +### Portal + +```jsx +import { FormControl, FormLabel, Portal } from '@chakra-ui/react' +import { + DateRangePicker, + DateRangeInput, + DateRangePickerDialog, + DateRangePickerCalendar, +} from '@saas-ui/date-picker' + +export default function WithPortal() { + return ( + + Dates + + + + + + + + + + ) +} +``` diff --git a/packages/saas-ui-date-picker/src/date-input.tsx b/packages/saas-ui-date-picker/src/date-input.tsx index 75d5dfdc7..71df05320 100644 --- a/packages/saas-ui-date-picker/src/date-input.tsx +++ b/packages/saas-ui-date-picker/src/date-input.tsx @@ -6,6 +6,7 @@ import { InputGroupProps, InputRightElement, Portal, + SystemCSSProperties, } from '@chakra-ui/react' import { FieldButton } from './button' @@ -18,7 +19,15 @@ import { SegmentedInput } from './segmented-input' import { CalendarIcon } from './icons' export interface DateInputProps extends DatePickerProps { + /** + * The icon to use in the calendar button + */ calendarIcon?: React.ReactNode + /** + * If `true`, the `DatePickerDialog` will open in a portal. + * Also accepts a `z-index` value that will be passed to the dialog. + */ + portal?: boolean | SystemCSSProperties['zIndex'] } /** @@ -27,7 +36,19 @@ export interface DateInputProps extends DatePickerProps { * @see Docs https://saas-ui.dev/docs/date-time/date-picker-input */ export const DateInput = forwardRef((props, ref) => { - const { children, calendarIcon, size, variant, ...rest } = props + const { children, calendarIcon, size, variant, portal, ...rest } = props + + const zIndex = typeof portal === 'boolean' ? undefined : portal + + const dialog = ( + + <> + + {children} + + + ) + return ( ((props, ref) => { variant={variant} ref={ref} /> - - - <> - - {children} - - - + + {portal ? {dialog} : dialog} ) }) diff --git a/packages/saas-ui-date-picker/src/date-range-input.tsx b/packages/saas-ui-date-picker/src/date-range-input.tsx index 2e04bee18..aa66c5810 100644 --- a/packages/saas-ui-date-picker/src/date-range-input.tsx +++ b/packages/saas-ui-date-picker/src/date-range-input.tsx @@ -15,6 +15,7 @@ import { InputGroupProps, InputRightElement, Portal, + SystemCSSProperties, } from '@chakra-ui/react' import { useDateRangePickerContext } from './date-picker-context' import { @@ -24,7 +25,15 @@ import { import { SegmentedInput } from './segmented-input' export interface DateRangeInputProps extends DateRangePickerContainerProps { + /** + * The icon to use in the calendar button + */ calendarIcon?: React.ReactNode + /** + * If `true`, the `DatePickerDialog` will open in a portal. + * Also accepts a `z-index` value. + */ + portal?: boolean | SystemCSSProperties['zIndex'] } /** @@ -36,7 +45,19 @@ export interface DateRangeInputProps extends DateRangePickerContainerProps { */ export const DateRangeInput = forwardRef( (props, ref) => { - const { children, size, variant, calendarIcon, ...rest } = props + const { children, size, variant, calendarIcon, portal, ...rest } = props + + const zIndex = typeof portal === 'boolean' ? undefined : portal + + const dialog = ( + + <> + + {children} + + + ) + return ( ( size={size} variant={variant} /> - - - <> - - {children} - - - + {portal ? {dialog} : dialog} ) } diff --git a/packages/saas-ui-date-picker/src/date-range-picker.tsx b/packages/saas-ui-date-picker/src/date-range-picker.tsx index 68e0a9631..16d58264f 100644 --- a/packages/saas-ui-date-picker/src/date-range-picker.tsx +++ b/packages/saas-ui-date-picker/src/date-range-picker.tsx @@ -20,6 +20,7 @@ import { useLocale } from '@react-aria/i18n' import { DateRangeValue } from './types' import { getLocalTimeZone } from '@internationalized/date' import { datePickerStyleConfig } from './date-picker-styles' +import { DatePickerDialog } from './date-picker-dialog' export interface DateRangePickerContainerProps extends ThemingProps<'SuiDatePicker'>, @@ -120,3 +121,5 @@ export interface DateRangePickerProps extends DateRangePickerContainerProps {} export const DateRangePicker: React.FC = (props) => { return } + +export const DateRangePickerDialog = DatePickerDialog diff --git a/packages/saas-ui-date-picker/src/index.ts b/packages/saas-ui-date-picker/src/index.ts index 5aaa68a33..c6d096545 100644 --- a/packages/saas-ui-date-picker/src/index.ts +++ b/packages/saas-ui-date-picker/src/index.ts @@ -15,7 +15,11 @@ export type { DatePickerDialogProps } from './date-picker-dialog' export { DatePickerCalendar } from './calendar' export type { DatePickerCalendarProps } from './calendar' -export { DateRangePicker, DateRangePickerContainer } from './date-range-picker' +export { + DateRangePicker, + DateRangePickerContainer, + DateRangePickerDialog, +} from './date-range-picker' export type { DateRangePickerProps, DateRangePickerContainerProps,