UNPKG

@fremtind/jkl-datepicker-react

Version:
506 lines (505 loc) 19 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropNames = Object.getOwnPropertyNames; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __objRest = (source, exclude) => { var target = {}; for (var prop in source) if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0) target[prop] = source[prop]; if (source != null && __getOwnPropSymbols) for (var prop of __getOwnPropSymbols(source)) { if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop)) target[prop] = source[prop]; } return target; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var Calendar_exports = {}; __export(Calendar_exports, { Calendar: () => Calendar }); module.exports = __toCommonJS(Calendar_exports); var import_jkl_button_react = require("@fremtind/jkl-button-react"); var import_jkl_icons_react = require("@fremtind/jkl-icons-react"); var import_jkl_react_hooks = require("@fremtind/jkl-react-hooks"); var import_react = __toESM(require("react")); var import_react_dom = require("react-dom"); var import_calendarReducer = require("./calendarReducer"); var import_useCalendar = require("./useCalendar"); var import_utils = require("./utils"); const defaultMonths = [ "Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember" ]; const defaultDays = ["man", "tir", "ons", "tor", "fre", "l\xF8r", "s\xF8n"]; const Calendar = (0, import_react.forwardRef)( (props, ref) => { const _a = props, { date, defaultSelected, density, minDate, maxDate, days = defaultDays, months = defaultMonths, monthLabel = "Velg m\xE5ned", yearLabel = "Velg \xE5r", yearsToShow = import_utils.DEFAULT_YEARS_TO_SHOW, onTabOutside } = _a, rest = __objRest(_a, [ "date", "defaultSelected", "density", "minDate", "maxDate", "days", "months", "monthLabel", "yearLabel", "yearsToShow", "onTabOutside" ]); const id = (0, import_jkl_react_hooks.useId)("jkl-calendar"); const [{ offset, selectedDate, shownDate }, dispatch] = (0, import_react.useReducer)( import_calendarReducer.calendarReducer, (0, import_utils.getInitialDateShown)(date, defaultSelected, minDate, maxDate), import_calendarReducer.calendarInitializer ); const shownMonth = shownDate.getMonth(); const shownYear = shownDate.getFullYear(); (0, import_react.useEffect)(() => { dispatch({ type: "SET_SELECTED_DATE", newDate: (0, import_utils.getInitialDateShown)( date, defaultSelected, minDate, maxDate ) }); }, [date, defaultSelected, minDate, maxDate]); const onOffsetChanged = (0, import_react.useCallback)((newOffset) => { dispatch({ type: "SET_OFFSET", newOffset }); }, []); const { calendars, getBackProps, getDateProps, getForwardProps, handleOffsetChanged } = (0, import_useCalendar.useCalendar)(__spreadValues({ date: selectedDate, selected: selectedDate, minDate, maxDate, offset, onOffsetChanged, firstDayOfWeek: 1 }, rest)); const calendarPaddingRef = (0, import_react.useRef)(null); const doFocusChange = (0, import_react.useCallback)( (offsetDiff) => { if (!calendarPaddingRef.current) { return; } const e = document.activeElement; const buttons = calendarPaddingRef.current.querySelectorAll( 'button.jkl-calendar-date-button:not([data-adjacent="true"]' ); const changeFocusTo = async (nextButton) => { e == null ? void 0 : e.setAttribute("tabindex", "-1"); nextButton.setAttribute("tabindex", "0"); nextButton.focus(); }; buttons.forEach((el, i) => { const newNodeKey = i + offsetDiff; if (el == e) { if (newNodeKey <= buttons.length - 1 && newNodeKey >= 0) { changeFocusTo(buttons[newNodeKey]); } else if (offsetDiff < 0) { if ((0, import_utils.isBackDisabled)({ calendars, minDate })) { return; } (0, import_react_dom.flushSync)(() => { handleOffsetChanged( offset - (0, import_utils.subtractMonth)({ calendars, offset: 1, minDate }) ); }); if (!calendarPaddingRef.current) { return; } const newButtons = calendarPaddingRef.current.querySelectorAll( 'button.jkl-calendar-date-button:not([data-adjacent="true"]' ); if (newButtons[newButtons.length + newNodeKey]) { newButtons[0].setAttribute("tabindex", "-1"); changeFocusTo( newButtons[newButtons.length + newNodeKey] ); } } else { if ((0, import_utils.isForwardDisabled)({ calendars, maxDate })) { return; } (0, import_react_dom.flushSync)(() => { handleOffsetChanged( offset + (0, import_utils.addMonth)({ calendars, offset: 1, maxDate }) ); }); if (!calendarPaddingRef.current) { return; } const newButtons = calendarPaddingRef.current.querySelectorAll( 'button.jkl-calendar-date-button:not([data-adjacent="true"]' ); if (newButtons[newNodeKey - buttons.length]) { newButtons[0].setAttribute("tabindex", "-1"); changeFocusTo( newButtons[newNodeKey - buttons.length] ); } } } }); }, [ handleOffsetChanged, calendarPaddingRef, offset, calendars, maxDate, minDate ] ); const handleArrowNavigation = (0, import_react.useCallback)( (event) => { switch (event.key) { case "ArrowUp": doFocusChange(-7); event.preventDefault(); break; case "ArrowRight": doFocusChange(1); event.preventDefault(); break; case "ArrowDown": doFocusChange(7); event.preventDefault(); break; case "ArrowLeft": doFocusChange(-1); event.preventDefault(); break; default: break; } }, [doFocusChange] ); const handleTabInside = (0, import_react.useCallback)( (event) => { var _a2; if (event.key !== "Tab") return; const focusableElements = (_a2 = calendarPaddingRef.current) == null ? void 0 : _a2.querySelectorAll( 'button:not([disabled]):not([tabindex="-1"]), select' ); if (!focusableElements) return; const firstElement = focusableElements[0]; const lastElement = focusableElements[focusableElements.length - 1]; if (!event.shiftKey && document.activeElement === lastElement) { firstElement.focus(); event.preventDefault(); } else if (event.shiftKey && document.activeElement === firstElement) { lastElement.focus(); event.preventDefault(); } }, [] ); const isFocusableDate = (0, import_react.useCallback)( (dateInfo) => { const { date: date2, selected, selectable, prevMonth, nextMonth } = dateInfo; if (!selectable) { return false; } if (selected) { return true; } if (date2.toString() === (minDate == null ? void 0 : minDate.toString())) { return true; } if (!prevMonth && !nextMonth && shownDate.getFullYear() === date2.getFullYear() && selectedDate.getMonth() !== date2.getMonth() && date2.getDate() === 1) { return true; } return false; }, [shownDate, minDate, selectedDate] ); const handleGotoEdgeMonth = (0, import_react.useCallback)(() => { if ( // Vi er i ferd med å gå til første måned minDate && shownDate.getFullYear() - minDate.getFullYear() === 0 && shownDate.getMonth() - minDate.getMonth() === 1 ) { document.querySelectorAll( ".jkl-calendar-navigation__arrow" )[1].focus(); } else if ( // Vi er i ferd med å gå til siste måned maxDate && maxDate.getFullYear() - shownDate.getFullYear() === 0 && maxDate.getMonth() - shownDate.getMonth() === 1 ) { document.querySelectorAll( ".jkl-calendar-navigation__arrow" )[0].focus(); } }, [minDate, maxDate, shownDate]); const handleYearChange = (0, import_react.useCallback)( (event) => { if (event.target.value.length !== 4) { return; } const year = Number.parseInt(event.target.value); if (Number.isNaN(year)) { return; } let offset2 = (year - shownDate.getFullYear()) * 12; const expectedDate = new Date( shownDate.getFullYear(), shownDate.getMonth() + offset2, shownDate.getDate() ); if (maxDate && maxDate.getFullYear() === expectedDate.getFullYear() && maxDate.getMonth() < expectedDate.getMonth()) { offset2 -= expectedDate.getMonth() - maxDate.getMonth(); } else if (minDate && minDate.getFullYear() === expectedDate.getFullYear() && minDate.getMonth() > expectedDate.getMonth()) { offset2 += minDate.getMonth() - expectedDate.getMonth(); } dispatch({ type: "ADD_OFFSET", addedOffset: offset2 }); return; }, [shownDate, minDate, maxDate] ); const handleMonthChange = (0, import_react.useCallback)( (event) => { if (!selectedDate && !date) { return; } const yearDiff = shownDate.getFullYear() - (selectedDate || /* @__PURE__ */ new Date()).getFullYear(); const monthDiff = Number.parseInt(event.target.value) - (selectedDate || /* @__PURE__ */ new Date()).getMonth(); dispatch({ type: "SET_OFFSET", newOffset: yearDiff * 12 + monthDiff }); return; }, [selectedDate, date, shownDate] ); const yearSelectOptions = (0, import_utils.getYearSelectOptions)( shownYear, minDate, maxDate, yearsToShow ); const monthSelectOptions = (0, import_utils.getMonthSelectOptions)( shownYear, months, minDate, maxDate ); return /* @__PURE__ */ import_react.default.createElement( "div", { ref, id, className: "jkl-calendar", "data-testid": "jkl-calendar" }, /* @__PURE__ */ import_react.default.createElement( "div", { className: "jkl-calendar__padding", ref: calendarPaddingRef, onKeyDown: handleTabInside }, /* @__PURE__ */ import_react.default.createElement("fieldset", { className: "jkl-calendar-navigation" }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement( import_jkl_button_react.Button, __spreadProps(__spreadValues({}, getBackProps({ calendars, onClick: handleGotoEdgeMonth })), { variant: "ghost", icon: /* @__PURE__ */ import_react.default.createElement(import_jkl_icons_react.ArrowLeftIcon, { variant: "medium", bold: true }) }) ), /* @__PURE__ */ import_react.default.createElement( import_jkl_button_react.Button, __spreadProps(__spreadValues({}, getForwardProps({ calendars, onClick: handleGotoEdgeMonth })), { variant: "ghost", icon: /* @__PURE__ */ import_react.default.createElement(import_jkl_icons_react.ArrowRightIcon, { variant: "medium", bold: true }) }) )), /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { className: "jkl-calendar-navigation-dropdown" }, /* @__PURE__ */ import_react.default.createElement( "select", { onChange: handleMonthChange, className: "jkl-calendar-navigation-dropdown__select", "aria-label": monthLabel, value: shownMonth.toString() }, monthSelectOptions.map( ({ label, value }) => /* @__PURE__ */ import_react.default.createElement("option", { key: value, value }, label) ) ), /* @__PURE__ */ import_react.default.createElement( import_jkl_icons_react.ChevronDownIcon, { bold: true, className: "jkl-calendar-navigation-dropdown__chevron" } )), /* @__PURE__ */ import_react.default.createElement("div", { className: "jkl-calendar-navigation-dropdown" }, /* @__PURE__ */ import_react.default.createElement( "select", { onChange: handleYearChange, className: "jkl-calendar-navigation-dropdown__select", "aria-label": yearLabel, value: shownYear.toString() }, yearSelectOptions.map((year) => /* @__PURE__ */ import_react.default.createElement("option", { key: year, value: year }, year)) ), /* @__PURE__ */ import_react.default.createElement( import_jkl_icons_react.ChevronDownIcon, { bold: true, className: "jkl-calendar-navigation-dropdown__chevron" } )))), calendars.map((calendar) => /* @__PURE__ */ import_react.default.createElement( "table", { className: "jkl-calendar-table", key: "".concat(calendar.month).concat(calendar.year), "data-testid": "jkl-datepicker-calendar" }, /* @__PURE__ */ import_react.default.createElement("caption", { className: "jkl-sr-only" }, months[calendar.month], ", ", calendar.year), /* @__PURE__ */ import_react.default.createElement("thead", null, /* @__PURE__ */ import_react.default.createElement("tr", null, days.map((weekday) => /* @__PURE__ */ import_react.default.createElement( "th", { key: "".concat(calendar.month).concat(calendar.year).concat(weekday) }, weekday )))), /* @__PURE__ */ import_react.default.createElement("tbody", { "data-testid": "jkl-datepicker-dates" }, calendar.weeks.map((week, weekIndex) => /* @__PURE__ */ import_react.default.createElement( "tr", { key: "".concat(calendar.month).concat(calendar.year).concat(weekIndex) }, week.map((dateInfo, index) => { const key = "".concat(calendar.month).concat(calendar.year).concat(weekIndex).concat(index); if (typeof dateInfo === "string") { return /* @__PURE__ */ import_react.default.createElement( "td", { className: "jkl-calendar__date jkl-calendar__date--empty", key }, dateInfo ); } const { date: date2, selectable, today, prevMonth, nextMonth } = dateInfo; return /* @__PURE__ */ import_react.default.createElement("td", { key }, /* @__PURE__ */ import_react.default.createElement( "button", __spreadProps(__spreadValues({}, getDateProps({ dateObj: dateInfo })), { type: "button", className: "jkl-calendar-date-button", tabIndex: isFocusableDate( dateInfo ) ? 0 : -1, "aria-label": "".concat(date2.getDate(), ". ").concat(months[date2.getMonth()].toLowerCase()), "aria-current": today ? "date" : void 0, "data-adjacent": prevMonth || nextMonth ? "true" : void 0, disabled: !selectable, onKeyDown: handleArrowNavigation }), /* @__PURE__ */ import_react.default.createElement("span", { "aria-hidden": "true" }, date2.getDate()) )); }) ))) )) ) ); } ); Calendar.displayName = "Calendar"; //# sourceMappingURL=Calendar.js.map