Skip to content

Commit

Permalink
fix(calendar): prevent handleBlur triggering on empty input focus (#1636
Browse files Browse the repository at this point in the history
)

* fix: prevent handleBlur triggering on empty input focus
  • Loading branch information
alaa-yahia authored Nov 25, 2024
1 parent 42f74ce commit 32b57bc
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 62 deletions.
45 changes: 15 additions & 30 deletions components/calendar/src/calendar-input/calendar-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,10 @@ export const CalendarInput = ({
...rest
} = {}) => {
const ref = useRef()
const calendarRef = useRef()
const [open, setOpen] = useState(false)
const [partialDate, setPartialDate] = useState(date)

const excludeRef = useRef(null)

useEffect(() => setPartialDate(date), [date])

const useDatePickerOptions = useMemo(
Expand All @@ -59,21 +58,14 @@ export const CalendarInput = ({
)

const onChooseDate = (date, validationOptions) => {
// Handling clearing (with clicking the Clear button, or deleting input)
if (clearable && (date === null || date === '')) {
if (!date) {
parentOnDateSelect?.({
calendarDateString: null,
validation: { valid: true },
})
return
}

// ToDo: This is now a workaround for handling choosing from the date picker
// where the blur event gets triggered causing a call with undefined first
if (date === undefined) {
return
}

const validation = validateDateString(date, validationOptions)
parentOnDateSelect?.({
calendarDateString: date,
Expand Down Expand Up @@ -108,13 +100,12 @@ export const CalendarInput = ({
}

const handleBlur = (_, e) => {
onChooseDate(partialDate, validationOptions)
if (
excludeRef.current &&
!excludeRef.current.contains(e.relatedTarget)
) {
setOpen(false)
if (e.relatedTarget && calendarRef.current?.contains(e.relatedTarget)) {
return
}

onChooseDate(partialDate, validationOptions)
setOpen(false)
}

const onFocus = () => {
Expand All @@ -124,8 +115,8 @@ export const CalendarInput = ({

const languageDirection = useResolvedDirection(dir, locale)

const calendarProps = useMemo(() => {
return {
const calendarProps = useMemo(
() => ({
date,
width,
cellSize,
Expand All @@ -139,8 +130,9 @@ export const CalendarInput = ({
prevMonth: pickerResults.prevMonth,
prevYear: pickerResults.prevYear,
languageDirection,
}
}, [cellSize, date, pickerResults, width, languageDirection])
}),
[cellSize, date, pickerResults, width, languageDirection]
)

return (
<>
Expand Down Expand Up @@ -171,9 +163,7 @@ export const CalendarInput = ({
dataTest="calendar-clear-button"
secondary
small
onClick={() => {
onChooseDate(null)
}}
onClick={() => onChooseDate(null)}
type="button"
>
{i18n.t('Clear')}
Expand All @@ -182,11 +172,7 @@ export const CalendarInput = ({
)}
</div>
{open && (
<Layer
onBackdropClick={() => {
setOpen(false)
}}
>
<Layer onBackdropClick={() => setOpen(false)}>
<Popper
reference={ref}
placement="bottom-start"
Expand All @@ -195,8 +181,7 @@ export const CalendarInput = ({
<Card>
<CalendarContainer
{...calendarProps}
excludedRef={excludeRef}
unfocusable
calendarRef={calendarRef}
/>
</Card>
</Popper>
Expand Down
12 changes: 3 additions & 9 deletions components/calendar/src/calendar/calendar-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ export const CalendarContainer = React.memo(function CalendarContainer({
prevMonth,
prevYear,
languageDirection,
excludedRef,
unfocusable = false,
calendarRef,
}) {
const navigationProps = useMemo(() => {
return {
Expand Down Expand Up @@ -52,18 +51,14 @@ export const CalendarContainer = React.memo(function CalendarContainer({
dir={languageDirection}
data-test="calendar"
>
<div ref={excludedRef}>
<NavigationContainer
{...navigationProps}
unfocusable={unfocusable}
/>
<div ref={calendarRef}>
<NavigationContainer {...navigationProps} />
<CalendarTable
selectedDate={date}
calendarWeekDays={calendarWeekDays}
weekDayLabels={weekDayLabels}
cellSize={cellSize}
width={width}
unfocusable={unfocusable}
/>
</div>
</div>
Expand All @@ -90,7 +85,6 @@ export const CalendarContainer = React.memo(function CalendarContainer({
CalendarContainer.propTypes = {
/** the currently selected date using an iso-like format YYYY-MM-DD, in the calendar system provided (not iso8601) */
date: PropTypes.string,
unfocusable: PropTypes.bool,
...CalendarTableProps,
...NavigationContainerProps,
}
9 changes: 1 addition & 8 deletions components/calendar/src/calendar/calendar-table-cell.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@ import cx from 'classnames'
import PropTypes from 'prop-types'
import React from 'react'

export const CalendarTableCell = ({
day,
cellSize,
selectedDate,
unfocusable,
}) => {
export const CalendarTableCell = ({ day, cellSize, selectedDate }) => {
const dayHoverBackgroundColor = colors.grey200
const selectedDayBackgroundColor = colors.teal700

Expand All @@ -21,7 +16,6 @@ export const CalendarTableCell = ({
isToday: day.isToday,
otherMonth: !day.isInCurrentMonth,
})}
tabIndex={unfocusable ? -1 : 0}
>
{day.label}
</button>
Expand Down Expand Up @@ -100,5 +94,4 @@ CalendarTableCell.propTypes = {
onClick: PropTypes.func,
}),
selectedDate: PropTypes.string,
unfocusable: PropTypes.bool,
}
3 changes: 0 additions & 3 deletions components/calendar/src/calendar/calendar-table.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export const CalendarTable = ({
width,
cellSize,
selectedDate,
unfocusable,
}) => (
<div className="calendar-table-wrapper">
<table className="calendar-table">
Expand All @@ -25,7 +24,6 @@ export const CalendarTable = ({
key={day?.dateValue}
cellSize={cellSize}
width={width}
unfocusable={unfocusable}
/>
))}
</tr>
Expand Down Expand Up @@ -69,7 +67,6 @@ export const CalendarTableProps = {
).isRequired,
cellSize: PropTypes.string,
selectedDate: PropTypes.string,
unfocusable: PropTypes.bool,
weekDayLabels: PropTypes.arrayOf(PropTypes.string),
width: PropTypes.string,
}
Expand Down
6 changes: 0 additions & 6 deletions components/calendar/src/calendar/navigation-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export const NavigationContainer = ({
nextYear,
prevMonth,
prevYear,
unfocusable,
}) => {
const PreviousIcon =
languageDirection === 'ltr' ? IconChevronLeft16 : IconChevronRight16
Expand All @@ -37,7 +36,6 @@ export const NavigationContainer = ({
data-test="calendar-previous-month"
aria-label={`${i18n.t(`Go to ${prevMonth.label}`)}`}
type="button"
tabIndex={unfocusable ? -1 : 0}
>
<PreviousIcon />
</button>
Expand All @@ -52,7 +50,6 @@ export const NavigationContainer = ({
name="next-month"
aria-label={`${i18n.t(`Go to ${nextMonth.label}`)}`}
type="button"
tabIndex={unfocusable ? -1 : 0}
>
<NextIcon />
</button>
Expand All @@ -65,7 +62,6 @@ export const NavigationContainer = ({
name="previous-year"
aria-label={`${i18n.t('Go to previous year')}`}
type="button"
tabIndex={unfocusable ? -1 : 0}
>
<PreviousIcon />
</button>
Expand All @@ -84,7 +80,6 @@ export const NavigationContainer = ({
name="next-year"
aria-label={`${i18n.t('Go to next year')}`}
type="button"
tabIndex={unfocusable ? -1 : 0}
>
<NextIcon />
</button>
Expand Down Expand Up @@ -180,7 +175,6 @@ export const NavigationContainerProps = {
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
navigateTo: PropTypes.func,
}),
unfocusable: PropTypes.bool,
}

NavigationContainer.propTypes = NavigationContainerProps
19 changes: 13 additions & 6 deletions components/calendar/src/stories/calendar-input.prod.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,23 +120,30 @@ export const CalendarWithClearButton = ({
}

export function CalendarWithEditiableInput() {
const [date, setDate] = useState('2020-07-03')
const [date, setDate] = useState('')
const [validation, setValidation] = useState({})

const errorProps = {
error: !!validation?.error,
validationText: validation?.validationText,
}

return (
<div>
<>
<CalendarInput
date={date}
calendar="gregory"
onDateSelect={(selectedDate) => {
const date = selectedDate?.calendarDateString
setDate(date)
onDateSelect={(result) => {
const { calendarDateString, validation } = result || {}
setDate(calendarDateString)
setValidation(validation)
}}
onFocus={() => {
console.log('focused')
}}
width="400px"
minDate="2020-07-01"
maxDate="2020-07-09"
{...errorProps}
clearable
/>
</>
Expand Down

0 comments on commit 32b57bc

Please sign in to comment.