Merge pull request #1621 from vector-im/renovate/prettier-3.x

Update dependency prettier to v3
This commit is contained in:
Robin
2023-10-11 10:45:16 -04:00
committed by GitHub
114 changed files with 633 additions and 607 deletions

View File

@@ -14,7 +14,7 @@ module.exports = {
Array.isArray(item) && Array.isArray(item) &&
item.length > 0 && item.length > 0 &&
item[0].name === "vite-plugin-mdx" item[0].name === "vite-plugin-mdx"
) ),
); );
config.plugins.push(svgrPlugin()); config.plugins.push(svgrPlugin());
config.resolve = config.resolve || {}; config.resolve = config.resolve || {};

View File

@@ -117,7 +117,7 @@
"jest": "^29.2.2", "jest": "^29.2.2",
"jest-environment-jsdom": "^29.3.1", "jest-environment-jsdom": "^29.3.1",
"jest-mock": "^29.5.0", "jest-mock": "^29.5.0",
"prettier": "^2.6.2", "prettier": "^3.0.0",
"sass": "^1.42.1", "sass": "^1.42.1",
"typescript": "^5.1.6", "typescript": "^5.1.6",
"typescript-eslint-language-service": "^5.0.5", "typescript-eslint-language-service": "^5.0.5",

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />

View File

@@ -58,7 +58,7 @@ export const Avatar: FC<Props> = ({
Object.values(Size).includes(size as Size) Object.values(Size).includes(size as Size)
? sizes.get(size as Size) ? sizes.get(size as Size)
: (size as number), : (size as number),
[size] [size],
); );
const resolvedSrc = useMemo(() => { const resolvedSrc = useMemo(() => {

View File

@@ -190,7 +190,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
user: session.user_id, user: session.user_id,
password: session.tempPassword, password: session.tempPassword,
}, },
password password,
); );
saveSession({ ...session, passwordlessUser: false }); saveSession({ ...session, passwordlessUser: false });
@@ -200,7 +200,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
passwordlessUser: false, passwordlessUser: false,
}); });
}, },
[initClientState?.client] [initClientState?.client],
); );
const setClient = useCallback( const setClient = useCallback(
@@ -222,7 +222,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
setInitClientState(null); setInitClientState(null);
} }
}, },
[initClientState?.client] [initClientState?.client],
); );
const logout = useCallback(async () => { const logout = useCallback(async () => {
@@ -250,7 +250,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
}, []); }, []);
const [alreadyOpenedErr, setAlreadyOpenedErr] = useState<Error | undefined>( const [alreadyOpenedErr, setAlreadyOpenedErr] = useState<Error | undefined>(
undefined undefined,
); );
useEventTarget( useEventTarget(
loadChannel, loadChannel,
@@ -258,9 +258,9 @@ export const ClientProvider: FC<Props> = ({ children }) => {
useCallback(() => { useCallback(() => {
initClientState?.client.stopClient(); initClientState?.client.stopClient();
setAlreadyOpenedErr( setAlreadyOpenedErr(
translatedError("This application has been opened in another tab.", t) translatedError("This application has been opened in another tab.", t),
); );
}, [initClientState?.client, setAlreadyOpenedErr, t]) }, [initClientState?.client, setAlreadyOpenedErr, t]),
); );
const [isDisconnected, setIsDisconnected] = useState(false); const [isDisconnected, setIsDisconnected] = useState(false);
@@ -301,7 +301,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
(state: SyncState, _old: SyncState | null, data?: ISyncStateData) => { (state: SyncState, _old: SyncState | null, data?: ISyncStateData) => {
setIsDisconnected(clientIsDisconnected(state, data)); setIsDisconnected(clientIsDisconnected(state, data));
}, },
[] [],
); );
useEffect(() => { useEffect(() => {
@@ -387,7 +387,7 @@ async function loadClient(): Promise<InitResult | null> {
logger.warn( logger.warn(
"The previous session was lost, and we couldn't log it out, " + "The previous session was lost, and we couldn't log it out, " +
err + err +
"either" "either",
); );
} }
} }
@@ -423,6 +423,6 @@ const loadSession = (): Session | undefined => {
const clientIsDisconnected = ( const clientIsDisconnected = (
syncState: SyncState, syncState: SyncState,
syncData?: ISyncStateData syncData?: ISyncStateData,
): boolean => ): boolean =>
syncState === "ERROR" && syncData?.error?.name === "ConnectionError"; syncState === "ERROR" && syncData?.error?.name === "ConnectionError";

View File

@@ -48,5 +48,5 @@ export const Glass = forwardRef<HTMLDivElement, Props>(
> >
{Children.only(children)} {Children.only(children)}
</div> </div>
) ),
); );

View File

@@ -58,7 +58,7 @@ export const LeftNav: FC<LeftNavProps> = ({
styles.nav, styles.nav,
styles.leftNav, styles.leftNav,
{ [styles.hideMobile]: hideMobile }, { [styles.hideMobile]: hideMobile },
className className,
)} )}
{...rest} {...rest}
> >
@@ -85,7 +85,7 @@ export const RightNav: FC<RightNavProps> = ({
styles.nav, styles.nav,
styles.rightNav, styles.rightNav,
{ [styles.hideMobile]: hideMobile }, { [styles.hideMobile]: hideMobile },
className className,
)} )}
{...rest} {...rest}
> >

View File

@@ -63,7 +63,7 @@ export class LazyEventEmitter extends EventEmitter {
public addListener( public addListener(
type: string | symbol, type: string | symbol,
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
listener: (...args: any[]) => void listener: (...args: any[]) => void,
): this { ): this {
return this.on(type, listener); return this.on(type, listener);
} }

View File

@@ -77,7 +77,7 @@ function Option<T>({ item, state, className }: OptionProps<T>): ReactNode {
const { optionProps, isSelected, isFocused, isDisabled } = useOption( const { optionProps, isSelected, isFocused, isDisabled } = useOption(
{ key: item.key }, { key: item.key },
state, state,
ref ref,
); );
// Hack: remove the onPointerUp event handler and re-wire it to // Hack: remove the onPointerUp event handler and re-wire it to
@@ -97,7 +97,7 @@ function Option<T>({ item, state, className }: OptionProps<T>): ReactNode {
// @ts-ignore // @ts-ignore
origPointerUp(e as unknown as PointerEvent<HTMLElement>); origPointerUp(e as unknown as PointerEvent<HTMLElement>);
}, },
[origPointerUp] [origPointerUp],
); );
return ( return (

View File

@@ -82,7 +82,7 @@ function MenuItem<T>({
onClose, onClose,
}, },
state, state,
ref ref,
); );
const [isFocused, setFocused] = useState(false); const [isFocused, setFocused] = useState(false);

View File

@@ -75,7 +75,7 @@ export const Modal: FC<Props> = ({
(open: boolean) => { (open: boolean) => {
if (!open) onDismiss?.(); if (!open) onDismiss?.();
}, },
[onDismiss] [onDismiss],
); );
if (touchscreen) { if (touchscreen) {
@@ -92,7 +92,7 @@ export const Modal: FC<Props> = ({
className, className,
overlayStyles.overlay, overlayStyles.overlay,
styles.modal, styles.modal,
styles.drawer styles.drawer,
)} )}
{...rest} {...rest}
> >
@@ -124,7 +124,7 @@ export const Modal: FC<Props> = ({
overlayStyles.overlay, overlayStyles.overlay,
overlayStyles.animate, overlayStyles.animate,
styles.modal, styles.modal,
styles.dialog styles.dialog,
)} )}
> >
<div className={styles.content}> <div className={styles.content}>

View File

@@ -70,7 +70,7 @@ export const Toast: FC<Props> = ({
(open: boolean) => { (open: boolean) => {
if (!open) onDismiss(); if (!open) onDismiss();
}, },
[onDismiss] [onDismiss],
); );
useEffect(() => { useEffect(() => {
@@ -91,7 +91,7 @@ export const Toast: FC<Props> = ({
className={classNames( className={classNames(
overlayStyles.overlay, overlayStyles.overlay,
overlayStyles.animate, overlayStyles.animate,
styles.toast styles.toast,
)} )}
> >
<DialogTitle asChild> <DialogTitle asChild>

View File

@@ -43,7 +43,7 @@ interface TooltipProps {
const Tooltip = forwardRef<HTMLDivElement, TooltipProps>( const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
( (
{ state, className, children, ...rest }: TooltipProps, { state, className, children, ...rest }: TooltipProps,
ref: ForwardedRef<HTMLDivElement> ref: ForwardedRef<HTMLDivElement>,
) => { ) => {
const { tooltipProps } = useTooltip(rest, state); const { tooltipProps } = useTooltip(rest, state);
@@ -56,7 +56,7 @@ const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
{children} {children}
</div> </div>
); );
} },
); );
interface TooltipTriggerProps { interface TooltipTriggerProps {
@@ -69,7 +69,7 @@ interface TooltipTriggerProps {
export const TooltipTrigger = forwardRef<HTMLElement, TooltipTriggerProps>( export const TooltipTrigger = forwardRef<HTMLElement, TooltipTriggerProps>(
( (
{ children, placement, tooltip, ...rest }: TooltipTriggerProps, { children, placement, tooltip, ...rest }: TooltipTriggerProps,
ref: ForwardedRef<HTMLElement> ref: ForwardedRef<HTMLElement>,
) => { ) => {
const tooltipTriggerProps = { delay: 250, ...rest }; const tooltipTriggerProps = { delay: 250, ...rest };
const tooltipState = useTooltipTriggerState(tooltipTriggerProps); const tooltipState = useTooltipTriggerState(tooltipTriggerProps);
@@ -78,7 +78,7 @@ export const TooltipTrigger = forwardRef<HTMLElement, TooltipTriggerProps>(
const { triggerProps, tooltipProps } = useTooltipTrigger( const { triggerProps, tooltipProps } = useTooltipTrigger(
tooltipTriggerProps, tooltipTriggerProps,
tooltipState, tooltipState,
triggerRef triggerRef,
); );
const { overlayProps } = useOverlayPosition({ const { overlayProps } = useOverlayPosition({
@@ -94,7 +94,7 @@ export const TooltipTrigger = forwardRef<HTMLElement, TooltipTriggerProps>(
<children.type <children.type
{...mergeProps<typeof children.props | typeof rest>( {...mergeProps<typeof children.props | typeof rest>(
children.props, children.props,
rest rest,
)} )}
/> />
{tooltipState.isOpen && ( {tooltipState.isOpen && (
@@ -110,5 +110,5 @@ export const TooltipTrigger = forwardRef<HTMLElement, TooltipTriggerProps>(
)} )}
</FocusableProvider> </FocusableProvider>
); );
} },
); );

View File

@@ -39,5 +39,5 @@ class TranslatedErrorImpl extends TranslatedError {}
// function instead // function instead
export const translatedError = ( export const translatedError = (
messageKey: string, messageKey: string,
t: typeof i18n.t t: typeof i18n.t,
): TranslatedError => new TranslatedErrorImpl(messageKey, t); ): TranslatedError => new TranslatedErrorImpl(messageKey, t);

View File

@@ -119,17 +119,17 @@ interface UrlParams {
// file. // file.
export function editFragmentQuery( export function editFragmentQuery(
hash: string, hash: string,
edit: (params: URLSearchParams) => URLSearchParams edit: (params: URLSearchParams) => URLSearchParams,
): string { ): string {
const fragmentQueryStart = hash.indexOf("?"); const fragmentQueryStart = hash.indexOf("?");
const fragmentParams = edit( const fragmentParams = edit(
new URLSearchParams( new URLSearchParams(
fragmentQueryStart === -1 ? "" : hash.substring(fragmentQueryStart) fragmentQueryStart === -1 ? "" : hash.substring(fragmentQueryStart),
) ),
); );
return `${hash.substring( return `${hash.substring(
0, 0,
fragmentQueryStart fragmentQueryStart,
)}?${fragmentParams.toString()}`; )}?${fragmentParams.toString()}`;
} }
@@ -142,7 +142,7 @@ class ParamParser {
const fragmentQueryStart = hash.indexOf("?"); const fragmentQueryStart = hash.indexOf("?");
this.fragmentParams = new URLSearchParams( this.fragmentParams = new URLSearchParams(
fragmentQueryStart === -1 ? "" : hash.substring(fragmentQueryStart) fragmentQueryStart === -1 ? "" : hash.substring(fragmentQueryStart),
); );
} }
@@ -174,7 +174,7 @@ class ParamParser {
*/ */
export const getUrlParams = ( export const getUrlParams = (
search = window.location.search, search = window.location.search,
hash = window.location.hash hash = window.location.hash,
): UrlParams => { ): UrlParams => {
const parser = new ParamParser(search, hash); const parser = new ParamParser(search, hash);
@@ -221,7 +221,7 @@ export const useUrlParams = (): UrlParams => {
export function getRoomIdentifierFromUrl( export function getRoomIdentifierFromUrl(
pathname: string, pathname: string,
search: string, search: string,
hash: string hash: string,
): RoomIdentifier { ): RoomIdentifier {
let roomAlias: string | null = null; let roomAlias: string | null = null;
pathname = pathname.substring(1); // Strip the "/" pathname = pathname.substring(1); // Strip the "/"
@@ -281,6 +281,6 @@ export const useRoomIdentifier = (): RoomIdentifier => {
const { pathname, search, hash } = useLocation(); const { pathname, search, hash } = useLocation();
return useMemo( return useMemo(
() => getRoomIdentifierFromUrl(pathname, search, hash), () => getRoomIdentifierFromUrl(pathname, search, hash),
[pathname, search, hash] [pathname, search, hash],
); );
}; };

View File

@@ -34,7 +34,7 @@ export const UserMenuContainer: FC<Props> = ({ preventNavigation = false }) => {
const [settingsModalOpen, setSettingsModalOpen] = useState(false); const [settingsModalOpen, setSettingsModalOpen] = useState(false);
const onDismissSettingsModal = useCallback( const onDismissSettingsModal = useCallback(
() => setSettingsModalOpen(false), () => setSettingsModalOpen(false),
[setSettingsModalOpen] [setSettingsModalOpen],
); );
const [defaultSettingsTab, setDefaultSettingsTab] = useState<string>(); const [defaultSettingsTab, setDefaultSettingsTab] = useState<string>();
@@ -58,7 +58,7 @@ export const UserMenuContainer: FC<Props> = ({ preventNavigation = false }) => {
break; break;
} }
}, },
[history, location, logout, setSettingsModalOpen] [history, location, logout, setSettingsModalOpen],
); );
const userName = client?.getUserIdLocalpart() ?? ""; const userName = client?.getUserIdLocalpart() ?? "";

View File

@@ -146,7 +146,7 @@ export class PosthogAnalytics {
this.enabled = true; this.enabled = true;
} else { } else {
logger.info( logger.info(
"Posthog is not enabled because there is no api key or no host given in the config" "Posthog is not enabled because there is no api key or no host given in the config",
); );
this.enabled = false; this.enabled = false;
} }
@@ -157,7 +157,7 @@ export class PosthogAnalytics {
private sanitizeProperties = ( private sanitizeProperties = (
properties: Properties, properties: Properties,
_eventName: string _eventName: string,
): Properties => { ): Properties => {
// Callback from posthog to sanitize properties before sending them to the server. // Callback from posthog to sanitize properties before sending them to the server.
// Here we sanitize posthog's built in properties which leak PII e.g. url reporting. // Here we sanitize posthog's built in properties which leak PII e.g. url reporting.
@@ -201,7 +201,7 @@ export class PosthogAnalytics {
private capture( private capture(
eventName: string, eventName: string,
properties: Properties, properties: Properties,
options?: CaptureOptions options?: CaptureOptions,
): void { ): void {
if (!this.enabled) { if (!this.enabled) {
return; return;
@@ -237,7 +237,7 @@ export class PosthogAnalytics {
} }
private async identifyUser( private async identifyUser(
analyticsIdGenerator: () => string analyticsIdGenerator: () => string,
): Promise<void> { ): Promise<void> {
if (this.anonymity == Anonymity.Pseudonymous && this.enabled) { if (this.anonymity == Anonymity.Pseudonymous && this.enabled) {
// Check the user's account_data for an analytics ID to use. Storing the ID in account_data allows // Check the user's account_data for an analytics ID to use. Storing the ID in account_data allows
@@ -260,14 +260,14 @@ export class PosthogAnalytics {
// The above could fail due to network requests, but not essential to starting the application, // The above could fail due to network requests, but not essential to starting the application,
// so swallow it. // so swallow it.
logger.log( logger.log(
"Unable to identify user for tracking" + (e as Error)?.toString() "Unable to identify user for tracking" + (e as Error)?.toString(),
); );
} }
if (analyticsID) { if (analyticsID) {
this.posthog.identify(analyticsID); this.posthog.identify(analyticsID);
} else { } else {
logger.info( logger.info(
"No analyticsID is availble. Should not try to setup posthog" "No analyticsID is availble. Should not try to setup posthog",
); );
} }
} }
@@ -280,7 +280,7 @@ export class PosthogAnalytics {
accountAnalyticsId = getUrlParams().analyticsID; accountAnalyticsId = getUrlParams().analyticsID;
} else { } else {
const accountData = await client.getAccountDataFromServer( const accountData = await client.getAccountDataFromServer(
PosthogAnalytics.ANALYTICS_EVENT_TYPE PosthogAnalytics.ANALYTICS_EVENT_TYPE,
); );
accountAnalyticsId = accountData?.id; accountAnalyticsId = accountData?.id;
} }
@@ -294,13 +294,13 @@ export class PosthogAnalytics {
} }
private async hashedEcAnalyticsId( private async hashedEcAnalyticsId(
accountAnalyticsId: string accountAnalyticsId: string,
): Promise<string> { ): Promise<string> {
const client: MatrixClient = window.matrixclient; const client: MatrixClient = window.matrixclient;
const posthogIdMaterial = "ec" + accountAnalyticsId + client.getUserId(); const posthogIdMaterial = "ec" + accountAnalyticsId + client.getUserId();
const bufferForPosthogId = await crypto.subtle.digest( const bufferForPosthogId = await crypto.subtle.digest(
"sha-256", "sha-256",
Buffer.from(posthogIdMaterial, "utf-8") Buffer.from(posthogIdMaterial, "utf-8"),
); );
const view = new Int32Array(bufferForPosthogId); const view = new Int32Array(bufferForPosthogId);
return Array.from(view) return Array.from(view)
@@ -314,11 +314,11 @@ export class PosthogAnalytics {
// the analytics ID only needs to be set in the standalone version. // the analytics ID only needs to be set in the standalone version.
const accountData = await client.getAccountDataFromServer( const accountData = await client.getAccountDataFromServer(
PosthogAnalytics.ANALYTICS_EVENT_TYPE PosthogAnalytics.ANALYTICS_EVENT_TYPE,
); );
await client.setAccountData( await client.setAccountData(
PosthogAnalytics.ANALYTICS_EVENT_TYPE, PosthogAnalytics.ANALYTICS_EVENT_TYPE,
Object.assign({ id: analyticsID }, accountData) Object.assign({ id: analyticsID }, accountData),
); );
} }
} }
@@ -360,7 +360,7 @@ export class PosthogAnalytics {
} }
private async updateAnonymityAndIdentifyUser( private async updateAnonymityAndIdentifyUser(
pseudonymousOptIn: boolean pseudonymousOptIn: boolean,
): Promise<void> { ): Promise<void> {
// Update this.anonymity based on the user's analytics opt-in settings // Update this.anonymity based on the user's analytics opt-in settings
const anonymity = pseudonymousOptIn const anonymity = pseudonymousOptIn
@@ -376,11 +376,11 @@ export class PosthogAnalytics {
this.setRegistrationType( this.setRegistrationType(
window.matrixclient.isGuest() || window.passwordlessUser window.matrixclient.isGuest() || window.passwordlessUser
? RegistrationType.Guest ? RegistrationType.Guest
: RegistrationType.Registered : RegistrationType.Registered,
); );
// store the promise to await posthog-tracking-events until the identification is done. // store the promise to await posthog-tracking-events until the identification is done.
this.identificationPromise = this.identifyUser( this.identificationPromise = this.identifyUser(
PosthogAnalytics.getRandomAnalyticsId PosthogAnalytics.getRandomAnalyticsId,
); );
await this.identificationPromise; await this.identificationPromise;
if (this.userRegisteredInThisSession()) { if (this.userRegisteredInThisSession()) {
@@ -395,7 +395,7 @@ export class PosthogAnalytics {
public async trackEvent<E extends IPosthogEvent>( public async trackEvent<E extends IPosthogEvent>(
{ eventName, ...properties }: E, { eventName, ...properties }: E,
options?: CaptureOptions options?: CaptureOptions,
): Promise<void> { ): Promise<void> {
if (this.identificationPromise) { if (this.identificationPromise) {
// only make calls to posthog after the identificaion is done // only make calls to posthog after the identificaion is done

View File

@@ -43,14 +43,14 @@ export class CallEndedTracker {
public cacheParticipantCountChanged(count: number): void { public cacheParticipantCountChanged(count: number): void {
this.cache.maxParticipantsCount = Math.max( this.cache.maxParticipantsCount = Math.max(
count, count,
this.cache.maxParticipantsCount this.cache.maxParticipantsCount,
); );
} }
public track( public track(
callId: string, callId: string,
callParticipantsNow: number, callParticipantsNow: number,
sendInstantly: boolean sendInstantly: boolean,
): void { ): void {
PosthogAnalytics.instance.trackEvent<CallEnded>( PosthogAnalytics.instance.trackEvent<CallEnded>(
{ {
@@ -60,7 +60,7 @@ export class CallEndedTracker {
callParticipantsOnLeave: callParticipantsNow, callParticipantsOnLeave: callParticipantsNow,
callDuration: (Date.now() - this.cache.startTime.getTime()) / 1000, callDuration: (Date.now() - this.cache.startTime.getTime()) / 1000,
}, },
{ send_instantly: sendInstantly } { send_instantly: sendInstantly },
); );
} }
} }

View File

@@ -148,7 +148,7 @@ export class PosthogSpanProcessor implements SpanProcessor {
ratioPeerConnectionToDevices: ratioPeerConnectionToDevices, ratioPeerConnectionToDevices: ratioPeerConnectionToDevices,
}, },
// Send instantly because the window might be closing // Send instantly because the window might be closing
{ send_instantly: true } { send_instantly: true },
); );
} }
} }

View File

@@ -23,7 +23,7 @@ import {
} from "@opentelemetry/sdk-trace-base"; } from "@opentelemetry/sdk-trace-base";
const dumpAttributes = ( const dumpAttributes = (
attr: Attributes attr: Attributes,
): { ): {
key: string; key: string;
type: type:

View File

@@ -22,7 +22,7 @@ limitations under the License.
// Array.prototype.findLastIndex // Array.prototype.findLastIndex
export function findLastIndex<T>( export function findLastIndex<T>(
array: T[], array: T[],
predicate: (item: T, index: number) => boolean predicate: (item: T, index: number) => boolean,
): number | null { ): number | null {
for (let i = array.length - 1; i >= 0; i--) { for (let i = array.length - 1; i >= 0; i--) {
if (predicate(array[i], i)) return i; if (predicate(array[i], i)) return i;
@@ -36,9 +36,9 @@ export function findLastIndex<T>(
*/ */
export const count = <T>( export const count = <T>(
array: T[], array: T[],
predicate: (item: T, index: number) => boolean predicate: (item: T, index: number) => boolean,
): number => ): number =>
array.reduce( array.reduce(
(acc, item, index) => (predicate(item, index) ? acc + 1 : acc), (acc, item, index) => (predicate(item, index) ? acc + 1 : acc),
0 0,
); );

View File

@@ -80,7 +80,7 @@ export const LoginPage: FC = () => {
setLoading(false); setLoading(false);
}); });
}, },
[login, location, history, homeserver, setClient] [login, location, history, homeserver, setClient],
); );
return ( return (

View File

@@ -78,7 +78,7 @@ export const RegisterPage: FC = () => {
password, password,
userName, userName,
recaptchaResponse, recaptchaResponse,
passwordlessUser passwordlessUser,
); );
if (client && client?.groupCallEventHandler && passwordlessUser) { if (client && client?.groupCallEventHandler && passwordlessUser) {
@@ -135,7 +135,7 @@ export const RegisterPage: FC = () => {
execute, execute,
client, client,
setClient, setClient,
] ],
); );
useEffect(() => { useEffect(() => {

View File

@@ -24,13 +24,13 @@ import { Session } from "../ClientContext";
export function useInteractiveLogin(): ( export function useInteractiveLogin(): (
homeserver: string, homeserver: string,
username: string, username: string,
password: string password: string,
) => Promise<[MatrixClient, Session]> { ) => Promise<[MatrixClient, Session]> {
return useCallback< return useCallback<
( (
homeserver: string, homeserver: string,
username: string, username: string,
password: string password: string,
) => Promise<[MatrixClient, Session]> ) => Promise<[MatrixClient, Session]>
>(async (homeserver: string, username: string, password: string) => { >(async (homeserver: string, username: string, password: string) => {
const authClient = createClient({ baseUrl: homeserver }); const authClient = createClient({ baseUrl: homeserver });
@@ -70,7 +70,7 @@ export function useInteractiveLogin(): (
userId: user_id, userId: user_id,
deviceId: device_id, deviceId: device_id,
}, },
false false,
); );
/* eslint-enable camelcase */ /* eslint-enable camelcase */
return [client, session]; return [client, session];

View File

@@ -30,14 +30,14 @@ export const useInteractiveRegistration = (): {
password: string, password: string,
displayName: string, displayName: string,
recaptchaResponse: string, recaptchaResponse: string,
passwordlessUser: boolean passwordlessUser: boolean,
) => Promise<[MatrixClient, Session]>; ) => Promise<[MatrixClient, Session]>;
} => { } => {
const [privacyPolicyUrl, setPrivacyPolicyUrl] = useState<string | undefined>( const [privacyPolicyUrl, setPrivacyPolicyUrl] = useState<string | undefined>(
undefined undefined,
); );
const [recaptchaKey, setRecaptchaKey] = useState<string | undefined>( const [recaptchaKey, setRecaptchaKey] = useState<string | undefined>(
undefined undefined,
); );
const authClient = useRef<MatrixClient>(); const authClient = useRef<MatrixClient>();
@@ -50,7 +50,7 @@ export const useInteractiveRegistration = (): {
useEffect(() => { useEffect(() => {
authClient.current!.registerRequest({}).catch((error) => { authClient.current!.registerRequest({}).catch((error) => {
setPrivacyPolicyUrl( setPrivacyPolicyUrl(
error.data?.params["m.login.terms"]?.policies?.privacy_policy?.en?.url error.data?.params["m.login.terms"]?.policies?.privacy_policy?.en?.url,
); );
setRecaptchaKey(error.data?.params["m.login.recaptcha"]?.public_key); setRecaptchaKey(error.data?.params["m.login.recaptcha"]?.public_key);
}); });
@@ -62,7 +62,7 @@ export const useInteractiveRegistration = (): {
password: string, password: string,
displayName: string, displayName: string,
recaptchaResponse: string, recaptchaResponse: string,
passwordlessUser: boolean passwordlessUser: boolean,
): Promise<[MatrixClient, Session]> => { ): Promise<[MatrixClient, Session]> => {
const interactiveAuth = new InteractiveAuth({ const interactiveAuth = new InteractiveAuth({
matrixClient: authClient.current!, matrixClient: authClient.current!,
@@ -106,7 +106,7 @@ export const useInteractiveRegistration = (): {
userId: user_id, userId: user_id,
deviceId: device_id, deviceId: device_id,
}, },
false false,
); );
await client.setDisplayName(displayName); await client.setDisplayName(displayName);
@@ -129,7 +129,7 @@ export const useInteractiveRegistration = (): {
return [client, session]; return [client, session];
}, },
[] [],
); );
return { privacyPolicyUrl, recaptchaKey, register }; return { privacyPolicyUrl, recaptchaKey, register };

View File

@@ -108,7 +108,7 @@ export function useRecaptcha(sitekey?: string): {
window.grecaptcha.execute(); window.grecaptcha.execute();
const iframe = document.querySelector<HTMLIFrameElement>( const iframe = document.querySelector<HTMLIFrameElement>(
'iframe[src*="recaptcha/api2/bframe"]' 'iframe[src*="recaptcha/api2/bframe"]',
); );
if (iframe?.parentNode?.parentNode) { if (iframe?.parentNode?.parentNode) {

View File

@@ -48,7 +48,7 @@ export function useRegisterPasswordlessUser(): UseRegisterPasswordlessUserType {
randomString(16), randomString(16),
displayName, displayName,
recaptchaResponse, recaptchaResponse,
true true,
); );
setClient({ client, session }); setClient({ client, session });
} catch (e) { } catch (e) {
@@ -56,7 +56,7 @@ export function useRegisterPasswordlessUser(): UseRegisterPasswordlessUserType {
throw e; throw e;
} }
}, },
[execute, reset, register, setClient] [execute, reset, register, setClient],
); );
return { privacyPolicyUrl, registerPasswordlessUser, recaptchaId }; return { privacyPolicyUrl, registerPasswordlessUser, recaptchaId };

View File

@@ -146,7 +146,9 @@ limitations under the License.
.copyButton { .copyButton {
width: 100%; width: 100%;
height: 40px; height: 40px;
transition: border-color 250ms, background-color 250ms; transition:
border-color 250ms,
background-color 250ms;
} }
.copyButton span { .copyButton span {

View File

@@ -94,12 +94,12 @@ export const Button = forwardRef<HTMLButtonElement, Props>(
onPressStart, onPressStart,
...rest ...rest
}, },
ref ref,
) => { ) => {
const buttonRef = useObjectRef<HTMLButtonElement>(ref); const buttonRef = useObjectRef<HTMLButtonElement>(ref);
const { buttonProps } = useButton( const { buttonProps } = useButton(
{ onPress, onPressStart, ...rest }, { onPress, onPressStart, ...rest },
buttonRef buttonRef,
); );
// TODO: react-aria's useButton hook prevents form submission via keyboard // TODO: react-aria's useButton hook prevents form submission via keyboard
@@ -121,7 +121,7 @@ export const Button = forwardRef<HTMLButtonElement, Props>(
{ {
[styles.on]: on, [styles.on]: on,
[styles.off]: off, [styles.off]: off,
} },
)} )}
{...mergeProps(rest, filteredButtonProps)} {...mergeProps(rest, filteredButtonProps)}
ref={buttonRef} ref={buttonRef}
@@ -132,7 +132,7 @@ export const Button = forwardRef<HTMLButtonElement, Props>(
</> </>
</button> </button>
); );
} },
); );
export const MicButton: FC<{ export const MicButton: FC<{

View File

@@ -47,7 +47,7 @@ export const LinkButton: FC<Props> = ({
className={classNames( className={classNames(
variantToClassName[variant || "secondary"], variantToClassName[variant || "secondary"],
size ? sizeToClassName[size] : [], size ? sizeToClassName[size] : [],
className className,
)} )}
to={to} to={to}
{...rest} {...rest}

View File

@@ -57,7 +57,7 @@ export class Config {
} }
async function downloadConfig( async function downloadConfig(
configJsonFilename: string configJsonFilename: string,
): Promise<ConfigOptions> { ): Promise<ConfigOptions> {
const url = new URL(configJsonFilename, window.location.href); const url = new URL(configJsonFilename, window.location.href);
url.searchParams.set("cachebuster", Date.now().toString()); url.searchParams.set("cachebuster", Date.now().toString());

View File

@@ -26,7 +26,7 @@ export const getRoomSharedKeyLocalStorageKey = (roomId: string): string =>
`room-shared-key-${roomId}`; `room-shared-key-${roomId}`;
const useInternalRoomSharedKey = ( const useInternalRoomSharedKey = (
roomId: string roomId: string,
): [string | null, (value: string) => void] => { ): [string | null, (value: string) => void] => {
const key = useMemo(() => getRoomSharedKeyLocalStorageKey(roomId), [roomId]); const key = useMemo(() => getRoomSharedKeyLocalStorageKey(roomId), [roomId]);
const [e2eeEnabled] = useEnableE2EE(); const [e2eeEnabled] = useEnableE2EE();
@@ -68,6 +68,6 @@ export const useIsRoomE2EE = (roomId: string): boolean | null => {
// should inspect the e2eEnabled URL parameter here? // should inspect the e2eEnabled URL parameter here?
return useMemo( return useMemo(
() => widget === null && (room === null || !room.getCanonicalAlias()), () => widget === null && (room === null || !room.getCanonicalAlias()),
[room] [room],
); );
}; };

View File

@@ -36,5 +36,5 @@ export const Form = forwardRef<HTMLFormElement, FormProps>(
{children} {children}
</form> </form>
); );
} },
); );

View File

@@ -74,7 +74,7 @@ const CallTile: FC<CallTileProps> = ({ name, avatarUrl, room }) => {
to={getRelativeRoomUrl( to={getRelativeRoomUrl(
room.roomId, room.roomId,
room.name, room.name,
roomSharedKey ?? undefined roomSharedKey ?? undefined,
)} )}
className={styles.callTileLink} className={styles.callTileLink}
> >
@@ -92,7 +92,7 @@ const CallTile: FC<CallTileProps> = ({ name, avatarUrl, room }) => {
value={getAbsoluteRoomUrl( value={getAbsoluteRoomUrl(
room.roomId, room.roomId,
room.name, room.name,
roomSharedKey ?? undefined roomSharedKey ?? undefined,
)} )}
/> />
</div> </div>

View File

@@ -56,7 +56,7 @@ export const RegisteredView: FC<Props> = ({ client }) => {
useState(false); useState(false);
const onDismissJoinExistingCallModal = useCallback( const onDismissJoinExistingCallModal = useCallback(
() => setJoinExistingCallModalOpen(false), () => setJoinExistingCallModalOpen(false),
[setJoinExistingCallModalOpen] [setJoinExistingCallModalOpen],
); );
const [e2eeEnabled] = useEnableE2EE(); const [e2eeEnabled] = useEnableE2EE();
@@ -77,15 +77,15 @@ export const RegisteredView: FC<Props> = ({ client }) => {
const createRoomResult = await createRoom( const createRoomResult = await createRoom(
client, client,
roomName, roomName,
e2eeEnabled ?? false e2eeEnabled ?? false,
); );
history.push( history.push(
getRelativeRoomUrl( getRelativeRoomUrl(
createRoomResult.roomId, createRoomResult.roomId,
roomName, roomName,
createRoomResult.password createRoomResult.password,
) ),
); );
} }
@@ -102,7 +102,7 @@ export const RegisteredView: FC<Props> = ({ client }) => {
} }
}); });
}, },
[client, history, setJoinExistingCallModalOpen, e2eeEnabled] [client, history, setJoinExistingCallModalOpen, e2eeEnabled],
); );
const recentRooms = useGroupCallRooms(client); const recentRooms = useGroupCallRooms(client);

View File

@@ -57,7 +57,7 @@ export const UnauthenticatedView: FC = () => {
useState(false); useState(false);
const onDismissJoinExistingCallModal = useCallback( const onDismissJoinExistingCallModal = useCallback(
() => setJoinExistingCallModalOpen(false), () => setJoinExistingCallModalOpen(false),
[setJoinExistingCallModalOpen] [setJoinExistingCallModalOpen],
); );
const [onFinished, setOnFinished] = useState<() => void>(); const [onFinished, setOnFinished] = useState<() => void>();
const history = useHistory(); const history = useHistory();
@@ -82,7 +82,7 @@ export const UnauthenticatedView: FC = () => {
randomString(16), randomString(16),
displayName, displayName,
recaptchaResponse, recaptchaResponse,
true true,
); );
let createRoomResult; let createRoomResult;
@@ -90,7 +90,7 @@ export const UnauthenticatedView: FC = () => {
createRoomResult = await createRoom( createRoomResult = await createRoom(
client, client,
roomName, roomName,
e2eeEnabled ?? false e2eeEnabled ?? false,
); );
} catch (error) { } catch (error) {
if (!setClient) { if (!setClient) {
@@ -124,8 +124,8 @@ export const UnauthenticatedView: FC = () => {
getRelativeRoomUrl( getRelativeRoomUrl(
createRoomResult.roomId, createRoomResult.roomId,
roomName, roomName,
createRoomResult.password createRoomResult.password,
) ),
); );
} }
@@ -144,7 +144,7 @@ export const UnauthenticatedView: FC = () => {
setJoinExistingCallModalOpen, setJoinExistingCallModalOpen,
setClient, setClient,
e2eeEnabled, e2eeEnabled,
] ],
); );
return ( return (

View File

@@ -47,7 +47,7 @@ function getLastTs(client: MatrixClient, r: Room): number {
if (r.getMyMembership() !== "join") { if (r.getMyMembership() !== "join") {
const membershipEvent = r.currentState.getStateEvents( const membershipEvent = r.currentState.getStateEvents(
"m.room.member", "m.room.member",
myUserId myUserId,
); );
if (membershipEvent && !Array.isArray(membershipEvent)) { if (membershipEvent && !Array.isArray(membershipEvent)) {
@@ -115,7 +115,7 @@ export function useGroupCallRooms(client: MatrixClient): GroupCallRoom[] {
client.removeListener(GroupCallEventHandlerEvent.Incoming, updateRooms); client.removeListener(GroupCallEventHandlerEvent.Incoming, updateRooms);
client.removeListener( client.removeListener(
GroupCallEventHandlerEvent.Participants, GroupCallEventHandlerEvent.Participants,
updateRooms updateRooms,
); );
}; };
}, [client]); }, [client]);

View File

@@ -68,7 +68,8 @@ limitations under the License.
font-weight: 400; font-weight: 400;
font-display: swap; font-display: swap;
unicode-range: var(--inter-unicode-range); unicode-range: var(--inter-unicode-range);
src: url("/fonts/Inter/Inter-Regular.woff2") format("woff2"), src:
url("/fonts/Inter/Inter-Regular.woff2") format("woff2"),
url("/fonts/Inter/Inter-Regular.woff") format("woff"); url("/fonts/Inter/Inter-Regular.woff") format("woff");
} }
@@ -78,7 +79,8 @@ limitations under the License.
font-weight: 400; font-weight: 400;
font-display: swap; font-display: swap;
unicode-range: var(--inter-unicode-range); unicode-range: var(--inter-unicode-range);
src: url("/fonts/Inter/Inter-Italic.woff2") format("woff2"), src:
url("/fonts/Inter/Inter-Italic.woff2") format("woff2"),
url("/fonts/Inter/Inter-Italic.woff") format("woff"); url("/fonts/Inter/Inter-Italic.woff") format("woff");
} }
@@ -88,7 +90,8 @@ limitations under the License.
font-weight: 500; font-weight: 500;
font-display: swap; font-display: swap;
unicode-range: var(--inter-unicode-range); unicode-range: var(--inter-unicode-range);
src: url("/fonts/Inter/Inter-Medium.woff2") format("woff2"), src:
url("/fonts/Inter/Inter-Medium.woff2") format("woff2"),
url("/fonts/Inter/Inter-Medium.woff") format("woff"); url("/fonts/Inter/Inter-Medium.woff") format("woff");
} }
@@ -98,7 +101,8 @@ limitations under the License.
font-weight: 500; font-weight: 500;
font-display: swap; font-display: swap;
unicode-range: var(--inter-unicode-range); unicode-range: var(--inter-unicode-range);
src: url("/fonts/Inter/Inter-MediumItalic.woff2") format("woff2"), src:
url("/fonts/Inter/Inter-MediumItalic.woff2") format("woff2"),
url("/fonts/Inter/Inter-MediumItalic.woff") format("woff"); url("/fonts/Inter/Inter-MediumItalic.woff") format("woff");
} }
@@ -108,7 +112,8 @@ limitations under the License.
font-weight: 600; font-weight: 600;
font-display: swap; font-display: swap;
unicode-range: var(--inter-unicode-range); unicode-range: var(--inter-unicode-range);
src: url("/fonts/Inter/Inter-SemiBold.woff2") format("woff2"), src:
url("/fonts/Inter/Inter-SemiBold.woff2") format("woff2"),
url("/fonts/Inter/Inter-SemiBold.woff") format("woff"); url("/fonts/Inter/Inter-SemiBold.woff") format("woff");
} }
@@ -118,7 +123,8 @@ limitations under the License.
font-weight: 600; font-weight: 600;
font-display: swap; font-display: swap;
unicode-range: var(--inter-unicode-range); unicode-range: var(--inter-unicode-range);
src: url("/fonts/Inter/Inter-SemiBoldItalic.woff2") format("woff2"), src:
url("/fonts/Inter/Inter-SemiBoldItalic.woff2") format("woff2"),
url("/fonts/Inter/Inter-SemiBoldItalic.woff") format("woff"); url("/fonts/Inter/Inter-SemiBoldItalic.woff") format("woff");
} }
@@ -128,7 +134,8 @@ limitations under the License.
font-weight: 700; font-weight: 700;
font-display: swap; font-display: swap;
unicode-range: var(--inter-unicode-range); unicode-range: var(--inter-unicode-range);
src: url("/fonts/Inter/Inter-Bold.woff2") format("woff2"), src:
url("/fonts/Inter/Inter-Bold.woff2") format("woff2"),
url("/fonts/Inter/Inter-Bold.woff") format("woff"); url("/fonts/Inter/Inter-Bold.woff") format("woff");
} }
@@ -138,7 +145,8 @@ limitations under the License.
font-weight: 700; font-weight: 700;
font-display: swap; font-display: swap;
unicode-range: var(--inter-unicode-range); unicode-range: var(--inter-unicode-range);
src: url("/fonts/Inter/Inter-BoldItalic.woff2") format("woff2"), src:
url("/fonts/Inter/Inter-BoldItalic.woff2") format("woff2"),
url("/fonts/Inter/Inter-BoldItalic.woff") format("woff"); url("/fonts/Inter/Inter-BoldItalic.woff") format("woff");
} }

View File

@@ -99,13 +99,13 @@ export class Initializer {
if (fontScale !== null) { if (fontScale !== null) {
document.documentElement.style.setProperty( document.documentElement.style.setProperty(
"--font-scale", "--font-scale",
fontScale.toString() fontScale.toString(),
); );
} }
if (fonts.length > 0) { if (fonts.length > 0) {
document.documentElement.style.setProperty( document.documentElement.style.setProperty(
"--font-family", "--font-family",
fonts.map((f) => `"${f}"`).join(", ") fonts.map((f) => `"${f}"`).join(", "),
); );
} }

View File

@@ -52,7 +52,7 @@ export const AvatarInputField = forwardRef<HTMLInputElement, Props>(
onRemoveAvatar, onRemoveAvatar,
...rest ...rest
}, },
ref ref,
) => { ) => {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -120,5 +120,5 @@ export const AvatarInputField = forwardRef<HTMLInputElement, Props>(
)} )}
</div> </div>
); );
} },
); );

View File

@@ -85,8 +85,11 @@ limitations under the License.
} }
.inputField label { .inputField label {
transition: font-size 0.25s ease-out 0.1s, color 0.25s ease-out 0.1s, transition:
top 0.25s ease-out 0.1s, background-color 0.25s ease-out 0.1s; font-size 0.25s ease-out 0.1s,
color 0.25s ease-out 0.1s,
top 0.25s ease-out 0.1s,
background-color 0.25s ease-out 0.1s;
color: var(--cpd-color-text-secondary); color: var(--cpd-color-text-secondary);
background-color: transparent; background-color: transparent;
font-size: var(--font-size-body); font-size: var(--font-size-body);
@@ -118,8 +121,11 @@ limitations under the License.
.inputField textarea:not(:placeholder-shown) + label, .inputField textarea:not(:placeholder-shown) + label,
.inputField.prefix textarea + label { .inputField.prefix textarea + label {
background-color: var(--cpd-color-bg-canvas-default); background-color: var(--cpd-color-bg-canvas-default);
transition: font-size 0.25s ease-out 0s, color 0.25s ease-out 0s, transition:
top 0.25s ease-out 0s, background-color 0.25s ease-out 0s; font-size 0.25s ease-out 0s,
color 0.25s ease-out 0s,
top 0.25s ease-out 0s,
background-color 0.25s ease-out 0s;
font-size: var(--font-size-micro); font-size: var(--font-size-micro);
top: -13px; top: -13px;
padding: 0 2px; padding: 0 2px;

View File

@@ -44,7 +44,7 @@ export function FieldRow({
className={classNames( className={classNames(
styles.fieldRow, styles.fieldRow,
{ [styles.rightAlign]: rightAlign }, { [styles.rightAlign]: rightAlign },
className className,
)} )}
> >
{children} {children}
@@ -102,7 +102,7 @@ export const InputField = forwardRef<
disabled, disabled,
...rest ...rest
}, },
ref ref,
) => { ) => {
const descriptionId = useId(); const descriptionId = useId();
@@ -114,7 +114,7 @@ export const InputField = forwardRef<
[styles.prefix]: !!prefix, [styles.prefix]: !!prefix,
[styles.disabled]: disabled, [styles.disabled]: disabled,
}, },
className className,
)} )}
> >
{prefix && <span>{prefix}</span>} {prefix && <span>{prefix}</span>}
@@ -163,7 +163,7 @@ export const InputField = forwardRef<
)} )}
</Field> </Field>
); );
} },
); );
interface ErrorMessageProps { interface ErrorMessageProps {

View File

@@ -38,7 +38,7 @@ export function SelectInput(props: Props): JSX.Element {
const { labelProps, triggerProps, valueProps, menuProps } = useSelect( const { labelProps, triggerProps, valueProps, menuProps } = useSelect(
props, props,
state, state,
ref ref,
); );
const { buttonProps } = useButton(triggerProps, ref); const { buttonProps } = useButton(triggerProps, ref);

View File

@@ -51,7 +51,7 @@ export interface MediaDevices {
// Cargo-culted from @livekit/components-react // Cargo-culted from @livekit/components-react
function useObservableState<T>( function useObservableState<T>(
observable: Observable<T> | undefined, observable: Observable<T> | undefined,
startWith: T startWith: T,
): T { ): T {
const [state, setState] = useState<T>(startWith); const [state, setState] = useState<T>(startWith);
useEffect(() => { useEffect(() => {
@@ -67,7 +67,7 @@ function useMediaDevice(
kind: MediaDeviceKind, kind: MediaDeviceKind,
fallbackDevice: string | undefined, fallbackDevice: string | undefined,
usingNames: boolean, usingNames: boolean,
alwaysDefault: boolean = false alwaysDefault: boolean = false,
): MediaDevice { ): MediaDevice {
// Make sure we don't needlessly reset to a device observer without names, // Make sure we don't needlessly reset to a device observer without names,
// once permissions are already given // once permissions are already given
@@ -83,7 +83,7 @@ function useMediaDevice(
// kind, which then results in multiple permissions requests. // kind, which then results in multiple permissions requests.
const deviceObserver = useMemo( const deviceObserver = useMemo(
() => createMediaDeviceObserver(kind, requestPermissions), () => createMediaDeviceObserver(kind, requestPermissions),
[kind, requestPermissions] [kind, requestPermissions],
); );
const available = useObservableState(deviceObserver, []); const available = useObservableState(deviceObserver, []);
const [selectedId, select] = useState(fallbackDevice); const [selectedId, select] = useState(fallbackDevice);
@@ -143,18 +143,18 @@ export const MediaDevicesProvider: FC<Props> = ({ children }) => {
const audioInput = useMediaDevice( const audioInput = useMediaDevice(
"audioinput", "audioinput",
audioInputSetting, audioInputSetting,
usingNames usingNames,
); );
const audioOutput = useMediaDevice( const audioOutput = useMediaDevice(
"audiooutput", "audiooutput",
audioOutputSetting, audioOutputSetting,
useOutputNames, useOutputNames,
alwaysUseDefaultAudio alwaysUseDefaultAudio,
); );
const videoInput = useMediaDevice( const videoInput = useMediaDevice(
"videoinput", "videoinput",
videoInputSetting, videoInputSetting,
usingNames usingNames,
); );
useEffect(() => { useEffect(() => {
@@ -176,11 +176,11 @@ export const MediaDevicesProvider: FC<Props> = ({ children }) => {
const startUsingDeviceNames = useCallback( const startUsingDeviceNames = useCallback(
() => setNumCallersUsingNames((n) => n + 1), () => setNumCallersUsingNames((n) => n + 1),
[setNumCallersUsingNames] [setNumCallersUsingNames],
); );
const stopUsingDeviceNames = useCallback( const stopUsingDeviceNames = useCallback(
() => setNumCallersUsingNames((n) => n - 1), () => setNumCallersUsingNames((n) => n - 1),
[setNumCallersUsingNames] [setNumCallersUsingNames],
); );
const context: MediaDevices = useMemo( const context: MediaDevices = useMemo(
@@ -197,7 +197,7 @@ export const MediaDevicesProvider: FC<Props> = ({ children }) => {
videoInput, videoInput,
startUsingDeviceNames, startUsingDeviceNames,
stopUsingDeviceNames, stopUsingDeviceNames,
] ],
); );
return ( return (
@@ -218,7 +218,7 @@ export const useMediaDevices = (): MediaDevices =>
*/ */
export const useMediaDeviceNames = ( export const useMediaDeviceNames = (
context: MediaDevices, context: MediaDevices,
enabled = true enabled = true,
): void => ): void =>
useEffect(() => { useEffect(() => {
if (enabled) { if (enabled) {

View File

@@ -42,7 +42,7 @@ export type OpenIDClientParts = Pick<
export function useOpenIDSFU( export function useOpenIDSFU(
client: OpenIDClientParts, client: OpenIDClientParts,
rtcSession: MatrixRTCSession rtcSession: MatrixRTCSession,
): SFUConfig | undefined { ): SFUConfig | undefined {
const [sfuConfig, setSFUConfig] = useState<SFUConfig | undefined>(undefined); const [sfuConfig, setSFUConfig] = useState<SFUConfig | undefined>(undefined);
@@ -62,20 +62,20 @@ export function useOpenIDSFU(
export async function getSFUConfigWithOpenID( export async function getSFUConfigWithOpenID(
client: OpenIDClientParts, client: OpenIDClientParts,
activeFocus: LivekitFocus activeFocus: LivekitFocus,
): Promise<SFUConfig | undefined> { ): Promise<SFUConfig | undefined> {
const openIdToken = await client.getOpenIdToken(); const openIdToken = await client.getOpenIdToken();
logger.debug("Got openID token", openIdToken); logger.debug("Got openID token", openIdToken);
try { try {
logger.info( logger.info(
`Trying to get JWT from call's active focus URL of ${activeFocus.livekit_service_url}...` `Trying to get JWT from call's active focus URL of ${activeFocus.livekit_service_url}...`,
); );
const sfuConfig = await getLiveKitJWT( const sfuConfig = await getLiveKitJWT(
client, client,
activeFocus.livekit_service_url, activeFocus.livekit_service_url,
activeFocus.livekit_alias, activeFocus.livekit_alias,
openIdToken openIdToken,
); );
logger.info(`Got JWT from call's active focus URL.`); logger.info(`Got JWT from call's active focus URL.`);
@@ -83,7 +83,7 @@ export async function getSFUConfigWithOpenID(
} catch (e) { } catch (e) {
logger.warn( logger.warn(
`Failed to get JWT from RTC session's active focus URL of ${activeFocus.livekit_service_url}.`, `Failed to get JWT from RTC session's active focus URL of ${activeFocus.livekit_service_url}.`,
e e,
); );
return undefined; return undefined;
} }
@@ -93,7 +93,7 @@ async function getLiveKitJWT(
client: OpenIDClientParts, client: OpenIDClientParts,
livekitServiceURL: string, livekitServiceURL: string,
roomName: string, roomName: string,
openIDToken: IOpenIDToken openIDToken: IOpenIDToken,
): Promise<SFUConfig> { ): Promise<SFUConfig> {
try { try {
const res = await fetch(livekitServiceURL + "/sfu/get", { const res = await fetch(livekitServiceURL + "/sfu/get", {

View File

@@ -51,7 +51,7 @@ async function doConnect(
livekitRoom: Room, livekitRoom: Room,
sfuConfig: SFUConfig, sfuConfig: SFUConfig,
audioEnabled: boolean, audioEnabled: boolean,
audioOptions: AudioCaptureOptions audioOptions: AudioCaptureOptions,
): Promise<void> { ): Promise<void> {
await livekitRoom!.connect(sfuConfig!.url, sfuConfig!.jwt); await livekitRoom!.connect(sfuConfig!.url, sfuConfig!.jwt);
@@ -76,12 +76,12 @@ export function useECConnectionState(
initialAudioOptions: AudioCaptureOptions, initialAudioOptions: AudioCaptureOptions,
initialAudioEnabled: boolean, initialAudioEnabled: boolean,
livekitRoom?: Room, livekitRoom?: Room,
sfuConfig?: SFUConfig sfuConfig?: SFUConfig,
): ECConnectionState { ): ECConnectionState {
const [connState, setConnState] = useState( const [connState, setConnState] = useState(
sfuConfig && livekitRoom sfuConfig && livekitRoom
? livekitRoom.state ? livekitRoom.state
: ECAddonConnectionState.ECWaiting : ECAddonConnectionState.ECWaiting,
); );
const [isSwitchingFocus, setSwitchingFocus] = useState(false); const [isSwitchingFocus, setSwitchingFocus] = useState(false);
@@ -116,7 +116,7 @@ export function useECConnectionState(
!sfuConfigEquals(currentSFUConfig.current, sfuConfig) !sfuConfigEquals(currentSFUConfig.current, sfuConfig)
) { ) {
logger.info( logger.info(
`SFU config changed! URL was ${currentSFUConfig.current?.url} now ${sfuConfig?.url}` `SFU config changed! URL was ${currentSFUConfig.current?.url} now ${sfuConfig?.url}`,
); );
(async (): Promise<void> => { (async (): Promise<void> => {
@@ -128,7 +128,7 @@ export function useECConnectionState(
livekitRoom!, livekitRoom!,
sfuConfig!, sfuConfig!,
initialAudioEnabled, initialAudioEnabled,
initialAudioOptions initialAudioOptions,
); );
} finally { } finally {
setIsInDoConnect(false); setIsInDoConnect(false);
@@ -149,7 +149,7 @@ export function useECConnectionState(
livekitRoom!, livekitRoom!,
sfuConfig!, sfuConfig!,
initialAudioEnabled, initialAudioEnabled,
initialAudioOptions initialAudioOptions,
).finally(() => setIsInDoConnect(false)); ).finally(() => setIsInDoConnect(false));
} }

View File

@@ -52,7 +52,7 @@ interface UseLivekitResult {
export function useLiveKit( export function useLiveKit(
muteStates: MuteStates, muteStates: MuteStates,
sfuConfig?: SFUConfig, sfuConfig?: SFUConfig,
e2eeConfig?: E2EEConfig e2eeConfig?: E2EEConfig,
): UseLivekitResult { ): UseLivekitResult {
const e2eeOptions = useMemo(() => { const e2eeOptions = useMemo(() => {
if (!e2eeConfig?.sharedKey) return undefined; if (!e2eeConfig?.sharedKey) return undefined;
@@ -67,7 +67,7 @@ export function useLiveKit(
if (!e2eeConfig?.sharedKey || !e2eeOptions) return; if (!e2eeConfig?.sharedKey || !e2eeOptions) return;
(e2eeOptions.keyProvider as ExternalE2EEKeyProvider).setKey( (e2eeOptions.keyProvider as ExternalE2EEKeyProvider).setKey(
e2eeConfig?.sharedKey e2eeConfig?.sharedKey,
); );
}, [e2eeOptions, e2eeConfig?.sharedKey]); }, [e2eeOptions, e2eeConfig?.sharedKey]);
@@ -93,7 +93,7 @@ export function useLiveKit(
}, },
e2ee: e2eeOptions, e2ee: e2eeOptions,
}), }),
[e2eeOptions] [e2eeOptions],
); );
// useECConnectionState creates and publishes an audio track by hand. To keep // useECConnectionState creates and publishes an audio track by hand. To keep
@@ -131,7 +131,7 @@ export function useLiveKit(
}, },
initialMuteStates.current.audio.enabled, initialMuteStates.current.audio.enabled,
room, room,
sfuConfig sfuConfig,
); );
// Unblock audio once the connection is finished // Unblock audio once the connection is finished
@@ -215,11 +215,11 @@ export function useLiveKit(
room.options.audioCaptureDefaults?.deviceId === "default" room.options.audioCaptureDefaults?.deviceId === "default"
) { ) {
const activeMicTrack = Array.from( const activeMicTrack = Array.from(
room.localParticipant.audioTracks.values() room.localParticipant.audioTracks.values(),
).find((d) => d.source === Track.Source.Microphone)?.track; ).find((d) => d.source === Track.Source.Microphone)?.track;
const defaultDevice = device.available.find( const defaultDevice = device.available.find(
(d) => d.deviceId === "default" (d) => d.deviceId === "default",
); );
if ( if (
defaultDevice && defaultDevice &&
@@ -245,7 +245,7 @@ export function useLiveKit(
room room
.switchActiveDevice(kind, id) .switchActiveDevice(kind, id)
.catch((e) => .catch((e) =>
logger.error(`Failed to sync ${kind} device with LiveKit`, e) logger.error(`Failed to sync ${kind} device with LiveKit`, e),
); );
} }
} }

View File

@@ -48,7 +48,7 @@ if (!window.isSecureContext) {
fatalError = new Error( fatalError = new Error(
"This app cannot run in an insecure context. To fix this, access the app " + "This app cannot run in an insecure context. To fix this, access the app " +
"via a local loopback address, or serve it over HTTPS.\n" + "via a local loopback address, or serve it over HTTPS.\n" +
"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts" "https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts",
); );
} else if (!navigator.mediaDevices) { } else if (!navigator.mediaDevices) {
fatalError = new Error("Your browser does not support WebRTC."); fatalError = new Error("Your browser does not support WebRTC.");
@@ -66,5 +66,5 @@ const history = createBrowserHistory();
root.render( root.render(
<StrictMode> <StrictMode>
<App history={history} /> <App history={history} />
</StrictMode> </StrictMode>,
); );

View File

@@ -59,7 +59,7 @@ function waitForSync(client: MatrixClient): Promise<void> {
const onSync = ( const onSync = (
state: SyncState, state: SyncState,
_old: SyncState | null, _old: SyncState | null,
data?: ISyncStateData data?: ISyncStateData,
): void => { ): void => {
if (state === "PREPARED") { if (state === "PREPARED") {
client.removeListener(ClientEvent.Sync, onSync); client.removeListener(ClientEvent.Sync, onSync);
@@ -83,7 +83,7 @@ function secureRandomString(entropyBytes: number): string {
// yet) so just use the built-in one and convert, replace the chars and strip the // yet) so just use the built-in one and convert, replace the chars and strip the
// padding from the end (otherwise we'd need to pull in another dependency). // padding from the end (otherwise we'd need to pull in another dependency).
return btoa( return btoa(
key.reduce((acc, current) => acc + String.fromCharCode(current), "") key.reduce((acc, current) => acc + String.fromCharCode(current), ""),
) )
.replace("+", "-") .replace("+", "-")
.replace("/", "_") .replace("/", "_")
@@ -101,7 +101,7 @@ function secureRandomString(entropyBytes: number): string {
*/ */
export async function initClient( export async function initClient(
clientOptions: ICreateClientOpts, clientOptions: ICreateClientOpts,
restore: boolean restore: boolean,
): Promise<MatrixClient> { ): Promise<MatrixClient> {
await loadOlm(); await loadOlm();
@@ -148,7 +148,7 @@ export async function initClient(
if (indexedDB) { if (indexedDB) {
const cryptoStoreExists = await IndexedDBCryptoStore.exists( const cryptoStoreExists = await IndexedDBCryptoStore.exists(
indexedDB, indexedDB,
CRYPTO_STORE_NAME CRYPTO_STORE_NAME,
); );
if (!cryptoStoreExists) throw new CryptoStoreIntegrityError(); if (!cryptoStoreExists) throw new CryptoStoreIntegrityError();
} else if (localStorage) { } else if (localStorage) {
@@ -164,7 +164,7 @@ export async function initClient(
if (indexedDB) { if (indexedDB) {
baseOpts.cryptoStore = new IndexedDBCryptoStore( baseOpts.cryptoStore = new IndexedDBCryptoStore(
indexedDB, indexedDB,
CRYPTO_STORE_NAME CRYPTO_STORE_NAME,
); );
} else if (localStorage) { } else if (localStorage) {
baseOpts.cryptoStore = new LocalStorageCryptoStore(localStorage); baseOpts.cryptoStore = new LocalStorageCryptoStore(localStorage);
@@ -198,7 +198,7 @@ export async function initClient(
} catch (error) { } catch (error) {
logger.error( logger.error(
"Error starting matrix client store. Falling back to memory store.", "Error starting matrix client store. Falling back to memory store.",
error error,
); );
client.store = new MemoryStore({ localStorage }); client.store = new MemoryStore({ localStorage });
await client.store.startup(); await client.store.startup();
@@ -268,7 +268,7 @@ export function roomNameFromRoomId(roomId: string): string {
.substring(1) .substring(1)
.split("-") .split("-")
.map((part) => .map((part) =>
part.length > 0 ? part.charAt(0).toUpperCase() + part.slice(1) : part part.length > 0 ? part.charAt(0).toUpperCase() + part.slice(1) : part,
) )
.join(" ") .join(" ")
.toLowerCase(); .toLowerCase();
@@ -297,7 +297,7 @@ interface CreateRoomResult {
export async function createRoom( export async function createRoom(
client: MatrixClient, client: MatrixClient,
name: string, name: string,
e2ee: boolean e2ee: boolean,
): Promise<CreateRoomResult> { ): Promise<CreateRoomResult> {
logger.log(`Creating room for group call`); logger.log(`Creating room for group call`);
const createPromise = client.createRoom({ const createPromise = client.createRoom({
@@ -358,7 +358,7 @@ export async function createRoom(
GroupCallType.Video, GroupCallType.Video,
false, false,
GroupCallIntent.Room, GroupCallIntent.Room,
true true,
); );
let password; let password;
@@ -366,7 +366,7 @@ export async function createRoom(
password = secureRandomString(16); password = secureRandomString(16);
setLocalStorageItem( setLocalStorageItem(
getRoomSharedKeyLocalStorageKey(result.room_id), getRoomSharedKeyLocalStorageKey(result.room_id),
password password,
); );
} }
@@ -386,7 +386,7 @@ export async function createRoom(
export function getAbsoluteRoomUrl( export function getAbsoluteRoomUrl(
roomId: string, roomId: string,
roomName?: string, roomName?: string,
password?: string password?: string,
): string { ): string {
return `${window.location.protocol}//${ return `${window.location.protocol}//${
window.location.host window.location.host
@@ -402,7 +402,7 @@ export function getAbsoluteRoomUrl(
export function getRelativeRoomUrl( export function getRelativeRoomUrl(
roomId: string, roomId: string,
roomName?: string, roomName?: string,
password?: string password?: string,
): string { ): string {
// The password shouldn't need URL encoding here (we generate URL-safe ones) but encode // The password shouldn't need URL encoding here (we generate URL-safe ones) but encode
// it in case it came from another client that generated a non url-safe one // it in case it came from another client that generated a non url-safe one
@@ -419,7 +419,7 @@ export function getRelativeRoomUrl(
export function getAvatarUrl( export function getAvatarUrl(
client: MatrixClient, client: MatrixClient,
mxcUrl: string, mxcUrl: string,
avatarSize = 96 avatarSize = 96,
): string { ): string {
const width = Math.floor(avatarSize * window.devicePixelRatio); const width = Math.floor(avatarSize * window.devicePixelRatio);
const height = Math.floor(avatarSize * window.devicePixelRatio); const height = Math.floor(avatarSize * window.devicePixelRatio);

View File

@@ -23,10 +23,10 @@ limitations under the License.
export async function findDeviceByName( export async function findDeviceByName(
deviceName: string, deviceName: string,
kind: MediaDeviceKind, kind: MediaDeviceKind,
devices: MediaDeviceInfo[] devices: MediaDeviceInfo[],
): Promise<string | undefined> { ): Promise<string | undefined> {
const deviceInfo = devices.find( const deviceInfo = devices.find(
(d) => d.kind === kind && d.label === deviceName (d) => d.kind === kind && d.label === deviceName,
); );
return deviceInfo?.deviceId; return deviceInfo?.deviceId;
} }

View File

@@ -48,14 +48,14 @@ export class OTelCall {
public userId: string, public userId: string,
public deviceId: string, public deviceId: string,
public call: MatrixCall, public call: MatrixCall,
public span: Span public span: Span,
) { ) {
if (call.peerConn) { if (call.peerConn) {
this.addCallPeerConnListeners(); this.addCallPeerConnListeners();
} else { } else {
this.call.once( this.call.once(
CallEvent.PeerConnectionCreated, CallEvent.PeerConnectionCreated,
this.addCallPeerConnListeners this.addCallPeerConnListeners,
); );
} }
} }
@@ -63,46 +63,46 @@ export class OTelCall {
public dispose(): void { public dispose(): void {
this.call.peerConn?.removeEventListener( this.call.peerConn?.removeEventListener(
"connectionstatechange", "connectionstatechange",
this.onCallConnectionStateChanged this.onCallConnectionStateChanged,
); );
this.call.peerConn?.removeEventListener( this.call.peerConn?.removeEventListener(
"signalingstatechange", "signalingstatechange",
this.onCallSignalingStateChanged this.onCallSignalingStateChanged,
); );
this.call.peerConn?.removeEventListener( this.call.peerConn?.removeEventListener(
"iceconnectionstatechange", "iceconnectionstatechange",
this.onIceConnectionStateChanged this.onIceConnectionStateChanged,
); );
this.call.peerConn?.removeEventListener( this.call.peerConn?.removeEventListener(
"icegatheringstatechange", "icegatheringstatechange",
this.onIceGatheringStateChanged this.onIceGatheringStateChanged,
); );
this.call.peerConn?.removeEventListener( this.call.peerConn?.removeEventListener(
"icecandidateerror", "icecandidateerror",
this.onIceCandidateError this.onIceCandidateError,
); );
} }
private addCallPeerConnListeners = (): void => { private addCallPeerConnListeners = (): void => {
this.call.peerConn?.addEventListener( this.call.peerConn?.addEventListener(
"connectionstatechange", "connectionstatechange",
this.onCallConnectionStateChanged this.onCallConnectionStateChanged,
); );
this.call.peerConn?.addEventListener( this.call.peerConn?.addEventListener(
"signalingstatechange", "signalingstatechange",
this.onCallSignalingStateChanged this.onCallSignalingStateChanged,
); );
this.call.peerConn?.addEventListener( this.call.peerConn?.addEventListener(
"iceconnectionstatechange", "iceconnectionstatechange",
this.onIceConnectionStateChanged this.onIceConnectionStateChanged,
); );
this.call.peerConn?.addEventListener( this.call.peerConn?.addEventListener(
"icegatheringstatechange", "icegatheringstatechange",
this.onIceGatheringStateChanged this.onIceGatheringStateChanged,
); );
this.call.peerConn?.addEventListener( this.call.peerConn?.addEventListener(
"icecandidateerror", "icecandidateerror",
this.onIceCandidateError this.onIceCandidateError,
); );
}; };
@@ -147,8 +147,8 @@ export class OTelCall {
new OTelCallFeedMediaStreamSpan( new OTelCallFeedMediaStreamSpan(
ElementCallOpenTelemetry.instance, ElementCallOpenTelemetry.instance,
this.span, this.span,
feed feed,
) ),
); );
} }
this.trackFeedSpan.get(feed.stream)?.update(feed); this.trackFeedSpan.get(feed.stream)?.update(feed);
@@ -171,13 +171,13 @@ export class OTelCall {
new OTelCallTransceiverMediaStreamSpan( new OTelCallTransceiverMediaStreamSpan(
ElementCallOpenTelemetry.instance, ElementCallOpenTelemetry.instance,
this.span, this.span,
transStats transStats,
) ),
); );
} }
this.trackTransceiverSpan.get(transStats.mid)?.update(transStats); this.trackTransceiverSpan.get(transStats.mid)?.update(transStats);
prvTransSpan = prvTransSpan.filter( prvTransSpan = prvTransSpan.filter(
(prvStreamId) => prvStreamId !== transStats.mid (prvStreamId) => prvStreamId !== transStats.mid,
); );
}); });
@@ -190,7 +190,7 @@ export class OTelCall {
public end(): void { public end(): void {
this.trackFeedSpan.forEach((feedSpan) => feedSpan.end()); this.trackFeedSpan.forEach((feedSpan) => feedSpan.end());
this.trackTransceiverSpan.forEach((transceiverSpan) => this.trackTransceiverSpan.forEach((transceiverSpan) =>
transceiverSpan.end() transceiverSpan.end(),
); );
this.span.end(); this.span.end();
} }

View File

@@ -32,11 +32,11 @@ export abstract class OTelCallAbstractMediaStreamSpan {
public constructor( public constructor(
protected readonly oTel: ElementCallOpenTelemetry, protected readonly oTel: ElementCallOpenTelemetry,
protected readonly callSpan: Span, protected readonly callSpan: Span,
protected readonly type: string protected readonly type: string,
) { ) {
const ctx = opentelemetry.trace.setSpan( const ctx = opentelemetry.trace.setSpan(
opentelemetry.context.active(), opentelemetry.context.active(),
callSpan callSpan,
); );
const options = { const options = {
links: [ links: [
@@ -54,7 +54,7 @@ export abstract class OTelCallAbstractMediaStreamSpan {
if (!this.trackSpans.has(t.id)) { if (!this.trackSpans.has(t.id)) {
this.trackSpans.set( this.trackSpans.set(
t.id, t.id,
new OTelCallMediaStreamTrackSpan(this.oTel, this.span, t) new OTelCallMediaStreamTrackSpan(this.oTel, this.span, t),
); );
} }
this.trackSpans.get(t.id)?.update(t); this.trackSpans.get(t.id)?.update(t);

View File

@@ -29,7 +29,7 @@ export class OTelCallFeedMediaStreamSpan extends OTelCallAbstractMediaStreamSpan
public constructor( public constructor(
protected readonly oTel: ElementCallOpenTelemetry, protected readonly oTel: ElementCallOpenTelemetry,
protected readonly callSpan: Span, protected readonly callSpan: Span,
callFeed: CallFeedStats callFeed: CallFeedStats,
) { ) {
const postFix = const postFix =
callFeed.type === "local" && callFeed.prefix === "from-call-feed" callFeed.type === "local" && callFeed.prefix === "from-call-feed"

View File

@@ -26,11 +26,11 @@ export class OTelCallMediaStreamTrackSpan {
public constructor( public constructor(
protected readonly oTel: ElementCallOpenTelemetry, protected readonly oTel: ElementCallOpenTelemetry,
protected readonly streamSpan: Span, protected readonly streamSpan: Span,
data: TrackStats data: TrackStats,
) { ) {
const ctx = opentelemetry.trace.setSpan( const ctx = opentelemetry.trace.setSpan(
opentelemetry.context.active(), opentelemetry.context.active(),
streamSpan streamSpan,
); );
const options = { const options = {
links: [ links: [

View File

@@ -32,7 +32,7 @@ export class OTelCallTransceiverMediaStreamSpan extends OTelCallAbstractMediaStr
public constructor( public constructor(
protected readonly oTel: ElementCallOpenTelemetry, protected readonly oTel: ElementCallOpenTelemetry,
protected readonly callSpan: Span, protected readonly callSpan: Span,
stats: TransceiverStats stats: TransceiverStats,
) { ) {
super(oTel, callSpan, `matrix.call.transceiver.${stats.mid}`); super(oTel, callSpan, `matrix.call.transceiver.${stats.mid}`);
this.span.setAttribute("transceiver.mid", stats.mid); this.span.setAttribute("transceiver.mid", stats.mid);

View File

@@ -62,7 +62,10 @@ export class OTelGroupCallMembership {
}; };
private readonly speakingSpans = new Map<RoomMember, Map<string, Span>>(); private readonly speakingSpans = new Map<RoomMember, Map<string, Span>>();
public constructor(private groupCall: GroupCall, client: MatrixClient) { public constructor(
private groupCall: GroupCall,
client: MatrixClient,
) {
const clientId = client.getUserId(); const clientId = client.getUserId();
if (clientId) { if (clientId) {
this.myUserId = clientId; this.myUserId = clientId;
@@ -79,7 +82,7 @@ export class OTelGroupCallMembership {
public dispose(): void { public dispose(): void {
this.groupCall.removeListener( this.groupCall.removeListener(
GroupCallEvent.CallsChanged, GroupCallEvent.CallsChanged,
this.onCallsChanged this.onCallsChanged,
); );
} }
@@ -93,22 +96,22 @@ export class OTelGroupCallMembership {
// Create the main span that tracks the time we intend to be in the call // Create the main span that tracks the time we intend to be in the call
this.callMembershipSpan = this.callMembershipSpan =
ElementCallOpenTelemetry.instance.tracer.startSpan( ElementCallOpenTelemetry.instance.tracer.startSpan(
"matrix.groupCallMembership" "matrix.groupCallMembership",
); );
this.callMembershipSpan.setAttribute( this.callMembershipSpan.setAttribute(
"matrix.confId", "matrix.confId",
this.groupCall.groupCallId this.groupCall.groupCallId,
); );
this.callMembershipSpan.setAttribute("matrix.userId", this.myUserId); this.callMembershipSpan.setAttribute("matrix.userId", this.myUserId);
this.callMembershipSpan.setAttribute("matrix.deviceId", this.myDeviceId); this.callMembershipSpan.setAttribute("matrix.deviceId", this.myDeviceId);
this.callMembershipSpan.setAttribute( this.callMembershipSpan.setAttribute(
"matrix.displayName", "matrix.displayName",
this.myMember ? this.myMember.name : "unknown-name" this.myMember ? this.myMember.name : "unknown-name",
); );
this.groupCallContext = opentelemetry.trace.setSpan( this.groupCallContext = opentelemetry.trace.setSpan(
opentelemetry.context.active(), opentelemetry.context.active(),
this.callMembershipSpan this.callMembershipSpan,
); );
this.callMembershipSpan?.addEvent("matrix.joinCall"); this.callMembershipSpan?.addEvent("matrix.joinCall");
@@ -138,7 +141,7 @@ export class OTelGroupCallMembership {
this.callMembershipSpan?.addEvent( this.callMembershipSpan?.addEvent(
`matrix.roomStateEvent_${event.getType()}`, `matrix.roomStateEvent_${event.getType()}`,
ObjectFlattener.flattenVoipEvent(event.getContent()) ObjectFlattener.flattenVoipEvent(event.getContent()),
); );
} }
@@ -150,7 +153,7 @@ export class OTelGroupCallMembership {
const span = ElementCallOpenTelemetry.instance.tracer.startSpan( const span = ElementCallOpenTelemetry.instance.tracer.startSpan(
`matrix.call`, `matrix.call`,
undefined, undefined,
this.groupCallContext this.groupCallContext,
); );
// XXX: anonymity // XXX: anonymity
span.setAttribute("matrix.call.target.userId", userId); span.setAttribute("matrix.call.target.userId", userId);
@@ -160,7 +163,7 @@ export class OTelGroupCallMembership {
span.setAttribute("matrix.call.target.displayName", displayName); span.setAttribute("matrix.call.target.displayName", displayName);
this.callsByCallId.set( this.callsByCallId.set(
call.callId, call.callId,
new OTelCall(userId, deviceId, call, span) new OTelCall(userId, deviceId, call, span),
); );
} }
} }
@@ -210,12 +213,12 @@ export class OTelGroupCallMembership {
if (event.type === "toDevice") { if (event.type === "toDevice") {
callTrackingInfo.span.addEvent( callTrackingInfo.span.addEvent(
`matrix.sendToDeviceEvent_${event.eventType}`, `matrix.sendToDeviceEvent_${event.eventType}`,
ObjectFlattener.flattenVoipEvent(event) ObjectFlattener.flattenVoipEvent(event),
); );
} else if (event.type === "sendEvent") { } else if (event.type === "sendEvent") {
callTrackingInfo.span.addEvent( callTrackingInfo.span.addEvent(
`matrix.sendToRoomEvent_${event.eventType}`, `matrix.sendToRoomEvent_${event.eventType}`,
ObjectFlattener.flattenVoipEvent(event) ObjectFlattener.flattenVoipEvent(event),
); );
} }
} }
@@ -239,7 +242,7 @@ export class OTelGroupCallMembership {
"matrix.receive_voip_event_unknown_callid", "matrix.receive_voip_event_unknown_callid",
{ {
"sender.userId": event.getSender(), "sender.userId": event.getSender(),
} },
); );
logger.error("Received call event for unknown call ID " + callId); logger.error("Received call event for unknown call ID " + callId);
return; return;
@@ -284,7 +287,7 @@ export class OTelGroupCallMembership {
public onSpeaking( public onSpeaking(
member: RoomMember, member: RoomMember,
deviceId: string, deviceId: string,
speaking: boolean speaking: boolean,
): void { ): void {
if (speaking) { if (speaking) {
// Ensure that there's an audio activity span for this speaker // Ensure that there's an audio activity span for this speaker
@@ -298,7 +301,7 @@ export class OTelGroupCallMembership {
const span = ElementCallOpenTelemetry.instance.tracer.startSpan( const span = ElementCallOpenTelemetry.instance.tracer.startSpan(
"matrix.audioActivity", "matrix.audioActivity",
undefined, undefined,
this.groupCallContext this.groupCallContext,
); );
span.setAttribute("matrix.userId", member.userId); span.setAttribute("matrix.userId", member.userId);
span.setAttribute("matrix.displayName", member.rawDisplayName); span.setAttribute("matrix.displayName", member.rawDisplayName);
@@ -336,7 +339,7 @@ export class OTelGroupCallMembership {
} }
public onCallFeedStatsReport( public onCallFeedStatsReport(
report: GroupCallStatsReport<CallFeedReport> report: GroupCallStatsReport<CallFeedReport>,
): void { ): void {
if (!ElementCallOpenTelemetry.instance) return; if (!ElementCallOpenTelemetry.instance) return;
let call: OTelCall | undefined; let call: OTelCall | undefined;
@@ -354,10 +357,10 @@ export class OTelGroupCallMembership {
"call.opponentMemberId": report.report?.opponentMemberId "call.opponentMemberId": report.report?.opponentMemberId
? report.report?.opponentMemberId ? report.report?.opponentMemberId
: "unknown", : "unknown",
} },
); );
logger.error( logger.error(
`Received ${OTelStatsReportType.CallFeedReport} with unknown call ID: ${callId}` `Received ${OTelStatsReportType.CallFeedReport} with unknown call ID: ${callId}`,
); );
return; return;
} else { } else {
@@ -367,26 +370,26 @@ export class OTelGroupCallMembership {
} }
public onConnectionStatsReport( public onConnectionStatsReport(
statsReport: GroupCallStatsReport<ConnectionStatsReport> statsReport: GroupCallStatsReport<ConnectionStatsReport>,
): void { ): void {
this.buildCallStatsSpan( this.buildCallStatsSpan(
OTelStatsReportType.ConnectionReport, OTelStatsReportType.ConnectionReport,
statsReport.report statsReport.report,
); );
} }
public onByteSentStatsReport( public onByteSentStatsReport(
statsReport: GroupCallStatsReport<ByteSentStatsReport> statsReport: GroupCallStatsReport<ByteSentStatsReport>,
): void { ): void {
this.buildCallStatsSpan( this.buildCallStatsSpan(
OTelStatsReportType.ByteSentReport, OTelStatsReportType.ByteSentReport,
statsReport.report statsReport.report,
); );
} }
public buildCallStatsSpan( public buildCallStatsSpan(
type: OTelStatsReportType, type: OTelStatsReportType,
report: ByteSentStatsReport | ConnectionStatsReport report: ByteSentStatsReport | ConnectionStatsReport,
): void { ): void {
if (!ElementCallOpenTelemetry.instance) return; if (!ElementCallOpenTelemetry.instance) return;
let call: OTelCall | undefined; let call: OTelCall | undefined;
@@ -409,7 +412,7 @@ export class OTelGroupCallMembership {
const data = ObjectFlattener.flattenReportObject(type, report); const data = ObjectFlattener.flattenReportObject(type, report);
const ctx = opentelemetry.trace.setSpan( const ctx = opentelemetry.trace.setSpan(
opentelemetry.context.active(), opentelemetry.context.active(),
call.span call.span,
); );
const options = { const options = {
@@ -423,20 +426,20 @@ export class OTelGroupCallMembership {
const span = ElementCallOpenTelemetry.instance.tracer.startSpan( const span = ElementCallOpenTelemetry.instance.tracer.startSpan(
type, type,
options, options,
ctx ctx,
); );
span.setAttribute("matrix.callId", callId ?? "unknown"); span.setAttribute("matrix.callId", callId ?? "unknown");
span.setAttribute( span.setAttribute(
"matrix.opponentMemberId", "matrix.opponentMemberId",
report.opponentMemberId ? report.opponentMemberId : "unknown" report.opponentMemberId ? report.opponentMemberId : "unknown",
); );
span.addEvent("matrix.call.connection_stats_event", data); span.addEvent("matrix.call.connection_stats_event", data);
span.end(); span.end();
} }
public onSummaryStatsReport( public onSummaryStatsReport(
statsReport: GroupCallStatsReport<SummaryStatsReport> statsReport: GroupCallStatsReport<SummaryStatsReport>,
): void { ): void {
if (!ElementCallOpenTelemetry.instance) return; if (!ElementCallOpenTelemetry.instance) return;
@@ -445,12 +448,12 @@ export class OTelGroupCallMembership {
if (this.statsReportSpan.span === undefined && this.callMembershipSpan) { if (this.statsReportSpan.span === undefined && this.callMembershipSpan) {
const ctx = setSpan( const ctx = setSpan(
opentelemetry.context.active(), opentelemetry.context.active(),
this.callMembershipSpan this.callMembershipSpan,
); );
const span = ElementCallOpenTelemetry.instance?.tracer.startSpan( const span = ElementCallOpenTelemetry.instance?.tracer.startSpan(
"matrix.groupCallMembership.summaryReport", "matrix.groupCallMembership.summaryReport",
undefined, undefined,
ctx ctx,
); );
if (span === undefined) { if (span === undefined) {
return; return;
@@ -459,7 +462,7 @@ export class OTelGroupCallMembership {
span.setAttribute("matrix.userId", this.myUserId); span.setAttribute("matrix.userId", this.myUserId);
span.setAttribute( span.setAttribute(
"matrix.displayName", "matrix.displayName",
this.myMember ? this.myMember.name : "unknown-name" this.myMember ? this.myMember.name : "unknown-name",
); );
span.addEvent(type, data); span.addEvent(type, data);
span.end(); span.end();

View File

@@ -25,7 +25,7 @@ import {
export class ObjectFlattener { export class ObjectFlattener {
public static flattenReportObject( public static flattenReportObject(
prefix: string, prefix: string,
report: ConnectionStatsReport | ByteSentStatsReport report: ConnectionStatsReport | ByteSentStatsReport,
): Attributes { ): Attributes {
const flatObject = {}; const flatObject = {};
ObjectFlattener.flattenObjectRecursive(report, flatObject, `${prefix}.`, 0); ObjectFlattener.flattenObjectRecursive(report, flatObject, `${prefix}.`, 0);
@@ -33,27 +33,27 @@ export class ObjectFlattener {
} }
public static flattenByteSentStatsReportObject( public static flattenByteSentStatsReportObject(
statsReport: GroupCallStatsReport<ByteSentStatsReport> statsReport: GroupCallStatsReport<ByteSentStatsReport>,
): Attributes { ): Attributes {
const flatObject = {}; const flatObject = {};
ObjectFlattener.flattenObjectRecursive( ObjectFlattener.flattenObjectRecursive(
statsReport.report, statsReport.report,
flatObject, flatObject,
"matrix.stats.bytesSent.", "matrix.stats.bytesSent.",
0 0,
); );
return flatObject; return flatObject;
} }
public static flattenSummaryStatsReportObject( public static flattenSummaryStatsReportObject(
statsReport: GroupCallStatsReport<SummaryStatsReport> statsReport: GroupCallStatsReport<SummaryStatsReport>,
): Attributes { ): Attributes {
const flatObject = {}; const flatObject = {};
ObjectFlattener.flattenObjectRecursive( ObjectFlattener.flattenObjectRecursive(
statsReport.report, statsReport.report,
flatObject, flatObject,
"matrix.stats.summary.", "matrix.stats.summary.",
0 0,
); );
return flatObject; return flatObject;
} }
@@ -67,7 +67,7 @@ export class ObjectFlattener {
event as unknown as Record<string, unknown>, // XXX Types event as unknown as Record<string, unknown>, // XXX Types
flatObject, flatObject,
"matrix.event.", "matrix.event.",
0 0,
); );
return flatObject; return flatObject;
@@ -77,12 +77,12 @@ export class ObjectFlattener {
obj: Object, obj: Object,
flatObject: Attributes, flatObject: Attributes,
prefix: string, prefix: string,
depth: number depth: number,
): void { ): void {
if (depth > 10) if (depth > 10)
throw new Error( throw new Error(
"Depth limit exceeded: aborting VoipEvent recursion. Prefix is " + "Depth limit exceeded: aborting VoipEvent recursion. Prefix is " +
prefix prefix,
); );
let entries; let entries;
if (obj instanceof Map) { if (obj instanceof Map) {
@@ -101,7 +101,7 @@ export class ObjectFlattener {
v, v,
flatObject, flatObject,
prefix + k + ".", prefix + k + ".",
depth + 1 depth + 1,
); );
} }
} }

View File

@@ -50,7 +50,7 @@ export class ElementCallOpenTelemetry {
sharedInstance = new ElementCallOpenTelemetry( sharedInstance = new ElementCallOpenTelemetry(
config.opentelemetry?.collector_url, config.opentelemetry?.collector_url,
config.rageshake?.submit_url config.rageshake?.submit_url,
); );
} }
} }
@@ -61,7 +61,7 @@ export class ElementCallOpenTelemetry {
private constructor( private constructor(
collectorUrl: string | undefined, collectorUrl: string | undefined,
rageshakeUrl: string | undefined rageshakeUrl: string | undefined,
) { ) {
// This is how we can make Jaeger show a reasonable service in the dropdown on the left. // This is how we can make Jaeger show a reasonable service in the dropdown on the left.
const providerConfig = { const providerConfig = {
@@ -77,7 +77,7 @@ export class ElementCallOpenTelemetry {
url: collectorUrl, url: collectorUrl,
}); });
this._provider.addSpanProcessor( this._provider.addSpanProcessor(
new SimpleSpanProcessor(this.otlpExporter) new SimpleSpanProcessor(this.otlpExporter),
); );
} else { } else {
logger.info("OTLP collector disabled"); logger.info("OTLP collector disabled");
@@ -93,7 +93,7 @@ export class ElementCallOpenTelemetry {
this._tracer = opentelemetry.trace.getTracer( this._tracer = opentelemetry.trace.getTracer(
// This is not the serviceName shown in jaeger // This is not the serviceName shown in jaeger
"my-element-call-otl-tracer" "my-element-call-otl-tracer",
); );
} }

View File

@@ -40,7 +40,7 @@ export const Popover = forwardRef<HTMLDivElement, Props>(
shouldCloseOnBlur: true, shouldCloseOnBlur: true,
isDismissable: true, isDismissable: true,
}, },
popoverRef popoverRef,
); );
return ( return (
@@ -56,5 +56,5 @@ export const Popover = forwardRef<HTMLDivElement, Props>(
</div> </div>
</FocusScope> </FocusScope>
); );
} },
); );

View File

@@ -43,7 +43,7 @@ export const PopoverMenuTrigger = forwardRef<
const { menuTriggerProps, menuProps } = useMenuTrigger( const { menuTriggerProps, menuProps } = useMenuTrigger(
{}, {},
popoverMenuState, popoverMenuState,
buttonRef buttonRef,
); );
const popoverRef = useRef(null); const popoverRef = useRef(null);
@@ -62,7 +62,7 @@ export const PopoverMenuTrigger = forwardRef<
typeof children[1] !== "function" typeof children[1] !== "function"
) { ) {
throw new Error( throw new Error(
"PopoverMenu must have two props. The first being a button and the second being a render prop." "PopoverMenu must have two props. The first being a button and the second being a render prop.",
); );
} }

View File

@@ -63,7 +63,7 @@ export function useProfile(client: MatrixClient | undefined): UseProfile {
useEffect(() => { useEffect(() => {
const onChangeUser = ( const onChangeUser = (
_event: MatrixEvent | undefined, _event: MatrixEvent | undefined,
{ displayName, avatarUrl }: User { displayName, avatarUrl }: User,
): void => { ): void => {
setState({ setState({
success: false, success: false,
@@ -108,9 +108,8 @@ export function useProfile(client: MatrixClient | undefined): UseProfile {
if (removeAvatar) { if (removeAvatar) {
await client.setAvatarUrl(""); await client.setAvatarUrl("");
} else if (avatar) { } else if (avatar) {
({ content_uri: mxcAvatarUrl } = await client.uploadContent( ({ content_uri: mxcAvatarUrl } =
avatar await client.uploadContent(avatar));
));
await client.setAvatarUrl(mxcAvatarUrl); await client.setAvatarUrl(mxcAvatarUrl);
} }
@@ -135,7 +134,7 @@ export function useProfile(client: MatrixClient | undefined): UseProfile {
logger.error("Client not initialized before calling saveProfile"); logger.error("Client not initialized before calling saveProfile");
} }
}, },
[client] [client],
); );
return { return {

View File

@@ -40,14 +40,14 @@ export const AppSelectionModal: FC<Props> = ({ roomId }) => {
e.stopPropagation(); e.stopPropagation();
setOpen(false); setOpen(false);
}, },
[setOpen] [setOpen],
); );
const roomSharedKey = useRoomSharedKey(roomId ?? ""); const roomSharedKey = useRoomSharedKey(roomId ?? "");
const roomIsEncrypted = useIsRoomE2EE(roomId ?? ""); const roomIsEncrypted = useIsRoomE2EE(roomId ?? "");
if (roomIsEncrypted && roomSharedKey === undefined) { if (roomIsEncrypted && roomSharedKey === undefined) {
logger.error( logger.error(
"Generating app redirect URL for encrypted room but don't have key available!" "Generating app redirect URL for encrypted room but don't have key available!",
); );
} }
@@ -60,7 +60,7 @@ export const AppSelectionModal: FC<Props> = ({ roomId }) => {
const url = new URL( const url = new URL(
roomId === null roomId === null
? window.location.href ? window.location.href
: getAbsoluteRoomUrl(roomId, undefined, roomSharedKey ?? undefined) : getAbsoluteRoomUrl(roomId, undefined, roomSharedKey ?? undefined),
); );
// Edit the URL to prevent the app selection prompt from appearing a second // Edit the URL to prevent the app selection prompt from appearing a second
// time within the app, and to keep the user confined to the current room // time within the app, and to keep the user confined to the current room

View File

@@ -64,7 +64,7 @@ export const CallEndedView: FC<Props> = ({
PosthogAnalytics.instance.eventQualitySurvey.track( PosthogAnalytics.instance.eventQualitySurvey.track(
endedCallId, endedCallId,
feedbackText, feedbackText,
starRating starRating,
); );
setSubmitting(true); setSubmitting(true);
@@ -83,7 +83,7 @@ export const CallEndedView: FC<Props> = ({
}, 1000); }, 1000);
}, 1000); }, 1000);
}, },
[endedCallId, history, isPasswordlessUser, confineToRoom, starRating] [endedCallId, history, isPasswordlessUser, confineToRoom, starRating],
); );
const createAccountDialog = isPasswordlessUser && ( const createAccountDialog = isPasswordlessUser && (

View File

@@ -47,7 +47,7 @@ export function GroupCallLoader({
ev.preventDefault(); ev.preventDefault();
history.push("/"); history.push("/");
}, },
[history] [history],
); );
switch (groupCallState.kind) { switch (groupCallState.kind) {
@@ -66,7 +66,7 @@ export function GroupCallLoader({
<Heading>{t("Call not found")}</Heading> <Heading>{t("Call not found")}</Heading>
<Text> <Text>
{t( {t(
"Calls are now end-to-end encrypted and need to be created from the home page. This helps make sure everyone's using the same encryption key." "Calls are now end-to-end encrypted and need to be created from the home page. This helps make sure everyone's using the same encryption key.",
)} )}
</Text> </Text>
{/* XXX: A 'create it for me' button would be the obvious UX here. Two screens already have {/* XXX: A 'create it for me' button would be the obvious UX here. Two screens already have

View File

@@ -111,7 +111,7 @@ export const GroupCallView: FC<Props> = ({
// Count each member only once, regardless of how many devices they use // Count each member only once, regardless of how many devices they use
const participantCount = useMemo( const participantCount = useMemo(
() => new Set<string>(memberships.map((m) => m.sender!)).size, () => new Set<string>(memberships.map((m) => m.sender!)).size,
[memberships] [memberships],
); );
const deviceContext = useMediaDevices(); const deviceContext = useMediaDevices();
@@ -126,7 +126,7 @@ export const GroupCallView: FC<Props> = ({
if (widget && preload) { if (widget && preload) {
// In preload mode, wait for a join action before entering // In preload mode, wait for a join action before entering
const onJoin = async ( const onJoin = async (
ev: CustomEvent<IWidgetApiRequest> ev: CustomEvent<IWidgetApiRequest>,
): Promise<void> => { ): Promise<void> => {
// XXX: I think this is broken currently - LiveKit *won't* request // XXX: I think this is broken currently - LiveKit *won't* request
// permissions and give you device names unless you specify a kind, but // permissions and give you device names unless you specify a kind, but
@@ -143,14 +143,14 @@ export const GroupCallView: FC<Props> = ({
const deviceId = await findDeviceByName( const deviceId = await findDeviceByName(
audioInput, audioInput,
"audioinput", "audioinput",
devices devices,
); );
if (!deviceId) { if (!deviceId) {
logger.warn("Unknown audio input: " + audioInput); logger.warn("Unknown audio input: " + audioInput);
latestMuteStates.current!.audio.setEnabled?.(false); latestMuteStates.current!.audio.setEnabled?.(false);
} else { } else {
logger.debug( logger.debug(
`Found audio input ID ${deviceId} for name ${audioInput}` `Found audio input ID ${deviceId} for name ${audioInput}`,
); );
latestDevices.current!.audioInput.select(deviceId); latestDevices.current!.audioInput.select(deviceId);
latestMuteStates.current!.audio.setEnabled?.(true); latestMuteStates.current!.audio.setEnabled?.(true);
@@ -163,14 +163,14 @@ export const GroupCallView: FC<Props> = ({
const deviceId = await findDeviceByName( const deviceId = await findDeviceByName(
videoInput, videoInput,
"videoinput", "videoinput",
devices devices,
); );
if (!deviceId) { if (!deviceId) {
logger.warn("Unknown video input: " + videoInput); logger.warn("Unknown video input: " + videoInput);
latestMuteStates.current!.video.setEnabled?.(false); latestMuteStates.current!.video.setEnabled?.(false);
} else { } else {
logger.debug( logger.debug(
`Found video input ID ${deviceId} for name ${videoInput}` `Found video input ID ${deviceId} for name ${videoInput}`,
); );
latestDevices.current!.videoInput.select(deviceId); latestDevices.current!.videoInput.select(deviceId);
latestMuteStates.current!.video.setEnabled?.(true); latestMuteStates.current!.video.setEnabled?.(true);
@@ -182,7 +182,7 @@ export const GroupCallView: FC<Props> = ({
PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date()); PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date());
// we only have room sessions right now, so call ID is the emprty string - we use the room ID // we only have room sessions right now, so call ID is the emprty string - we use the room ID
PosthogAnalytics.instance.eventCallStarted.track( PosthogAnalytics.instance.eventCallStarted.track(
rtcSession.room.roomId rtcSession.room.roomId,
); );
await Promise.all([ await Promise.all([
@@ -213,7 +213,7 @@ export const GroupCallView: FC<Props> = ({
PosthogAnalytics.instance.eventCallEnded.track( PosthogAnalytics.instance.eventCallEnded.track(
rtcSession.room.roomId, rtcSession.room.roomId,
rtcSession.memberships.length, rtcSession.memberships.length,
sendInstantly sendInstantly,
); );
await leaveRTCSession(rtcSession); await leaveRTCSession(rtcSession);
@@ -237,13 +237,13 @@ export const GroupCallView: FC<Props> = ({
history.push("/"); history.push("/");
} }
}, },
[rtcSession, isPasswordlessUser, confineToRoom, history] [rtcSession, isPasswordlessUser, confineToRoom, history],
); );
useEffect(() => { useEffect(() => {
if (widget && isJoined) { if (widget && isJoined) {
const onHangup = async ( const onHangup = async (
ev: CustomEvent<IWidgetApiRequest> ev: CustomEvent<IWidgetApiRequest>,
): Promise<void> => { ): Promise<void> => {
leaveRTCSession(rtcSession); leaveRTCSession(rtcSession);
widget!.api.transport.reply(ev.detail, {}); widget!.api.transport.reply(ev.detail, {});
@@ -260,7 +260,7 @@ export const GroupCallView: FC<Props> = ({
const e2eeConfig = useMemo( const e2eeConfig = useMemo(
() => (e2eeSharedKey ? { sharedKey: e2eeSharedKey } : undefined), () => (e2eeSharedKey ? { sharedKey: e2eeSharedKey } : undefined),
[e2eeSharedKey] [e2eeSharedKey],
); );
const onReconnect = useCallback(() => { const onReconnect = useCallback(() => {
@@ -274,12 +274,12 @@ export const GroupCallView: FC<Props> = ({
const [shareModalOpen, setInviteModalOpen] = useState(false); const [shareModalOpen, setInviteModalOpen] = useState(false);
const onDismissInviteModal = useCallback( const onDismissInviteModal = useCallback(
() => setInviteModalOpen(false), () => setInviteModalOpen(false),
[setInviteModalOpen] [setInviteModalOpen],
); );
const onShareClickFn = useCallback( const onShareClickFn = useCallback(
() => setInviteModalOpen(true), () => setInviteModalOpen(true),
[setInviteModalOpen] [setInviteModalOpen],
); );
const onShareClick = joinRule === JoinRule.Public ? onShareClickFn : null; const onShareClick = joinRule === JoinRule.Public ? onShareClickFn : null;
@@ -288,7 +288,7 @@ export const GroupCallView: FC<Props> = ({
ev.preventDefault(); ev.preventDefault();
history.push("/"); history.push("/");
}, },
[history] [history],
); );
const { t } = useTranslation(); const { t } = useTranslation();
@@ -298,7 +298,7 @@ export const GroupCallView: FC<Props> = ({
<ErrorView <ErrorView
error={ error={
new Error( new Error(
"No E2EE key provided: please make sure the URL you're using to join this call has been retrieved using the in-app button." "No E2EE key provided: please make sure the URL you're using to join this call has been retrieved using the in-app button.",
) )
} }
/> />
@@ -309,7 +309,7 @@ export const GroupCallView: FC<Props> = ({
<Heading>Incompatible Browser</Heading> <Heading>Incompatible Browser</Heading>
<Text> <Text>
{t( {t(
"Your web browser does not support media end-to-end encryption. Supported Browsers are Chrome, Safari, Firefox >=117" "Your web browser does not support media end-to-end encryption. Supported Browsers are Chrome, Safari, Firefox >=117",
)} )}
</Text> </Text>
<Link href="/" onClick={onHomeClick}> <Link href="/" onClick={onHomeClick}>

View File

@@ -105,7 +105,7 @@ export const ActiveCall: FC<ActiveCallProps> = (props) => {
const { livekitRoom, connState } = useLiveKit( const { livekitRoom, connState } = useLiveKit(
props.muteStates, props.muteStates,
sfuConfig, sfuConfig,
props.e2eeConfig props.e2eeConfig,
); );
if (!livekitRoom) { if (!livekitRoom) {
@@ -172,10 +172,10 @@ export const InCallView: FC<InCallViewProps> = ({
[{ source: Track.Source.ScreenShare, withPlaceholder: false }], [{ source: Track.Source.ScreenShare, withPlaceholder: false }],
{ {
room: livekitRoom, room: livekitRoom,
} },
); );
const { layout, setLayout } = useVideoGridLayout( const { layout, setLayout } = useVideoGridLayout(
screenSharingTracks.length > 0 screenSharingTracks.length > 0,
); );
const [showConnectionStats] = useShowConnectionStats(); const [showConnectionStats] = useShowConnectionStats();
@@ -188,11 +188,11 @@ export const InCallView: FC<InCallViewProps> = ({
const toggleMicrophone = useCallback( const toggleMicrophone = useCallback(
() => muteStates.audio.setEnabled?.((e) => !e), () => muteStates.audio.setEnabled?.((e) => !e),
[muteStates] [muteStates],
); );
const toggleCamera = useCallback( const toggleCamera = useCallback(
() => muteStates.video.setEnabled?.((e) => !e), () => muteStates.video.setEnabled?.((e) => !e),
[muteStates] [muteStates],
); );
// This function incorrectly assumes that there is a camera and microphone, which is not always the case. // This function incorrectly assumes that there is a camera and microphone, which is not always the case.
@@ -201,7 +201,7 @@ export const InCallView: FC<InCallViewProps> = ({
containerRef1, containerRef1,
toggleMicrophone, toggleMicrophone,
toggleCamera, toggleCamera,
(muted) => muteStates.audio.setEnabled?.(!muted) (muted) => muteStates.audio.setEnabled?.(!muted),
); );
const onLeavePress = useCallback(() => { const onLeavePress = useCallback(() => {
@@ -213,7 +213,7 @@ export const InCallView: FC<InCallViewProps> = ({
layout === "grid" layout === "grid"
? ElementWidgetActions.TileLayout ? ElementWidgetActions.TileLayout
: ElementWidgetActions.SpotlightLayout, : ElementWidgetActions.SpotlightLayout,
{} {},
); );
}, [layout]); }, [layout]);
@@ -231,14 +231,14 @@ export const InCallView: FC<InCallViewProps> = ({
widget.lazyActions.on(ElementWidgetActions.TileLayout, onTileLayout); widget.lazyActions.on(ElementWidgetActions.TileLayout, onTileLayout);
widget.lazyActions.on( widget.lazyActions.on(
ElementWidgetActions.SpotlightLayout, ElementWidgetActions.SpotlightLayout,
onSpotlightLayout onSpotlightLayout,
); );
return () => { return () => {
widget!.lazyActions.off(ElementWidgetActions.TileLayout, onTileLayout); widget!.lazyActions.off(ElementWidgetActions.TileLayout, onTileLayout);
widget!.lazyActions.off( widget!.lazyActions.off(
ElementWidgetActions.SpotlightLayout, ElementWidgetActions.SpotlightLayout,
onSpotlightLayout onSpotlightLayout,
); );
}; };
} }
@@ -261,7 +261,7 @@ export const InCallView: FC<InCallViewProps> = ({
(noControls (noControls
? items.find((item) => item.isSpeaker) ?? items.at(0) ?? null ? items.find((item) => item.isSpeaker) ?? items.at(0) ?? null
: null), : null),
[fullscreenItem, noControls, items] [fullscreenItem, noControls, items],
); );
const Grid = const Grid =
@@ -320,18 +320,18 @@ export const InCallView: FC<InCallViewProps> = ({
}; };
const rageshakeRequestModalProps = useRageshakeRequestModal( const rageshakeRequestModalProps = useRageshakeRequestModal(
rtcSession.room.roomId rtcSession.room.roomId,
); );
const [settingsModalOpen, setSettingsModalOpen] = useState(false); const [settingsModalOpen, setSettingsModalOpen] = useState(false);
const openSettings = useCallback( const openSettings = useCallback(
() => setSettingsModalOpen(true), () => setSettingsModalOpen(true),
[setSettingsModalOpen] [setSettingsModalOpen],
); );
const closeSettings = useCallback( const closeSettings = useCallback(
() => setSettingsModalOpen(false), () => setSettingsModalOpen(false),
[setSettingsModalOpen] [setSettingsModalOpen],
); );
const toggleScreensharing = useCallback(async () => { const toggleScreensharing = useCallback(async () => {
@@ -365,7 +365,7 @@ export const InCallView: FC<InCallViewProps> = ({
onPress={toggleCamera} onPress={toggleCamera}
disabled={muteStates.video.setEnabled === null} disabled={muteStates.video.setEnabled === null}
data-testid="incall_videomute" data-testid="incall_videomute"
/> />,
); );
if (!reducedControls) { if (!reducedControls) {
@@ -376,14 +376,18 @@ export const InCallView: FC<InCallViewProps> = ({
enabled={isScreenShareEnabled} enabled={isScreenShareEnabled}
onPress={toggleScreensharing} onPress={toggleScreensharing}
data-testid="incall_screenshare" data-testid="incall_screenshare"
/> />,
); );
} }
buttons.push(<SettingsButton key="4" onPress={openSettings} />); buttons.push(<SettingsButton key="4" onPress={openSettings} />);
} }
buttons.push( buttons.push(
<HangupButton key="6" onPress={onLeavePress} data-testid="incall_leave" /> <HangupButton
key="6"
onPress={onLeavePress}
data-testid="incall_leave"
/>,
); );
footer = ( footer = (
<div className={styles.footer}> <div className={styles.footer}>
@@ -447,7 +451,7 @@ export const InCallView: FC<InCallViewProps> = ({
function findMatrixMember( function findMatrixMember(
room: MatrixRoom, room: MatrixRoom,
id: string id: string,
): RoomMember | undefined { ): RoomMember | undefined {
if (!id) return undefined; if (!id) return undefined;
@@ -455,7 +459,7 @@ function findMatrixMember(
// must be at least 3 parts because we know the first part is a userId which must necessarily contain a colon // must be at least 3 parts because we know the first part is a userId which must necessarily contain a colon
if (parts.length < 3) { if (parts.length < 3) {
logger.warn( logger.warn(
"Livekit participants ID doesn't look like a userId:deviceId combination" "Livekit participants ID doesn't look like a userId:deviceId combination",
); );
return undefined; return undefined;
} }
@@ -469,7 +473,7 @@ function findMatrixMember(
function useParticipantTiles( function useParticipantTiles(
livekitRoom: Room, livekitRoom: Room,
matrixRoom: MatrixRoom, matrixRoom: MatrixRoom,
connState: ECConnectionState connState: ECConnectionState,
): TileDescriptor<ItemData>[] { ): TileDescriptor<ItemData>[] {
const previousTiles = useRef<TileDescriptor<ItemData>[]>([]); const previousTiles = useRef<TileDescriptor<ItemData>[]>([]);
@@ -498,7 +502,7 @@ function useParticipantTiles(
// connected, this is fine and we'll be in "all ghosts" mode. // connected, this is fine and we'll be in "all ghosts" mode.
if (id !== "" && member === undefined) { if (id !== "" && member === undefined) {
logger.warn( logger.warn(
`Ruh, roh! No matrix member found for SFU participant '${id}': creating g-g-g-ghost!` `Ruh, roh! No matrix member found for SFU participant '${id}': creating g-g-g-ghost!`,
); );
} }
allGhosts &&= member === undefined; allGhosts &&= member === undefined;
@@ -542,11 +546,11 @@ function useParticipantTiles(
return screenShareTile return screenShareTile
? [userMediaTile, screenShareTile] ? [userMediaTile, screenShareTile]
: [userMediaTile]; : [userMediaTile];
} },
); );
PosthogAnalytics.instance.eventCallEnded.cacheParticipantCountChanged( PosthogAnalytics.instance.eventCallEnded.cacheParticipantCountChanged(
tiles.length tiles.length,
); );
// If every item is a ghost, that probably means we're still connecting and // If every item is a ghost, that probably means we're still connecting and

View File

@@ -40,7 +40,7 @@ export const InviteModal: FC<Props> = ({ room, open, onDismiss }) => {
const url = useMemo( const url = useMemo(
() => () =>
getAbsoluteRoomUrl(room.roomId, room.name, roomSharedKey ?? undefined), getAbsoluteRoomUrl(room.roomId, room.name, roomSharedKey ?? undefined),
[room, roomSharedKey] [room, roomSharedKey],
); );
const [, setCopied] = useClipboard(url); const [, setCopied] = useClipboard(url);
const [toastOpen, setToastOpen] = useState(false); const [toastOpen, setToastOpen] = useState(false);
@@ -53,7 +53,7 @@ export const InviteModal: FC<Props> = ({ room, open, onDismiss }) => {
onDismiss(); onDismiss();
setToastOpen(true); setToastOpen(true);
}, },
[setCopied, onDismiss] [setCopied, onDismiss],
); );
return ( return (

View File

@@ -36,7 +36,7 @@ export const LayoutToggle: FC<Props> = ({ layout, setLayout, className }) => {
const onChange = useCallback( const onChange = useCallback(
(e: ChangeEvent<HTMLInputElement>) => setLayout(e.target.value as Layout), (e: ChangeEvent<HTMLInputElement>) => setLayout(e.target.value as Layout),
[setLayout] [setLayout],
); );
const spotlightId = useId(); const spotlightId = useId();

View File

@@ -63,22 +63,22 @@ export const LobbyView: FC<Props> = ({
const onAudioPress = useCallback( const onAudioPress = useCallback(
() => muteStates.audio.setEnabled?.((e) => !e), () => muteStates.audio.setEnabled?.((e) => !e),
[muteStates] [muteStates],
); );
const onVideoPress = useCallback( const onVideoPress = useCallback(
() => muteStates.video.setEnabled?.((e) => !e), () => muteStates.video.setEnabled?.((e) => !e),
[muteStates] [muteStates],
); );
const [settingsModalOpen, setSettingsModalOpen] = useState(false); const [settingsModalOpen, setSettingsModalOpen] = useState(false);
const openSettings = useCallback( const openSettings = useCallback(
() => setSettingsModalOpen(true), () => setSettingsModalOpen(true),
[setSettingsModalOpen] [setSettingsModalOpen],
); );
const closeSettings = useCallback( const closeSettings = useCallback(
() => setSettingsModalOpen(false), () => setSettingsModalOpen(false),
[setSettingsModalOpen] [setSettingsModalOpen],
); );
const history = useHistory(); const history = useHistory();

View File

@@ -49,18 +49,18 @@ export interface MuteStates {
function useMuteState( function useMuteState(
device: MediaDevice, device: MediaDevice,
enabledByDefault: () => boolean enabledByDefault: () => boolean,
): MuteState { ): MuteState {
const [enabled, setEnabled] = useReactiveState<boolean>( const [enabled, setEnabled] = useReactiveState<boolean>(
(prev) => device.available.length > 0 && (prev ?? enabledByDefault()), (prev) => device.available.length > 0 && (prev ?? enabledByDefault()),
[device] [device],
); );
return useMemo( return useMemo(
() => () =>
device.available.length === 0 device.available.length === 0
? deviceUnavailable ? deviceUnavailable
: { enabled, setEnabled }, : { enabled, setEnabled },
[device, enabled, setEnabled] [device, enabled, setEnabled],
); );
} }
@@ -69,7 +69,7 @@ export function useMuteStates(participantCount: number): MuteStates {
const audio = useMuteState( const audio = useMuteState(
devices.audioInput, devices.audioInput,
() => participantCount <= MUTE_PARTICIPANT_COUNT () => participantCount <= MUTE_PARTICIPANT_COUNT,
); );
const video = useMuteState(devices.videoInput, () => true); const video = useMuteState(devices.videoInput, () => true);

View File

@@ -47,7 +47,7 @@ export const RageshakeRequestModal: FC<Props> = ({
<Modal title={t("Debug log request")} open={open} onDismiss={onDismiss}> <Modal title={t("Debug log request")} open={open} onDismiss={onDismiss}>
<Body> <Body>
{t( {t(
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log." "Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.",
)} )}
</Body> </Body>
<FieldRow> <FieldRow>

View File

@@ -52,7 +52,7 @@ export const RoomAuthView: FC = () => {
setError(error); setError(error);
}); });
}, },
[registerPasswordlessUser] [registerPasswordlessUser],
); );
const { t } = useTranslation(); const { t } = useTranslation();

View File

@@ -81,7 +81,7 @@ export const RoomPage: FC = () => {
hideHeader={hideHeader} hideHeader={hideHeader}
/> />
), ),
[client, passwordlessUser, confineToRoom, preload, hideHeader] [client, passwordlessUser, confineToRoom, preload, hideHeader],
); );
let content: ReactNode; let content: ReactNode;

View File

@@ -82,14 +82,14 @@ export const VideoPreview: FC<Props> = ({
}, },
(error) => { (error) => {
logger.error("Error while creating preview Tracks:", error); logger.error("Error while creating preview Tracks:", error);
} },
); );
const videoTrack = useMemo( const videoTrack = useMemo(
() => () =>
tracks?.find((t) => t.kind === Track.Kind.Video) as tracks?.find((t) => t.kind === Track.Kind.Video) as
| LocalVideoTrack | LocalVideoTrack
| undefined, | undefined,
[tracks] [tracks],
); );
const videoEl = useRef<HTMLVideoElement | null>(null); const videoEl = useRef<HTMLVideoElement | null>(null);

View File

@@ -24,7 +24,7 @@ import { deepCompare } from "matrix-js-sdk/src/utils";
import { LivekitFocus } from "../livekit/LivekitFocus"; import { LivekitFocus } from "../livekit/LivekitFocus";
function getActiveFocus( function getActiveFocus(
rtcSession: MatrixRTCSession rtcSession: MatrixRTCSession,
): LivekitFocus | undefined { ): LivekitFocus | undefined {
const oldestMembership = rtcSession.getOldestMembership(); const oldestMembership = rtcSession.getOldestMembership();
return oldestMembership?.getActiveFoci()[0] as LivekitFocus; return oldestMembership?.getActiveFoci()[0] as LivekitFocus;
@@ -36,10 +36,10 @@ function getActiveFocus(
* and the same focus. * and the same focus.
*/ */
export function useActiveFocus( export function useActiveFocus(
rtcSession: MatrixRTCSession rtcSession: MatrixRTCSession,
): LivekitFocus | undefined { ): LivekitFocus | undefined {
const [activeFocus, setActiveFocus] = useState(() => const [activeFocus, setActiveFocus] = useState(() =>
getActiveFocus(rtcSession) getActiveFocus(rtcSession),
); );
const onMembershipsChanged = useCallback(() => { const onMembershipsChanged = useCallback(() => {
@@ -53,13 +53,13 @@ export function useActiveFocus(
useEffect(() => { useEffect(() => {
rtcSession.on( rtcSession.on(
MatrixRTCSessionEvent.MembershipsChanged, MatrixRTCSessionEvent.MembershipsChanged,
onMembershipsChanged onMembershipsChanged,
); );
return () => { return () => {
rtcSession.off( rtcSession.off(
MatrixRTCSessionEvent.MembershipsChanged, MatrixRTCSessionEvent.MembershipsChanged,
onMembershipsChanged onMembershipsChanged,
); );
}; };
}); });

View File

@@ -66,7 +66,7 @@ export function useFullscreen<T>(items: TileDescriptor<T>[]): {
prevItem == null prevItem == null
? null ? null
: items.find((i) => i.id === prevItem.id) ?? null, : items.find((i) => i.id === prevItem.id) ?? null,
[items] [items],
); );
const latestItems = useRef<TileDescriptor<T>[]>(items); const latestItems = useRef<TileDescriptor<T>[]>(items);
@@ -80,15 +80,15 @@ export function useFullscreen<T>(items: TileDescriptor<T>[]): {
setFullscreenItem( setFullscreenItem(
latestFullscreenItem.current === null latestFullscreenItem.current === null
? latestItems.current.find((i) => i.id === itemId) ?? null ? latestItems.current.find((i) => i.id === itemId) ?? null
: null : null,
); );
}, },
[setFullscreenItem] [setFullscreenItem],
); );
const exitFullscreenCallback = useCallback( const exitFullscreenCallback = useCallback(
() => setFullscreenItem(null), () => setFullscreenItem(null),
[setFullscreenItem] [setFullscreenItem],
); );
useLayoutEffect(() => { useLayoutEffect(() => {
@@ -103,7 +103,7 @@ export function useFullscreen<T>(items: TileDescriptor<T>[]): {
useFullscreenChange( useFullscreenChange(
useCallback(() => { useCallback(() => {
if (!isFullscreen()) setFullscreenItem(null); if (!isFullscreen()) setFullscreenItem(null);
}, [setFullscreenItem]) }, [setFullscreenItem]),
); );
return { return {

View File

@@ -23,6 +23,6 @@ import { useRoomState } from "./useRoomState";
export function useJoinRule(room: Room): JoinRule { export function useJoinRule(room: Room): JoinRule {
return useRoomState( return useRoomState(
room, room,
useCallback((state) => state.getJoinRule(), []) useCallback((state) => state.getJoinRule(), []),
); );
} }

View File

@@ -52,7 +52,7 @@ export interface GroupCallLoadState {
export const useLoadGroupCall = ( export const useLoadGroupCall = (
client: MatrixClient, client: MatrixClient,
roomIdOrAlias: string, roomIdOrAlias: string,
viaServers: string[] viaServers: string[],
): GroupCallStatus => { ): GroupCallStatus => {
const { t } = useTranslation(); const { t } = useTranslation();
const [state, setState] = useState<GroupCallStatus>({ kind: "loading" }); const [state, setState] = useState<GroupCallStatus>({ kind: "loading" });
@@ -70,7 +70,7 @@ export const useLoadGroupCall = (
// join anyway but the js-sdk recreates the room if you pass the alias for a // join anyway but the js-sdk recreates the room if you pass the alias for a
// room you're already joined to (which it probably ought not to). // room you're already joined to (which it probably ought not to).
const lookupResult = await client.getRoomIdForAlias( const lookupResult = await client.getRoomIdForAlias(
roomIdOrAlias.toLowerCase() roomIdOrAlias.toLowerCase(),
); );
logger.info(`${roomIdOrAlias} resolved to ${lookupResult.room_id}`); logger.info(`${roomIdOrAlias} resolved to ${lookupResult.room_id}`);
room = client.getRoom(lookupResult.room_id); room = client.getRoom(lookupResult.room_id);
@@ -81,7 +81,7 @@ export const useLoadGroupCall = (
}); });
} else { } else {
logger.info( logger.info(
`Already in room ${lookupResult.room_id}, not rejoining.` `Already in room ${lookupResult.room_id}, not rejoining.`,
); );
} }
} else { } else {
@@ -92,7 +92,7 @@ export const useLoadGroupCall = (
} }
logger.info( logger.info(
`Joined ${roomIdOrAlias}, waiting room to be ready for group calls` `Joined ${roomIdOrAlias}, waiting room to be ready for group calls`,
); );
await client.waitUntilRoomReadyForGroupCalls(room.roomId); await client.waitUntilRoomReadyForGroupCalls(room.roomId);
logger.info(`${roomIdOrAlias}, is ready for group calls`); logger.info(`${roomIdOrAlias}, is ready for group calls`);
@@ -110,7 +110,7 @@ export const useLoadGroupCall = (
const waitForClientSyncing = async (): Promise<void> => { const waitForClientSyncing = async (): Promise<void> => {
if (client.getSyncState() !== SyncState.Syncing) { if (client.getSyncState() !== SyncState.Syncing) {
logger.debug( logger.debug(
"useLoadGroupCall: waiting for client to start syncing..." "useLoadGroupCall: waiting for client to start syncing...",
); );
await new Promise<void>((resolve) => { await new Promise<void>((resolve) => {
const onSync = (): void => { const onSync = (): void => {

View File

@@ -22,6 +22,6 @@ import { useRoomState } from "./useRoomState";
export function useRoomAvatar(room: Room): string | null { export function useRoomAvatar(room: Room): string | null {
return useRoomState( return useRoomState(
room, room,
useCallback(() => room.getMxcAvatarUrl(), [room]) useCallback(() => room.getMxcAvatarUrl(), [room]),
); );
} }

View File

@@ -31,7 +31,7 @@ export const useRoomState = <T>(room: Room, f: (state: RoomState) => T): T => {
useTypedEventEmitter( useTypedEventEmitter(
room, room,
RoomStateEvent.Update, RoomStateEvent.Update,
useCallback(() => setNumUpdates((n) => n + 1), [setNumUpdates]) useCallback(() => setNumUpdates((n) => n + 1), [setNumUpdates]),
); );
// We want any change to the update counter to trigger an update here // We want any change to the update counter to trigger an update here
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps

View File

@@ -48,7 +48,7 @@ export function enterRTCSession(rtcSession: MatrixRTCSession): void {
} }
export async function leaveRTCSession( export async function leaveRTCSession(
rtcSession: MatrixRTCSession rtcSession: MatrixRTCSession,
): Promise<void> { ): Promise<void> {
//groupCallOTelMembership?.onLeaveCall(); //groupCallOTelMembership?.onLeaveCall();
await rtcSession.leaveRoomSession(); await rtcSession.leaveRoomSession();

View File

@@ -57,7 +57,7 @@ export const FeedbackSettingsTab: FC<Props> = ({ roomId }) => {
sendRageshakeRequest(roomId, rageshakeRequestId); sendRageshakeRequest(roomId, rageshakeRequestId);
} }
}, },
[submitRageshake, roomId, sendRageshakeRequest] [submitRageshake, roomId, sendRageshakeRequest],
); );
return ( return (
@@ -65,7 +65,7 @@ export const FeedbackSettingsTab: FC<Props> = ({ roomId }) => {
<h4 className={styles.label}>{t("Submit feedback")}</h4> <h4 className={styles.label}>{t("Submit feedback")}</h4>
<Body> <Body>
{t( {t(
"If you are experiencing issues or simply would like to provide some feedback, please send us a short description below." "If you are experiencing issues or simply would like to provide some feedback, please send us a short description below.",
)} )}
</Body> </Body>
<form onSubmit={onSubmitFeedback}> <form onSubmit={onSubmitFeedback}>

View File

@@ -69,7 +69,7 @@ export const SettingsModal: FC<Props> = (props) => {
// Generate a `SelectInput` with a list of devices for a given device kind. // Generate a `SelectInput` with a list of devices for a given device kind.
const generateDeviceSelection = ( const generateDeviceSelection = (
devices: MediaDevice, devices: MediaDevice,
caption: string caption: string,
): ReactNode => { ): ReactNode => {
if (devices.available.length == 0) return null; if (devices.available.length == 0) return null;
@@ -100,7 +100,7 @@ export const SettingsModal: FC<Props> = (props) => {
(tab: Key) => { (tab: Key) => {
setSelectedTab(tab.toString()); setSelectedTab(tab.toString());
}, },
[setSelectedTab] [setSelectedTab],
); );
const optInDescription = ( const optInDescription = (

View File

@@ -133,7 +133,7 @@ class IndexedDBLogStore {
public constructor( public constructor(
private indexedDB: IDBFactory, private indexedDB: IDBFactory,
private loggerInstance: ConsoleLogger private loggerInstance: ConsoleLogger,
) { ) {
this.id = "instance-" + randomString(16); this.id = "instance-" + randomString(16);
@@ -177,7 +177,7 @@ class IndexedDBLogStore {
logObjStore.createIndex("id", "id", { unique: false }); logObjStore.createIndex("id", "id", { unique: false });
logObjStore.add( logObjStore.add(
this.generateLogEntry(new Date() + " ::: Log database was created.") this.generateLogEntry(new Date() + " ::: Log database was created."),
); );
// This records the last time each instance ID generated a log message, such // This records the last time each instance ID generated a log message, such
@@ -208,7 +208,7 @@ class IndexedDBLogStore {
{ {
leading: false, leading: false,
trailing: true, trailing: true,
} },
); );
/** /**
@@ -366,8 +366,8 @@ class IndexedDBLogStore {
txn.onerror = (): void => { txn.onerror = (): void => {
reject( reject(
new Error( new Error(
"Failed to delete logs for " + `'${id}' : ${txn?.error?.message}` "Failed to delete logs for " + `'${id}' : ${txn?.error?.message}`,
) ),
); );
}; };
// delete last modified entries // delete last modified entries
@@ -410,7 +410,7 @@ class IndexedDBLogStore {
}, },
(err) => { (err) => {
logger.error(err); logger.error(err);
} },
); );
} }
return logs; return logs;
@@ -445,7 +445,7 @@ class IndexedDBLogStore {
function selectQuery<T>( function selectQuery<T>(
store: IDBObjectStore, store: IDBObjectStore,
keyRange: IDBKeyRange | undefined, keyRange: IDBKeyRange | undefined,
resultMapper: (cursor: IDBCursorWithValue) => T resultMapper: (cursor: IDBCursorWithValue) => T,
): Promise<T[]> { ): Promise<T[]> {
const query = store.openCursor(keyRange); const query = store.openCursor(keyRange);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@@ -510,7 +510,7 @@ function tryInitStorage(): Promise<void> {
if (indexedDB) { if (indexedDB) {
global.mx_rage_store = new IndexedDBLogStore( global.mx_rage_store = new IndexedDBLogStore(
indexedDB, indexedDB,
global.mx_rage_logger global.mx_rage_logger,
); );
global.mx_rage_initStoragePromise = global.mx_rage_store.connect(); global.mx_rage_initStoragePromise = global.mx_rage_store.connect();
return global.mx_rage_initStoragePromise; return global.mx_rage_initStoragePromise;
@@ -547,7 +547,7 @@ export async function getLogsForReport(): Promise<LogEntry[]> {
type StringifyReplacer = ( type StringifyReplacer = (
this: unknown, this: unknown,
key: string, key: string,
value: unknown value: unknown,
) => unknown; ) => unknown;
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#circular_references // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#circular_references
@@ -600,7 +600,7 @@ export function setLogExtension(extension: LogExtensionFunc): void {
logger.methodFactory = function ( logger.methodFactory = function (
methodName, methodName,
configLevel, configLevel,
loggerName loggerName,
): LoggingMethod { ): LoggingMethod {
const rawMethod = originalFactory(methodName, configLevel, loggerName); const rawMethod = originalFactory(methodName, configLevel, loggerName);

View File

@@ -95,12 +95,12 @@ export function useSubmitRageshake(): {
const body = new FormData(); const body = new FormData();
body.append( body.append(
"text", "text",
description ?? "User did not supply any additional text." description ?? "User did not supply any additional text.",
); );
body.append("app", "matrix-video-chat"); body.append("app", "matrix-video-chat");
body.append( body.append(
"version", "version",
(import.meta.env.VITE_APP_VERSION as string) || "dev" (import.meta.env.VITE_APP_VERSION as string) || "dev",
); );
body.append("user_agent", userAgent); body.append("user_agent", userAgent);
body.append("installed_pwa", "false"); body.append("installed_pwa", "false");
@@ -132,22 +132,22 @@ export function useSubmitRageshake(): {
body.append( body.append(
"cross_signing_ready", "cross_signing_ready",
String(await client.isCrossSigningReady()) String(await client.isCrossSigningReady()),
); );
body.append( body.append(
"cross_signing_supported_by_hs", "cross_signing_supported_by_hs",
String( String(
await client.doesServerSupportUnstableFeature( await client.doesServerSupportUnstableFeature(
"org.matrix.e2e_cross_signing" "org.matrix.e2e_cross_signing",
) ),
) ),
); );
body.append("cross_signing_key", crossSigning.getId()!); body.append("cross_signing_key", crossSigning.getId()!);
body.append( body.append(
"cross_signing_privkey_in_secret_storage", "cross_signing_privkey_in_secret_storage",
String( String(
!!(await crossSigning.isStoredInSecretStorage(secretStorage)) !!(await crossSigning.isStoredInSecretStorage(secretStorage)),
) ),
); );
const pkCache = client.getCrossSigningCacheCallbacks(); const pkCache = client.getCrossSigningCacheCallbacks();
@@ -157,8 +157,8 @@ export function useSubmitRageshake(): {
!!( !!(
pkCache?.getCrossSigningKeyCache && pkCache?.getCrossSigningKeyCache &&
(await pkCache.getCrossSigningKeyCache("master")) (await pkCache.getCrossSigningKeyCache("master"))
) ),
) ),
); );
body.append( body.append(
"cross_signing_self_signing_privkey_cached", "cross_signing_self_signing_privkey_cached",
@@ -166,8 +166,8 @@ export function useSubmitRageshake(): {
!!( !!(
pkCache?.getCrossSigningKeyCache && pkCache?.getCrossSigningKeyCache &&
(await pkCache.getCrossSigningKeyCache("self_signing")) (await pkCache.getCrossSigningKeyCache("self_signing"))
) ),
) ),
); );
body.append( body.append(
"cross_signing_user_signing_privkey_cached", "cross_signing_user_signing_privkey_cached",
@@ -175,32 +175,32 @@ export function useSubmitRageshake(): {
!!( !!(
pkCache?.getCrossSigningKeyCache && pkCache?.getCrossSigningKeyCache &&
(await pkCache.getCrossSigningKeyCache("user_signing")) (await pkCache.getCrossSigningKeyCache("user_signing"))
) ),
) ),
); );
body.append( body.append(
"secret_storage_ready", "secret_storage_ready",
String(await client.isSecretStorageReady()) String(await client.isSecretStorageReady()),
); );
body.append( body.append(
"secret_storage_key_in_account", "secret_storage_key_in_account",
String(!!(await secretStorage.hasKey())) String(!!(await secretStorage.hasKey())),
); );
body.append( body.append(
"session_backup_key_in_secret_storage", "session_backup_key_in_secret_storage",
String(!!(await client.isKeyBackupKeyStored())) String(!!(await client.isKeyBackupKeyStored())),
); );
const sessionBackupKeyFromCache = const sessionBackupKeyFromCache =
await client.crypto!.getSessionBackupPrivateKey(); await client.crypto!.getSessionBackupPrivateKey();
body.append( body.append(
"session_backup_key_cached", "session_backup_key_cached",
String(!!sessionBackupKeyFromCache) String(!!sessionBackupKeyFromCache),
); );
body.append( body.append(
"session_backup_key_well_formed", "session_backup_key_well_formed",
String(sessionBackupKeyFromCache instanceof Uint8Array) String(sessionBackupKeyFromCache instanceof Uint8Array),
); );
} }
} }
@@ -214,7 +214,7 @@ export function useSubmitRageshake(): {
try { try {
body.append( body.append(
"storageManager_persisted", "storageManager_persisted",
String(await navigator.storage.persisted()) String(await navigator.storage.persisted()),
); );
} catch (e) {} } catch (e) {}
} else if (document.hasStorageAccess) { } else if (document.hasStorageAccess) {
@@ -222,7 +222,7 @@ export function useSubmitRageshake(): {
try { try {
body.append( body.append(
"storageManager_persisted", "storageManager_persisted",
String(await document.hasStorageAccess()) String(await document.hasStorageAccess()),
); );
} catch (e) {} } catch (e) {}
} }
@@ -240,7 +240,7 @@ export function useSubmitRageshake(): {
Object.keys(estimate.usageDetails).forEach((k) => { Object.keys(estimate.usageDetails).forEach((k) => {
body.append( body.append(
`storageManager_usage_${k}`, `storageManager_usage_${k}`,
String(estimate.usageDetails![k]) String(estimate.usageDetails![k]),
); );
}); });
} }
@@ -257,14 +257,14 @@ export function useSubmitRageshake(): {
body.append( body.append(
"file", "file",
gzip(ElementCallOpenTelemetry.instance.rageshakeProcessor!.dump()), gzip(ElementCallOpenTelemetry.instance.rageshakeProcessor!.dump()),
"traces.json.gz" "traces.json.gz",
); );
} }
if (opts.rageshakeRequestId) { if (opts.rageshakeRequestId) {
body.append( body.append(
"group_call_rageshake_request_id", "group_call_rageshake_request_id",
opts.rageshakeRequestId opts.rageshakeRequestId,
); );
} }
@@ -279,7 +279,7 @@ export function useSubmitRageshake(): {
logger.error(error); logger.error(error);
} }
}, },
[client, sending] [client, sending],
); );
return { return {
@@ -292,7 +292,7 @@ export function useSubmitRageshake(): {
export function useRageshakeRequest(): ( export function useRageshakeRequest(): (
roomId: string, roomId: string,
rageshakeRequestId: string rageshakeRequestId: string,
) => void { ) => void {
const { client } = useClient(); const { client } = useClient();
@@ -302,14 +302,14 @@ export function useRageshakeRequest(): (
request_id: rageshakeRequestId, request_id: rageshakeRequestId,
}); });
}, },
[client] [client],
); );
return sendRageshakeRequest; return sendRageshakeRequest;
} }
export function useRageshakeRequestModal( export function useRageshakeRequestModal(
roomId: string roomId: string,
): ComponentProps<typeof RageshakeRequestModal> { ): ComponentProps<typeof RageshakeRequestModal> {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const onDismiss = useCallback(() => setOpen(false), [setOpen]); const onDismiss = useCallback(() => setOpen(false), [setOpen]);

View File

@@ -38,13 +38,13 @@ export const useSetting = <T>(name: string, defaultValue: T): Setting<T> => {
const value = useMemo( const value = useMemo(
() => (item == null ? defaultValue : JSON.parse(item)), () => (item == null ? defaultValue : JSON.parse(item)),
[item, defaultValue] [item, defaultValue],
); );
const setValue = useCallback( const setValue = useCallback(
(value: T) => { (value: T) => {
setItem(JSON.stringify(value)); setItem(JSON.stringify(value));
}, },
[setItem] [setItem],
); );
return [value, setValue]; return [value, setValue];
@@ -94,7 +94,7 @@ export const useOptInAnalytics = (): DisableableSetting<boolean | null> => {
export const useEnableE2EE = (): DisableableSetting<boolean | null> => { export const useEnableE2EE = (): DisableableSetting<boolean | null> => {
const settingVal = useSetting<boolean | null>( const settingVal = useSetting<boolean | null>(
"enable-end-to-end-encryption", "enable-end-to-end-encryption",
true true,
); );
if (isE2EESupported()) return settingVal; if (isE2EESupported()) return settingVal;

View File

@@ -29,7 +29,7 @@ interface TabContainerProps<T> extends TabListProps<T> {
} }
export function TabContainer<T extends object>( export function TabContainer<T extends object>(
props: TabContainerProps<T> props: TabContainerProps<T>,
): JSX.Element { ): JSX.Element {
const state = useTabListState<T>(props); const state = useTabListState<T>(props);
const ref = useRef<HTMLUListElement>(null); const ref = useRef<HTMLUListElement>(null);

View File

@@ -39,7 +39,7 @@ export const Headline = forwardRef<HTMLHeadingElement, TypographyProps>(
overflowEllipsis, overflowEllipsis,
...rest ...rest
}, },
ref ref,
) => { ) => {
return createElement( return createElement(
Component, Component,
@@ -48,13 +48,13 @@ export const Headline = forwardRef<HTMLHeadingElement, TypographyProps>(
className: classNames( className: classNames(
styles[fontWeight ?? ""], styles[fontWeight ?? ""],
{ [styles.overflowEllipsis]: overflowEllipsis }, { [styles.overflowEllipsis]: overflowEllipsis },
className className,
), ),
ref, ref,
}, },
children children,
); );
} },
); );
export const Title = forwardRef<HTMLHeadingElement, TypographyProps>( export const Title = forwardRef<HTMLHeadingElement, TypographyProps>(
@@ -67,7 +67,7 @@ export const Title = forwardRef<HTMLHeadingElement, TypographyProps>(
overflowEllipsis, overflowEllipsis,
...rest ...rest
}, },
ref ref,
) => { ) => {
return createElement( return createElement(
Component, Component,
@@ -76,13 +76,13 @@ export const Title = forwardRef<HTMLHeadingElement, TypographyProps>(
className: classNames( className: classNames(
styles[fontWeight ?? ""], styles[fontWeight ?? ""],
{ [styles.overflowEllipsis]: overflowEllipsis }, { [styles.overflowEllipsis]: overflowEllipsis },
className className,
), ),
ref, ref,
}, },
children children,
); );
} },
); );
export const Subtitle = forwardRef<HTMLParagraphElement, TypographyProps>( export const Subtitle = forwardRef<HTMLParagraphElement, TypographyProps>(
@@ -95,7 +95,7 @@ export const Subtitle = forwardRef<HTMLParagraphElement, TypographyProps>(
overflowEllipsis, overflowEllipsis,
...rest ...rest
}, },
ref ref,
) => { ) => {
return createElement( return createElement(
Component, Component,
@@ -104,13 +104,13 @@ export const Subtitle = forwardRef<HTMLParagraphElement, TypographyProps>(
className: classNames( className: classNames(
styles[fontWeight ?? ""], styles[fontWeight ?? ""],
{ [styles.overflowEllipsis]: overflowEllipsis }, { [styles.overflowEllipsis]: overflowEllipsis },
className className,
), ),
ref, ref,
}, },
children children,
); );
} },
); );
export const Body = forwardRef<HTMLParagraphElement, TypographyProps>( export const Body = forwardRef<HTMLParagraphElement, TypographyProps>(
@@ -123,7 +123,7 @@ export const Body = forwardRef<HTMLParagraphElement, TypographyProps>(
overflowEllipsis, overflowEllipsis,
...rest ...rest
}, },
ref ref,
) => { ) => {
return createElement( return createElement(
Component, Component,
@@ -132,13 +132,13 @@ export const Body = forwardRef<HTMLParagraphElement, TypographyProps>(
className: classNames( className: classNames(
styles[fontWeight ?? ""], styles[fontWeight ?? ""],
{ [styles.overflowEllipsis]: overflowEllipsis }, { [styles.overflowEllipsis]: overflowEllipsis },
className className,
), ),
ref, ref,
}, },
children children,
); );
} },
); );
export const Caption = forwardRef<HTMLParagraphElement, TypographyProps>( export const Caption = forwardRef<HTMLParagraphElement, TypographyProps>(
@@ -151,7 +151,7 @@ export const Caption = forwardRef<HTMLParagraphElement, TypographyProps>(
overflowEllipsis, overflowEllipsis,
...rest ...rest
}, },
ref ref,
) => { ) => {
return createElement( return createElement(
Component, Component,
@@ -161,13 +161,13 @@ export const Caption = forwardRef<HTMLParagraphElement, TypographyProps>(
styles.caption, styles.caption,
styles[fontWeight ?? ""], styles[fontWeight ?? ""],
{ [styles.overflowEllipsis]: overflowEllipsis }, { [styles.overflowEllipsis]: overflowEllipsis },
className className,
), ),
ref, ref,
}, },
children children,
); );
} },
); );
export const Micro = forwardRef<HTMLParagraphElement, TypographyProps>( export const Micro = forwardRef<HTMLParagraphElement, TypographyProps>(
@@ -180,7 +180,7 @@ export const Micro = forwardRef<HTMLParagraphElement, TypographyProps>(
overflowEllipsis, overflowEllipsis,
...rest ...rest
}, },
ref ref,
) => { ) => {
return createElement( return createElement(
Component, Component,
@@ -190,13 +190,13 @@ export const Micro = forwardRef<HTMLParagraphElement, TypographyProps>(
styles.micro, styles.micro,
styles[fontWeight ?? ""], styles[fontWeight ?? ""],
{ [styles.overflowEllipsis]: overflowEllipsis }, { [styles.overflowEllipsis]: overflowEllipsis },
className className,
), ),
ref, ref,
}, },
children children,
); );
} },
); );
interface LinkProps extends TypographyProps { interface LinkProps extends TypographyProps {
@@ -217,7 +217,7 @@ export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
overflowEllipsis, overflowEllipsis,
...rest ...rest
}, },
ref ref,
) => { ) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
@@ -246,11 +246,11 @@ export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
styles[color], styles[color],
styles[fontWeight ?? ""], styles[fontWeight ?? ""],
{ [styles.overflowEllipsis]: overflowEllipsis }, { [styles.overflowEllipsis]: overflowEllipsis },
className className,
), ),
ref: ref, ref: ref,
}, },
children children,
); );
} },
); );

View File

@@ -34,7 +34,7 @@ export function useCallViewKeyboardShortcuts(
focusElement: RefObject<HTMLElement | null>, focusElement: RefObject<HTMLElement | null>,
toggleMicrophoneMuted: () => void, toggleMicrophoneMuted: () => void,
toggleLocalVideoMuted: () => void, toggleLocalVideoMuted: () => void,
setMicrophoneMuted: (muted: boolean) => void setMicrophoneMuted: (muted: boolean) => void,
): void { ): void {
const spacebarHeld = useRef(false); const spacebarHeld = useRef(false);
@@ -63,8 +63,8 @@ export function useCallViewKeyboardShortcuts(
toggleLocalVideoMuted, toggleLocalVideoMuted,
toggleMicrophoneMuted, toggleMicrophoneMuted,
setMicrophoneMuted, setMicrophoneMuted,
] ],
) ),
); );
useEventTarget( useEventTarget(
@@ -80,8 +80,8 @@ export function useCallViewKeyboardShortcuts(
setMicrophoneMuted(true); setMicrophoneMuted(true);
} }
}, },
[focusElement, setMicrophoneMuted] [focusElement, setMicrophoneMuted],
) ),
); );
useEventTarget( useEventTarget(
@@ -92,6 +92,6 @@ export function useCallViewKeyboardShortcuts(
spacebarHeld.current = false; spacebarHeld.current = false;
setMicrophoneMuted(true); setMicrophoneMuted(true);
} }
}, [setMicrophoneMuted, spacebarHeld]) }, [setMicrophoneMuted, spacebarHeld]),
); );
} }

View File

@@ -28,7 +28,7 @@ export function useEventTarget<T extends Event>(
target: EventTarget | null | undefined, target: EventTarget | null | undefined,
eventType: string, eventType: string,
listener: (event: T) => void, listener: (event: T) => void,
options?: AddEventListenerOptions options?: AddEventListenerOptions,
): void { ): void {
useEffect(() => { useEffect(() => {
if (target) { if (target) {
@@ -37,7 +37,7 @@ export function useEventTarget<T extends Event>(
target.removeEventListener( target.removeEventListener(
eventType, eventType,
listener as EventListener, listener as EventListener,
options options,
); );
} }
}, [target, eventType, listener, options]); }, [target, eventType, listener, options]);
@@ -47,11 +47,11 @@ export function useEventTarget<T extends Event>(
export function useTypedEventEmitter< export function useTypedEventEmitter<
Events extends string, Events extends string,
Arguments extends ListenerMap<Events>, Arguments extends ListenerMap<Events>,
T extends Events T extends Events,
>( >(
emitter: TypedEventEmitter<Events, Arguments>, emitter: TypedEventEmitter<Events, Arguments>,
eventType: T, eventType: T,
listener: Listener<Events, Arguments, T> listener: Listener<Events, Arguments, T>,
): void { ): void {
useEffect(() => { useEffect(() => {
emitter.on(eventType, listener); emitter.on(eventType, listener);
@@ -64,11 +64,11 @@ export function useTypedEventEmitter<
// Shortcut for registering a listener on an eventemitter3 EventEmitter (ie. what the LiveKit SDK uses) // Shortcut for registering a listener on an eventemitter3 EventEmitter (ie. what the LiveKit SDK uses)
export function useEventEmitterThree< export function useEventEmitterThree<
EventType extends keyof T, EventType extends keyof T,
T extends EventMap T extends EventMap,
>( >(
emitter: EventEmitter<T>, emitter: EventEmitter<T>,
eventType: EventType, eventType: EventType,
listener: T[EventType] listener: T[EventType],
): void { ): void {
useEffect(() => { useEffect(() => {
emitter.on(eventType, listener); emitter.on(eventType, listener);

View File

@@ -24,10 +24,10 @@ export const localStorageBus = new EventEmitter();
// Like useState, but reads from and persists the value to localStorage // Like useState, but reads from and persists the value to localStorage
export const useLocalStorage = ( export const useLocalStorage = (
key: string key: string,
): [LocalStorageItem, (value: string) => void] => { ): [LocalStorageItem, (value: string) => void] => {
const [value, setValue] = useState<LocalStorageItem>(() => const [value, setValue] = useState<LocalStorageItem>(() =>
localStorage.getItem(key) localStorage.getItem(key),
); );
useEffect(() => { useEffect(() => {
@@ -45,7 +45,7 @@ export const useLocalStorage = (
localStorage.setItem(key, newValue); localStorage.setItem(key, newValue);
localStorageBus.emit(key, newValue); localStorageBus.emit(key, newValue);
}, },
[key, setValue] [key, setValue],
), ),
]; ];
}; };

View File

@@ -22,7 +22,7 @@ import {
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
export function useMatrixRTCSessionJoinState( export function useMatrixRTCSessionJoinState(
rtcSession: MatrixRTCSession rtcSession: MatrixRTCSession,
): boolean { ): boolean {
const [isJoined, setJoined] = useState(rtcSession.isJoined()); const [isJoined, setJoined] = useState(rtcSession.isJoined());
@@ -30,7 +30,7 @@ export function useMatrixRTCSessionJoinState(
logger.info( logger.info(
`Session in room ${rtcSession.room.roomId} changed to ${ `Session in room ${rtcSession.room.roomId} changed to ${
rtcSession.isJoined() ? "joined" : "left" rtcSession.isJoined() ? "joined" : "left"
}` }`,
); );
setJoined(rtcSession.isJoined()); setJoined(rtcSession.isJoined());
}, [rtcSession]); }, [rtcSession]);
@@ -41,7 +41,7 @@ export function useMatrixRTCSessionJoinState(
return () => { return () => {
rtcSession.off( rtcSession.off(
MatrixRTCSessionEvent.JoinStateChanged, MatrixRTCSessionEvent.JoinStateChanged,
onJoinStateChanged onJoinStateChanged,
); );
}; };
}, [rtcSession, onJoinStateChanged]); }, [rtcSession, onJoinStateChanged]);

View File

@@ -23,13 +23,13 @@ import {
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
export function useMatrixRTCSessionMemberships( export function useMatrixRTCSessionMemberships(
rtcSession: MatrixRTCSession rtcSession: MatrixRTCSession,
): CallMembership[] { ): CallMembership[] {
const [memberships, setMemberships] = useState(rtcSession.memberships); const [memberships, setMemberships] = useState(rtcSession.memberships);
const onMembershipsChanged = useCallback(() => { const onMembershipsChanged = useCallback(() => {
logger.info( logger.info(
`Memberships changed for call in room ${rtcSession.room.roomId} (${rtcSession.memberships.length} members)` `Memberships changed for call in room ${rtcSession.room.roomId} (${rtcSession.memberships.length} members)`,
); );
setMemberships(rtcSession.memberships); setMemberships(rtcSession.memberships);
}, [rtcSession]); }, [rtcSession]);
@@ -37,13 +37,13 @@ export function useMatrixRTCSessionMemberships(
useEffect(() => { useEffect(() => {
rtcSession.on( rtcSession.on(
MatrixRTCSessionEvent.MembershipsChanged, MatrixRTCSessionEvent.MembershipsChanged,
onMembershipsChanged onMembershipsChanged,
); );
return () => { return () => {
rtcSession.off( rtcSession.off(
MatrixRTCSessionEvent.MembershipsChanged, MatrixRTCSessionEvent.MembershipsChanged,
onMembershipsChanged onMembershipsChanged,
); );
}; };
}, [rtcSession, onMembershipsChanged]); }, [rtcSession, onMembershipsChanged]);

View File

@@ -28,7 +28,7 @@ export function useMediaQuery(query: string): boolean {
useEventTarget( useEventTarget(
mediaQuery, mediaQuery,
"change", "change",
useCallback(() => setNumChanges((n) => n + 1), [setNumChanges]) useCallback(() => setNumChanges((n) => n + 1), [setNumChanges]),
); );
// We want any change to the update counter to trigger an update here // We want any change to the update counter to trigger an update here

View File

@@ -35,5 +35,5 @@ export const useMergedRefs = <T>(
// Since this isn't an array literal, we can't use the static dependency // Since this isn't an array literal, we can't use the static dependency
// checker, but that's okay // checker, but that's okay
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
refs refs,
); );

View File

@@ -30,7 +30,7 @@ import {
*/ */
export const useReactiveState = <T>( export const useReactiveState = <T>(
updateFn: (prevState?: T) => T, updateFn: (prevState?: T) => T,
deps: DependencyList deps: DependencyList,
): [T, Dispatch<SetStateAction<T>>] => { ): [T, Dispatch<SetStateAction<T>>] => {
const state = useRef<T>(); const state = useRef<T>();
if (state.current === undefined) state.current = updateFn(); if (state.current === undefined) state.current = updateFn();
@@ -61,7 +61,7 @@ export const useReactiveState = <T>(
} }
setNumUpdates((n) => n + 1); // Force an update setNumUpdates((n) => n + 1); // Force an update
}, },
[setNumUpdates] [setNumUpdates],
), ),
]; ];
}; };

View File

@@ -78,7 +78,7 @@ export interface SparseGrid {
export function getPaths( export function getPaths(
g: SparseGrid, g: SparseGrid,
dest: number, dest: number,
avoid: (cell: number) => boolean = (): boolean => false avoid: (cell: number) => boolean = (): boolean => false,
): (number | null)[] { ): (number | null)[] {
const destRow = row(dest, g); const destRow = row(dest, g);
const destColumn = column(dest, g); const destColumn = column(dest, g);
@@ -145,7 +145,7 @@ function inArea(
index: number, index: number,
start: number, start: number,
end: number, end: number,
g: SparseGrid g: SparseGrid,
): boolean { ): boolean {
const indexColumn = column(index, g); const indexColumn = column(index, g);
const indexRow = row(index, g); const indexRow = row(index, g);
@@ -160,7 +160,7 @@ function inArea(
function* cellsInArea( function* cellsInArea(
start: number, start: number,
end: number, end: number,
g: SparseGrid g: SparseGrid,
): Generator<number, void, unknown> { ): Generator<number, void, unknown> {
const startColumn = column(start, g); const startColumn = column(start, g);
const endColumn = column(end, g); const endColumn = column(end, g);
@@ -179,7 +179,7 @@ export function forEachCellInArea<G extends Grid | SparseGrid>(
start: number, start: number,
end: number, end: number,
g: G, g: G,
fn: (c: G["cells"][0], i: number) => void fn: (c: G["cells"][0], i: number) => void,
): void { ): void {
for (const i of cellsInArea(start, end, g)) fn(g.cells[i], i); for (const i of cellsInArea(start, end, g)) fn(g.cells[i], i);
} }
@@ -188,7 +188,7 @@ function allCellsInArea<G extends Grid | SparseGrid>(
start: number, start: number,
end: number, end: number,
g: G, g: G,
fn: (c: G["cells"][0], i: number) => boolean fn: (c: G["cells"][0], i: number) => boolean,
): boolean { ): boolean {
for (const i of cellsInArea(start, end, g)) { for (const i of cellsInArea(start, end, g)) {
if (!fn(g.cells[i], i)) return false; if (!fn(g.cells[i], i)) return false;
@@ -204,7 +204,7 @@ function countCellsInArea<G extends Grid | SparseGrid>(
start: number, start: number,
end: number, end: number,
g: G, g: G,
predicate: (c: G["cells"][0], i: number) => boolean predicate: (c: G["cells"][0], i: number) => boolean,
): number { ): number {
let count = 0; let count = 0;
for (const i of cellsInArea(start, end, g)) { for (const i of cellsInArea(start, end, g)) {
@@ -217,7 +217,7 @@ const areaEnd = (
start: number, start: number,
columns: number, columns: number,
rows: number, rows: number,
g: SparseGrid g: SparseGrid,
): number => start + columns - 1 + g.columns * (rows - 1); ): number => start + columns - 1 + g.columns * (rows - 1);
const cloneGrid = <G extends Grid | SparseGrid>(g: G): G => ({ const cloneGrid = <G extends Grid | SparseGrid>(g: G): G => ({
@@ -231,7 +231,7 @@ const cloneGrid = <G extends Grid | SparseGrid>(g: G): G => ({
*/ */
function getNextGap( function getNextGap(
g: SparseGrid, g: SparseGrid,
ignoreGap: (cell: number) => boolean ignoreGap: (cell: number) => boolean,
): number | null { ): number | null {
const last1By1Index = findLast1By1Index(g); const last1By1Index = findLast1By1Index(g);
if (last1By1Index === null) return null; if (last1By1Index === null) return null;
@@ -278,13 +278,13 @@ function moveTileUnchecked(g: SparseGrid, from: number, to: number): void {
to, to,
toEnd, toEnd,
g, g,
(_c, i) => (g.cells[i] = movingCells.shift()) (_c, i) => (g.cells[i] = movingCells.shift()),
); );
forEachCellInArea( forEachCellInArea(
from, from,
fromEnd, fromEnd,
g, g,
(_c, i) => (g.cells[i] ??= displacedTiles.shift()) (_c, i) => (g.cells[i] ??= displacedTiles.shift()),
); );
} }
@@ -294,7 +294,7 @@ function moveTileUnchecked(g: SparseGrid, from: number, to: number): void {
export function moveTile<G extends Grid | SparseGrid>( export function moveTile<G extends Grid | SparseGrid>(
g: G, g: G,
from: number, from: number,
to: number to: number,
): G { ): G {
const tile = g.cells[from]!; const tile = g.cells[from]!;
@@ -333,7 +333,7 @@ function pushTileUp(
g: SparseGrid, g: SparseGrid,
from: number, from: number,
rows: number, rows: number,
avoid: (cell: number) => boolean = (): boolean => false avoid: (cell: number) => boolean = (): boolean => false,
): number { ): number {
const tile = g.cells[from]!; const tile = g.cells[from]!;
@@ -347,7 +347,7 @@ function pushTileUp(
to, to,
Math.min(from - g.columns + tile.columns - 1, toEnd), Math.min(from - g.columns + tile.columns - 1, toEnd),
g, g,
(c, i) => (c === undefined || is1By1(c)) && !avoid(i) (c, i) => (c === undefined || is1By1(c)) && !avoid(i),
); );
if (cellsAboveAreDisplacable) { if (cellsAboveAreDisplacable) {
@@ -376,7 +376,7 @@ function canVacateArea(g: SparseGrid, start: number, end: number): boolean {
start, start,
end - newFullRows * g.columns, end - newFullRows * g.columns,
g, g,
(c) => c === undefined || is1By1(c) (c) => c === undefined || is1By1(c),
); );
} }
@@ -391,7 +391,7 @@ function vacateArea(g: SparseGrid, start: number, end: number): SparseGrid {
start, start,
end, end,
g, g,
(c, i) => c !== undefined || i >= g.cells.length (c, i) => c !== undefined || i >= g.cells.length,
); );
const newFullRows = Math.floor(newCellCount / g.columns); const newFullRows = Math.floor(newCellCount / g.columns);
const endRow = row(end, g); const endRow = row(end, g);
@@ -452,7 +452,7 @@ function vacateArea(g: SparseGrid, start: number, end: number): SparseGrid {
const inputStructure = fillGaps( const inputStructure = fillGaps(
outputStructure, outputStructure,
false, false,
(i) => inArea(i, start, end, g) && g.cells[i] === undefined (i) => inArea(i, start, end, g) && g.cells[i] === undefined,
); );
// We exploit the fact that g and inputStructure have the same structure to // We exploit the fact that g and inputStructure have the same structure to
@@ -464,7 +464,7 @@ function vacateArea(g: SparseGrid, start: number, end: number): SparseGrid {
return { return {
columns: g.columns, columns: g.columns,
cells: outputStructure.cells.map((placeholder) => cells: outputStructure.cells.map((placeholder) =>
structureMapping.get(placeholder) structureMapping.get(placeholder),
), ),
}; };
} }
@@ -475,21 +475,21 @@ function vacateArea(g: SparseGrid, start: number, end: number): SparseGrid {
export function fillGaps( export function fillGaps(
g: SparseGrid, g: SparseGrid,
packLargeTiles?: true, packLargeTiles?: true,
ignoreGap?: () => false ignoreGap?: () => false,
): Grid; ): Grid;
export function fillGaps( export function fillGaps(
g: SparseGrid, g: SparseGrid,
packLargeTiles?: boolean, packLargeTiles?: boolean,
ignoreGap?: (cell: number) => boolean ignoreGap?: (cell: number) => boolean,
): SparseGrid; ): SparseGrid;
export function fillGaps( export function fillGaps(
g: SparseGrid, g: SparseGrid,
packLargeTiles = true, packLargeTiles = true,
ignoreGap: (cell: number) => boolean = (): boolean => false ignoreGap: (cell: number) => boolean = (): boolean => false,
): SparseGrid { ): SparseGrid {
const lastGap = findLastIndex( const lastGap = findLastIndex(
g.cells, g.cells,
(c, i) => c === undefined && !ignoreGap(i) (c, i) => c === undefined && !ignoreGap(i),
); );
if (lastGap === null) return g; // There are no gaps to fill if (lastGap === null) return g; // There are no gaps to fill
const lastGapRow = row(lastGap, g); const lastGapRow = row(lastGap, g);
@@ -500,10 +500,10 @@ export function fillGaps(
// allowed to pack the large tiles into the rest of the grid as necessary) // allowed to pack the large tiles into the rest of the grid as necessary)
let idealLength = count( let idealLength = count(
result.cells, result.cells,
(c, i) => c !== undefined || ignoreGap(i) (c, i) => c !== undefined || ignoreGap(i),
); );
const fullRowsRemoved = Math.floor( const fullRowsRemoved = Math.floor(
(g.cells.length - idealLength) / g.columns (g.cells.length - idealLength) / g.columns,
); );
// Step 1: Push all large tiles below the last gap upwards, so that they move // Step 1: Push all large tiles below the last gap upwards, so that they move
@@ -620,7 +620,7 @@ function createRows(g: SparseGrid, count: number, atRow: number): SparseGrid {
g, g,
(c, i) => { (c, i) => {
result.cells[i + offset] = c; result.cells[i + offset] = c;
} },
); );
} }
}); });
@@ -633,7 +633,7 @@ function createRows(g: SparseGrid, count: number, atRow: number): SparseGrid {
*/ */
export function addItems( export function addItems(
items: TileDescriptor<unknown>[], items: TileDescriptor<unknown>[],
g: SparseGrid g: SparseGrid,
): SparseGrid { ): SparseGrid {
let result: SparseGrid = cloneGrid(g); let result: SparseGrid = cloneGrid(g);
@@ -655,7 +655,7 @@ export function addItems(
// This item wants to be placed near another; let's put it on a row // This item wants to be placed near another; let's put it on a row
// directly below the related tile // directly below the related tile
const placeNear = result.cells.findIndex( const placeNear = result.cells.findIndex(
(c) => c?.item.id === item.placeNear (c) => c?.item.id === item.placeNear,
); );
if (placeNear === -1) { if (placeNear === -1) {
// Can't find the related tile, so let's give up and place it at the end // Can't find the related tile, so let's give up and place it at the end
@@ -666,7 +666,7 @@ export function addItems(
placeNear, placeNear,
placeNearCell.columns, placeNearCell.columns,
placeNearCell.rows, placeNearCell.rows,
result result,
); );
result = createRows(result, 1, row(placeNearEnd, result) + 1); result = createRows(result, 1, row(placeNearEnd, result) + 1);
@@ -699,7 +699,7 @@ const extraLargeTileDimensions = (g: SparseGrid): [number, number] =>
export function cycleTileSize<G extends Grid | SparseGrid>( export function cycleTileSize<G extends Grid | SparseGrid>(
g: G, g: G,
tile: TileDescriptor<unknown> tile: TileDescriptor<unknown>,
): G { ): G {
const from = g.cells.findIndex((c) => c?.item === tile); const from = g.cells.findIndex((c) => c?.item === tile);
if (from === -1) return g; // Tile removed, no change if (from === -1) return g; // Tile removed, no change
@@ -727,7 +727,7 @@ function findNearestCell<G extends Grid | SparseGrid>(
g: G, g: G,
nearestTo: number, nearestTo: number,
shouldScan: (index: number) => boolean, shouldScan: (index: number) => boolean,
predicate: (cell: G["cells"][0], index: number) => boolean predicate: (cell: G["cells"][0], index: number) => boolean,
): number | null { ): number | null {
const scanLocations = new Set([nearestTo]); const scanLocations = new Set([nearestTo]);
@@ -758,7 +758,7 @@ export function setTileSize<G extends Grid | SparseGrid>(
g: G, g: G,
from: number, from: number,
toWidth: number, toWidth: number,
toHeight: number toHeight: number,
): G { ): G {
const fromCell = g.cells[from]!; const fromCell = g.cells[from]!;
const fromWidth = fromCell.columns; const fromWidth = fromCell.columns;
@@ -771,12 +771,12 @@ export function setTileSize<G extends Grid | SparseGrid>(
0, 0,
Math.min( Math.min(
g.columns - toWidth, g.columns - toWidth,
column(from, g) + Math.trunc((fromWidth - toWidth) / 2) column(from, g) + Math.trunc((fromWidth - toWidth) / 2),
) ),
); );
const toRow = Math.max( const toRow = Math.max(
0, 0,
row(from, g) + Math.trunc((fromHeight - toHeight) / 2) row(from, g) + Math.trunc((fromHeight - toHeight) / 2),
); );
const targetDest = toColumn + toRow * g.columns; const targetDest = toColumn + toRow * g.columns;
@@ -788,7 +788,7 @@ export function setTileSize<G extends Grid | SparseGrid>(
const placeTile = ( const placeTile = (
to: number, to: number,
toEnd: number, toEnd: number,
grid: Grid | SparseGrid grid: Grid | SparseGrid,
): void => { ): void => {
forEachCellInArea(to, toEnd, grid, (_c, i) => { forEachCellInArea(to, toEnd, grid, (_c, i) => {
grid.cells[i] = { grid.cells[i] = {
@@ -824,7 +824,7 @@ export function setTileSize<G extends Grid | SparseGrid>(
(_c, i) => { (_c, i) => {
const end = areaEnd(i, toWidth, toHeight, g); const end = areaEnd(i, toWidth, toHeight, g);
return end < newGridSize && canVacateArea(gridWithoutTile, i, end); return end < newGridSize && canVacateArea(gridWithoutTile, i, end);
} },
); );
if (to !== null) { if (to !== null) {
@@ -848,7 +848,7 @@ export function setTileSize<G extends Grid | SparseGrid>(
(_c, i) => { (_c, i) => {
const end = areaEnd(i, toWidth, toHeight, g); const end = areaEnd(i, toWidth, toHeight, g);
return end < newGridSize && canVacateArea(packedGridWithoutTile, i, end); return end < newGridSize && canVacateArea(packedGridWithoutTile, i, end);
} },
); );
if (to === null) return g; // There's no space anywhere; give up if (to === null) return g; // There's no space anywhere; give up
@@ -949,7 +949,7 @@ function updateTiles(g: Grid, tiles: TileDescriptor<unknown>[]): Grid {
// Step 2: Add new tiles // Step 2: Add new tiles
const existingItemIds = new Set( const existingItemIds = new Set(
grid1.cells.filter((c) => c !== undefined).map((c) => c!.item.id) grid1.cells.filter((c) => c !== undefined).map((c) => c!.item.id),
); );
const newItems = tiles.filter((i) => !existingItemIds.has(i.id)); const newItems = tiles.filter((i) => !existingItemIds.has(i.id));
const grid2 = addItems(newItems, grid1); const grid2 = addItems(newItems, grid1);
@@ -967,7 +967,7 @@ function updateBounds(g: Grid, bounds: RectReadOnly): Grid {
const Slots: FC<{ s: Grid }> = memo(({ s: g }) => { const Slots: FC<{ s: Grid }> = memo(({ s: g }) => {
const areas = new Array<(number | null)[]>( const areas = new Array<(number | null)[]>(
Math.ceil(g.cells.length / g.columns) Math.ceil(g.cells.length / g.columns),
); );
for (let i = 0; i < areas.length; i++) for (let i = 0; i < areas.length; i++)
areas[i] = new Array<number | null>(g.columns).fill(null); areas[i] = new Array<number | null>(g.columns).fill(null);
@@ -981,7 +981,7 @@ const Slots: FC<{ s: Grid }> = memo(({ s: g }) => {
i, i,
slotEnd, slotEnd,
g, g,
(_c, j) => (areas[row(j, g)][column(j, g)] = slotCount) (_c, j) => (areas[row(j, g)][column(j, g)] = slotCount),
); );
slotCount++; slotCount++;
} }
@@ -993,7 +993,7 @@ const Slots: FC<{ s: Grid }> = memo(({ s: g }) => {
(row) => (row) =>
`'${row `'${row
.map((slotId) => (slotId === null ? "." : `s${slotId}`)) .map((slotId) => (slotId === null ? "." : `s${slotId}`))
.join(" ")}'` .join(" ")}'`,
) )
.join(" "), .join(" "),
gridTemplateColumns: `repeat(${g.columns}, 1fr)`, gridTemplateColumns: `repeat(${g.columns}, 1fr)`,
@@ -1019,7 +1019,7 @@ function positionOnTileToCell(
g: SparseGrid, g: SparseGrid,
tileOriginIndex: number, tileOriginIndex: number,
xPositionOnTile: number, xPositionOnTile: number,
yPositionOnTile: number yPositionOnTile: number,
): number { ): number {
const tileOrigin = g.cells[tileOriginIndex]!; const tileOrigin = g.cells[tileOriginIndex]!;
const columnOnTile = Math.floor(xPositionOnTile * tileOrigin.columns); const columnOnTile = Math.floor(xPositionOnTile * tileOrigin.columns);
@@ -1034,7 +1034,7 @@ function dragTile(
xPositionOnFrom: number, xPositionOnFrom: number,
yPositionOnFrom: number, yPositionOnFrom: number,
xPositionOnTo: number, xPositionOnTo: number,
yPositionOnTo: number yPositionOnTo: number,
): Grid { ): Grid {
const fromOrigin = g.cells.findIndex((c) => c.item === from); const fromOrigin = g.cells.findIndex((c) => c.item === from);
const toOrigin = g.cells.findIndex((c) => c.item === to); const toOrigin = g.cells.findIndex((c) => c.item === to);
@@ -1042,13 +1042,13 @@ function dragTile(
g, g,
fromOrigin, fromOrigin,
xPositionOnFrom, xPositionOnFrom,
yPositionOnFrom yPositionOnFrom,
); );
const toCell = positionOnTileToCell( const toCell = positionOnTileToCell(
g, g,
toOrigin, toOrigin,
xPositionOnTo, xPositionOnTo,
yPositionOnTo yPositionOnTo,
); );
return moveTile(g, fromOrigin, fromOrigin + toCell - fromCell); return moveTile(g, fromOrigin, fromOrigin + toCell - fromCell);

View File

@@ -61,7 +61,7 @@ export interface Layout<State> {
xPositionOnFrom: number, xPositionOnFrom: number,
yPositionOnFrom: number, yPositionOnFrom: number,
xPositionOnTo: number, xPositionOnTo: number,
yPositionOnTo: number yPositionOnTo: number,
) => State; ) => State;
/** /**
* Toggles the focus of the given tile (if this layout has the concept of * Toggles the focus of the given tile (if this layout has the concept of
@@ -109,7 +109,7 @@ interface UseLayout<State, T> {
xPositionOnFrom: number, xPositionOnFrom: number,
yPositionOnFrom: number, yPositionOnFrom: number,
xPositionOnTo: number, xPositionOnTo: number,
yPositionOnTo: number yPositionOnTo: number,
) => void; ) => void;
toggleFocus: ((tile: TileDescriptor<T>) => void) | undefined; toggleFocus: ((tile: TileDescriptor<T>) => void) | undefined;
slots: ReactNode; slots: ReactNode;
@@ -123,7 +123,7 @@ export function useLayout<State, T>(
layout: Layout<State>, layout: Layout<State>,
items: TileDescriptor<T>[], items: TileDescriptor<T>[],
bounds: RectReadOnly, bounds: RectReadOnly,
layoutStates: LayoutStatesMap layoutStates: LayoutStatesMap,
): UseLayout<State, T> { ): UseLayout<State, T> {
const prevLayout = useRef<Layout<unknown>>(); const prevLayout = useRef<Layout<unknown>>();
const prevState = layoutStates.get(layout); const prevState = layoutStates.get(layout);
@@ -159,7 +159,7 @@ export function useLayout<State, T>(
generation: generation.current, generation: generation.current,
canDragTile: useCallback( canDragTile: useCallback(
(tile: TileDescriptor<T>) => layout.canDragTile(state, tile), (tile: TileDescriptor<T>) => layout.canDragTile(state, tile),
[layout, state] [layout, state],
), ),
dragTile: useCallback( dragTile: useCallback(
( (
@@ -168,7 +168,7 @@ export function useLayout<State, T>(
xPositionOnFrom: number, xPositionOnFrom: number,
yPositionOnFrom: number, yPositionOnFrom: number,
xPositionOnTo: number, xPositionOnTo: number,
yPositionOnTo: number yPositionOnTo: number,
) => ) =>
setState((s) => setState((s) =>
layout.dragTile( layout.dragTile(
@@ -178,17 +178,17 @@ export function useLayout<State, T>(
xPositionOnFrom, xPositionOnFrom,
yPositionOnFrom, yPositionOnFrom,
xPositionOnTo, xPositionOnTo,
yPositionOnTo yPositionOnTo,
)
), ),
[layout, setState] ),
[layout, setState],
), ),
toggleFocus: useMemo( toggleFocus: useMemo(
() => () =>
layout.toggleFocus && layout.toggleFocus &&
((tile: TileDescriptor<T>): void => ((tile: TileDescriptor<T>): void =>
setState((s) => layout.toggleFocus!(s, tile))), setState((s) => layout.toggleFocus!(s, tile))),
[layout, setState] [layout, setState],
), ),
slots: <layout.Slots s={state} />, slots: <layout.Slots s={state} />,
}; };

View File

@@ -98,13 +98,13 @@ export function NewVideoGrid<T>({
useEffect(() => { useEffect(() => {
if (slotsRoot !== null) { if (slotsRoot !== null) {
setRenderedGeneration( setRenderedGeneration(
parseInt(slotsRoot.getAttribute("data-generation")!) parseInt(slotsRoot.getAttribute("data-generation")!),
); );
const observer = new MutationObserver((mutations) => { const observer = new MutationObserver((mutations) => {
if (mutations.some((m) => m.type === "attributes")) { if (mutations.some((m) => m.type === "attributes")) {
setRenderedGeneration( setRenderedGeneration(
parseInt(slotsRoot.getAttribute("data-generation")!) parseInt(slotsRoot.getAttribute("data-generation")!),
); );
} }
}); });
@@ -158,13 +158,13 @@ export function NewVideoGrid<T>({
if (renderedGeneration !== generation) return prevTiles ?? []; if (renderedGeneration !== generation) return prevTiles ?? [];
const tileRects = new Map( const tileRects = new Map(
zip(orderedItems, slotRects) as [TileDescriptor<T>, Rect][] zip(orderedItems, slotRects) as [TileDescriptor<T>, Rect][],
); );
// In order to not break drag gestures, it's critical that we render tiles // In order to not break drag gestures, it's critical that we render tiles
// in a stable order (that of 'items') // in a stable order (that of 'items')
return items.map((item) => ({ ...tileRects.get(item)!, item })); return items.map((item) => ({ ...tileRects.get(item)!, item }));
}, },
[slotRects, grid, renderedGeneration] [slotRects, grid, renderedGeneration],
); );
// Drag state is stored in a ref rather than component state, because we use // Drag state is stored in a ref rather than component state, because we use
@@ -200,7 +200,7 @@ export function NewVideoGrid<T>({
}, },
leave: { opacity: 0, scale: 0, immediate: disableAnimations }, leave: { opacity: 0, scale: 0, immediate: disableAnimations },
config: { mass: 0.7, tension: 252, friction: 25 }, config: { mass: 0.7, tension: 252, friction: 25 },
}) }),
// react-spring's types are bugged and can't infer the spring type // react-spring's types are bugged and can't infer the spring type
) as unknown as [TransitionFn<Tile<T>, TileSpring>, SpringRef<TileSpring>]; ) as unknown as [TransitionFn<Tile<T>, TileSpring>, SpringRef<TileSpring>];
@@ -242,7 +242,7 @@ export function NewVideoGrid<T>({
disableAnimations || disableAnimations ||
((key): boolean => ((key): boolean =>
key === "zIndex" || key === "x" || key === "y"), key === "zIndex" || key === "x" || key === "y"),
} },
); );
const overTile = tiles.find( const overTile = tiles.find(
@@ -250,7 +250,7 @@ export function NewVideoGrid<T>({
cursorX >= t.x && cursorX >= t.x &&
cursorX < t.x + t.width && cursorX < t.x + t.width &&
cursorY >= t.y && cursorY >= t.y &&
cursorY < t.y + t.height cursorY < t.y + t.height,
); );
if (overTile !== undefined) if (overTile !== undefined)
@@ -260,7 +260,7 @@ export function NewVideoGrid<T>({
(cursorX - tileX) / tile.width, (cursorX - tileX) / tile.width,
(cursorY - tileY) / tile.height, (cursorY - tileY) / tile.height,
(cursorX - overTile.x) / overTile.width, (cursorX - overTile.x) / overTile.width,
(cursorY - overTile.y) / overTile.height (cursorY - overTile.y) / overTile.height,
); );
}; };
@@ -287,7 +287,7 @@ export function NewVideoGrid<T>({
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
last, last,
}: Parameters<Handler<"drag", EventTypes["drag"]>>[0] }: Parameters<Handler<"drag", EventTypes["drag"]>>[0],
): void => { ): void => {
if (tap) { if (tap) {
const now = Date.now(); const now = Date.now();
@@ -303,7 +303,7 @@ export function NewVideoGrid<T>({
} }
} else { } else {
const tileController = springRef.current.find( const tileController = springRef.current.find(
(c) => (c.item as Tile<T>).item.id === tileId (c) => (c.item as Tile<T>).item.id === tileId,
)!; )!;
if (canDragTile((tileController.item as Tile<T>).item)) { if (canDragTile((tileController.item as Tile<T>).item)) {
@@ -347,7 +347,7 @@ export function NewVideoGrid<T>({
animateDraggedTile(false); animateDraggedTile(false);
} }
}, },
{ target: gridRef2 } { target: gridRef2 },
); );
// Render nothing if the grid has yet to be generated // Render nothing if the grid has yet to be generated

View File

@@ -25,7 +25,7 @@ interface Props<T> {
onDragRef: RefObject< onDragRef: RefObject<
( (
tileId: string, tileId: string,
state: Parameters<Handler<"drag", EventTypes["drag"]>>[0] state: Parameters<Handler<"drag", EventTypes["drag"]>>[0],
) => void ) => void
>; >;
targetWidth: number; targetWidth: number;
@@ -87,7 +87,7 @@ export const TileWrapper = memo(
height, height,
boxShadow: to( boxShadow: to(
[shadow, shadowSpread], [shadow, shadowSpread],
(s, ss) => `rgba(0, 0, 0, 0.5) 0px ${s}px ${2 * s}px ${ss}px` (s, ss) => `rgba(0, 0, 0, 0.5) 0px ${s}px ${2 * s}px ${ss}px`,
), ),
}, },
targetWidth, targetWidth,
@@ -96,7 +96,7 @@ export const TileWrapper = memo(
})} })}
</> </>
); );
} },
// We pretend this component is a simple function rather than a // We pretend this component is a simple function rather than a
// NamedExoticComponent, because that's the only way we can fit in a type // NamedExoticComponent, because that's the only way we can fit in a type
// parameter // parameter

Some files were not shown because too many files have changed in this diff Show More