@sb1/ffe-datepicker-react 100.12.0 → 100.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/calendar/Calendar.js +36 -11
- package/es/calendar/Header.js +3 -3
- package/es/input/DateInput.js +7 -2
- package/es/tsconfig.esm.tsbuildinfo +1 -1
- package/es/util/isIOSSafari.js +22 -0
- package/lib/calendar/Calendar.js +36 -11
- package/lib/calendar/Header.js +3 -3
- package/lib/input/DateInput.js +40 -2
- package/lib/tsconfig.cjs.tsbuildinfo +1 -1
- package/lib/util/isIOSSafari.js +26 -0
- package/package.json +8 -8
- package/types/calendar/Calendar.d.ts +2 -0
- package/types/calendar/Header.d.ts +2 -0
- package/types/tsconfig.types.tsbuildinfo +1 -1
- package/types/util/isIOSSafari.d.ts +11 -0
package/es/calendar/Calendar.js
CHANGED
|
@@ -27,35 +27,60 @@ var Calendar = /** @class */ (function (_super) {
|
|
|
27
27
|
_this.clickableDateRef = React.createRef();
|
|
28
28
|
_this.prevMonthButtonElementRef = React.createRef();
|
|
29
29
|
_this.nextMonthButtonElementRef = React.createRef();
|
|
30
|
+
_this.monthSelectRef = React.createRef();
|
|
31
|
+
_this.yearSelectRef = React.createRef();
|
|
30
32
|
_this.focusTrap = function (event) {
|
|
31
|
-
var _a, _b, _c, _d, _e, _f;
|
|
33
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
32
34
|
var activeElement = document.activeElement;
|
|
33
35
|
if (event.key === 'Tab') {
|
|
34
36
|
event.preventDefault();
|
|
37
|
+
var dropdownCaption = _this.props.dropdownCaption;
|
|
35
38
|
if (event.shiftKey) {
|
|
36
39
|
if (activeElement === _this.clickableDateRef.current) {
|
|
37
40
|
(_a = _this.nextMonthButtonElementRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
38
41
|
_this.setState({ isFocusingHeader: true });
|
|
39
42
|
}
|
|
40
|
-
if (activeElement === _this.nextMonthButtonElementRef.current) {
|
|
41
|
-
(
|
|
43
|
+
else if (activeElement === _this.nextMonthButtonElementRef.current) {
|
|
44
|
+
if (dropdownCaption) {
|
|
45
|
+
(_b = _this.yearSelectRef.current) === null || _b === void 0 ? void 0 : _b.focus();
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
(_c = _this.prevMonthButtonElementRef.current) === null || _c === void 0 ? void 0 : _c.focus();
|
|
49
|
+
}
|
|
42
50
|
}
|
|
43
|
-
if (activeElement === _this.
|
|
44
|
-
(
|
|
51
|
+
else if (dropdownCaption && activeElement === _this.yearSelectRef.current) {
|
|
52
|
+
(_d = _this.monthSelectRef.current) === null || _d === void 0 ? void 0 : _d.focus();
|
|
53
|
+
}
|
|
54
|
+
else if (dropdownCaption && activeElement === _this.monthSelectRef.current) {
|
|
55
|
+
(_e = _this.prevMonthButtonElementRef.current) === null || _e === void 0 ? void 0 : _e.focus();
|
|
56
|
+
}
|
|
57
|
+
else if (activeElement === _this.prevMonthButtonElementRef.current) {
|
|
58
|
+
(_f = _this.clickableDateRef.current) === null || _f === void 0 ? void 0 : _f.focus();
|
|
45
59
|
_this.setState({ isFocusingHeader: false });
|
|
46
60
|
_this.forceUpdate();
|
|
47
61
|
}
|
|
48
62
|
}
|
|
49
63
|
else {
|
|
50
64
|
if (activeElement === _this.clickableDateRef.current) {
|
|
51
|
-
(
|
|
65
|
+
(_g = _this.prevMonthButtonElementRef.current) === null || _g === void 0 ? void 0 : _g.focus();
|
|
52
66
|
_this.setState({ isFocusingHeader: true });
|
|
53
67
|
}
|
|
54
|
-
if (activeElement === _this.prevMonthButtonElementRef.current) {
|
|
55
|
-
(
|
|
68
|
+
else if (activeElement === _this.prevMonthButtonElementRef.current) {
|
|
69
|
+
if (dropdownCaption) {
|
|
70
|
+
(_h = _this.monthSelectRef.current) === null || _h === void 0 ? void 0 : _h.focus();
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
(_j = _this.nextMonthButtonElementRef.current) === null || _j === void 0 ? void 0 : _j.focus();
|
|
74
|
+
}
|
|
56
75
|
}
|
|
57
|
-
if (activeElement === _this.
|
|
58
|
-
(
|
|
76
|
+
else if (dropdownCaption && activeElement === _this.monthSelectRef.current) {
|
|
77
|
+
(_k = _this.yearSelectRef.current) === null || _k === void 0 ? void 0 : _k.focus();
|
|
78
|
+
}
|
|
79
|
+
else if (dropdownCaption && activeElement === _this.yearSelectRef.current) {
|
|
80
|
+
(_l = _this.nextMonthButtonElementRef.current) === null || _l === void 0 ? void 0 : _l.focus();
|
|
81
|
+
}
|
|
82
|
+
else if (activeElement === _this.nextMonthButtonElementRef.current) {
|
|
83
|
+
(_m = _this.clickableDateRef.current) === null || _m === void 0 ? void 0 : _m.focus();
|
|
59
84
|
_this.setState({ isFocusingHeader: false });
|
|
60
85
|
_this.forceUpdate();
|
|
61
86
|
}
|
|
@@ -222,7 +247,7 @@ var Calendar = /** @class */ (function (_super) {
|
|
|
222
247
|
React.createElement("div", { className: this.props.calendarClassName || 'ffe-calendar', role: "application", onKeyDown: this.focusTrap },
|
|
223
248
|
React.createElement(Header, { datepickerId: this.datepickerId, month: calendar.focusedMonth, nextMonthHandler: this.nextMonth, nextMonthLabel: calendar.nextName, previousMonthHandler: this.previousMonth, previousMonthLabel: calendar.previousName, year: calendar.focusedYear, prevMonthButtonElement: this.prevMonthButtonElementRef, nextMonthButtonElement: this.nextMonthButtonElementRef, monthNumber: calendar.focusedDate.month + 1, locale: this.props.locale, dropdownCaption: this.props.dropdownCaption, onMonthYearChange: function (month, year) {
|
|
224
249
|
return _this.navigateToMonthYear(month, year);
|
|
225
|
-
}, minDate: this.props.minDate, maxDate: this.props.maxDate }),
|
|
250
|
+
}, minDate: this.props.minDate, maxDate: this.props.maxDate, monthSelectRef: this.monthSelectRef, yearSelectRef: this.yearSelectRef }),
|
|
226
251
|
React.createElement("table", { className: "ffe-calendar__grid", onKeyDown: this.keyDown, role: "presentation" },
|
|
227
252
|
React.createElement("thead", null,
|
|
228
253
|
React.createElement("tr", null, calendar.dayNames.map(this.renderDay))),
|
package/es/calendar/Header.js
CHANGED
|
@@ -3,7 +3,7 @@ import { Icon } from '@sb1/ffe-icons-react';
|
|
|
3
3
|
import { Dropdown } from '@sb1/ffe-dropdown-react';
|
|
4
4
|
import { getMonthOptions, getYearOptions } from '../util/dateRangeUtils';
|
|
5
5
|
export var Header = function (_a) {
|
|
6
|
-
var datepickerId = _a.datepickerId, month = _a.month, nextMonthHandler = _a.nextMonthHandler, nextMonthLabel = _a.nextMonthLabel, previousMonthHandler = _a.previousMonthHandler, previousMonthLabel = _a.previousMonthLabel, year = _a.year, prevMonthButtonElement = _a.prevMonthButtonElement, nextMonthButtonElement = _a.nextMonthButtonElement, monthNumber = _a.monthNumber, _b = _a.dropdownCaption, dropdownCaption = _b === void 0 ? false : _b, locale = _a.locale, onMonthYearChange = _a.onMonthYearChange, minDate = _a.minDate, maxDate = _a.maxDate;
|
|
6
|
+
var datepickerId = _a.datepickerId, month = _a.month, nextMonthHandler = _a.nextMonthHandler, nextMonthLabel = _a.nextMonthLabel, previousMonthHandler = _a.previousMonthHandler, previousMonthLabel = _a.previousMonthLabel, year = _a.year, prevMonthButtonElement = _a.prevMonthButtonElement, nextMonthButtonElement = _a.nextMonthButtonElement, monthNumber = _a.monthNumber, _b = _a.dropdownCaption, dropdownCaption = _b === void 0 ? false : _b, locale = _a.locale, onMonthYearChange = _a.onMonthYearChange, minDate = _a.minDate, maxDate = _a.maxDate, monthSelectRef = _a.monthSelectRef, yearSelectRef = _a.yearSelectRef;
|
|
7
7
|
var arrowBackIosIcon = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgLTk2MCA5NjAgOTYwIiB3aWR0aD0iMjQiPjxwYXRoIGQ9Im0zNjcuMzg0LTQ4MCAzMDEuMzA4IDMwMS4zMDhxMTEuOTIzIDExLjkyMyAxMS42MTUgMjguMDc3LS4zMDggMTYuMTUzLTEyLjIzMSAyOC4wNzZxLTExLjkyMiAxMS45MjMtMjguMDc2IDExLjkyM3QtMjguMDc2LTExLjkyM0wzMDUuMDc4LTQyOC43N3EtMTAuODQ3LTEwLjg0Ni0xNi4wNzctMjQuMzA3LTUuMjMxLTEzLjQ2Mi01LjIzMS0yNi45MjMgMC0xMy40NjEgNS4yMzEtMjYuOTIzIDUuMjMtMTMuNDYxIDE2LjA3Ny0yNC4zMDdsMzA2Ljg0Ni0zMDYuODQ2cTExLjkyMi0xMS45MjMgMjguMzg0LTExLjYxNiAxNi40NjEuMzA4IDI4LjM4NCAxMi4yMzEgMTEuOTIzIDExLjkyMyAxMS45MjMgMjguMDc2IDAgMTYuMTU0LTExLjkyMyAyOC4wNzdMMzY3LjM4NC00ODBaIi8+PC9zdmc+';
|
|
8
8
|
var monthOptions = getMonthOptions(locale);
|
|
9
9
|
var yearOptions = getYearOptions(minDate, maxDate);
|
|
@@ -31,9 +31,9 @@ export var Header = function (_a) {
|
|
|
31
31
|
React.createElement(Icon, { fileUrl: arrowBackIosIcon, size: "md", className: "ffe-calendar__icon-prev" })),
|
|
32
32
|
React.createElement("header", { "aria-live": "polite", className: "ffe-calendar__title", id: "".concat(datepickerId, "-title") }, dropdownCaption ? (React.createElement("div", { className: "ffe-calendar__dropdown-container" },
|
|
33
33
|
React.createElement("div", { className: "ffe-calendar__dropdown ffe-calendar__month-dropdown" },
|
|
34
|
-
React.createElement(Dropdown, { id: "".concat(datepickerId, "__month-select"), className: "ffe-calendar__month-select", value: monthNumber, onChange: handleMonthChange, "aria-label": "".concat(month, " ").concat(year), onClick: handleDropdownClick, onFocus: handleDropdownFocus }, monthOptions.map(function (option) { return (React.createElement("option", { key: option.value, value: option.value }, option.label)); }))),
|
|
34
|
+
React.createElement(Dropdown, { id: "".concat(datepickerId, "__month-select"), className: "ffe-calendar__month-select", value: monthNumber, onChange: handleMonthChange, "aria-label": "".concat(month, " ").concat(year), onClick: handleDropdownClick, onFocus: handleDropdownFocus, ref: monthSelectRef }, monthOptions.map(function (option) { return (React.createElement("option", { key: option.value, value: option.value }, option.label)); }))),
|
|
35
35
|
React.createElement("div", { className: "ffe-calendar__dropdown ffe-calendar__year-dropdown" },
|
|
36
|
-
React.createElement(Dropdown, { id: "".concat(datepickerId, "__year-select"), className: "ffe-calendar__year-select", value: year, onChange: handleYearChange, "aria-label": "".concat(year), onClick: handleDropdownClick, onFocus: handleDropdownFocus }, yearOptions.map(function (option) { return (React.createElement("option", { key: option.value, value: option.value }, option.label)); }))))) : (React.createElement("div", { id: "".concat(datepickerId, "__month-label"), "data-testid": "".concat(datepickerId, "__month-label") },
|
|
36
|
+
React.createElement(Dropdown, { id: "".concat(datepickerId, "__year-select"), className: "ffe-calendar__year-select", value: year, onChange: handleYearChange, "aria-label": "".concat(year), onClick: handleDropdownClick, onFocus: handleDropdownFocus, ref: yearSelectRef }, yearOptions.map(function (option) { return (React.createElement("option", { key: option.value, value: option.value }, option.label)); }))))) : (React.createElement("div", { id: "".concat(datepickerId, "__month-label"), "data-testid": "".concat(datepickerId, "__month-label") },
|
|
37
37
|
React.createElement("span", { className: "ffe-calendar__month" }, month),
|
|
38
38
|
React.createElement("span", { className: "ffe-calendar__year" }, year)))),
|
|
39
39
|
React.createElement("button", { className: "ffe-calendar__month-nav ffe-calendar__next", onClick: nextMonthHandler, "aria-label": nextMonthLabel, type: "button", ref: nextMonthButtonElement, tabIndex: -1 },
|
package/es/input/DateInput.js
CHANGED
|
@@ -20,10 +20,15 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
20
20
|
}
|
|
21
21
|
return t;
|
|
22
22
|
};
|
|
23
|
-
import React from 'react';
|
|
23
|
+
import React, { useMemo } from 'react';
|
|
24
24
|
import classNames from 'classnames';
|
|
25
25
|
import i18n from '../i18n/i18n';
|
|
26
|
+
import { isIOSSafari } from '../util/isIOSSafari';
|
|
26
27
|
export var DateInput = React.forwardRef(function (_a, ref) {
|
|
27
28
|
var ariaInvalid = _a.ariaInvalid, value = _a.value, className = _a.className, _b = _a.locale, locale = _b === void 0 ? 'nb' : _b, rest = __rest(_a, ["ariaInvalid", "value", "className", "locale"]);
|
|
28
|
-
|
|
29
|
+
// VoiceOver on iOS Safari blocks interaction with date-related inputs.
|
|
30
|
+
// Using role="textbox" as a workaround on that platform.
|
|
31
|
+
// https://dev.to/mfranzke/voiceover-bug-on-ios-safari-blocks-date-time-related-inputs-especially-in-react-4f61
|
|
32
|
+
var role = useMemo(function () { return (isIOSSafari() ? 'textbox' : undefined); }, []);
|
|
33
|
+
return (React.createElement("input", __assign({ type: "date", role: role, "aria-invalid": ariaInvalid, maxLength: 10, ref: ref, "aria-placeholder": i18n[locale].DATE_FORMAT, value: value, className: classNames('ffe-input-field ffe-dateinput__field', className) }, rest)));
|
|
29
34
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/index.ts","../src/types.ts","../src/button/Button.tsx","../src/button/index.ts","../src/calendar/Calendar.tsx","../src/calendar/ClickableDate.tsx","../src/calendar/Header.tsx","../src/calendar/NonClickableDate.tsx","../src/calendar/index.ts","../src/datelogic/simplecalendar.ts","../src/datelogic/simpledate.ts","../src/datelogic/types.ts","../src/datepicker/Datepicker.tsx","../src/datepicker/DatepickerComp.tsx","../src/datepicker/DatepickerContext.tsx","../src/datepicker/SpinButton.tsx","../src/datepicker/index.ts","../src/datepicker/padZero.ts","../src/datepicker/testHelper.ts","../src/datepicker/toNumber.ts","../src/i18n/en.ts","../src/i18n/i18n.ts","../src/i18n/nb.ts","../src/i18n/nn.ts","../src/input/DateInput.tsx","../src/input/index.ts","../src/util/dateRangeUtils.ts","../src/util/dateUtil.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["../src/index.ts","../src/types.ts","../src/button/Button.tsx","../src/button/index.ts","../src/calendar/Calendar.tsx","../src/calendar/ClickableDate.tsx","../src/calendar/Header.tsx","../src/calendar/NonClickableDate.tsx","../src/calendar/index.ts","../src/datelogic/simplecalendar.ts","../src/datelogic/simpledate.ts","../src/datelogic/types.ts","../src/datepicker/Datepicker.tsx","../src/datepicker/DatepickerComp.tsx","../src/datepicker/DatepickerContext.tsx","../src/datepicker/SpinButton.tsx","../src/datepicker/index.ts","../src/datepicker/padZero.ts","../src/datepicker/testHelper.ts","../src/datepicker/toNumber.ts","../src/i18n/en.ts","../src/i18n/i18n.ts","../src/i18n/nb.ts","../src/i18n/nn.ts","../src/input/DateInput.tsx","../src/input/index.ts","../src/util/dateRangeUtils.ts","../src/util/dateUtil.ts","../src/util/isIOSSafari.ts"],"version":"5.9.3"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detects iOS/iPadOS Safari to work around a VoiceOver bug that blocks
|
|
3
|
+
* interaction with date-related inputs.
|
|
4
|
+
* @see https://dev.to/mfranzke/voiceover-bug-on-ios-safari-blocks-date-time-related-inputs-especially-in-react-4f61
|
|
5
|
+
*
|
|
6
|
+
* Known limitations:
|
|
7
|
+
* - iOS WebViews (in-app browsers like Instagram, Facebook) use WebKit and may
|
|
8
|
+
* be affected by the same bug, but are not detected here since they don't
|
|
9
|
+
* include "Safari" in the user agent string.
|
|
10
|
+
*/
|
|
11
|
+
export var isIOSSafari = function () {
|
|
12
|
+
if (typeof navigator === 'undefined') {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
var ua = navigator.userAgent;
|
|
16
|
+
// iPadOS 13+ in desktop mode reports as Macintosh, but can be identified
|
|
17
|
+
// by having touch points (real Macs have maxTouchPoints === 0).
|
|
18
|
+
var isIOS = /iP(ad|hone|od)/.test(ua) ||
|
|
19
|
+
(/Macintosh/.test(ua) && navigator.maxTouchPoints > 1);
|
|
20
|
+
var isSafari = !!ua.match(/Safari/) && !ua.match(/CriOS|FxiOS|OPiOS|EdgiOS/);
|
|
21
|
+
return isIOS && isSafari;
|
|
22
|
+
};
|
package/lib/calendar/Calendar.js
CHANGED
|
@@ -63,35 +63,60 @@ var Calendar = /** @class */ (function (_super) {
|
|
|
63
63
|
_this.clickableDateRef = react_1.default.createRef();
|
|
64
64
|
_this.prevMonthButtonElementRef = react_1.default.createRef();
|
|
65
65
|
_this.nextMonthButtonElementRef = react_1.default.createRef();
|
|
66
|
+
_this.monthSelectRef = react_1.default.createRef();
|
|
67
|
+
_this.yearSelectRef = react_1.default.createRef();
|
|
66
68
|
_this.focusTrap = function (event) {
|
|
67
|
-
var _a, _b, _c, _d, _e, _f;
|
|
69
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
68
70
|
var activeElement = document.activeElement;
|
|
69
71
|
if (event.key === 'Tab') {
|
|
70
72
|
event.preventDefault();
|
|
73
|
+
var dropdownCaption = _this.props.dropdownCaption;
|
|
71
74
|
if (event.shiftKey) {
|
|
72
75
|
if (activeElement === _this.clickableDateRef.current) {
|
|
73
76
|
(_a = _this.nextMonthButtonElementRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
74
77
|
_this.setState({ isFocusingHeader: true });
|
|
75
78
|
}
|
|
76
|
-
if (activeElement === _this.nextMonthButtonElementRef.current) {
|
|
77
|
-
(
|
|
79
|
+
else if (activeElement === _this.nextMonthButtonElementRef.current) {
|
|
80
|
+
if (dropdownCaption) {
|
|
81
|
+
(_b = _this.yearSelectRef.current) === null || _b === void 0 ? void 0 : _b.focus();
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
(_c = _this.prevMonthButtonElementRef.current) === null || _c === void 0 ? void 0 : _c.focus();
|
|
85
|
+
}
|
|
78
86
|
}
|
|
79
|
-
if (activeElement === _this.
|
|
80
|
-
(
|
|
87
|
+
else if (dropdownCaption && activeElement === _this.yearSelectRef.current) {
|
|
88
|
+
(_d = _this.monthSelectRef.current) === null || _d === void 0 ? void 0 : _d.focus();
|
|
89
|
+
}
|
|
90
|
+
else if (dropdownCaption && activeElement === _this.monthSelectRef.current) {
|
|
91
|
+
(_e = _this.prevMonthButtonElementRef.current) === null || _e === void 0 ? void 0 : _e.focus();
|
|
92
|
+
}
|
|
93
|
+
else if (activeElement === _this.prevMonthButtonElementRef.current) {
|
|
94
|
+
(_f = _this.clickableDateRef.current) === null || _f === void 0 ? void 0 : _f.focus();
|
|
81
95
|
_this.setState({ isFocusingHeader: false });
|
|
82
96
|
_this.forceUpdate();
|
|
83
97
|
}
|
|
84
98
|
}
|
|
85
99
|
else {
|
|
86
100
|
if (activeElement === _this.clickableDateRef.current) {
|
|
87
|
-
(
|
|
101
|
+
(_g = _this.prevMonthButtonElementRef.current) === null || _g === void 0 ? void 0 : _g.focus();
|
|
88
102
|
_this.setState({ isFocusingHeader: true });
|
|
89
103
|
}
|
|
90
|
-
if (activeElement === _this.prevMonthButtonElementRef.current) {
|
|
91
|
-
(
|
|
104
|
+
else if (activeElement === _this.prevMonthButtonElementRef.current) {
|
|
105
|
+
if (dropdownCaption) {
|
|
106
|
+
(_h = _this.monthSelectRef.current) === null || _h === void 0 ? void 0 : _h.focus();
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
(_j = _this.nextMonthButtonElementRef.current) === null || _j === void 0 ? void 0 : _j.focus();
|
|
110
|
+
}
|
|
92
111
|
}
|
|
93
|
-
if (activeElement === _this.
|
|
94
|
-
(
|
|
112
|
+
else if (dropdownCaption && activeElement === _this.monthSelectRef.current) {
|
|
113
|
+
(_k = _this.yearSelectRef.current) === null || _k === void 0 ? void 0 : _k.focus();
|
|
114
|
+
}
|
|
115
|
+
else if (dropdownCaption && activeElement === _this.yearSelectRef.current) {
|
|
116
|
+
(_l = _this.nextMonthButtonElementRef.current) === null || _l === void 0 ? void 0 : _l.focus();
|
|
117
|
+
}
|
|
118
|
+
else if (activeElement === _this.nextMonthButtonElementRef.current) {
|
|
119
|
+
(_m = _this.clickableDateRef.current) === null || _m === void 0 ? void 0 : _m.focus();
|
|
95
120
|
_this.setState({ isFocusingHeader: false });
|
|
96
121
|
_this.forceUpdate();
|
|
97
122
|
}
|
|
@@ -258,7 +283,7 @@ var Calendar = /** @class */ (function (_super) {
|
|
|
258
283
|
react_1.default.createElement("div", { className: this.props.calendarClassName || 'ffe-calendar', role: "application", onKeyDown: this.focusTrap },
|
|
259
284
|
react_1.default.createElement(Header_1.Header, { datepickerId: this.datepickerId, month: calendar.focusedMonth, nextMonthHandler: this.nextMonth, nextMonthLabel: calendar.nextName, previousMonthHandler: this.previousMonth, previousMonthLabel: calendar.previousName, year: calendar.focusedYear, prevMonthButtonElement: this.prevMonthButtonElementRef, nextMonthButtonElement: this.nextMonthButtonElementRef, monthNumber: calendar.focusedDate.month + 1, locale: this.props.locale, dropdownCaption: this.props.dropdownCaption, onMonthYearChange: function (month, year) {
|
|
260
285
|
return _this.navigateToMonthYear(month, year);
|
|
261
|
-
}, minDate: this.props.minDate, maxDate: this.props.maxDate }),
|
|
286
|
+
}, minDate: this.props.minDate, maxDate: this.props.maxDate, monthSelectRef: this.monthSelectRef, yearSelectRef: this.yearSelectRef }),
|
|
262
287
|
react_1.default.createElement("table", { className: "ffe-calendar__grid", onKeyDown: this.keyDown, role: "presentation" },
|
|
263
288
|
react_1.default.createElement("thead", null,
|
|
264
289
|
react_1.default.createElement("tr", null, calendar.dayNames.map(this.renderDay))),
|
package/lib/calendar/Header.js
CHANGED
|
@@ -9,7 +9,7 @@ var ffe_icons_react_1 = require("@sb1/ffe-icons-react");
|
|
|
9
9
|
var ffe_dropdown_react_1 = require("@sb1/ffe-dropdown-react");
|
|
10
10
|
var dateRangeUtils_1 = require("../util/dateRangeUtils");
|
|
11
11
|
var Header = function (_a) {
|
|
12
|
-
var datepickerId = _a.datepickerId, month = _a.month, nextMonthHandler = _a.nextMonthHandler, nextMonthLabel = _a.nextMonthLabel, previousMonthHandler = _a.previousMonthHandler, previousMonthLabel = _a.previousMonthLabel, year = _a.year, prevMonthButtonElement = _a.prevMonthButtonElement, nextMonthButtonElement = _a.nextMonthButtonElement, monthNumber = _a.monthNumber, _b = _a.dropdownCaption, dropdownCaption = _b === void 0 ? false : _b, locale = _a.locale, onMonthYearChange = _a.onMonthYearChange, minDate = _a.minDate, maxDate = _a.maxDate;
|
|
12
|
+
var datepickerId = _a.datepickerId, month = _a.month, nextMonthHandler = _a.nextMonthHandler, nextMonthLabel = _a.nextMonthLabel, previousMonthHandler = _a.previousMonthHandler, previousMonthLabel = _a.previousMonthLabel, year = _a.year, prevMonthButtonElement = _a.prevMonthButtonElement, nextMonthButtonElement = _a.nextMonthButtonElement, monthNumber = _a.monthNumber, _b = _a.dropdownCaption, dropdownCaption = _b === void 0 ? false : _b, locale = _a.locale, onMonthYearChange = _a.onMonthYearChange, minDate = _a.minDate, maxDate = _a.maxDate, monthSelectRef = _a.monthSelectRef, yearSelectRef = _a.yearSelectRef;
|
|
13
13
|
var arrowBackIosIcon = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgLTk2MCA5NjAgOTYwIiB3aWR0aD0iMjQiPjxwYXRoIGQ9Im0zNjcuMzg0LTQ4MCAzMDEuMzA4IDMwMS4zMDhxMTEuOTIzIDExLjkyMyAxMS42MTUgMjguMDc3LS4zMDggMTYuMTUzLTEyLjIzMSAyOC4wNzZxLTExLjkyMiAxMS45MjMtMjguMDc2IDExLjkyM3QtMjguMDc2LTExLjkyM0wzMDUuMDc4LTQyOC43N3EtMTAuODQ3LTEwLjg0Ni0xNi4wNzctMjQuMzA3LTUuMjMxLTEzLjQ2Mi01LjIzMS0yNi45MjMgMC0xMy40NjEgNS4yMzEtMjYuOTIzIDUuMjMtMTMuNDYxIDE2LjA3Ny0yNC4zMDdsMzA2Ljg0Ni0zMDYuODQ2cTExLjkyMi0xMS45MjMgMjguMzg0LTExLjYxNiAxNi40NjEuMzA4IDI4LjM4NCAxMi4yMzEgMTEuOTIzIDExLjkyMyAxMS45MjMgMjguMDc2IDAgMTYuMTU0LTExLjkyMyAyOC4wNzdMMzY3LjM4NC00ODBaIi8+PC9zdmc+';
|
|
14
14
|
var monthOptions = (0, dateRangeUtils_1.getMonthOptions)(locale);
|
|
15
15
|
var yearOptions = (0, dateRangeUtils_1.getYearOptions)(minDate, maxDate);
|
|
@@ -37,9 +37,9 @@ var Header = function (_a) {
|
|
|
37
37
|
react_1.default.createElement(ffe_icons_react_1.Icon, { fileUrl: arrowBackIosIcon, size: "md", className: "ffe-calendar__icon-prev" })),
|
|
38
38
|
react_1.default.createElement("header", { "aria-live": "polite", className: "ffe-calendar__title", id: "".concat(datepickerId, "-title") }, dropdownCaption ? (react_1.default.createElement("div", { className: "ffe-calendar__dropdown-container" },
|
|
39
39
|
react_1.default.createElement("div", { className: "ffe-calendar__dropdown ffe-calendar__month-dropdown" },
|
|
40
|
-
react_1.default.createElement(ffe_dropdown_react_1.Dropdown, { id: "".concat(datepickerId, "__month-select"), className: "ffe-calendar__month-select", value: monthNumber, onChange: handleMonthChange, "aria-label": "".concat(month, " ").concat(year), onClick: handleDropdownClick, onFocus: handleDropdownFocus }, monthOptions.map(function (option) { return (react_1.default.createElement("option", { key: option.value, value: option.value }, option.label)); }))),
|
|
40
|
+
react_1.default.createElement(ffe_dropdown_react_1.Dropdown, { id: "".concat(datepickerId, "__month-select"), className: "ffe-calendar__month-select", value: monthNumber, onChange: handleMonthChange, "aria-label": "".concat(month, " ").concat(year), onClick: handleDropdownClick, onFocus: handleDropdownFocus, ref: monthSelectRef }, monthOptions.map(function (option) { return (react_1.default.createElement("option", { key: option.value, value: option.value }, option.label)); }))),
|
|
41
41
|
react_1.default.createElement("div", { className: "ffe-calendar__dropdown ffe-calendar__year-dropdown" },
|
|
42
|
-
react_1.default.createElement(ffe_dropdown_react_1.Dropdown, { id: "".concat(datepickerId, "__year-select"), className: "ffe-calendar__year-select", value: year, onChange: handleYearChange, "aria-label": "".concat(year), onClick: handleDropdownClick, onFocus: handleDropdownFocus }, yearOptions.map(function (option) { return (react_1.default.createElement("option", { key: option.value, value: option.value }, option.label)); }))))) : (react_1.default.createElement("div", { id: "".concat(datepickerId, "__month-label"), "data-testid": "".concat(datepickerId, "__month-label") },
|
|
42
|
+
react_1.default.createElement(ffe_dropdown_react_1.Dropdown, { id: "".concat(datepickerId, "__year-select"), className: "ffe-calendar__year-select", value: year, onChange: handleYearChange, "aria-label": "".concat(year), onClick: handleDropdownClick, onFocus: handleDropdownFocus, ref: yearSelectRef }, yearOptions.map(function (option) { return (react_1.default.createElement("option", { key: option.value, value: option.value }, option.label)); }))))) : (react_1.default.createElement("div", { id: "".concat(datepickerId, "__month-label"), "data-testid": "".concat(datepickerId, "__month-label") },
|
|
43
43
|
react_1.default.createElement("span", { className: "ffe-calendar__month" }, month),
|
|
44
44
|
react_1.default.createElement("span", { className: "ffe-calendar__year" }, year)))),
|
|
45
45
|
react_1.default.createElement("button", { className: "ffe-calendar__month-nav ffe-calendar__next", onClick: nextMonthHandler, "aria-label": nextMonthLabel, type: "button", ref: nextMonthButtonElement, tabIndex: -1 },
|
package/lib/input/DateInput.js
CHANGED
|
@@ -10,6 +10,39 @@ var __assign = (this && this.__assign) || function () {
|
|
|
10
10
|
};
|
|
11
11
|
return __assign.apply(this, arguments);
|
|
12
12
|
};
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
30
|
+
var ownKeys = function(o) {
|
|
31
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
32
|
+
var ar = [];
|
|
33
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
34
|
+
return ar;
|
|
35
|
+
};
|
|
36
|
+
return ownKeys(o);
|
|
37
|
+
};
|
|
38
|
+
return function (mod) {
|
|
39
|
+
if (mod && mod.__esModule) return mod;
|
|
40
|
+
var result = {};
|
|
41
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
42
|
+
__setModuleDefault(result, mod);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
})();
|
|
13
46
|
var __rest = (this && this.__rest) || function (s, e) {
|
|
14
47
|
var t = {};
|
|
15
48
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
@@ -26,10 +59,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
59
|
};
|
|
27
60
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
61
|
exports.DateInput = void 0;
|
|
29
|
-
var react_1 =
|
|
62
|
+
var react_1 = __importStar(require("react"));
|
|
30
63
|
var classnames_1 = __importDefault(require("classnames"));
|
|
31
64
|
var i18n_1 = __importDefault(require("../i18n/i18n"));
|
|
65
|
+
var isIOSSafari_1 = require("../util/isIOSSafari");
|
|
32
66
|
exports.DateInput = react_1.default.forwardRef(function (_a, ref) {
|
|
33
67
|
var ariaInvalid = _a.ariaInvalid, value = _a.value, className = _a.className, _b = _a.locale, locale = _b === void 0 ? 'nb' : _b, rest = __rest(_a, ["ariaInvalid", "value", "className", "locale"]);
|
|
34
|
-
|
|
68
|
+
// VoiceOver on iOS Safari blocks interaction with date-related inputs.
|
|
69
|
+
// Using role="textbox" as a workaround on that platform.
|
|
70
|
+
// https://dev.to/mfranzke/voiceover-bug-on-ios-safari-blocks-date-time-related-inputs-especially-in-react-4f61
|
|
71
|
+
var role = (0, react_1.useMemo)(function () { return ((0, isIOSSafari_1.isIOSSafari)() ? 'textbox' : undefined); }, []);
|
|
72
|
+
return (react_1.default.createElement("input", __assign({ type: "date", role: role, "aria-invalid": ariaInvalid, maxLength: 10, ref: ref, "aria-placeholder": i18n_1.default[locale].DATE_FORMAT, value: value, className: (0, classnames_1.default)('ffe-input-field ffe-dateinput__field', className) }, rest)));
|
|
35
73
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/index.ts","../src/types.ts","../src/button/Button.tsx","../src/button/index.ts","../src/calendar/Calendar.tsx","../src/calendar/ClickableDate.tsx","../src/calendar/Header.tsx","../src/calendar/NonClickableDate.tsx","../src/calendar/index.ts","../src/datelogic/simplecalendar.ts","../src/datelogic/simpledate.ts","../src/datelogic/types.ts","../src/datepicker/Datepicker.tsx","../src/datepicker/DatepickerComp.tsx","../src/datepicker/DatepickerContext.tsx","../src/datepicker/SpinButton.tsx","../src/datepicker/index.ts","../src/datepicker/padZero.ts","../src/datepicker/testHelper.ts","../src/datepicker/toNumber.ts","../src/i18n/en.ts","../src/i18n/i18n.ts","../src/i18n/nb.ts","../src/i18n/nn.ts","../src/input/DateInput.tsx","../src/input/index.ts","../src/util/dateRangeUtils.ts","../src/util/dateUtil.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["../src/index.ts","../src/types.ts","../src/button/Button.tsx","../src/button/index.ts","../src/calendar/Calendar.tsx","../src/calendar/ClickableDate.tsx","../src/calendar/Header.tsx","../src/calendar/NonClickableDate.tsx","../src/calendar/index.ts","../src/datelogic/simplecalendar.ts","../src/datelogic/simpledate.ts","../src/datelogic/types.ts","../src/datepicker/Datepicker.tsx","../src/datepicker/DatepickerComp.tsx","../src/datepicker/DatepickerContext.tsx","../src/datepicker/SpinButton.tsx","../src/datepicker/index.ts","../src/datepicker/padZero.ts","../src/datepicker/testHelper.ts","../src/datepicker/toNumber.ts","../src/i18n/en.ts","../src/i18n/i18n.ts","../src/i18n/nb.ts","../src/i18n/nn.ts","../src/input/DateInput.tsx","../src/input/index.ts","../src/util/dateRangeUtils.ts","../src/util/dateUtil.ts","../src/util/isIOSSafari.ts"],"version":"5.9.3"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isIOSSafari = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Detects iOS/iPadOS Safari to work around a VoiceOver bug that blocks
|
|
6
|
+
* interaction with date-related inputs.
|
|
7
|
+
* @see https://dev.to/mfranzke/voiceover-bug-on-ios-safari-blocks-date-time-related-inputs-especially-in-react-4f61
|
|
8
|
+
*
|
|
9
|
+
* Known limitations:
|
|
10
|
+
* - iOS WebViews (in-app browsers like Instagram, Facebook) use WebKit and may
|
|
11
|
+
* be affected by the same bug, but are not detected here since they don't
|
|
12
|
+
* include "Safari" in the user agent string.
|
|
13
|
+
*/
|
|
14
|
+
var isIOSSafari = function () {
|
|
15
|
+
if (typeof navigator === 'undefined') {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
var ua = navigator.userAgent;
|
|
19
|
+
// iPadOS 13+ in desktop mode reports as Macintosh, but can be identified
|
|
20
|
+
// by having touch points (real Macs have maxTouchPoints === 0).
|
|
21
|
+
var isIOS = /iP(ad|hone|od)/.test(ua) ||
|
|
22
|
+
(/Macintosh/.test(ua) && navigator.maxTouchPoints > 1);
|
|
23
|
+
var isSafari = !!ua.match(/Safari/) && !ua.match(/CriOS|FxiOS|OPiOS|EdgiOS/);
|
|
24
|
+
return isIOS && isSafari;
|
|
25
|
+
};
|
|
26
|
+
exports.isIOSSafari = isIOSSafari;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sb1/ffe-datepicker-react",
|
|
3
|
-
"version": "100.12.
|
|
3
|
+
"version": "100.12.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "SpareBank 1",
|
|
6
6
|
"files": [
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
"test:watch": "ffe-buildtool jest --watch"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@sb1/ffe-datepicker": "^100.12.
|
|
28
|
-
"@sb1/ffe-dropdown-react": "^100.12.
|
|
29
|
-
"@sb1/ffe-form": "^100.12.
|
|
30
|
-
"@sb1/ffe-form-react": "^100.12.
|
|
31
|
-
"@sb1/ffe-icons-react": "^100.12.
|
|
27
|
+
"@sb1/ffe-datepicker": "^100.12.3",
|
|
28
|
+
"@sb1/ffe-dropdown-react": "^100.12.3",
|
|
29
|
+
"@sb1/ffe-form": "^100.12.3",
|
|
30
|
+
"@sb1/ffe-form-react": "^100.12.3",
|
|
31
|
+
"@sb1/ffe-icons-react": "^100.12.3",
|
|
32
32
|
"@testing-library/react": "^16.0.0",
|
|
33
33
|
"@types/lodash.debounce": "^4.0.9",
|
|
34
34
|
"classnames": "^2.3.1",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"uuid": "^9.0.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@sb1/ffe-buildtool": "^100.12.
|
|
39
|
+
"@sb1/ffe-buildtool": "^100.12.3",
|
|
40
40
|
"eslint": "^9.22.0",
|
|
41
41
|
"react": "^18.2.0",
|
|
42
42
|
"react-dom": "^18.2.0"
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"publishConfig": {
|
|
48
48
|
"access": "public"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "c250edc3d20e5ed115c5c5951495d700e96a3be3"
|
|
51
51
|
}
|
|
@@ -27,6 +27,8 @@ export declare class Calendar extends Component<CalendarProps, State> {
|
|
|
27
27
|
clickableDateRef: React.RefObject<HTMLTableCellElement>;
|
|
28
28
|
prevMonthButtonElementRef: React.RefObject<HTMLButtonElement>;
|
|
29
29
|
nextMonthButtonElementRef: React.RefObject<HTMLButtonElement>;
|
|
30
|
+
monthSelectRef: React.RefObject<HTMLSelectElement>;
|
|
31
|
+
yearSelectRef: React.RefObject<HTMLSelectElement>;
|
|
30
32
|
componentDidUpdate(prevProps: CalendarProps): void;
|
|
31
33
|
shouldComponentUpdate(nextProps: CalendarProps): boolean;
|
|
32
34
|
keyDown(event: React.KeyboardEvent<HTMLTableElement>): void;
|
|
@@ -10,6 +10,8 @@ interface HeaderProps {
|
|
|
10
10
|
year: number;
|
|
11
11
|
prevMonthButtonElement: React.RefObject<HTMLButtonElement>;
|
|
12
12
|
nextMonthButtonElement: React.RefObject<HTMLButtonElement>;
|
|
13
|
+
monthSelectRef?: React.RefObject<HTMLSelectElement>;
|
|
14
|
+
yearSelectRef?: React.RefObject<HTMLSelectElement>;
|
|
13
15
|
/** Nåværende månedsnummer (1-12) */
|
|
14
16
|
monthNumber: number;
|
|
15
17
|
/** Om måned- og år-dropdown skal vises i kalenderen */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/index.ts","../src/types.ts","../src/button/Button.tsx","../src/button/index.ts","../src/calendar/Calendar.tsx","../src/calendar/ClickableDate.tsx","../src/calendar/Header.tsx","../src/calendar/NonClickableDate.tsx","../src/calendar/index.ts","../src/datelogic/simplecalendar.ts","../src/datelogic/simpledate.ts","../src/datelogic/types.ts","../src/datepicker/Datepicker.tsx","../src/datepicker/DatepickerComp.tsx","../src/datepicker/DatepickerContext.tsx","../src/datepicker/SpinButton.tsx","../src/datepicker/index.ts","../src/datepicker/padZero.ts","../src/datepicker/testHelper.ts","../src/datepicker/toNumber.ts","../src/i18n/en.ts","../src/i18n/i18n.ts","../src/i18n/nb.ts","../src/i18n/nn.ts","../src/input/DateInput.tsx","../src/input/index.ts","../src/util/dateRangeUtils.ts","../src/util/dateUtil.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["../src/index.ts","../src/types.ts","../src/button/Button.tsx","../src/button/index.ts","../src/calendar/Calendar.tsx","../src/calendar/ClickableDate.tsx","../src/calendar/Header.tsx","../src/calendar/NonClickableDate.tsx","../src/calendar/index.ts","../src/datelogic/simplecalendar.ts","../src/datelogic/simpledate.ts","../src/datelogic/types.ts","../src/datepicker/Datepicker.tsx","../src/datepicker/DatepickerComp.tsx","../src/datepicker/DatepickerContext.tsx","../src/datepicker/SpinButton.tsx","../src/datepicker/index.ts","../src/datepicker/padZero.ts","../src/datepicker/testHelper.ts","../src/datepicker/toNumber.ts","../src/i18n/en.ts","../src/i18n/i18n.ts","../src/i18n/nb.ts","../src/i18n/nn.ts","../src/input/DateInput.tsx","../src/input/index.ts","../src/util/dateRangeUtils.ts","../src/util/dateUtil.ts","../src/util/isIOSSafari.ts"],"version":"5.9.3"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detects iOS/iPadOS Safari to work around a VoiceOver bug that blocks
|
|
3
|
+
* interaction with date-related inputs.
|
|
4
|
+
* @see https://dev.to/mfranzke/voiceover-bug-on-ios-safari-blocks-date-time-related-inputs-especially-in-react-4f61
|
|
5
|
+
*
|
|
6
|
+
* Known limitations:
|
|
7
|
+
* - iOS WebViews (in-app browsers like Instagram, Facebook) use WebKit and may
|
|
8
|
+
* be affected by the same bug, but are not detected here since they don't
|
|
9
|
+
* include "Safari" in the user agent string.
|
|
10
|
+
*/
|
|
11
|
+
export declare const isIOSSafari: () => boolean;
|