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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing date picker and field components event props not working #3605

Merged
merged 11 commits into from
Oct 26, 2022

Conversation

ktabors
Copy link
Member

@ktabors ktabors commented Oct 5, 2022

Closes #3272 #3346

The key and focus events will only happen when navigating the field and picker button. They (key events) won't occur in the calendar picker. And focus isn't lost when moving to the picker button or when the picker is open. Blur happens when you leave the component.

Changed the state API by adding isFocused and setFocused. This is replicating how picker managed these events.

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria Practices

📝 Test Instructions:

Added a story called "all events" to TimeField, DateField, DatePicker, and DateRangePicker. It allows us to test and confirm all the missing events.

🧢 Your Project:

RSP

@ktabors ktabors marked this pull request as draft October 5, 2022 23:41
@adobe-bot
Copy link

@adobe-bot
Copy link

@adobe-bot
Copy link

@@ -124,6 +124,10 @@ storiesOf('Date and Time/DateField', module)
.add(
'showFormatHelpText',
() => render({showFormatHelpText: true})
)
.add(
'all the events',
Copy link
Member Author

@ktabors ktabors Oct 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better story name?

}
},
onFocus(e: ReactFocusEvent) {
if (state.isFocused) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was modeled on how Picker handles these events. Picker had the state.isFocused and e.currentTarget.contains(e.relatedTarget as Node) logic. In this case, the state.isFocused is to not keep calling focus when moving between the segments and the trigger button. The e.currentTarget.contains(e.relatedTarget as Node) keeps the blur from being called when moving between segments and to the trigger button. The state.isOpen keeps the focus, blur, and keyup/down events from being called while using the calendar popover. There weren't comments on this in Picker so I'm not sure if we want them here.

While this logic is identical for the two picker hooks, date and time fields don't have a popover and state.isOpen, so it didn't seem worthwhile to generalize.

@ktabors ktabors marked this pull request as ready for review October 11, 2022 16:35
Copy link
Member

@snowystinger snowystinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have tests for these changes?

@adobe-bot
Copy link

@adobe-bot
Copy link

@adobe-bot
Copy link

API Changes

@react-stately/datepicker

DateFieldState

 DateFieldState {
   calendar: Calendar
   clearSegment: (SegmentType) => void
   confirmPlaceholder: () => void
   dateFormatter: DateFormatter
   dateValue: Date
   decrement: (SegmentType) => void
   decrementPage: (SegmentType) => void
   formatValue: (FieldOptions) => string
   granularity: Granularity
   increment: (SegmentType) => void
   incrementPage: (SegmentType) => void
   isDisabled: boolean
+  isFocused: boolean
   isReadOnly: boolean
   isRequired: boolean
   maxGranularity: 'year' | 'month' | Granularity
   segments: Array<DateSegment>
+  setFocused: (boolean) => void
   setSegment: (SegmentType, number) => void
   setValue: (DateValue) => void
   validationState: ValidationState
   value: DateValue
 

it changed:

  • useDateSegment
  • useDateField
  • useTimeField
  • useDateFieldState
  • useTimeFieldState

DatePickerState

 DatePickerState {
   close: () => void
   dateValue: DateValue
   formatValue: (string, FieldOptions) => string
   granularity: Granularity
   hasTime: boolean
+  isFocused: boolean
   isOpen: boolean
   open: () => void
   setDateValue: (CalendarDate) => void
+  setFocused: (boolean) => void
   setOpen: (boolean) => void
   setTimeValue: (TimeValue) => void
   setValue: (DateValue) => void
   timeValue: TimeValue
   validationState: ValidationState
   value: DateValue
 }
 

it changed:

  • useDatePicker
  • useDatePickerState

DateRangePickerState

 DateRangePickerState {
   close: () => void
   dateRange: DateRange
   formatValue: (string, FieldOptions) => {
     start: string
   end: string
 }
   granularity: Granularity
   hasTime: boolean
+  isFocused: boolean
   isOpen: boolean
   open: () => void
   setDate: ('start' | 'end', DateValue) => void
   setDateRange: (DateRange) => void
   setDateTime: ('start' | 'end', DateValue) => void
+  setFocused: (boolean) => void
   setOpen: (boolean) => void
   setTime: ('start' | 'end', TimeValue) => void
   setTimeRange: (TimeRange) => void
   setValue: (DateRange) => void
   toggle: () => void
   validationState: ValidationState
   value: DateRange
 }
 

it changed:

  • useDateRangePicker
  • useDateRangePickerState

@adobe adobe deleted a comment from adobe-bot Oct 17, 2022
@adobe adobe deleted a comment from adobe-bot Oct 17, 2022
@adobe adobe deleted a comment from adobe-bot Oct 17, 2022
Copy link
Member

@snowystinger snowystinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one last question, i don't seem to get an onKeyDown when I press enter on the button to open the calendar popover. what's swallowing that event?

otherwise works as expected in chrome and safari

@ktabors
Copy link
Member Author

ktabors commented Oct 18, 2022

one last question, i don't seem to get an onKeyDown when I press enter on the button to open the calendar popover. what's swallowing that event?

Good catch, the key events should be added to buttonProps. I'll add a test for that too.
This appears to be a general DialogTrigger issue and not specific to DatePicker. I tested and confirmed this in the DialogTrigger stories and made the following codesandbox to demonstrate it.

https://codesandbox.io/s/shy-bush-bnlplz?file=/src/App.js The story has a div wrapping a TextField and DialogTrigger, with onKeyDown and onKeyUp event listeners attached to the div. It logs the key press events in the TextField. When focused on the ActionButton of the DialogTrigger, a enter key press only logs an onKeyUp. While still on the ActionButton of the DialogTrigger, if you press another key, like left arrow, both the onKeyUp and onKeyDown are logged.

Copy link
Member

@reidbarber reidbarber left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@adobe-bot
Copy link

@adobe-bot
Copy link

API Changes

@react-stately/datepicker

DateFieldState

 DateFieldState {
   calendar: Calendar
   clearSegment: (SegmentType) => void
   confirmPlaceholder: () => void
   dateFormatter: DateFormatter
   dateValue: Date
   decrement: (SegmentType) => void
   decrementPage: (SegmentType) => void
   formatValue: (FieldOptions) => string
   granularity: Granularity
   increment: (SegmentType) => void
   incrementPage: (SegmentType) => void
   isDisabled: boolean
+  isFocused: boolean
   isReadOnly: boolean
   isRequired: boolean
   maxGranularity: 'year' | 'month' | Granularity
   segments: Array<DateSegment>
+  setFocused: (boolean) => void
   setSegment: (SegmentType, number) => void
   setValue: (DateValue) => void
   validationState: ValidationState
   value: DateValue
 

it changed:

  • useDateSegment
  • useDateField
  • useTimeField
  • useDateFieldState
  • useTimeFieldState

DatePickerState

 DatePickerState {
   close: () => void
   dateValue: DateValue
   formatValue: (string, FieldOptions) => string
   granularity: Granularity
   hasTime: boolean
+  isFocused: boolean
   isOpen: boolean
   open: () => void
   setDateValue: (CalendarDate) => void
+  setFocused: (boolean) => void
   setOpen: (boolean) => void
   setTimeValue: (TimeValue) => void
   setValue: (DateValue) => void
   timeValue: TimeValue
   validationState: ValidationState
   value: DateValue
 }
 

it changed:

  • useDatePicker
  • useDatePickerState

DateRangePickerState

 DateRangePickerState {
   close: () => void
   dateRange: DateRange
   formatValue: (string, FieldOptions) => {
     start: string
   end: string
 }
   granularity: Granularity
   hasTime: boolean
+  isFocused: boolean
   isOpen: boolean
   open: () => void
   setDate: ('start' | 'end', DateValue) => void
   setDateRange: (DateRange) => void
   setDateTime: ('start' | 'end', DateValue) => void
+  setFocused: (boolean) => void
   setOpen: (boolean) => void
   setTime: ('start' | 'end', TimeValue) => void
   setTimeRange: (TimeRange) => void
   setValue: (DateRange) => void
   toggle: () => void
   validationState: ValidationState
   value: DateRange
 }
 

it changed:

  • useDateRangePicker
  • useDateRangePickerState

@ktabors ktabors merged commit 4e68e5a into main Oct 26, 2022
@ktabors ktabors deleted the date_events branch October 26, 2022 17:21
@ethangclark
Copy link

Can we get a release cut? The date picker API is completely busted without this.

@snowystinger
Copy link
Member

It will go out in our next release which we are prepping. It takes time to get a quality release out and we appreciate your patience. In the meantime, you could probably use capture events on a parent to work around this. Also, we don't stopPropagation on the focus events I don't think, so you can just listen to those on a parent element.

}

state.setFocused(false);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, this is basically recreating the logic that useFocusWithin already implements. We could probably combine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

DatePicker focus and blur events are not being triggered
7 participants