@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
258 lines (257 loc) • 8.58 kB
JavaScript
"use client";
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 clsx from 'clsx';
import { applySpacing } 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";
import withComponentMarkers from "../../shared/helpers/withComponentMarkers.js";
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
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(undefined);
const date = useMemo(() => {
return getDate({
value,
children
});
}, [value, children]);
const durationValue = useMemo(() => {
const durationString = String(value || children);
if (!durationString || !isValidDuration(durationString)) {
return undefined;
}
return parseDuration(durationString);
}, [value, children]);
const getDuration = useCallback(dateStyle => {
if (durationValue === undefined) {
return undefined;
}
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 = applySpacing(props, {
className: clsx('dnb-date-format', 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 undefined;
}
return format(date, style);
}, [date]);
const getAbsoluteDateFormatted = useCallback(({
options = {
dateStyle,
...(timeStyle ? {
timeStyle
} : {})
},
hideYear: hideYearOverride,
hideCurrentYear: hideCurrentYearOverride
} = {}) => {
if (!date || isNaN(date.getTime())) {
return undefined;
}
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 undefined;
}
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 _jsxs(_Fragment, {
children: [_jsx("time", {
...attributes,
dateTime: originalDurationString,
"aria-label": hasAriaLabel ? durationFormattedFull : undefined,
ref: showTooltip ? ref : undefined,
children: _jsx("span", {
"aria-hidden": hasAriaLabel,
children: durationFormatted
})
}), showTooltip && _jsx(Tooltip, {
targetElement: ref,
tooltip: durationFormattedFull,
triggerOffset: 8
})]
});
}
if (!hasValidDate) {
return _jsx("span", {
className: "dnb-date-format",
children: invalidDate.replace('{value}', getInvalidValue({
value,
children
}))
});
}
if (relativeTime) {
const relativeTooltip = getAbsoluteDateFormatted({
options: {
dateStyle: 'full',
timeStyle: timeStyle || 'short'
},
hideYear: false,
hideCurrentYear: false
});
return _jsxs(_Fragment, {
children: [_jsx("time", {
dateTime: getAbsoluteDateTime('yyyy-MM-dd HH:mm:ss'),
...attributes,
ref: ref,
children: label
}), _jsx(Tooltip, {
targetElement: ref,
tooltip: relativeTooltip,
triggerOffset: 8
})]
});
}
const displayedContent = getAbsoluteDateFormatted();
const showTooltip = tooltipContent && tooltipContent !== displayedContent;
return _jsxs(_Fragment, {
children: [_jsx("time", {
dateTime: getAbsoluteDateTime(),
...attributes,
ref: showTooltip ? ref : undefined,
children: displayedContent
}), showTooltip && _jsx(Tooltip, {
targetElement: ref,
tooltip: tooltipContent,
triggerOffset: 8
})]
});
}
function getDate({
value,
children
}) {
if (value) {
if (typeof value === 'string' && isValidDuration(value)) {
return undefined;
}
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 undefined;
}
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;
withComponentMarkers(DateFormat, {
_supportsSpacingProps: true
});
//# sourceMappingURL=DateFormat.js.map