Repository: adobe/react-spectrum
File: packages/react-aria-components/src/HiddenDateInput.tsx (TypeScript)

Code before:
    },
    inputProps: {
      tabIndex: -1,
      autoComplete,
      disabled: isDisabled,
      type: inputType,
      // We set the form prop to an empty string to prevent the hidden date input's value from being submitted
      form: '',
      name,
      step: inputStep,
      value: dateValue,
      onChange: (e) => {
        let targetString = e.target.value.toString();
        if (targetString) {
          let targetValue: CalendarDateTime | CalendarDate = parseDateTime(targetString);
          if (state.granularity === 'day') {
            targetValue = parseDate(targetString);
          }
          setDateValue(targetString);
          // We check to to see if setSegment exists in the state since it only exists in DateFieldState and not DatePickerState.
          // The setValue method has different behavior depending on if it's coming from DateFieldState or DatePickerState.
          // In DateFieldState, setValue firsts checks to make sure that each segment is filled before committing the newValue 
          // which is why in the code below we first set each segment to validate it before committing the new value. 
          // However, in DatePickerState, since we have to be able to commit values from the Calendar popover, we are also able to 
          // set a new value when the field itself is empty. 
          if ('setSegment' in state) {
            for (let type in targetValue) {
              if (dateSegments.includes(type)) {
                state.setSegment(type as DateSegmentType, targetValue[type]);
              }
              if (timeSegments.includes(type)) {
                state.setSegment(type as DateSegmentType, targetValue[type]);
              }
            }
            
          }
          state.setValue(targetValue);
        }
      }
    }
  };
}

export function HiddenDateInput(props: HiddenDateInputProps) {
  let {state} = props;
  let {containerProps, inputProps} = useHiddenDateInput({...props}, state);
  return (
    <div {...containerProps} data-testid="hidden-dateinput-container">
      <input {...inputProps} />
    </div>
  );

Review comment (suggestion):
a little unsure if this is the direction we want to go. i left some comments in the code to explain what's going on but essentially the issue is that depending if the state is DateFieldState or DatePickerState, the setValue method behaves a bit differently.

i've tried validating each segment inside setValue in useDateFieldState but the problem is that we aren't able to differentiate between a newValue that is the placeholder date versus something external (like in this case). as a result, we end up committing the placeholder value as an actual value that we want to display. in any case, it causes some really strange behavior when trying to validate segments inside setValue so it worked better to do it here inside HiddenDateInput

Code after:
      form: '',
      name,
      step: inputStep,
      value: dateValue,
      onChange: (e) => {
        let targetString = e.target.value.toString();
        if (targetString) {
          try {
            let targetValue: CalendarDateTime | CalendarDate = parseDateTime(targetString);
            if (state.granularity === 'day') {
              targetValue = parseDate(targetString);
            }
            // We check to to see if setSegment exists in the state since it only exists in DateFieldState and not DatePickerState.
            // The setValue method has different behavior depending on if it's coming from DateFieldState or DatePickerState.
            // In DateFieldState, setValue firsts checks to make sure that each segment is filled before committing the newValue 
            // which is why in the code below we first set each segment to validate it before committing the new value. 
            // However, in DatePickerState, since we have to be able to commit values from the Calendar popover, we are also able to 
            // set a new value when the field itself is empty.
            if ('setSegment' in state) {
              for (let type in targetValue) {
                if (dateSegments.includes(type)) {
                  state.setSegment(type as DateSegmentType, targetValue[type]);
                }
                if (timeSegments.includes(type)) {
                  state.setSegment(type as DateSegmentType, targetValue[type]);
                }
              }
            }
            state.setValue(targetValue);
          } catch {
            // ignore
          }
        }
      }
    }
  };
}

export function HiddenDateInput(props: HiddenDateInputProps): ReactNode | null {
  let {state} = props;
  let {containerProps, inputProps} = useHiddenDateInput({...props}, state);
  return (
    <div {...containerProps} data-testid="hidden-dateinput-container">
      <input {...inputProps} />
    </div>
  );
}