Max Muxammil
Max Muxammil

Reputation: 1

Material UI issue in Calendar which is moving up & down and works after clicking two times

Problem with this code is when I select multiple dates although my calendar remains open which I want to be but for example if I select 19 from calendar then calendar remains in openstate() but move little up in ui then I select date again 19 then it comes down in ui and then my selected date appears in the date picker field now going to select another date for eg I have now selected 20 from calendar again calendar moves up then down Then I have to select 20 again now 19 and 20 will be shown in date picker text field this is inappropriate behavior also Calendar not closing when clicking outside. I am using typescript along with Material UI.

Material UI bug (VIDEO)

`

const handleDateChange = (date: Dayjs | null) => {
    console.log("inside handle Date change");
    if (!date) return;
    if (mode === "multiple") {
      console.log("inside multiple mode");
      setSelectedDates((prevDates) => {
        const isAlreadySelected = prevDates.some((d) => d.isSame(date, "day"));
        return isAlreadySelected
          ? prevDates.filter((d) => !d.isSame(date, "day"))
          : [...prevDates, date];
      });
      setTimeout(() => setOpen(true), 0); // Ensures state update propagates
      console.log("state of open is " + open);
    } else {
      setSelectedDates(date ? [date] : []);
      setOpen(false); // Close calendar for single selection
    }
  };

  // Keep the picker open in multiple mode
  React.useEffect(() => {
    if (mode === "multiple") {
      setOpen(true);
    }
  }, [selectedDates]);

  const handleClear = () => {
    const confirmClear = window.confirm("Are you sure you want to clear the date field?");
    if (confirmClear) {
      setSelectedDates([]);
      setOpen(false);
    }
  };

  const handleClickOutside = (event: MouseEvent) => {
    if (mode === "multiple") {
      setOpen(true); // Prevent closing when clicking outside
    }
  };

  React.useEffect(() => {
    document.addEventListener("click", handleClickOutside);
    return () => {
      document.removeEventListener("click", handleClickOutside);
    };
  }, []);

`

I tried using different logics in typescript and used chatGPT for further assistance but the behavior is still same and buggy.

import * as React from "react";
import { DemoContainer } from "@mui/x-date-pickers/internals/demo";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
import { DatePicker } from "@mui/x-date-pickers/DatePicker";
import { PickersActionBar } from "@mui/x-date-pickers/PickersActionBar";
import { TextField, Box } from "@mui/material";
import dayjs, { Dayjs } from "dayjs";

const NS_DATE_FORMAT: "m/d/Y" | "d/m/Y" | "Y/m/d" = "m/d/Y";
const DATE_FORMAT_UK = "d/m/Y";
const DATE_FORMAT_HK = "Y/m/d";
const DATE_FORMAT_US = "m/d/Y";
let LastKey = "";

interface FlagsObject {
  // fieldName: string;
  // fieldValue: string;
  otherField?: string;
  pastDate: boolean;
  futureDate: boolean;
  reqd: boolean;
  empty: boolean;
  emptyFuture: boolean;
  emptyPast: boolean;
  checkPast: boolean;
  checkFuture: boolean;
  disableBlur: boolean;
  msg?: string;
}

// Function to initialize FlagsObject
const createFlagsObject = (
  // fieldName: string,
  // fieldValue: string,
  flags: string[]
): FlagsObject => {
  return {
    // fieldName,
    // fieldValue,
    otherField: flags.find((flag) => document.getElementById(flag) !== null) || undefined,
    pastDate: flags.includes("_PAST"),
    futureDate: flags.includes("_FUTURE"),
    reqd: flags.includes("_REQD"),
    empty: flags.includes("_EMPTY"),
    emptyFuture: flags.includes("_EMPTYFUTURE"),
    emptyPast: flags.includes("_EMPTYPAST"),
    checkPast: flags.includes("_CHECKPAST"),
    checkFuture: flags.includes("_CHECKFUTURE"),
    disableBlur: flags.includes("_DISABLEBLUR"),
  };
};
export default function DatePickerComponent({
  modeArg,
  disabled,
  disableDates = 0,
  blockedDatesStr = "",
  flags = []
}: {
  modeArg?: string;
  disabled?: boolean;
  disableDates?: number;
  blockedDatesStr?: string;
  flags?: string[];
}) {
  const [mode, setMode] = React.useState<string>("single");
  const [selectedDates, setSelectedDates] = React.useState<Dayjs[]>([]);
  const [inputValue, setInputValue] = React.useState("");
  const [open, setOpen] = React.useState(false);
  const inputRef = React.useRef<HTMLInputElement | null>(null);
  const pressedKeyRef = React.useRef<string | null>(null);

  
  React.useEffect(() => {
    setMode(modeArg === "multiple" ? "multiple" : "single");
  }, [modeArg]);

  const dateFormat =
    NS_DATE_FORMAT === "d/m/Y"
      ? "DD/MM/YYYY"
      : NS_DATE_FORMAT === "Y/m/d"
        ? "YYYY/MM/DD"
        : "MM/DD/YYYY";

  const DEFAULT_DATE = dayjs().format(
    NS_DATE_FORMAT === "d/m/Y"
      ? "DD/MM/YYYY"
      : NS_DATE_FORMAT === "Y/m/d"
        ? "YYYY/MM/DD"
        : "MM/DD/YYYY"
  );

  const blockedDates: Dayjs[] =
    disableDates === 1 && blockedDatesStr
      ? blockedDatesStr.split(",").map((date) => dayjs(date.trim()))
      : [];

  const shouldDisableDate = (date: Dayjs) => {
    if (disableDates !== 1) return false;
    return blockedDates.some((blockedDate) => blockedDate.isSame(date, "day"));
  };

  const handleDateChange = (date: Dayjs | null) => {
    if (!date) return;

    setSelectedDates((prevDates) => {
      if (mode === "single") {
        setTimeout(() => setOpen(false), 100);
        setInputValue(date.format(dateFormat));
        return [date];
      } else {
        const isAlreadySelected = prevDates.some((d) => d.isSame(date, "day"));
        const updatedDates = isAlreadySelected
          ? prevDates.filter((d) => !d.isSame(date, "day"))
          : [...prevDates, date];

        setInputValue(updatedDates.map((d) => d.format(dateFormat)).join(", "));

        return updatedDates;
      }
    });

    setTimeout(() => {
      if (inputRef.current) {
        inputRef.current.focus();
      }
    }, 150); // Small delay taake state update hone ke baad focus apply ho
  };

  // Determine which value to pass to DatePicker
  const pickerValue = mode === "single"
    ? (selectedDates.length > 0 ? selectedDates[0] : null) // First date for single mode
    : (selectedDates.length > 0 ? selectedDates[selectedDates.length - 1] : null); // Last date for multi mode



  const handleClear = () => {
    if (window.confirm("Are you sure you want to clear the date field?")) {
      setSelectedDates([]);  // Dates ko empty karna
      setInputValue(""); // Input field bhi clear karna
      setOpen(false);

      setTimeout(() => {
        if (inputRef.current) {
          inputRef.current.focus(); // Focus wapas input field pe
        }
      }, 100);
    }
  };

  const handleCancel = () => {
    setOpen(false);
  };

  React.useEffect(() => {
    if (inputRef.current) {
      inputRef.current.focus();
    }
  }, [inputValue]); // Jab bhi inputValue update ho, focus wapas aaye

  const setTextInputRef = (element: HTMLInputElement) => {
    inputRef.current = element;
  };

  // ✅ Function to check if a character is a digit
  const isDigit = (char: string) => {
    return /^\d$/.test(char);
  };

  // ✅ Explicit Date Formatting (Add leading zeros, format 2-digit year, etc.)
  const formatDateSeparatorExplicit = (inputValue: string) => {
    if (inputValue.length === 2) {
      return `0${removeSlashes(inputValue)}/`;
    }

    if (inputValue.length === 5 && inputValue.charAt(2) === "/") {
      let tokens = inputValue.split("/");
      return `${tokens[0]}/0${tokens[1]}/`;
    }

    if (inputValue.length === 8 && inputValue.charAt(2) === "/" && inputValue.charAt(5) === "/") {
      let tokens = inputValue.split("/");
      return `${tokens[0]}/${tokens[1]}/200${tokens[2]}`;
    }

    let year = inputValue.substring(6, 8);
    if (year !== "20" && year !== "19") {
      return update2DigitYearExplicit(inputValue);
    }

    return inputValue;
  };

  // ✅ 2-digit Year Update
  const update2DigitYearExplicit = (inputValue: string) => {
    if (inputValue.length === 9 && inputValue.charAt(2) === "/" && inputValue.charAt(5) === "/" && inputValue.charAt(8) === "/") {
      let tokens = inputValue.split("/");
      return `${tokens[0]}/${tokens[1]}/20${tokens[2]}`;
    }
    return inputValue;
  };

  // ✅ Remove all `/` from string
  const removeSlashes = (str: string) => {
    return str.replace(/\//g, "");
  };

  const ensureCorrectDate = (inputField: string): boolean => {
    return ensureCorrectDateAndShowAlert(inputField, true);
  };

  const ensureCorrectDateAndShowAlert = (inputField: string, showAlert: boolean): boolean => {
    if (!inputField || inputField.trim().length === 0) {
      return false;
    }

    const tokens = inputField.split("/");
    if (tokens.length !== 3) {
      if (showAlert) dateWarning(inputField, "");
      return false;
    }

    let [month, day, year] = tokens.map(token => parseInt(token, 10));

    // Handling different date formats
    if (NS_DATE_FORMAT === DATE_FORMAT_UK) {
      [day, month, year] = [parseInt(tokens[0]), parseInt(tokens[1]), parseInt(tokens[2])];
    } else if (NS_DATE_FORMAT === DATE_FORMAT_HK) {
      [year, month, day] = [parseInt(tokens[0]), parseInt(tokens[1]), parseInt(tokens[2])];
    }

    if (isNaN(month) || isNaN(day) || isNaN(year)) {
      if (showAlert) dateWarning(inputField, "");
      return false;
    }

    if (year.toString().length !== 4) {
      if (showAlert) dateWarning(inputField, "Wrong year");
      return false;
    }

    if (month < 1 || month > 12) {
      if (showAlert) dateWarning(inputField, " Month is wrong");
      return false;
    }

    // Handle February
    if (month === 2) {
      const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
      if (isLeapYear && (day < 1 || day > 29)) {
        if (showAlert) dateWarning(inputField, " Wrong Day in leap year!");
        return false;
      } else if (!isLeapYear && (day < 1 || day > 28)) {
        if (showAlert) dateWarning(inputField, " Wrong Day in Feburary!");
        return false;
      }
    }
    // Handle months with 30 days
    else if ([4, 6, 9, 11].includes(month) && (day < 1 || day > 30)) {
      if (showAlert) dateWarning(inputField, " Wrong Day !");
      return false;
    }
    // Handle months with 31 days
    else if ((day < 1 || day > 31)) {
      if (showAlert) dateWarning(inputField, " Wrong Day !");
      return false;
    }

    if (year < 1900 || year > 2100) {
      if (showAlert) dateWarning(inputField, " Year must be within range (1900-2100)");
      return true; // Date is valid but out of range
    }

    return true; // ✅ Date is valid
  };

  // Function to show warnings
  const dateWarning = (inputField: string, message: string) => {
    alert("Invalid Date ! " + message);
    inputField = ""; // Clear invalid date
  };

  const update2DigitYearImplicit = (inputField: string): string => {
    let inputValue = inputField;

    if (inputValue.length === 8 && inputValue.charAt(2) === "/" && inputValue.charAt(5) === "/") {
      let tokens = inputValue.split("/");
      if (tokens[2].length === 2) {
        let year = parseInt(tokens[2], 10);
        let fullYear = (year >= 0 && year <= 50) ? `20${tokens[2]}` : `19${tokens[2]}`;
        let updatedValue = `${tokens[0]}/${tokens[1]}/${fullYear}`;

        console.log("Updated Date Value:", updatedValue);
        ensureCorrectDate(updatedValue); // ✅ Ensure date is valid

        return updatedValue; // ✅ Return updated value
      }
    }

    return inputValue; // ✅ Return original value if no change
  };

  const formatDateSeparatorImplicit = (inputValue: string, event: React.ChangeEvent<HTMLInputElement>): string => {

    const fieldName = event?.target?.name || ""

    console.log("field name is " + fieldName);

    if (inputValue.length === 2) {
      if (ensureMonth(inputValue)) {
        return inputValue + "/"; // ✅ Automatically add "/"
      } else {
        setInputValue(inputValue); // ✅ Pehle poora input show karo

        setTimeout(() => {
          if (NS_DATE_FORMAT === DATE_FORMAT_UK) {
            alert("Invalid Day! It must be between 1 and 31.");
          } else if (NS_DATE_FORMAT === DATE_FORMAT_US) {
            alert("Invalid Month! It must be between 1 and 12.");
          }

          setInputValue(""); // ✅ Alert ke baad field empty kar do
        }, 10);

        return inputValue; // ✅ Pehle entered value return karo
      }
    }

    if ((inputValue.length === 4 || inputValue.length === 7) && NS_DATE_FORMAT === DATE_FORMAT_HK) {
      return inputValue + "/";
    }
    if (inputValue.length === 5 && inputValue.charAt(2) === "/") {
      if (ensureDay(inputValue)) {
        return inputValue + "/"; // ✅ Automatically add "/"
      } else {
        setInputValue(inputValue); // ✅ Pehle full value dikhaye

        setTimeout(() => {
          if (NS_DATE_FORMAT === DATE_FORMAT_UK) {
            alert("Invalid Month! It must be between 1 and 12.");
          } else if (NS_DATE_FORMAT === DATE_FORMAT_US) {
            alert("Invalid Day! It must be between 1 and 31.");
          }

          setInputValue(""); // ✅ Alert ke baad clear kare
        }, 10);

        return inputValue; // ✅ Pehle entered value return kare
      }
    }

    if (fieldName !== "DateOfBirth" && fieldName !== "WeddingDate") {
      let year = inputValue.substring(6, 8);

      if (NS_DATE_FORMAT == DATE_FORMAT_HK) {
        year = inputValue.substring(0, 2);
      }

      return update2DigitYearImplicit(inputValue);
    }

    return inputValue;
  };

  const ensureMonth = (inputValue: string): boolean => {
    if (NS_DATE_FORMAT === DATE_FORMAT_UK) {
      return ensureDayBody(parseInt(inputValue, 10));
    } else if (NS_DATE_FORMAT === DATE_FORMAT_HK) {
      return ensureMonthBody(parseInt(inputValue.split("/")[1], 10));
    } else {
      return ensureMonthBody(parseInt(inputValue, 10));
    }
  };
  const ensureDay = (inputValue: string): boolean => {
    if (NS_DATE_FORMAT === DATE_FORMAT_UK) {
      return ensureMonthBody(parseInt(inputValue.split("/")[1], 10));
    } else if (NS_DATE_FORMAT === DATE_FORMAT_HK) {
      return ensureDayBody(parseInt(inputValue.split("/")[2], 10));
    } else {
      return ensureDayBody(parseInt(inputValue.split("/")[1], 10));
    }
  };
  const ensureDayBody = (day: number): boolean => {
    return day >= 1 && day <= 31;
  };

  const ensureMonthBody = (month: number): boolean => {
    return month >= 1 && month <= 12;
  };


    // Function to check if the key is a navigation key
  const isNavigationKey = (): boolean => {
    const key = pressedKeyRef.current; // Access the latest key press
    if (!key) return false;

    return ["ArrowRight", "ArrowLeft", "End", "Home", "Backspace", "Delete"].includes(key);
  };

  // Function to update LastKey when a navigation key is pressed
  function updateLastKey(event: React.ChangeEvent<HTMLInputElement>, dateTextField: HTMLInputElement) {
    if (dateTextField.value.length > 0) {
      LastKey = dateTextField.value.charAt(dateTextField.value.length - 1);
    }
  }

  function changeAllDotsAndHyphensToSlashes(value: string): string {
    let str = "";
    for (let i = 0; i < value.length; i++) {
        let c = value.charAt(i);
        if (c === '.' || c === '-') {
            c = '/';
        }
        str += c;
    }
    return str;  // Return the modified value instead of modifying input field directly
}
  const removeLastCharacterIfNotDigit = (inputValue: string, event: React.ChangeEvent<HTMLInputElement>) => {
    let correctedDate = "";

    for (let i = 0; i < inputValue.length; i++) {
      let c = inputValue.charAt(i);
      if (c === "." || c === "-" || c === "/" || isDigit(c)) {
        correctedDate += c;
      }
    }
    let dateSeparator = false;

    if (["/", "-", "."].includes(inputValue.slice(-1))) {
      dateSeparator = true;
    }
    console.log("corrected date is " + correctedDate);
    console.log("date separator is " + dateSeparator);

    if (dateSeparator) {
      return formatDateSeparatorExplicit(correctedDate);
    } else {
      return formatDateSeparatorImplicit(correctedDate, event);
    }
  };

  const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    // Capture the current caret position
    const originalCaretPos = event.target.selectionStart || 0;
    let updatedValue = event.target.value;

    if (updatedValue.length > 10) {
      const year = updatedValue.substring(6);
      if (year.length === 4 && year !== "2020") {
        updatedValue = updatedValue.substring(0, 10);
        event.target.focus();
      } else if (year.length > 4) {
        updatedValue = updatedValue.substring(0, updatedValue.length - 2);
      }
      setInputValue(updatedValue);
      return;
    }
  
    updatedValue = event.target.value.replace(/[-.]/g, "/"); // Replace . or - with /
  
    if (updatedValue === "/") {
      updatedValue = DEFAULT_DATE;
      setInputValue(updatedValue);
      return;
    }

    if (!isNavigationKey()) {
      updatedValue = changeAllDotsAndHyphensToSlashes(updatedValue);
    } else {
        LastKey = '';
    }
    if (updatedValue.length > 1) {
      const lastCh = updatedValue.charAt(updatedValue.length - 1);
      const secondLastCh = updatedValue.charAt(updatedValue.length - 2);
      if (lastCh === "/" && secondLastCh === "/") {
        updatedValue = updatedValue.substring(0, updatedValue.length - 1);
      }
    }
    
     // Check if the pressed key is a navigation key
    if (isNavigationKey()) {
      console.log("Navigation key pressed:", pressedKeyRef.current);
      updateLastKey(event, event.target);
      setInputValue(updatedValue);

      // Set caret position before returning
      setTimeout(() => {
        if (inputRef.current) {
          inputRef.current.setSelectionRange(originalCaretPos, originalCaretPos);
        }
      }, 0);

      return; // Prevent further execution
    }
    // Process formatting using your custom function.
    updatedValue = removeLastCharacterIfNotDigit(updatedValue, event);
  
    console.log("Updated Value:", updatedValue);
    setInputValue(updatedValue);
  
    // Calculate new caret position using old logic:
    // (Assuming format MM/DD/YYYY and NS_DATE_FORMAT === "m/d/Y")
    const newLength = updatedValue.length;
    let newCaretPos = originalCaretPos;
    if (originalCaretPos < newLength) {
      const yearPart = updatedValue.substring(6, 10);
      if (originalCaretPos === 2 || originalCaretPos === 5) {
        newCaretPos = originalCaretPos + 1;
      } else if (originalCaretPos === 8 && yearPart !== "2020") {
        newCaretPos = newLength;
      } else if ((originalCaretPos === 4 || originalCaretPos === 7) && NS_DATE_FORMAT === DATE_FORMAT_HK) {
        newCaretPos = originalCaretPos + 1;
      } else {
        newCaretPos = originalCaretPos;
      }
    } else {
      newCaretPos = newLength;
    }
  
    // Restore caret position after the state update.
    setTimeout(() => {
      if (inputRef.current) {
        inputRef.current.setSelectionRange(newCaretPos, newCaretPos);
      }
    }, 0);
  };

  const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
    if (!inputRef.current) return;
    pressedKeyRef.current = event.key;
    if (event.key === "ArrowUp") {
      console.log("arrow up key");
      event.preventDefault();
      inputRef.current.setSelectionRange(0, 0);
    } else if (event.key === "ArrowDown") {
      console.log("arrow down key");
      event.preventDefault();
      const len = inputRef.current.value.length;
      inputRef.current.setSelectionRange(len, len);
    }
    else {
      console.log("arrow left or right key");
    }
  };

  const dateFormatter = {
    // ✅ Convert a date string to a Date object
    getDateObject: (dateStr: string): Date | null => {
      if (!dateStr) return null;
      
      let formattedDateStr = dateFormatter.checkDateFormat(dateStr);
      let parsedDate = new Date(formattedDateStr);

      if (isNaN(parsedDate.getTime())) {
        let parts = formattedDateStr.split("/");
        if (parts.length === 3) {
          let year = parseInt(parts[2], 10);
          let month = parseInt(parts[1], 10) - 1;
          let day = parseInt(parts[0], 10);
          parsedDate = new Date(year, month, day);
        }
      }

      return isNaN(parsedDate.getTime()) ? null : parsedDate;
    },

    // ✅ Convert date format based on NS_DATE_FORMAT
    checkDateFormat: (strDate: string): string => {
      dateFormatter.validateDateFormat();

      if (NS_DATE_FORMAT === "Y/m/d") // HK Format (YYYY/MM/DD → MM/DD/YYYY)
        return strDate.replace(/(\d+)\/(\d+)\/(\d+)/, '$3/$1/$2');
      else if (NS_DATE_FORMAT === "d/m/Y") // UK Format (DD/MM/YYYY → MM/DD/YYYY)
        return strDate.replace(/(\d+)\/(\d+)\/(\d+)/, '$2/$1/$3');
      else
        return strDate; // US Format (MM/DD/YYYY)
    },

    // ✅ Ensure NS_DATE_FORMAT is set
    validateDateFormat: () => {
      if (typeof NS_DATE_FORMAT === "undefined") {
        dateFormatter.setDefaultDateFormat();
      }
    },

    setDefaultDateFormat: () => {
      // Default: US Format
      (NS_DATE_FORMAT as any) = "m/d/Y";
    },

    // ✅ Compare two dates (returns -1, 0, or 1)
    compareDates: (date1: string, date2: string): number => {
      let d1 = dateFormatter.getDateObject(date1);
      let d2 = dateFormatter.getDateObject(date2);

      if (!d1 || !d2) return 0;
      
      return d1 > d2 ? 1 : d1 < d2 ? -1 : 0;
    }
  };

  const getFieldName = (elem: HTMLElement | null): string => {
    if (!elem) return "";
    
    const parentElem = elem.parentElement;
    if (!parentElem) return "";
  
    let fieldTitle = "";
    if (parentElem.childNodes[0]?.nodeType === Node.TEXT_NODE) {
      fieldTitle = parentElem.childNodes[0].nodeValue?.trim() || "";
    }
  
    return fieldTitle;
  };

  

  const handleVerifyDate = (event: React.ChangeEvent<HTMLInputElement>)=>{

    const field = event.target;
    const fieldValue = field.value;
    if (fieldValue.length === 10) {
      const flagsObject = createFlagsObject(flags);
      console.log("Flags Object:", flagsObject);
    

    const parentObj = field.parentElement;  // React ke liye `parentNode` ka use avoid karo
    const titleText = parentObj ? parentObj.innerHTML : "";  
    let notOptional = false;
    if (titleText.includes("*") || flagsObject.reqd) {
      notOptional = true;
    }
     // If field is required but empty
     if (fieldValue.length <= 0 && notOptional) {
      if (field.name !== "DateOfBirth") {
          alert("The date is required!");
          field.value = DEFAULT_DATE; // Default date set karo
          setInputValue(field.value);
          field.select();
      }
      return;
    }

        // If field is empty but optional, return
      if (fieldValue.length <= 0 && !notOptional) {
          return;
      }

      var valDate = ensureCorrectDate( fieldValue ); 
      // var datePicked = pickDate(fieldValue,flagsObject);
      console.log("date validation is " + valDate);
      return;
      // setInputValue("");
    }
    else{
      setInputValue("");
    }
  }
  const handlePaste = (event: React.ClipboardEvent<HTMLInputElement>) => {
    console.log("Pasting:", event.clipboardData.getData("Text"));
  };

  React.useEffect(() => {
    if (mode === "single" && selectedDates.length > 0) {
      setInputValue(selectedDates[0].format(dateFormat));
    } else {
      setInputValue(selectedDates.map((d) => d.format(dateFormat)).join(", "));
    }
  }, [selectedDates]);
  

  return (
    <LocalizationProvider dateAdapter={AdapterDayjs}>
      <DemoContainer components={["DatePicker"]}>
        <DatePicker
          label="Due Date"
          format={dateFormat}
          shouldDisableDate={disableDates === 1 ? shouldDisableDate : undefined}
          value={pickerValue}
          onChange={handleDateChange}
          open={open}
          onOpen={() => setOpen(true)}
          onClose={() => setOpen(false)}
          slots={{
            textField: ({ inputRef, inputProps, InputProps }) => (
              <TextField
                name="DueDate"
                {...inputProps}
                InputProps={InputProps}
                fullWidth
                value={inputValue}
                onChange={handleInputChange}
                onKeyDown={handleKeyDown}
                onBlur={handleVerifyDate}
                inputRef={setTextInputRef}
                onPaste={handlePaste}
              />
            ),
            actionBar: (props) => (
              <PickersActionBar
                {...props}
                actions={disabled ? ["clear", "cancel"] : ["today", "clear", "cancel"]}
                onClear={handleClear}
                onCancel={handleCancel}
              />
            ),
          }}
          slotProps={{
            actionBar: {
              sx: {
                "& .MuiButton-root": {
                  fontWeight: "bold",
                  fontSize: "12px",
                  padding: "6px 12px",
                  borderRadius: "5px",
                },
                "& .MuiButton-root:nth-of-type(1)": {
                  backgroundColor: "blue",
                  color: "white",
                  "&:hover": { backgroundColor: "darkblue" },
                },
                "& .MuiButton-root:nth-of-type(2)": {
                  backgroundColor: "blue",
                  color: "white",
                  "&:hover": { backgroundColor: "darkblue" },
                },
                "& .MuiButton-root:nth-of-type(3)": {
                  backgroundColor: "red",
                  color: "white",
                  "&:hover": { backgroundColor: "darkred" },
                },
              },
            },
          }}
        />
      </DemoContainer>
    </LocalizationProvider>
  );
}

Upvotes: 0

Views: 23

Answers (1)

Raghavendra N
Raghavendra N

Reputation: 5494

Seems like the bug is coming from this line:

setTimeout(() => setOpen(true), 0);

You are trying to keep the datepicker open when the select mode is multiple. So the datepicker is closing and opening again which is causing the jumping issue.

Instead do not close the datepicker after selecting the date. To keep it open use the prop closeOnSelect and set it to false.

Example:

<DatePicker
  label="Due Date"
  format={dateFormat}
  ...
  closeOnSelect={ (mode == 'multiple') ? false : true }
  ...
/>

Upvotes: 0

Related Questions