Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@

> timeago-react is a simple react component used to format date with `*** time ago` statement. eg: '3 hours ago'.

**The component based on [timeago.js](https://github.com/hustcc/timeago.js)** which is a simple javascript module.
**Now uses native-time-ago** - a zero-dependency library using the native Intl.RelativeTimeFormat API.

- Realtime render. Automatic release the resources.
- Simple. Only 2kb.
- Efficient. When the time is `3 hour ago`, the interval will an hour (3600 * 1000 ms).
- Locales supported.
- Zero dependencies (uses native Intl.RelativeTimeFormat API)
- Supports 100+ languages automatically via native browser API
- No locale files needed

[![npm](https://img.shields.io/npm/v/timeago-react.svg)](https://www.npmjs.com/package/timeago-react)
[![build](https://github.com/hustcc/timeago-react/workflows/ci/badge.svg)](https://github.com/hustcc/timeago-react)
Expand Down
4 changes: 2 additions & 2 deletions packages/timeago-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@
"typescript-eslint": "^8.26.0",
"vitest": "^3.0.7"
},
"dependencies": {
"timeago.js": "^4.0.0"
"dependencies": {
"native-time-ago": "1.0.1"
},
"peerDependencies": {
"react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
Expand Down
91 changes: 26 additions & 65 deletions packages/timeago-react/src/timeago-react.tsx
Original file line number Diff line number Diff line change
@@ -1,71 +1,27 @@
import * as React from 'react';
import { format, cancel, render } from 'timeago.js';
import { Opts, TDate } from 'timeago.js/lib/interface';
export { Opts, TDate };

/**
* Convert input to a valid datetime string of <time> tag
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time
* @param input
* @returns datetime string
*/
const toDateTime = (input: TDate): string => {
// let date: Date = new Date();
// if (input instanceof Date) {
// date = input;
// //@ts-ignore
// } else if (!isNaN(input) || /^\d+$/.test(input)) {
// //@ts-ignore
// date = new Date(parseInt(input));
// } else {
// date = new Date(input);
// }

// try {
// return date.toISOString();
// } catch (e) {
// console.error('invalid datetime');
// return '';
// }
import timeAgo from 'native-time-ago';

const toDateTime = (input: any): string => {
return '' + (input instanceof Date ? input.getTime() : input);
};

// These ts-ignores are to import types from different React versions
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
export interface TimeAgoProps
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
extends React.ComponentProps<'time'>,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
React.HTMLProps<HTMLTimeElement> {
readonly datetime: TDate; // date to be formatted
readonly live?: boolean; // real time render.
readonly opts?: Opts;
readonly locale?: string; // locale lang
export interface TimeAgoProps extends React.HTMLAttributes<HTMLTimeElement> {
readonly datetime: any;
readonly live?: boolean;
readonly opts?: any; // Not supported in native-time-ago
readonly locale?: string;
}

export default class TimeAgo extends React.PureComponent<TimeAgoProps, unknown> {
static defaultProps = {
live: true,
live: false,
className: '',
};

dom: HTMLTimeElement = null;
intervalId: ReturnType<typeof setInterval> = null;

componentDidMount(): void {
// fixed #6 https://github.com/hustcc/timeago-react/issues/6
// to reduce the file size.
// const { locale } = this.props;
// if (locale !== 'en' && locale !== 'zh_CN') {
// timeago.register(locale, require('timeago.js/locales/' + locale));
// }
// render it.
this.renderTimeAgo();
}

Expand All @@ -74,26 +30,31 @@ export default class TimeAgo extends React.PureComponent<TimeAgoProps, unknown>
}

renderTimeAgo(): void {
const { live, datetime, locale, opts } = this.props;
// cancel all the interval
cancel(this.dom);
// if is live
const { live, datetime, locale } = this.props;
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
if (live !== false) {
// live render
this.dom.setAttribute('datetime', toDateTime(datetime));

render(this.dom, locale, opts);
const update = () => {
if (this.dom) {
this.dom.textContent = timeAgo(datetime, locale || 'en');
}
};
update();
this.intervalId = setInterval(update, 60000);
}
}

// remove
componentWillUnmount(): void {
cancel(this.dom);
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
}

// for render
render(): React.JSX.Element {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { datetime, live, locale, opts, ...others } = this.props;
return (
<time
Expand All @@ -102,7 +63,7 @@ export default class TimeAgo extends React.PureComponent<TimeAgoProps, unknown>
}}
{...others}
>
{format(datetime, locale, opts)}
{timeAgo(datetime, locale || 'en')}
</time>
);
}
Expand Down
1 change: 1 addition & 0 deletions packages/timeago-react/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"sourceMap": true,
"pretty": true,
"lib": ["dom", "esnext"],
"esModuleInterop": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
Expand Down