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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DateTimePicker] Add Single Column Time Picker to DateTimePicker (dateTimeViewRenderers) #9207

Closed
2 tasks done
SlowBurner opened this issue Jun 3, 2023 · 1 comment 路 Fixed by #10624
Closed
2 tasks done
Assignees
Labels
component: DateTimePicker The React component. component: pickers This is the name of the generic UI component, not the React module! enhancement This is not a bug, nor a new feature

Comments

@SlowBurner
Copy link

Duplicates

  • I have searched the existing issues

Latest version

  • I have tested the latest version

Summary 馃挕

Our use case is for a DateTimePicker with a TimePicker that has single column.

The MultiSectionDigitalClock was recently adding to the DateTimePicker via packages/x-date-pickers/src/dateTimeViewRenderers/dateTimeViewRenderers.tsx
#8946

However,
I think a function should be added to dateTimeViewRenderers.tsx for rendering a single column time with the DigitalClock.

See example code below.

Examples 馃寛

This example code, where I created new renderDesktopDateDigitalTimeView function works pretty well.
codesandbox example

// dateTimeViewRenderers.tsx
import * as React from "react";
import Divider from "@mui/material/Divider";
import { resolveComponentProps } from "@mui/base/utils";
import {
  DateCalendar,
  DateCalendarProps
} from "@mui/x-date-pickers/DateCalendar";
import { DateOrTimeViewWithMeridiem } from "@mui/x-date-pickers/internals/models";
import {
  DigitalClock,
  DigitalClockProps
} from "@mui/x-date-pickers/DigitalClock";
import { isInternalTimeView } from "@mui/x-date-pickers/internals/utils/time-utils";
import { isDatePickerView } from "@mui/x-date-pickers/internals/utils/date-utils";
import type { DateTimePickerProps } from "@mui/x-date-pickers/DateTimePicker/DateTimePicker.types";
import { VIEW_HEIGHT } from "@mui/x-date-pickers/internals/constants/dimensions";
import { styled } from "@mui/material/styles";

export const DateTimeViewWrapper = styled("div")({
  display: "flex",
  margin: "0 auto"
});

export interface DateTimeViewRendererProps<TDate>
  extends Omit<
      DateCalendarProps<TDate> & DigitalClockProps<TDate>,
      | "views"
      | "openTo"
      | "view"
      | "onViewChange"
      | "focusedView"
      | "components"
      | "componentsProps"
      | "slots"
      | "slotProps"
    >,
    Pick<
      DateTimePickerProps<TDate>,
      "components" | "componentsProps" | "slots" | "slotProps"
    > {
  view: DateOrTimeViewWithMeridiem;
  onViewChange?: (view: DateOrTimeViewWithMeridiem) => void;
  views: readonly DateOrTimeViewWithMeridiem[];
  focusedView: DateOrTimeViewWithMeridiem | null;
  timeViewsCount: number;
}

export const renderDesktopDateDigitalTimeView = <TDate extends unknown>({
  view,
  onViewChange,
  views,
  focusedView,
  onFocusedViewChange,
  value,
  defaultValue,
  onChange,
  className,
  classes,
  disableFuture,
  disablePast,
  minDate,
  minTime,
  maxDate,
  maxTime,
  shouldDisableDate,
  shouldDisableMonth,
  shouldDisableYear,
  shouldDisableTime,
  shouldDisableClock,
  reduceAnimations,
  minutesStep,
  ampm,
  onMonthChange,
  monthsPerRow,
  onYearChange,
  yearsPerRow,
  defaultCalendarMonth,
  components,
  componentsProps,
  slots,
  slotProps,
  loading,
  renderLoading,
  disableHighlightToday,
  readOnly,
  disabled,
  showDaysOutsideCurrentMonth,
  dayOfWeekFormatter,
  sx,
  autoFocus,
  fixedWeekNumber,
  displayWeekNumber,
  disableIgnoringDatePartForTimeValidation,
  timeSteps,
  skipDisabled,
  timeViewsCount
}: DateTimeViewRendererProps<TDate>) => {
  const isActionBarVisible = !!resolveComponentProps(
    slotProps?.actionBar ?? componentsProps?.actionBar,
    {} as any
  )?.actions?.length;
  return (
    <React.Fragment>
      <DateTimeViewWrapper>
        <DateCalendar
          view={isDatePickerView(view) ? view : "day"}
          onViewChange={onViewChange}
          views={views.filter(isDatePickerView)}
          focusedView={
            focusedView && isDatePickerView(focusedView) ? focusedView : null
          }
          onFocusedViewChange={onFocusedViewChange}
          value={value}
          defaultValue={defaultValue}
          onChange={onChange}
          className={className}
          classes={classes}
          disableFuture={disableFuture}
          disablePast={disablePast}
          minDate={minDate}
          maxDate={maxDate}
          shouldDisableDate={shouldDisableDate}
          shouldDisableMonth={shouldDisableMonth}
          shouldDisableYear={shouldDisableYear}
          reduceAnimations={reduceAnimations}
          onMonthChange={onMonthChange}
          monthsPerRow={monthsPerRow}
          onYearChange={onYearChange}
          yearsPerRow={yearsPerRow}
          defaultCalendarMonth={defaultCalendarMonth}
          components={components}
          componentsProps={componentsProps}
          slots={slots}
          slotProps={slotProps}
          loading={loading}
          renderLoading={renderLoading}
          disableHighlightToday={disableHighlightToday}
          readOnly={readOnly}
          disabled={disabled}
          showDaysOutsideCurrentMonth={showDaysOutsideCurrentMonth}
          dayOfWeekFormatter={dayOfWeekFormatter}
          sx={sx}
          autoFocus={autoFocus}
          fixedWeekNumber={fixedWeekNumber}
          displayWeekNumber={displayWeekNumber}
        />
        {timeViewsCount > 0 && (
          <React.Fragment>
            <Divider orientation="vertical" />
            <DigitalClock
              view={isInternalTimeView(view) ? view : "hours"}
              onViewChange={onViewChange}
              focusedView={
                focusedView && isInternalTimeView(focusedView)
                  ? focusedView
                  : null
              }
              onFocusedViewChange={onFocusedViewChange}
              views={views.filter(isInternalTimeView)}
              value={value}
              defaultValue={defaultValue}
              onChange={onChange}
              className={className}
              classes={classes}
              disableFuture={disableFuture}
              disablePast={disablePast}
              minTime={minTime}
              maxTime={maxTime}
              shouldDisableTime={shouldDisableTime}
              shouldDisableClock={shouldDisableClock}
              minutesStep={minutesStep}
              ampm={ampm}
              components={components}
              componentsProps={componentsProps}
              slots={slots}
              slotProps={slotProps}
              readOnly={readOnly}
              disabled={disabled}
              sx={{
                borderBottom: 0,
                width: "auto",
                maxHeight: VIEW_HEIGHT,
                ...(Array.isArray(sx) ? sx : [sx])
              }}
              autoFocus={autoFocus}
              disableIgnoringDatePartForTimeValidation={
                disableIgnoringDatePartForTimeValidation
              }
              timeSteps={timeSteps}
              skipDisabled={skipDisabled}
            />
          </React.Fragment>
        )}
      </DateTimeViewWrapper>
      {isActionBarVisible && <Divider />}
    </React.Fragment>
  );
};
// demo.js
import * as React from "react";
import dayjs from "dayjs";
import { DemoContainer, DemoItem } from "@mui/x-date-pickers/internals/demo";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
import { DesktopDateTimePicker } from "@mui/x-date-pickers/DesktopDateTimePicker";
import { renderDesktopDateDigitalTimeView } from "./dateTimeViewRenderers";

export default function ResponsiveDateTimePickers() {
  return (
    <LocalizationProvider dateAdapter={AdapterDayjs}>
      <DemoContainer components={["DesktopDateTimePicker"]}>
        <DemoItem label="Desktop single column time variant">
          <DesktopDateTimePicker
            defaultValue={dayjs("2022-04-17T15:30")}
            views={["hours"]}
            closeOnSelect={false}
            viewRenderers={{
              day: renderDesktopDateDigitalTimeView,
              hours: renderDesktopDateDigitalTimeView,
              meridiem: renderDesktopDateDigitalTimeView,
              minutes: renderDesktopDateDigitalTimeView,
              month: renderDesktopDateDigitalTimeView,
              seconds: renderDesktopDateDigitalTimeView,
              year: renderDesktopDateDigitalTimeView
            }}
          />
        </DemoItem>
      </DemoContainer>
    </LocalizationProvider>
  );
}

Motivation 馃敠

We exclusively use a TimePicker with limited options, on the 1/2 hour. We do not need 4 clicks to pick the time. We want DateTimePicker that has a single column time dropdown. I was able to implement the feature in our code base.

Order ID 馃挸 (optional)

56150

@SlowBurner SlowBurner added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Jun 3, 2023
@SlowBurner SlowBurner changed the title Add Date Digital TimeViewRenderer Add Single Cloumn Time Picker to DateTimePicker (dateTimeViewRenderers) Jun 3, 2023
@SlowBurner SlowBurner changed the title Add Single Cloumn Time Picker to DateTimePicker (dateTimeViewRenderers) Add Single Column Time Picker to DateTimePicker (dateTimeViewRenderers) Jun 3, 2023
@LukasTy LukasTy changed the title Add Single Column Time Picker to DateTimePicker (dateTimeViewRenderers) [pickers] Add Single Column Time Picker to DateTimePicker (dateTimeViewRenderers) Jun 4, 2023
@LukasTy LukasTy added component: pickers This is the name of the generic UI component, not the React module! component: DateTimePicker The React component. enhancement This is not a bug, nor a new feature and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Jun 4, 2023
@LukasTy
Copy link
Member

LukasTy commented Jun 4, 2023

@SlowBurner Thank you for pointing out the need for this! 馃憤
We'll look into providing a solution on our end, hopefully, one that would work similarly to the current behavior of the TimePicker: using a certain timeSteps configuration or changing the thresholdToRenderTimeInASingleColumn prop.

As for your solution, it's nice that you were able to easily cover your use case by providing a custom view renderer! 馃憤 馃挴

@LukasTy LukasTy self-assigned this Oct 9, 2023
@LukasTy LukasTy changed the title [pickers] Add Single Column Time Picker to DateTimePicker (dateTimeViewRenderers) [DateTimePicker] Add Single Column Time Picker to DateTimePicker (dateTimeViewRenderers) Oct 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: DateTimePicker The React component. component: pickers This is the name of the generic UI component, not the React module! enhancement This is not a bug, nor a new feature
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants