]> source.dussan.org Git - sonarqube.git/commitdiff
[NO JIRA] Make date picker dropdown dismissable on Esc
authorWouter Admiraal <wouter.admiraal@sonarsource.com>
Fri, 7 Oct 2022 09:55:59 +0000 (11:55 +0200)
committersonartech <sonartech@sonarsource.com>
Tue, 11 Oct 2022 20:03:59 +0000 (20:03 +0000)
server/sonar-web/src/main/js/components/controls/DateInput.tsx
server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/DateInput-test.tsx.snap

index 166d7717aee60547b93a9ed2dfef1b26a6356f70..67168910d28bdc6a95299c06a258ef70041202c2 100644 (file)
@@ -35,6 +35,7 @@ import {
   translate
 } from '../../helpers/l10n';
 import './DayPicker.css';
+import EscKeydownHandler from './EscKeydownHandler';
 import Select from './Select';
 import './styles.css';
 
@@ -163,71 +164,73 @@ export default class DateInput extends React.PureComponent<Props, State> {
 
     return (
       <OutsideClickHandler onClickOutside={this.closeCalendar}>
-        <span className={classNames('date-input-control', className)}>
-          <InputWrapper
-            className={classNames('date-input-control-input', inputClassName, {
-              'is-filled': value !== undefined
-            })}
-            id={id}
-            innerRef={(node: HTMLInputElement | null) => (this.input = node)}
-            name={name}
-            onFocus={this.openCalendar}
-            placeholder={placeholder}
-            readOnly={true}
-            type="text"
-            value={value}
-          />
-          <CalendarIcon className="date-input-control-icon" fill="" />
-          {value !== undefined && (
-            <ClearButton
-              aria-label={translate('reset_verb')}
-              className="button-tiny date-input-control-reset"
-              iconProps={{ size: 12 }}
-              onClick={this.handleResetClick}
+        <EscKeydownHandler onKeydown={this.closeCalendar}>
+          <span className={classNames('date-input-control', className)}>
+            <InputWrapper
+              className={classNames('date-input-control-input', inputClassName, {
+                'is-filled': value !== undefined
+              })}
+              id={id}
+              innerRef={(node: HTMLInputElement | null) => (this.input = node)}
+              name={name}
+              onFocus={this.openCalendar}
+              placeholder={placeholder}
+              readOnly={true}
+              type="text"
+              value={value}
             />
-          )}
-          {open && (
-            <div className="date-input-calendar">
-              <nav className="date-input-calendar-nav">
-                <ButtonIcon className="button-small" onClick={this.handlePreviousMonthClick}>
-                  <ChevronLeftIcon />
-                </ButtonIcon>
-                <div className="date-input-calender-month">
-                  <Select
-                    aria-label={translate('select_month')}
-                    className="date-input-calender-month-select"
-                    onChange={this.handleCurrentMonthChange}
-                    options={monthOptions}
-                    value={monthOptions.find(month => month.value === currentMonth.getMonth())}
-                  />
-                  <Select
-                    aria-label={translate('select_year')}
-                    className="date-input-calender-month-select spacer-left"
-                    onChange={this.handleCurrentYearChange}
-                    options={yearOptions}
-                    value={yearOptions.find(year => year.value === currentMonth.getFullYear())}
-                  />
-                </div>
-                <ButtonIcon className="button-small" onClick={this.handleNextMonthClick}>
-                  <ChevronRightIcon />
-                </ButtonIcon>
-              </nav>
-              <DayPicker
-                captionElement={<NullComponent />}
-                disabledDays={{ after, before: minDate }}
-                firstDayOfWeek={1}
-                modifiers={modifiers}
-                month={currentMonth}
-                navbarElement={<NullComponent />}
-                onDayClick={this.handleDayClick}
-                onDayMouseEnter={this.handleDayMouseEnter}
-                selectedDays={selectedDays}
-                weekdaysLong={weekdaysLong}
-                weekdaysShort={weekdaysShort}
+            <CalendarIcon className="date-input-control-icon" fill="" />
+            {value !== undefined && (
+              <ClearButton
+                aria-label={translate('reset_verb')}
+                className="button-tiny date-input-control-reset"
+                iconProps={{ size: 12 }}
+                onClick={this.handleResetClick}
               />
-            </div>
-          )}
-        </span>
+            )}
+            {open && (
+              <div className="date-input-calendar">
+                <nav className="date-input-calendar-nav">
+                  <ButtonIcon className="button-small" onClick={this.handlePreviousMonthClick}>
+                    <ChevronLeftIcon />
+                  </ButtonIcon>
+                  <div className="date-input-calender-month">
+                    <Select
+                      aria-label={translate('select_month')}
+                      className="date-input-calender-month-select"
+                      onChange={this.handleCurrentMonthChange}
+                      options={monthOptions}
+                      value={monthOptions.find(month => month.value === currentMonth.getMonth())}
+                    />
+                    <Select
+                      aria-label={translate('select_year')}
+                      className="date-input-calender-month-select spacer-left"
+                      onChange={this.handleCurrentYearChange}
+                      options={yearOptions}
+                      value={yearOptions.find(year => year.value === currentMonth.getFullYear())}
+                    />
+                  </div>
+                  <ButtonIcon className="button-small" onClick={this.handleNextMonthClick}>
+                    <ChevronRightIcon />
+                  </ButtonIcon>
+                </nav>
+                <DayPicker
+                  captionElement={<NullComponent />}
+                  disabledDays={{ after, before: minDate }}
+                  firstDayOfWeek={1}
+                  modifiers={modifiers}
+                  month={currentMonth}
+                  navbarElement={<NullComponent />}
+                  onDayClick={this.handleDayClick}
+                  onDayMouseEnter={this.handleDayMouseEnter}
+                  selectedDays={selectedDays}
+                  weekdaysLong={weekdaysLong}
+                  weekdaysShort={weekdaysShort}
+                />
+              </div>
+            )}
+          </span>
+        </EscKeydownHandler>
       </OutsideClickHandler>
     );
   }
index fab0f857c18a7d3a4facad27fc5dc44ac6051669..6a3e0e6fb19bfbe2f49b1f9d9d0eb4dd56bec6d1 100644 (file)
@@ -4,22 +4,26 @@ exports[`should render 1`] = `
 <OutsideClickHandler
   onClickOutside={[Function]}
 >
-  <span
-    className="date-input-control"
+  <EscKeydownHandler
+    onKeydown={[Function]}
   >
-    <injectIntl(Component)
-      className="date-input-control-input"
-      innerRef={[Function]}
-      onFocus={[Function]}
-      placeholder="placeholder"
-      readOnly={true}
-      type="text"
-    />
-    <CalendarIcon
-      className="date-input-control-icon"
-      fill=""
-    />
-  </span>
+    <span
+      className="date-input-control"
+    >
+      <injectIntl(Component)
+        className="date-input-control-input"
+        innerRef={[Function]}
+        onFocus={[Function]}
+        placeholder="placeholder"
+        readOnly={true}
+        type="text"
+      />
+      <CalendarIcon
+        className="date-input-control-icon"
+        fill=""
+      />
+    </span>
+  </EscKeydownHandler>
 </OutsideClickHandler>
 `;
 
@@ -27,33 +31,37 @@ exports[`should render 2`] = `
 <OutsideClickHandler
   onClickOutside={[Function]}
 >
-  <span
-    className="date-input-control"
+  <EscKeydownHandler
+    onKeydown={[Function]}
   >
-    <injectIntl(Component)
-      className="date-input-control-input is-filled"
-      innerRef={[Function]}
-      onFocus={[Function]}
-      placeholder="placeholder"
-      readOnly={true}
-      type="text"
-      value={2018-01-17T00:00:00.000Z}
-    />
-    <CalendarIcon
-      className="date-input-control-icon"
-      fill=""
-    />
-    <ClearButton
-      aria-label="reset_verb"
-      className="button-tiny date-input-control-reset"
-      iconProps={
-        Object {
-          "size": 12,
+    <span
+      className="date-input-control"
+    >
+      <injectIntl(Component)
+        className="date-input-control-input is-filled"
+        innerRef={[Function]}
+        onFocus={[Function]}
+        placeholder="placeholder"
+        readOnly={true}
+        type="text"
+        value={2018-01-17T00:00:00.000Z}
+      />
+      <CalendarIcon
+        className="date-input-control-icon"
+        fill=""
+      />
+      <ClearButton
+        aria-label="reset_verb"
+        className="button-tiny date-input-control-reset"
+        iconProps={
+          Object {
+            "size": 12,
+          }
         }
-      }
-      onClick={[Function]}
-    />
-  </span>
+        onClick={[Function]}
+      />
+    </span>
+  </EscKeydownHandler>
 </OutsideClickHandler>
 `;
 
@@ -61,285 +69,289 @@ exports[`should render 3`] = `
 <OutsideClickHandler
   onClickOutside={[Function]}
 >
-  <span
-    className="date-input-control"
+  <EscKeydownHandler
+    onKeydown={[Function]}
   >
-    <injectIntl(Component)
-      className="date-input-control-input is-filled"
-      innerRef={[Function]}
-      onFocus={[Function]}
-      placeholder="placeholder"
-      readOnly={true}
-      type="text"
-      value={2018-01-17T00:00:00.000Z}
-    />
-    <CalendarIcon
-      className="date-input-control-icon"
-      fill=""
-    />
-    <ClearButton
-      aria-label="reset_verb"
-      className="button-tiny date-input-control-reset"
-      iconProps={
-        Object {
-          "size": 12,
-        }
-      }
-      onClick={[Function]}
-    />
-    <div
-      className="date-input-calendar"
+    <span
+      className="date-input-control"
     >
-      <nav
-        className="date-input-calendar-nav"
+      <injectIntl(Component)
+        className="date-input-control-input is-filled"
+        innerRef={[Function]}
+        onFocus={[Function]}
+        placeholder="placeholder"
+        readOnly={true}
+        type="text"
+        value={2018-01-17T00:00:00.000Z}
+      />
+      <CalendarIcon
+        className="date-input-control-icon"
+        fill=""
+      />
+      <ClearButton
+        aria-label="reset_verb"
+        className="button-tiny date-input-control-reset"
+        iconProps={
+          Object {
+            "size": 12,
+          }
+        }
+        onClick={[Function]}
+      />
+      <div
+        className="date-input-calendar"
       >
-        <ButtonIcon
-          className="button-small"
-          onClick={[Function]}
-        >
-          <ChevronLeftIcon />
-        </ButtonIcon>
-        <div
-          className="date-input-calender-month"
+        <nav
+          className="date-input-calendar-nav"
         >
-          <Select
-            aria-label="select_month"
-            className="date-input-calender-month-select"
-            onChange={[Function]}
-            options={
-              Array [
+          <ButtonIcon
+            className="button-small"
+            onClick={[Function]}
+          >
+            <ChevronLeftIcon />
+          </ButtonIcon>
+          <div
+            className="date-input-calender-month"
+          >
+            <Select
+              aria-label="select_month"
+              className="date-input-calender-month-select"
+              onChange={[Function]}
+              options={
+                Array [
+                  Object {
+                    "label": "Jan",
+                    "value": 0,
+                  },
+                  Object {
+                    "label": "Feb",
+                    "value": 1,
+                  },
+                  Object {
+                    "label": "Mar",
+                    "value": 2,
+                  },
+                  Object {
+                    "label": "Apr",
+                    "value": 3,
+                  },
+                  Object {
+                    "label": "May",
+                    "value": 4,
+                  },
+                  Object {
+                    "label": "Jun",
+                    "value": 5,
+                  },
+                  Object {
+                    "label": "Jul",
+                    "value": 6,
+                  },
+                  Object {
+                    "label": "Aug",
+                    "value": 7,
+                  },
+                  Object {
+                    "label": "Sep",
+                    "value": 8,
+                  },
+                  Object {
+                    "label": "Oct",
+                    "value": 9,
+                  },
+                  Object {
+                    "label": "Nov",
+                    "value": 10,
+                  },
+                  Object {
+                    "label": "Dec",
+                    "value": 11,
+                  },
+                ]
+              }
+              value={
                 Object {
                   "label": "Jan",
                   "value": 0,
-                },
-                Object {
-                  "label": "Feb",
-                  "value": 1,
-                },
-                Object {
-                  "label": "Mar",
-                  "value": 2,
-                },
-                Object {
-                  "label": "Apr",
-                  "value": 3,
-                },
-                Object {
-                  "label": "May",
-                  "value": 4,
-                },
-                Object {
-                  "label": "Jun",
-                  "value": 5,
-                },
-                Object {
-                  "label": "Jul",
-                  "value": 6,
-                },
-                Object {
-                  "label": "Aug",
-                  "value": 7,
-                },
-                Object {
-                  "label": "Sep",
-                  "value": 8,
-                },
-                Object {
-                  "label": "Oct",
-                  "value": 9,
-                },
-                Object {
-                  "label": "Nov",
-                  "value": 10,
-                },
-                Object {
-                  "label": "Dec",
-                  "value": 11,
-                },
-              ]
-            }
-            value={
-              Object {
-                "label": "Jan",
-                "value": 0,
+                }
               }
-            }
-          />
-          <Select
-            aria-label="select_year"
-            className="date-input-calender-month-select spacer-left"
-            onChange={[Function]}
-            options={
-              Array [
-                Object {
-                  "label": "2008",
-                  "value": 2008,
-                },
-                Object {
-                  "label": "2009",
-                  "value": 2009,
-                },
-                Object {
-                  "label": "2010",
-                  "value": 2010,
-                },
-                Object {
-                  "label": "2011",
-                  "value": 2011,
-                },
-                Object {
-                  "label": "2012",
-                  "value": 2012,
-                },
-                Object {
-                  "label": "2013",
-                  "value": 2013,
-                },
-                Object {
-                  "label": "2014",
-                  "value": 2014,
-                },
-                Object {
-                  "label": "2015",
-                  "value": 2015,
-                },
-                Object {
-                  "label": "2016",
-                  "value": 2016,
-                },
-                Object {
-                  "label": "2017",
-                  "value": 2017,
-                },
+            />
+            <Select
+              aria-label="select_year"
+              className="date-input-calender-month-select spacer-left"
+              onChange={[Function]}
+              options={
+                Array [
+                  Object {
+                    "label": "2008",
+                    "value": 2008,
+                  },
+                  Object {
+                    "label": "2009",
+                    "value": 2009,
+                  },
+                  Object {
+                    "label": "2010",
+                    "value": 2010,
+                  },
+                  Object {
+                    "label": "2011",
+                    "value": 2011,
+                  },
+                  Object {
+                    "label": "2012",
+                    "value": 2012,
+                  },
+                  Object {
+                    "label": "2013",
+                    "value": 2013,
+                  },
+                  Object {
+                    "label": "2014",
+                    "value": 2014,
+                  },
+                  Object {
+                    "label": "2015",
+                    "value": 2015,
+                  },
+                  Object {
+                    "label": "2016",
+                    "value": 2016,
+                  },
+                  Object {
+                    "label": "2017",
+                    "value": 2017,
+                  },
+                  Object {
+                    "label": "2018",
+                    "value": 2018,
+                  },
+                ]
+              }
+              value={
                 Object {
                   "label": "2018",
                   "value": 2018,
-                },
-              ]
-            }
-            value={
-              Object {
-                "label": "2018",
-                "value": 2018,
+                }
               }
+            />
+          </div>
+          <ButtonIcon
+            className="button-small"
+            onClick={[Function]}
+          >
+            <ChevronRightIcon />
+          </ButtonIcon>
+        </nav>
+        <DayPicker
+          canChangeMonth={true}
+          captionElement={<NullComponent />}
+          classNames={
+            Object {
+              "body": "DayPicker-Body",
+              "caption": "DayPicker-Caption",
+              "container": "DayPicker",
+              "day": "DayPicker-Day",
+              "disabled": "disabled",
+              "footer": "DayPicker-Footer",
+              "interactionDisabled": "DayPicker--interactionDisabled",
+              "month": "DayPicker-Month",
+              "months": "DayPicker-Months",
+              "navBar": "DayPicker-NavBar",
+              "navButtonInteractionDisabled": "DayPicker-NavButton--interactionDisabled",
+              "navButtonNext": "DayPicker-NavButton DayPicker-NavButton--next",
+              "navButtonPrev": "DayPicker-NavButton DayPicker-NavButton--prev",
+              "outside": "outside",
+              "selected": "selected",
+              "today": "today",
+              "todayButton": "DayPicker-TodayButton",
+              "week": "DayPicker-Week",
+              "weekNumber": "DayPicker-WeekNumber",
+              "weekday": "DayPicker-Weekday",
+              "weekdays": "DayPicker-Weekdays",
+              "weekdaysRow": "DayPicker-WeekdaysRow",
+              "wrapper": "DayPicker-wrapper",
             }
-          />
-        </div>
-        <ButtonIcon
-          className="button-small"
-          onClick={[Function]}
-        >
-          <ChevronRightIcon />
-        </ButtonIcon>
-      </nav>
-      <DayPicker
-        canChangeMonth={true}
-        captionElement={<NullComponent />}
-        classNames={
-          Object {
-            "body": "DayPicker-Body",
-            "caption": "DayPicker-Caption",
-            "container": "DayPicker",
-            "day": "DayPicker-Day",
-            "disabled": "disabled",
-            "footer": "DayPicker-Footer",
-            "interactionDisabled": "DayPicker--interactionDisabled",
-            "month": "DayPicker-Month",
-            "months": "DayPicker-Months",
-            "navBar": "DayPicker-NavBar",
-            "navButtonInteractionDisabled": "DayPicker-NavButton--interactionDisabled",
-            "navButtonNext": "DayPicker-NavButton DayPicker-NavButton--next",
-            "navButtonPrev": "DayPicker-NavButton DayPicker-NavButton--prev",
-            "outside": "outside",
-            "selected": "selected",
-            "today": "today",
-            "todayButton": "DayPicker-TodayButton",
-            "week": "DayPicker-Week",
-            "weekNumber": "DayPicker-WeekNumber",
-            "weekday": "DayPicker-Weekday",
-            "weekdays": "DayPicker-Weekdays",
-            "weekdaysRow": "DayPicker-WeekdaysRow",
-            "wrapper": "DayPicker-wrapper",
           }
-        }
-        disabledDays={
-          Object {
-            "after": 2018-02-05T00:00:00.000Z,
-            "before": 2018-01-17T00:00:00.000Z,
+          disabledDays={
+            Object {
+              "after": 2018-02-05T00:00:00.000Z,
+              "before": 2018-01-17T00:00:00.000Z,
+            }
           }
-        }
-        enableOutsideDaysClick={true}
-        firstDayOfWeek={1}
-        fixedWeeks={false}
-        labels={
-          Object {
-            "nextMonth": "Next Month",
-            "previousMonth": "Previous Month",
+          enableOutsideDaysClick={true}
+          firstDayOfWeek={1}
+          fixedWeeks={false}
+          labels={
+            Object {
+              "nextMonth": "Next Month",
+              "previousMonth": "Previous Month",
+            }
           }
-        }
-        locale="en"
-        localeUtils={
-          Object {
-            "default": Object {
+          locale="en"
+          localeUtils={
+            Object {
+              "default": Object {
+                "formatDay": [Function],
+                "formatMonthTitle": [Function],
+                "formatWeekdayLong": [Function],
+                "formatWeekdayShort": [Function],
+                "getFirstDayOfWeek": [Function],
+                "getMonths": [Function],
+              },
               "formatDay": [Function],
               "formatMonthTitle": [Function],
               "formatWeekdayLong": [Function],
               "formatWeekdayShort": [Function],
               "getFirstDayOfWeek": [Function],
               "getMonths": [Function],
-            },
-            "formatDay": [Function],
-            "formatMonthTitle": [Function],
-            "formatWeekdayLong": [Function],
-            "formatWeekdayShort": [Function],
-            "getFirstDayOfWeek": [Function],
-            "getMonths": [Function],
+            }
           }
-        }
-        month={2018-01-17T00:00:00.000Z}
-        navbarElement={<NullComponent />}
-        numberOfMonths={1}
-        onDayClick={[Function]}
-        onDayMouseEnter={[Function]}
-        pagedNavigation={false}
-        renderDay={[Function]}
-        renderWeek={[Function]}
-        reverseMonths={false}
-        selectedDays={
-          Array [
-            2018-01-17T00:00:00.000Z,
-          ]
-        }
-        showOutsideDays={false}
-        showWeekDays={true}
-        showWeekNumbers={false}
-        tabIndex={0}
-        weekdayElement={<Weekday />}
-        weekdaysLong={
-          Array [
-            "Sunday",
-            "Monday",
-            "Tuesday",
-            "Wednesday",
-            "Thursday",
-            "Friday",
-            "Saturday",
-          ]
-        }
-        weekdaysShort={
-          Array [
-            "Sun",
-            "Mon",
-            "Tue",
-            "Wed",
-            "Thu",
-            "Fri",
-            "Sat",
-          ]
-        }
-      />
-    </div>
-  </span>
+          month={2018-01-17T00:00:00.000Z}
+          navbarElement={<NullComponent />}
+          numberOfMonths={1}
+          onDayClick={[Function]}
+          onDayMouseEnter={[Function]}
+          pagedNavigation={false}
+          renderDay={[Function]}
+          renderWeek={[Function]}
+          reverseMonths={false}
+          selectedDays={
+            Array [
+              2018-01-17T00:00:00.000Z,
+            ]
+          }
+          showOutsideDays={false}
+          showWeekDays={true}
+          showWeekNumbers={false}
+          tabIndex={0}
+          weekdayElement={<Weekday />}
+          weekdaysLong={
+            Array [
+              "Sunday",
+              "Monday",
+              "Tuesday",
+              "Wednesday",
+              "Thursday",
+              "Friday",
+              "Saturday",
+            ]
+          }
+          weekdaysShort={
+            Array [
+              "Sun",
+              "Mon",
+              "Tue",
+              "Wed",
+              "Thu",
+              "Fri",
+              "Sat",
+            ]
+          }
+        />
+      </div>
+    </span>
+  </EscKeydownHandler>
 </OutsideClickHandler>
 `;
 
@@ -347,21 +359,25 @@ exports[`should select a day 1`] = `
 <OutsideClickHandler
   onClickOutside={[Function]}
 >
-  <span
-    className="date-input-control"
+  <EscKeydownHandler
+    onKeydown={[Function]}
   >
-    <injectIntl(Component)
-      className="date-input-control-input"
-      innerRef={[Function]}
-      onFocus={[Function]}
-      placeholder="placeholder"
-      readOnly={true}
-      type="text"
-    />
-    <CalendarIcon
-      className="date-input-control-icon"
-      fill=""
-    />
-  </span>
+    <span
+      className="date-input-control"
+    >
+      <injectIntl(Component)
+        className="date-input-control-input"
+        innerRef={[Function]}
+        onFocus={[Function]}
+        placeholder="placeholder"
+        readOnly={true}
+        type="text"
+      />
+      <CalendarIcon
+        className="date-input-control-icon"
+        fill=""
+      />
+    </span>
+  </EscKeydownHandler>
 </OutsideClickHandler>
 `;