UNPKG

@fremtind/jkl-datepicker-react

Version:
344 lines (343 loc) 10.7 kB
var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; 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; }; import { IconButton } from "@fremtind/jkl-icon-button-react"; import { CalendarIcon } from "@fremtind/jkl-icons-react"; import { InputGroup } from "@fremtind/jkl-input-group-react"; import { Popover } from "@fremtind/jkl-popover-react"; import { BaseTextInput } from "@fremtind/jkl-text-input-react"; import cn from "classnames"; import startOfDay from "date-fns/startOfDay"; import React, { forwardRef, useCallback, useRef, useState } from "react"; import { flushSync } from "react-dom"; import { Calendar } from "./internal/Calendar"; import { getInitialDate } from "./internal/utils"; import { formatInput, parseDateString } from "./utils"; import { isWithinLowerBound, isWithinUpperBound } from "./validation"; const DatePicker = forwardRef( (props, forwardedInputRef) => { const _a = props, { "data-testautoid": testAutoId, id, className = "", label = "Velg dato", labelProps, defaultValue, defaultShow = false, value, disableBeforeDate: disableBefore, disableAfterDate: disableAfter, yearsToShow, name, helpLabel, errorLabel, invalid, density, days, months, monthLabel, yearLabel, placeholder = "dd.mm.\xE5\xE5\xE5\xE5", width = "11.25rem", onChange, onBlur, onFocus, onKeyDown, action, showCalendarLabel = "\xC5pne kalender", hideCalendarLabel = "Lukk kalender", supportLabelProps, tooltip, textInputProps } = _a, rest = __objRest(_a, [ "data-testautoid", "id", "className", "label", "labelProps", "defaultValue", "defaultShow", "value", "disableBeforeDate", "disableAfterDate", "yearsToShow", "name", "helpLabel", "errorLabel", "invalid", "density", "days", "months", "monthLabel", "yearLabel", "placeholder", "width", "onChange", "onBlur", "onFocus", "onKeyDown", "action", "showCalendarLabel", "hideCalendarLabel", "supportLabelProps", "tooltip", "textInputProps" ]); if (value && defaultValue) { console.warn( "DatePicker m\xE5 enten v\xE6re controlled eller uncontrolled. Hvis du bruker defaultValue og value sammen vil defaultValue bli ignorert." ); } const disableBeforeDate = parseDateString(disableBefore); const minDate = disableBeforeDate ? startOfDay(disableBeforeDate) : void 0; const disableAfterDate = parseDateString(disableAfter); const maxDate = disableAfterDate ? startOfDay(disableAfterDate) : void 0; const [date, setDate] = useState( getInitialDate(value, defaultValue, minDate, maxDate) ); const [error, setError] = useState(null); const [showCalendar, setShowCalendar] = useState(defaultShow); const calendarRef = useRef(null); const datepickerRef = useRef(null); const iconButtonRef = useRef(null); const inputRef = useRef(null); const unifiedInputRef = useCallback( (instance) => { inputRef.current = instance; if (forwardedInputRef) { if (typeof forwardedInputRef === "function") { forwardedInputRef(instance); } else { forwardedInputRef.current = instance; } } }, [inputRef, forwardedInputRef] ); const handleFocus = useCallback( (e) => { if (!onFocus || !datepickerRef.current) { return; } const nextFocusIsInside = datepickerRef.current.contains( e.relatedTarget ); if (!nextFocusIsInside) { onFocus(e, date, { error, value: e.target.value }); } }, [onFocus, date, error] ); const handleBlur = useCallback( (e) => { if (onBlur) { onBlur(e, date, { error, value: e.target.value }); } }, [onBlur, date, error] ); const handleKeyDownAction = useCallback( (e) => { if (e.key === "Escape") { setShowCalendar(false); e.preventDefault(); e.stopPropagation(); } if (action == null ? void 0 : action.onKeyDown) { action.onKeyDown(e); } }, [setShowCalendar, action] ); const handleChange = useCallback( (e) => { let nextDate = null; let nextError = null; if (e.target.value) { const val = parseDateString(e.target.value); if (!val) { nextError = "WRONG_FORMAT"; } else if (minDate && !isWithinLowerBound(val, minDate)) { nextError = "OUTSIDE_LOWER_BOUND"; } else if (maxDate && !isWithinUpperBound(val, maxDate)) { nextError = "OUTSIDE_UPPER_BOUND"; } else { setShowCalendar(false); } nextDate = val || null; } setError(nextError); setDate(nextDate); if (onChange) { onChange(e, nextDate, { error: nextError, value: e.target.value }); } }, [onChange, setError, setDate, setShowCalendar, minDate, maxDate] ); const clickCalendar = useCallback( (e) => { flushSync(() => { setShowCalendar(!showCalendar); }); const calendarEl = calendarRef.current; const button = calendarEl && calendarEl.querySelector( '[aria-pressed="true"]' ); window.requestAnimationFrame(() => button && button.focus()); if (action == null ? void 0 : action.onClick) { action.onClick(e); } }, [setShowCalendar, showCalendar, action, calendarRef] ); const handleClickCalendarDay = useCallback( ({ date: date2 }) => { setShowCalendar(false); setDate(date2); if (inputRef.current) { const node = inputRef.current; node.value = formatInput(date2); const event = document.createEvent("HTMLEvents"); event.initEvent("input", true, false); node.dispatchEvent(event); node.focus(); if (onChange) { onChange( event, date2, { error: null, value: node.value } ); } } }, [setShowCalendar, setDate, onChange] ); const handleTabOutsideCalendar = useCallback( (e) => { e.preventDefault(); setShowCalendar(false); iconButtonRef.current && iconButtonRef.current.focus(); }, [setShowCalendar] ); return /* @__PURE__ */ React.createElement( InputGroup, __spreadProps(__spreadValues({ id, className: cn("jkl-datepicker", className) }, rest), { ref: datepickerRef, label, labelProps, density, helpLabel, errorLabel, supportLabelProps, tooltip, render: (inputProps) => /* @__PURE__ */ React.createElement( BaseTextInput, __spreadValues(__spreadValues({ "data-focused": showCalendar ? "true" : void 0, ref: unifiedInputRef, "data-testid": "jkl-datepicker__input", "data-testautoid": testAutoId, className: "jkl-datepicker__input", name, defaultValue, density, value, type: "text", placeholder, width, onFocus: handleFocus, onBlur: handleBlur, onChange: handleChange, actionButton: /* @__PURE__ */ React.createElement( Popover, { positionReference: inputRef, open: showCalendar, onOpenChange: () => setShowCalendar(!showCalendar), offset: 8 }, /* @__PURE__ */ React.createElement( Popover.Trigger, __spreadProps(__spreadValues({}, action), { "data-testid": "jkl-datepicker__trigger", className: "jkl-text-input-action-button", title: showCalendar ? hideCalendarLabel : showCalendarLabel, tabIndex: 0, onClick: clickCalendar, onKeyDown: handleKeyDownAction, asChild: true }), /* @__PURE__ */ React.createElement(IconButton, null, /* @__PURE__ */ React.createElement(CalendarIcon, null)) ), /* @__PURE__ */ React.createElement(Popover.Content, { initialFocus: -1, padding: 24 }, /* @__PURE__ */ React.createElement( Calendar, { ref: calendarRef, density, date, minDate, maxDate, days, months, monthLabel, yearLabel, yearsToShow, onDateSelected: handleClickCalendarDay, onTabOutside: handleTabOutsideCalendar } )) ) }, textInputProps), inputProps) ) }) ); } ); DatePicker.displayName = "DatePicker"; export { DatePicker }; //# sourceMappingURL=DatePicker.js.map