mirror of
https://github.com/vector-im/element-web.git
synced 2026-05-05 12:16:53 +02:00
refactor: move Clock from class component to functional component (#31964)
This commit is contained in:
parent
ae013686f5
commit
877ab183d9
@ -5,13 +5,16 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type HTMLProps } from "react";
|
||||
import React, { type JSX, type HTMLProps, useMemo } from "react";
|
||||
import { Temporal } from "temporal-polyfill";
|
||||
import classNames from "classnames";
|
||||
|
||||
import { formatSeconds } from "../../utils/DateUtils";
|
||||
|
||||
export interface Props extends Pick<HTMLProps<HTMLSpanElement>, "aria-live" | "role" | "className"> {
|
||||
/**
|
||||
* The number of seconds to display.
|
||||
*/
|
||||
seconds: number;
|
||||
}
|
||||
|
||||
@ -19,33 +22,39 @@ export interface Props extends Pick<HTMLProps<HTMLSpanElement>, "aria-live" | "r
|
||||
* Clock which represents time periods rather than absolute time.
|
||||
* Simply converts seconds using formatSeconds().
|
||||
* Note that in this case hours will not be displayed, making it possible to see "82:29".
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <Clock seconds={125} />
|
||||
* ```
|
||||
*/
|
||||
export class Clock extends React.Component<Props> {
|
||||
public shouldComponentUpdate(nextProps: Readonly<Props>): boolean {
|
||||
const currentFloor = Math.floor(this.props.seconds);
|
||||
const nextFloor = Math.floor(nextProps.seconds);
|
||||
return currentFloor !== nextFloor;
|
||||
}
|
||||
export function Clock({ seconds, className, ...rest }: Props): JSX.Element {
|
||||
// Memoize current second to avoid recalculating the duration when seconds changes slightly (e.g. 1.2 -> 1.3)
|
||||
const currentSecond = useMemo(() => Math.floor(seconds), [seconds]);
|
||||
const duration = useMemo(() => calculateDuration(currentSecond), [currentSecond]);
|
||||
|
||||
private calculateDuration(seconds: number): string | undefined {
|
||||
if (isNaN(seconds)) return undefined;
|
||||
return new Temporal.Duration(0, 0, 0, 0, 0, 0, Math.round(seconds))
|
||||
.round({ smallestUnit: "seconds", largestUnit: "hours" })
|
||||
.toString();
|
||||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
const { seconds, role } = this.props;
|
||||
return (
|
||||
<time
|
||||
dateTime={this.calculateDuration(seconds)}
|
||||
aria-live={this.props["aria-live"]}
|
||||
role={role}
|
||||
/* Keep class for backward compatibility with parent component */
|
||||
className={classNames("mx_Clock", this.props.className)}
|
||||
>
|
||||
{formatSeconds(seconds)}
|
||||
</time>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<time
|
||||
dateTime={duration}
|
||||
/* Keep class for backward compatibility with parent component */
|
||||
className={classNames("mx_Clock", className)}
|
||||
{...rest}
|
||||
>
|
||||
{formatSeconds(seconds)}
|
||||
</time>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates an ISO 8601 duration string from seconds.
|
||||
* @param seconds
|
||||
* @returns ISO 8601 duration string or undefined if input is NaN
|
||||
*/
|
||||
function calculateDuration(seconds: number): string | undefined {
|
||||
// This shouldn't happen but it's in the original implementation
|
||||
if (isNaN(seconds)) return undefined;
|
||||
|
||||
return new Temporal.Duration(0, 0, 0, 0, 0, 0, Math.round(seconds))
|
||||
.round({ smallestUnit: "seconds", largestUnit: "hours" })
|
||||
.toString();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user