@liveblocks/react-ui
Version:
A set of React pre-built components for the Liveblocks products. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.
125 lines (120 loc) • 3.67 kB
JavaScript
"use client";
;
var jsxRuntime = require('react/jsx-runtime');
var reactSlot = require('@radix-ui/react-slot');
var react = require('react');
var capitalize = require('../utils/capitalize.cjs');
var intl = require('../utils/intl.cjs');
var useInterval = require('../utils/use-interval.cjs');
var useRerender = require('../utils/use-rerender.cjs');
const DYNAMIC_DATE_THRESHOLD = 3 * 24 * 60 * 60 * 1e3;
const RENDER_INTERVAL = 30 * 1e3;
const TIMESTAMP_NAME = "Timestamp";
const relativeUnits = {
seconds: 60,
minutes: 60,
hours: 24,
days: 7,
weeks: 4.34524,
months: 12
};
function formatVerboseDate(date, locale) {
const formatter = intl.dateTimeFormat(locale, {
year: "numeric",
month: "numeric",
day: "numeric",
hour: "numeric",
minute: "numeric"
});
return capitalize.capitalize(formatter.format(date));
}
function formatShortDate(date, locale) {
const formatter = intl.dateTimeFormat(locale, {
month: "short",
day: "numeric"
});
return capitalize.capitalize(formatter.format(date));
}
const localesWithBrokenNarrowRelativeFormatting = [
"br",
"fr",
"nb",
"nn",
"no",
"ro",
"sv"
];
function formatRelativeDate(date, locale) {
let resolvedLocale;
if (locale) {
resolvedLocale = locale;
} else {
const formatter2 = intl.relativeTimeFormat();
resolvedLocale = formatter2.resolvedOptions().locale;
}
const isBrokenWhenNarrow = localesWithBrokenNarrowRelativeFormatting.some(
(locale2) => resolvedLocale === locale2 || resolvedLocale.startsWith(`${locale2}-`)
);
const formatter = intl.relativeTimeFormat(resolvedLocale, {
style: isBrokenWhenNarrow ? "short" : "narrow",
numeric: "auto"
});
let difference = (date.getTime() - Date.now()) / 1e3;
if (difference > -relativeUnits.seconds && difference < relativeUnits.seconds) {
return formatter.format(0, "seconds");
}
for (const [unit, length] of Object.entries(relativeUnits)) {
if (Math.abs(difference) < length) {
return formatter.format(
Math.round(difference),
unit
);
}
difference /= length;
}
return capitalize.capitalize(formatter.format(Math.round(difference), "years"));
}
function formatDynamicDate(date, locale) {
return date.getTime() > Date.now() - DYNAMIC_DATE_THRESHOLD ? formatRelativeDate(date, locale) : formatShortDate(date, locale);
}
const Timestamp = react.forwardRef(
({
date,
locale,
children: renderChildren = formatDynamicDate,
title: renderTitle = formatVerboseDate,
dateTime,
interval = RENDER_INTERVAL,
asChild,
...props
}, forwardedRef) => {
const Component = asChild ? reactSlot.Slot : "time";
const [rerender, key] = useRerender.useRerender();
const parsedDate = react.useMemo(() => new Date(date), [date]);
const normalizedDate = react.useMemo(
() => parsedDate.toISOString(),
[parsedDate]
);
const title = react.useMemo(
() => typeof renderTitle === "function" ? renderTitle(parsedDate, locale) : renderTitle,
[renderTitle, parsedDate, key]
);
const children = react.useMemo(
() => typeof renderChildren === "function" ? renderChildren(parsedDate, locale) : renderChildren,
[renderChildren, parsedDate, key]
);
useInterval.useInterval(rerender, interval);
return /* @__PURE__ */ jsxRuntime.jsx(Component, {
...props,
ref: forwardedRef,
dateTime: dateTime ?? normalizedDate,
title,
children
});
}
);
if (process.env.NODE_ENV !== "production") {
Timestamp.displayName = TIMESTAMP_NAME;
}
exports.Timestamp = Timestamp;
//# sourceMappingURL=Timestamp.cjs.map