react-intl
Version:
Internationalize React apps. This library provides React components and an API to format dates, numbers, and strings, including pluralization and handling translations.
126 lines (125 loc) • 4.96 kB
JavaScript
import { __assign, __rest } from "tslib";
/*
* Copyright 2015, Yahoo Inc.
* Copyrights licensed under the New BSD License.
* See the accompanying LICENSE file for terms.
*/
import * as React from 'react';
import { invariant } from '../utils';
import useIntl from './useIntl';
var MINUTE = 60;
var HOUR = 60 * 60;
var DAY = 60 * 60 * 24;
function selectUnit(seconds) {
var absValue = Math.abs(seconds);
if (absValue < MINUTE) {
return 'second';
}
if (absValue < HOUR) {
return 'minute';
}
if (absValue < DAY) {
return 'hour';
}
return 'day';
}
function getDurationInSeconds(unit) {
switch (unit) {
case 'second':
return 1;
case 'minute':
return MINUTE;
case 'hour':
return HOUR;
default:
return DAY;
}
}
function valueToSeconds(value, unit) {
if (!value) {
return 0;
}
switch (unit) {
case 'second':
return value;
case 'minute':
return value * MINUTE;
default:
return value * HOUR;
}
}
var INCREMENTABLE_UNITS = [
'second',
'minute',
'hour',
];
function canIncrement(unit) {
if (unit === void 0) { unit = 'second'; }
return INCREMENTABLE_UNITS.indexOf(unit) > -1;
}
var SimpleFormattedRelativeTime = function (props) {
var _a = useIntl(), formatRelativeTime = _a.formatRelativeTime, Text = _a.textComponent;
var children = props.children, value = props.value, unit = props.unit, otherProps = __rest(props, ["children", "value", "unit"]);
var formattedRelativeTime = formatRelativeTime(value || 0, unit, otherProps);
if (typeof children === 'function') {
return children(formattedRelativeTime);
}
if (Text) {
return React.createElement(Text, null, formattedRelativeTime);
}
return React.createElement(React.Fragment, null, formattedRelativeTime);
};
var FormattedRelativeTime = function (_a) {
var _b = _a.value, value = _b === void 0 ? 0 : _b, _c = _a.unit, unit = _c === void 0 ? 'second' : _c, updateIntervalInSeconds = _a.updateIntervalInSeconds, otherProps = __rest(_a, ["value", "unit", "updateIntervalInSeconds"]);
invariant(!updateIntervalInSeconds ||
!!(updateIntervalInSeconds && canIncrement(unit)), 'Cannot schedule update with unit longer than hour');
var _d = React.useState(), prevUnit = _d[0], setPrevUnit = _d[1];
var _e = React.useState(0), prevValue = _e[0], setPrevValue = _e[1];
var _f = React.useState(0), currentValueInSeconds = _f[0], setCurrentValueInSeconds = _f[1];
var updateTimer;
if (unit !== prevUnit || value !== prevValue) {
setPrevValue(value || 0);
setPrevUnit(unit);
setCurrentValueInSeconds(canIncrement(unit) ? valueToSeconds(value, unit) : 0);
}
React.useEffect(function () {
function clearUpdateTimer() {
clearTimeout(updateTimer);
}
clearUpdateTimer();
// If there's no interval and we cannot increment this unit, do nothing
if (!updateIntervalInSeconds || !canIncrement(unit)) {
return clearUpdateTimer;
}
// Figure out the next interesting time
var nextValueInSeconds = currentValueInSeconds - updateIntervalInSeconds;
var nextUnit = selectUnit(nextValueInSeconds);
// We've reached the max auto incrementable unit, don't schedule another update
if (nextUnit === 'day') {
return clearUpdateTimer;
}
var unitDuration = getDurationInSeconds(nextUnit);
var remainder = nextValueInSeconds % unitDuration;
var prevInterestingValueInSeconds = nextValueInSeconds - remainder;
var nextInterestingValueInSeconds = prevInterestingValueInSeconds >= currentValueInSeconds
? prevInterestingValueInSeconds - unitDuration
: prevInterestingValueInSeconds;
var delayInSeconds = Math.abs(nextInterestingValueInSeconds - currentValueInSeconds);
if (currentValueInSeconds !== nextInterestingValueInSeconds) {
updateTimer = setTimeout(function () { return setCurrentValueInSeconds(nextInterestingValueInSeconds); }, delayInSeconds * 1e3);
}
return clearUpdateTimer;
}, [currentValueInSeconds, updateIntervalInSeconds, unit]);
var currentValue = value || 0;
var currentUnit = unit;
if (canIncrement(unit) &&
typeof currentValueInSeconds === 'number' &&
updateIntervalInSeconds) {
currentUnit = selectUnit(currentValueInSeconds);
var unitDuration = getDurationInSeconds(currentUnit);
currentValue = Math.round(currentValueInSeconds / unitDuration);
}
return (React.createElement(SimpleFormattedRelativeTime, __assign({ value: currentValue, unit: currentUnit }, otherProps)));
};
FormattedRelativeTime.displayName = 'FormattedRelativeTime';
export default FormattedRelativeTime;