UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

243 lines (242 loc) 8.4 kB
"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