@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.
197 lines (193 loc) • 5.58 kB
JavaScript
"use client";
import { jsx } from 'react/jsx-runtime';
import { Slot } from '@radix-ui/react-slot';
import { forwardRef, useMemo } from 'react';
import { numberFormat } from '../utils/intl.js';
import { useInterval } from '../utils/use-interval.js';
import { useRerender } from '../utils/use-rerender.js';
const RENDER_INTERVAL = 0.5 * 1e3;
const DURATION_NAME = "Duration";
function getDurationParts(duration) {
let remaining = Math.max(duration, 0);
const milliseconds = remaining % 1e3;
remaining = Math.floor(remaining / 1e3);
const seconds = remaining % 60;
remaining = Math.floor(remaining / 60);
const minutes = remaining % 60;
remaining = Math.floor(remaining / 60);
const hours = remaining % 24;
remaining = Math.floor(remaining / 24);
const days = remaining % 7;
const weeks = Math.floor(remaining / 7);
return { weeks, days, hours, minutes, seconds, milliseconds };
}
const durationPartsToNumberFormatOptions = {
weeks: "week",
days: "day",
hours: "hour",
minutes: "minute",
seconds: "second",
milliseconds: "millisecond"
};
function formatShortDuration(duration, locale) {
let resolvedLocale;
if (locale) {
resolvedLocale = locale;
} else {
const formatter = numberFormat();
resolvedLocale = formatter.resolvedOptions().locale;
}
const parts = getDurationParts(duration);
const formattedParts = [];
for (const [unit, value] of Object.entries(parts)) {
if (value === 0 || unit === "milliseconds") {
continue;
}
const formatter = numberFormat(resolvedLocale, {
style: "unit",
unit: durationPartsToNumberFormatOptions[unit],
unitDisplay: "narrow"
});
formattedParts.push(formatter.format(value));
}
if (!formattedParts.length) {
formattedParts.push(
numberFormat(resolvedLocale, {
style: "unit",
unit: "second",
unitDisplay: "narrow"
}).format(0)
);
}
return formattedParts.join(" ");
}
function formatVerboseDuration(duration, locale) {
let resolvedLocale;
if (locale) {
resolvedLocale = locale;
} else {
const formatter = numberFormat();
resolvedLocale = formatter.resolvedOptions().locale;
}
const parts = getDurationParts(duration);
const formattedParts = [];
for (const [unit, value] of Object.entries(parts)) {
if (value === 0 || unit === "milliseconds") {
continue;
}
const formatter = numberFormat(resolvedLocale, {
style: "unit",
unit: durationPartsToNumberFormatOptions[unit],
unitDisplay: "long"
});
formattedParts.push(formatter.format(value));
}
if (!formattedParts.length) {
formattedParts.push(
numberFormat(resolvedLocale, {
style: "unit",
unit: "second",
unitDisplay: "long"
}).format(0)
);
}
return formattedParts.join(" ");
}
function formatIso8601Duration(duration) {
const normalizedDuration = Math.max(duration, 0);
if (normalizedDuration === 0) {
return "PT0S";
}
const { weeks, days, hours, minutes, seconds, milliseconds } = getDurationParts(normalizedDuration);
let isoDuration = "P";
if (weeks > 0) {
isoDuration += `${weeks}W`;
}
if (days > 0) {
isoDuration += `${days}D`;
}
if (hours > 0 || minutes > 0 || seconds > 0 || milliseconds > 0) {
isoDuration += "T";
if (hours > 0) {
isoDuration += `${hours}H`;
}
if (minutes > 0) {
isoDuration += `${minutes}M`;
}
if (seconds > 0 || milliseconds > 0) {
if (milliseconds > 0) {
isoDuration += `${seconds}.${milliseconds.toString().padStart(3, "0").replace(/0+$/, "")}S`;
} else {
isoDuration += `${seconds}S`;
}
}
}
return isoDuration;
}
function getDateTime(date) {
if (date instanceof Date) {
return date.getTime();
}
return new Date(date).getTime();
}
function getDuration(from, to) {
return getDateTime(to) - getDateTime(from);
}
const Duration = forwardRef(
({
duration,
from,
to,
locale,
dateTime,
title: renderTitle = formatVerboseDuration,
children: renderChildren = formatShortDuration,
interval = RENDER_INTERVAL,
asChild,
...props
}, forwardedRef) => {
const Component = asChild ? Slot : "time";
const [rerender, key] = useRerender();
const resolvedDuration = useMemo(() => {
if (duration !== void 0) {
return duration;
}
if (from !== void 0) {
return getDuration(from, to ?? Date.now());
}
return 0;
}, [duration, from, to, key]);
const normalizedDuration = useMemo(
() => formatIso8601Duration(resolvedDuration),
[resolvedDuration]
);
const title = useMemo(
() => typeof renderTitle === "function" ? renderTitle(resolvedDuration, locale) : renderTitle,
// eslint-disable-next-line react-hooks/exhaustive-deps
[renderTitle, resolvedDuration, locale]
);
const children = useMemo(
() => typeof renderChildren === "function" ? renderChildren(resolvedDuration, locale) : renderChildren,
[renderChildren, resolvedDuration, locale]
);
useInterval(
rerender,
from !== void 0 && to === void 0 ? interval : false
);
return /* @__PURE__ */ jsx(
Component,
{
...props,
ref: forwardedRef,
dateTime: dateTime ?? normalizedDuration,
title,
children
}
);
}
);
if (process.env.NODE_ENV !== "production") {
Duration.displayName = DURATION_NAME;
}
export { Duration, formatIso8601Duration, getDuration };
//# sourceMappingURL=Duration.js.map