Repository: h2oai/wave
File: ui/src/time_picker.tsx (TypeScript)

Code before:
        palette: {
          background: {
            paper: cssVar('$card'),
          },
          primary: {
            main: fluentPalette.themePrimary,
            contrastText: cssVar('$neutralLight')
          },
          text: {
            primary: fluentPalette.neutralPrimary,
            secondary: cssVar('$neutralSecondary'),
            disabled: cssVar('$neutralTertiaryAlt'),
          },
          action: {
            active: fluentPalette.themePrimary,
            disabled: cssVar('$neutralLight'),
            hover: cssVar('$neutralLight'),
            hoverOpacity: 0.04
          }
        },
      },
      { format, AdapterDateFns, theme } = useTime(themeObj),
      formatDateToTimeString = React.useCallback((date: D, hour_format: S) => format ? format(date, hour_format === '12' ? 'hh:mm aa' : 'HH:mm') : '', [format]),
      errMsg = React.useMemo(() =>
        `Wrong input. Please enter the time in range from ${formatDateToTimeString(minTime, hour_format)} 
        to ${formatDateToTimeString(maxTime, hour_format)}.`, [formatDateToTimeString, minTime, hour_format, maxTime])

    React.useEffect(() => {
      const time = m.value ? parseTimeStringToDate(m.value) : null
      const newTime = time && isBelowMin(time) ? minTime : time && isOverMax(time) ? maxTime : time
      if (format) wave.args[m.name] = newTime ? formatDateToTimeString(newTime, '24') : null
      setValue(newTime)
    }, [format, formatDateToTimeString, isBelowMin, isOverMax, m.name, m.value, maxTime, minTime])

    // TODO: Remove once CSS vars are fully supported - https://github.com/mui/material-ui/issues/27651
    React.useEffect(() => {
      if (theme) {
        theme.palette.primary.main = fluentPalette.themePrimary
        theme.palette.text.primary = fluentPalette.neutralPrimary
        theme.palette.action.active = fluentPalette.themePrimary
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [fluentPalette.themePrimary, theme])

    return <>
      <React.Suspense fallback={<LazyLoadPlaceholder />}>
        {theme && AdapterDateFns && format
          ? <ThemeProvider theme={theme}>
            <LocalizationProvider dateAdapter={AdapterDateFns}>
              <TimePicker
                value={value}

Review comment (suggestion):
Wrapping `errMsg` in `useMemo` is unnecessary. Revert back to regular function instead. No need to store extra memory and React overhead.

Code after:
            primary: fluentPalette.neutralPrimary,
            secondary: cssVar('$neutralSecondary'),
            disabled: cssVar('$neutralTertiaryAlt'),
          },
          action: {
            active: fluentPalette.themePrimary,
            disabled: cssVar('$neutralLight'),
            hover: cssVar('$neutralLight'),
            hoverOpacity: 0.04
          }
        },
      },
      { format, AdapterDateFns, theme } = useTime(themeObj),
      formatDateToTimeString = React.useCallback((date: D, hour_format: S) => format ? format(date, hour_format === '12' ? 'hh:mm aa' : 'HH:mm') : '', [format])

    React.useEffect(() => {
      const time = m.value ? parseTimeStringToDate(m.value) : null
      const newTime = time && isBelowMin(time, minTime) ? minTime : time && isOverMax(time, maxTime) ? maxTime : time
      if (format) wave.args[m.name] = newTime ? formatDateToTimeString(newTime, '24') : null
      setValue(newTime)
    }, [format, formatDateToTimeString, m.name, m.value, maxTime, minTime])

    // TODO: Remove once CSS vars are fully supported - https://github.com/mui/material-ui/issues/27651
    React.useEffect(() => {
      if (theme) {
        theme.palette.primary.main = fluentPalette.themePrimary
        theme.palette.text.primary = fluentPalette.neutralPrimary
        theme.palette.action.active = fluentPalette.themePrimary
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [fluentPalette.themePrimary, theme])

    return <>
      <React.Suspense fallback={<LazyLoadPlaceholder />}>
        {theme && AdapterDateFns && format
          ? <ThemeProvider theme={theme}>
            <LocalizationProvider dateAdapter={AdapterDateFns}>
              <TimePicker
                value={value}
                label={label}
                open={isDialogOpen}
                onChange={onChangeTime}
                onAccept={onSelectTime}
                onClose={() => setIsDialogOpen(false)}
                ampm={hour_format === '12'}
                showToolbar
                ToolbarComponent={({ parsedValue, setOpenView, ampm }) =>
                  // Traps focus inside the popover.
                  // TODO: Check why focus gets back to the textfield after opening the popover from dialog.
                  <Fluent.FocusTrapZone isClickableOutsideFocusTrap>
                    <Toolbar