@fremtind/jkl-datepicker-react
Version:
Jøkul react datepicker component
344 lines (343 loc) • 10.7 kB
JavaScript
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