@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
243 lines (242 loc) • 8.4 kB
JavaScript
"use client";
import _extends from "@babel/runtime-corejs3/helpers/esm/extends";
import React, { useCallback, useContext, useEffect, useMemo, useState, useRef } from 'react';
import SharedContext from "../../shared/Context.js";
import { convertStringToDate } from "../date-picker/DatePickerCalc.js";
import { formatDate, getRelativeTime, getRelativeTimeNextUpdateMs, parseDuration, formatDuration, isValidDuration, getDateTimeSeparator } from "./DateFormatUtils.js";
import { format } from 'date-fns';
import classnames from 'classnames';
import { createSpacingClasses } from "../space/SpacingUtils.js";
import Tooltip from "../Tooltip.js";
import { createSkeletonClass, skeletonDOMAttributes } from "../skeleton/SkeletonHelper.js";
import { useTranslation } from "../../shared/index.js";
import { convertJsxToString } from "../../shared/component-helper.js";
function DateFormat(props) {
const context = useContext(SharedContext);
const {
invalidDate
} = useTranslation().DateFormat;
const {
value,
children,
locale: localeProp,
dateStyle = 'long',
timeStyle,
dateTimeSeparator,
hideCurrentYear = false,
hideYear = false,
relativeTimeStyle,
skeleton,
relativeTime = false,
relativeTimeReference
} = props;
const locale = localeProp || context.locale;
const ref = useRef();
const date = useMemo(() => {
return getDate({
value,
children
});
}, [value, children]);
const durationValue = useMemo(() => {
const durationString = String(value || children);
if (!durationString || !isValidDuration(durationString)) {
return;
}
return parseDuration(durationString);
}, [value, children]);
const getDuration = useCallback(dateStyle => {
if (durationValue === undefined) {
return;
}
return formatDuration(durationValue, locale, dateStyle, String(value || children));
}, [children, durationValue, locale, value]);
const durationFormatted = useMemo(() => {
return getDuration(dateStyle);
}, [dateStyle, getDuration]);
const durationFormattedFull = useMemo(() => {
return getDuration('full');
}, [getDuration]);
const attributes = useMemo(() => {
const attrs = {
className: classnames('dnb-date-format', createSpacingClasses(props), createSkeletonClass('font', skeleton, context)),
lang: locale
};
skeletonDOMAttributes(attrs, skeleton, context);
return attrs;
}, [props, skeleton, context, locale]);
const getAbsoluteDateTime = useCallback((style = 'yyyy-MM-dd') => {
if (!date || isNaN(date.getTime())) {
return;
}
return format(date, style);
}, [date]);
const getAbsoluteDateFormatted = useCallback(({
options = {
dateStyle,
...(timeStyle ? {
timeStyle
} : {})
},
hideYear: hideYearOverride,
hideCurrentYear: hideCurrentYearOverride
} = {}) => {
if (!date || isNaN(date.getTime())) {
return;
}
const originalValue = value !== undefined ? value : children !== undefined ? convertJsxToString(children) : date;
if (options !== null && options !== void 0 && options.timeStyle) {
const formattedDate = formatDate(originalValue, {
locale,
options: {
dateStyle: options.dateStyle
},
hideCurrentYear: hideCurrentYearOverride !== undefined ? hideCurrentYearOverride : hideCurrentYear,
hideYear: hideYearOverride !== undefined ? hideYearOverride : hideYear
});
const formattedTime = formatDate(originalValue, {
locale,
options: {
timeStyle: options.timeStyle
}
});
const separator = dateTimeSeparator !== undefined ? dateTimeSeparator : getDateTimeSeparator(locale, options.dateStyle, options.timeStyle);
return `${formattedDate}${separator}${formattedTime}`;
}
return formatDate(originalValue, {
locale,
options,
hideCurrentYear: hideCurrentYearOverride !== undefined ? hideCurrentYearOverride : hideCurrentYear,
hideYear: hideYearOverride !== undefined ? hideYearOverride : hideYear
});
}, [date, locale, dateStyle, timeStyle, dateTimeSeparator, hideCurrentYear, hideYear, value, children]);
const [label, setLabel] = useState(() => {
return relativeTime && date ? getRelativeTime(date, locale, undefined, relativeTimeStyle || dateStyle, relativeTimeReference) : undefined;
});
useEffect(() => {
if (!relativeTime || !date) {
return;
}
let timeoutId;
const scheduleNextUpdate = () => {
const delay = getRelativeTimeNextUpdateMs(date, relativeTimeReference);
timeoutId = setTimeout(() => {
const next = getRelativeTime(date, locale, undefined, relativeTimeStyle || dateStyle, relativeTimeReference);
setLabel(prev => prev !== next ? next : prev);
scheduleNextUpdate();
}, delay);
};
setLabel(getRelativeTime(date, locale, undefined, relativeTimeStyle || dateStyle, relativeTimeReference));
scheduleNextUpdate();
return () => {
clearTimeout(timeoutId);
};
}, [date, locale, relativeTime, dateStyle, relativeTimeStyle, relativeTimeReference]);
const hasValidDate = date && !isNaN(date.getTime());
const tooltipContent = useMemo(() => {
if (!hasValidDate) {
return undefined;
}
return getAbsoluteDateFormatted({
options: {
dateStyle: 'full',
...(timeStyle ? {
timeStyle
} : {})
},
hideYear: false,
hideCurrentYear: false
});
}, [hasValidDate, getAbsoluteDateFormatted, timeStyle]);
if (durationValue !== undefined) {
const originalDurationString = String(value || children);
const hasAriaLabel = durationFormattedFull !== durationFormatted;
const showTooltip = durationFormattedFull !== durationFormatted;
return React.createElement(React.Fragment, null, React.createElement("time", _extends({}, attributes, {
dateTime: originalDurationString,
"aria-label": hasAriaLabel ? durationFormattedFull : undefined,
ref: showTooltip ? ref : undefined
}), React.createElement("span", {
"aria-hidden": hasAriaLabel
}, durationFormatted)), showTooltip && React.createElement(Tooltip, {
targetElement: ref,
tooltip: durationFormattedFull,
triggerOffset: 8
}));
}
if (!hasValidDate) {
return React.createElement("span", {
className: "dnb-date-format"
}, invalidDate.replace('{value}', getInvalidValue({
value,
children
})));
}
if (relativeTime) {
const relativeTooltip = getAbsoluteDateFormatted({
options: {
dateStyle: 'full',
timeStyle: timeStyle || 'short'
},
hideYear: false,
hideCurrentYear: false
});
return React.createElement(React.Fragment, null, React.createElement("time", _extends({
dateTime: getAbsoluteDateTime('yyyy-MM-dd HH:mm:ss')
}, attributes, {
ref: ref
}), label), React.createElement(Tooltip, {
targetElement: ref,
tooltip: relativeTooltip,
triggerOffset: 8
}));
}
const displayedContent = getAbsoluteDateFormatted();
const showTooltip = tooltipContent && tooltipContent !== displayedContent;
return React.createElement(React.Fragment, null, React.createElement("time", _extends({
dateTime: getAbsoluteDateTime()
}, attributes, {
ref: showTooltip ? ref : undefined
}), displayedContent), showTooltip && React.createElement(Tooltip, {
targetElement: ref,
tooltip: tooltipContent,
triggerOffset: 8
}));
}
function getDate({
value,
children
}) {
if (value) {
if (typeof value === 'string' && isValidDuration(value)) {
return;
}
if (typeof value === 'string') {
return convertStringToDate(value);
}
if (value instanceof Date) {
return value;
}
return convertStringToDate(String(value));
}
const childrenValue = convertJsxToString(children);
if (childrenValue && isValidDuration(childrenValue)) {
return;
}
return convertStringToDate(childrenValue);
}
function getInvalidValue({
value,
children
}) {
if (value instanceof Date) {
return value.toString();
}
if (children !== undefined && value === undefined) {
return String(children);
}
return String(value);
}
export default DateFormat;
DateFormat._supportsSpacingProps = true;
//# sourceMappingURL=DateFormat.js.map