Conform more of the codebase to strictNullChecks
(#10358
* Conform more of the codebase to `strictNullChecks` * Fix types * Iterate * Iterate
This commit is contained in:
parent
41d88ad6ae
commit
503df62191
76 changed files with 323 additions and 327 deletions
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { HTMLAttributes, InputHTMLAttributes, ReactHTML, ReactNode } from "react";
|
||||
import React, { HTMLAttributes, InputHTMLAttributes, ReactNode } from "react";
|
||||
import classnames from "classnames";
|
||||
|
||||
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
|
||||
|
@ -91,7 +91,7 @@ export interface IAccessibleButtonProps extends React.InputHTMLAttributes<Elemen
|
|||
* @returns {Object} rendered react
|
||||
*/
|
||||
export default function AccessibleButton<T extends keyof JSX.IntrinsicElements>({
|
||||
element,
|
||||
element = "div" as T,
|
||||
onClick,
|
||||
children,
|
||||
kind,
|
||||
|
@ -169,7 +169,6 @@ export default function AccessibleButton<T extends keyof JSX.IntrinsicElements>(
|
|||
}
|
||||
|
||||
AccessibleButton.defaultProps = {
|
||||
element: "div" as keyof ReactHTML,
|
||||
role: "button",
|
||||
tabIndex: 0,
|
||||
};
|
||||
|
|
|
@ -61,8 +61,6 @@ export default class AppPermission extends React.Component<IProps, IState> {
|
|||
|
||||
// Set all this into the initial state
|
||||
this.state = {
|
||||
widgetDomain: null,
|
||||
isWrapped: null,
|
||||
roomMember,
|
||||
...urlInfo,
|
||||
};
|
||||
|
|
|
@ -33,7 +33,8 @@ export function getDesktopCapturerSources(): Promise<Array<DesktopCapturerSource
|
|||
},
|
||||
types: ["screen", "window"],
|
||||
};
|
||||
return PlatformPeg.get().getDesktopCapturerSources(options);
|
||||
const plaf = PlatformPeg.get();
|
||||
return plaf ? plaf?.getDesktopCapturerSources(options) : Promise.resolve<DesktopCapturerSource[]>([]);
|
||||
}
|
||||
|
||||
export enum Tabs {
|
||||
|
|
|
@ -69,7 +69,7 @@ export default class DialogButtons extends React.Component<IProps> {
|
|||
};
|
||||
|
||||
private onCancelClick = (event: React.MouseEvent): void => {
|
||||
this.props.onCancel(event);
|
||||
this.props.onCancel?.(event);
|
||||
};
|
||||
|
||||
public render(): React.ReactNode {
|
||||
|
@ -77,9 +77,9 @@ export default class DialogButtons extends React.Component<IProps> {
|
|||
if (this.props.primaryButtonClass) {
|
||||
primaryButtonClassName += " " + this.props.primaryButtonClass;
|
||||
}
|
||||
let cancelButton;
|
||||
|
||||
if (this.props.cancelButton || this.props.hasCancel) {
|
||||
let cancelButton: JSX.Element | undefined;
|
||||
if (this.props.hasCancel) {
|
||||
cancelButton = (
|
||||
<button
|
||||
// important: the default type is 'submit' and this button comes before the
|
||||
|
@ -95,7 +95,7 @@ export default class DialogButtons extends React.Component<IProps> {
|
|||
);
|
||||
}
|
||||
|
||||
let additive = null;
|
||||
let additive: JSX.Element | undefined;
|
||||
if (this.props.additive) {
|
||||
additive = <div className="mx_Dialog_buttons_additive">{this.props.additive}</div>;
|
||||
}
|
||||
|
|
|
@ -113,8 +113,8 @@ interface IState {
|
|||
*/
|
||||
export default class Dropdown extends React.Component<DropdownProps, IState> {
|
||||
private readonly buttonRef = createRef<HTMLDivElement>();
|
||||
private dropdownRootElement: HTMLDivElement = null;
|
||||
private ignoreEvent: MouseEvent = null;
|
||||
private dropdownRootElement: HTMLDivElement | null = null;
|
||||
private ignoreEvent: MouseEvent | null = null;
|
||||
private childrenByKey: Record<string, ReactNode> = {};
|
||||
|
||||
public constructor(props: DropdownProps) {
|
||||
|
@ -373,18 +373,14 @@ export default class Dropdown extends React.Component<DropdownProps, IState> {
|
|||
);
|
||||
}
|
||||
|
||||
const dropdownClasses: Record<string, boolean> = {
|
||||
mx_Dropdown: true,
|
||||
mx_Dropdown_disabled: this.props.disabled,
|
||||
};
|
||||
if (this.props.className) {
|
||||
dropdownClasses[this.props.className] = true;
|
||||
}
|
||||
const dropdownClasses = classnames("mx_Dropdown", this.props.className, {
|
||||
mx_Dropdown_disabled: !!this.props.disabled,
|
||||
});
|
||||
|
||||
// Note the menu sits inside the AccessibleButton div so it's anchored
|
||||
// to the input, but overflows below it. The root contains both.
|
||||
return (
|
||||
<div className={classnames(dropdownClasses)} ref={this.collectRoot}>
|
||||
<div className={dropdownClasses} ref={this.collectRoot}>
|
||||
<AccessibleButton
|
||||
className="mx_Dropdown_input mx_no_textinput"
|
||||
onClick={this.onAccessibleButtonClick}
|
||||
|
|
|
@ -30,7 +30,7 @@ const EffectsOverlay: FunctionComponent<IProps> = ({ roomWidth }) => {
|
|||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const effectsRef = useRef<Map<string, ICanvasEffect>>(new Map<string, ICanvasEffect>());
|
||||
|
||||
const lazyLoadEffectModule = async (name: string): Promise<ICanvasEffect> => {
|
||||
const lazyLoadEffectModule = async (name: string): Promise<ICanvasEffect | null> => {
|
||||
if (!name) return null;
|
||||
let effect: ICanvasEffect | null = effectsRef.current.get(name) || null;
|
||||
if (effect === null) {
|
||||
|
@ -38,7 +38,7 @@ const EffectsOverlay: FunctionComponent<IProps> = ({ roomWidth }) => {
|
|||
try {
|
||||
const { default: Effect } = await import(`../../../effects/${name}`);
|
||||
effect = new Effect(options);
|
||||
effectsRef.current.set(name, effect);
|
||||
effectsRef.current.set(name, effect!);
|
||||
} catch (err) {
|
||||
logger.warn(`Unable to load effect module at '../../../effects/${name}.`, err);
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ const EffectsOverlay: FunctionComponent<IProps> = ({ roomWidth }) => {
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const currentEffects = effectsRef.current; // this is not a react node ref, warning can be safely ignored
|
||||
for (const effect in currentEffects) {
|
||||
const effectModule: ICanvasEffect = currentEffects.get(effect);
|
||||
const effectModule: ICanvasEffect = currentEffects.get(effect)!;
|
||||
if (effectModule && effectModule.isRunning) {
|
||||
effectModule.stop();
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ interface Props {
|
|||
}
|
||||
|
||||
interface IState {
|
||||
error: Error;
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,9 +41,7 @@ export default class ErrorBoundary extends React.PureComponent<Props, IState> {
|
|||
public constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
error: null,
|
||||
};
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
public static getDerivedStateFromError(error: Error): Partial<IState> {
|
||||
|
@ -66,7 +64,7 @@ export default class ErrorBoundary extends React.PureComponent<Props, IState> {
|
|||
MatrixClientPeg.get()
|
||||
.store.deleteAllData()
|
||||
.then(() => {
|
||||
PlatformPeg.get().reload();
|
||||
PlatformPeg.get()?.reload();
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -121,7 +119,7 @@ export default class ErrorBoundary extends React.PureComponent<Props, IState> {
|
|||
);
|
||||
}
|
||||
|
||||
let clearCacheButton: JSX.Element;
|
||||
let clearCacheButton: JSX.Element | undefined;
|
||||
// we only show this button if there is an initialised MatrixClient otherwise we can't clear the cache
|
||||
if (MatrixClientPeg.get()) {
|
||||
clearCacheButton = (
|
||||
|
|
|
@ -113,7 +113,7 @@ export default class EventListSummary extends React.Component<IProps> {
|
|||
private generateSummary(
|
||||
eventAggregates: Record<string, string[]>,
|
||||
orderedTransitionSequences: string[],
|
||||
): string | JSX.Element {
|
||||
): ReactNode {
|
||||
const summaries = orderedTransitionSequences.map((transitions) => {
|
||||
const userNames = eventAggregates[transitions];
|
||||
const nameList = this.renderNameList(userNames);
|
||||
|
@ -392,7 +392,7 @@ export default class EventListSummary extends React.Component<IProps> {
|
|||
* @returns {string?} the transition type given to this event. This defaults to `null`
|
||||
* if a transition is not recognised.
|
||||
*/
|
||||
private static getTransition(e: IUserEvents): TransitionType {
|
||||
private static getTransition(e: IUserEvents): TransitionType | null {
|
||||
if (e.mxEvent.isRedacted()) {
|
||||
return TransitionType.MessageRemoved;
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ export interface IInputProps extends IProps, InputHTMLAttributes<HTMLInputElemen
|
|||
// The ref pass through to the input
|
||||
inputRef?: RefObject<HTMLInputElement>;
|
||||
// The element to create. Defaults to "input".
|
||||
element?: "input";
|
||||
element: "input";
|
||||
// The input's value. This is a controlled component, so the value is required.
|
||||
value: string;
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ export default class Field extends React.PureComponent<PropShapes, IState> {
|
|||
const value = this.inputRef.current?.value ?? null;
|
||||
const { valid, feedback } = await this.props.onValidate({
|
||||
value,
|
||||
focused,
|
||||
focused: !!focused,
|
||||
allowEmpty,
|
||||
});
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ interface IProps {
|
|||
// The list of room members for which to show avatars next to the summary
|
||||
"summaryMembers"?: RoomMember[];
|
||||
// The text to show as the summary of this event list
|
||||
"summaryText"?: string | JSX.Element;
|
||||
"summaryText"?: ReactNode;
|
||||
// An array of EventTiles to render when expanded
|
||||
"children": ReactNode[];
|
||||
// Called when the event list expansion is toggled
|
||||
|
|
|
@ -29,7 +29,7 @@ interface IProps {
|
|||
|
||||
interface IState {
|
||||
width: number;
|
||||
IRCLayoutRoot: HTMLElement;
|
||||
IRCLayoutRoot: HTMLElement | null;
|
||||
}
|
||||
|
||||
export default class IRCTimelineProfileResizer extends React.Component<IProps, IState> {
|
||||
|
@ -77,7 +77,7 @@ export default class IRCTimelineProfileResizer extends React.Component<IProps, I
|
|||
};
|
||||
|
||||
private updateCSSWidth(newWidth: number): void {
|
||||
this.state.IRCLayoutRoot.style.setProperty("--name-width", newWidth + "px");
|
||||
this.state.IRCLayoutRoot?.style.setProperty("--name-width", newWidth + "px");
|
||||
}
|
||||
|
||||
private onMoueUp = (): void => {
|
||||
|
|
|
@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { createRef } from "react";
|
||||
import React, { createRef, CSSProperties } from "react";
|
||||
import FocusLock from "react-focus-lock";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
|
||||
|
@ -395,7 +395,7 @@ export default class ImageView extends React.Component<IProps, IState> {
|
|||
};
|
||||
|
||||
private renderContextMenu(): JSX.Element {
|
||||
let contextMenu = null;
|
||||
let contextMenu: JSX.Element | undefined;
|
||||
if (this.state.contextMenuDisplayed) {
|
||||
contextMenu = (
|
||||
<MessageContextMenu
|
||||
|
@ -419,11 +419,6 @@ export default class ImageView extends React.Component<IProps, IState> {
|
|||
else if (this.state.moving || !this.imageIsLoaded) transitionClassName = "";
|
||||
else transitionClassName = "mx_ImageView_image_animating";
|
||||
|
||||
let cursor;
|
||||
if (this.state.moving) cursor = "grabbing";
|
||||
else if (this.state.zoom === this.state.minZoom) cursor = "zoom-in";
|
||||
else cursor = "zoom-out";
|
||||
|
||||
const rotationDegrees = this.state.rotation + "deg";
|
||||
const zoom = this.state.zoom;
|
||||
const translatePixelsX = this.state.translationX + "px";
|
||||
|
@ -432,15 +427,18 @@ export default class ImageView extends React.Component<IProps, IState> {
|
|||
// First, we translate and only then we rotate, otherwise
|
||||
// we would apply the translation to an already rotated
|
||||
// image causing it translate in the wrong direction.
|
||||
const style = {
|
||||
cursor: cursor,
|
||||
const style: CSSProperties = {
|
||||
transform: `translateX(${translatePixelsX})
|
||||
translateY(${translatePixelsY})
|
||||
scale(${zoom})
|
||||
rotate(${rotationDegrees})`,
|
||||
};
|
||||
|
||||
let info;
|
||||
if (this.state.moving) style.cursor = "grabbing";
|
||||
else if (this.state.zoom === this.state.minZoom) style.cursor = "zoom-in";
|
||||
else style.cursor = "zoom-out";
|
||||
|
||||
let info: JSX.Element | undefined;
|
||||
if (showEventMeta) {
|
||||
const mxEvent = this.props.mxEvent;
|
||||
const showTwelveHour = SettingsStore.getValue("showTwelveHourTimestamps");
|
||||
|
@ -449,7 +447,7 @@ export default class ImageView extends React.Component<IProps, IState> {
|
|||
permalink = this.props.permalinkCreator.forEvent(this.props.mxEvent.getId());
|
||||
}
|
||||
|
||||
const senderName = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender();
|
||||
const senderName = mxEvent.sender?.name ?? mxEvent.getSender();
|
||||
const sender = <div className="mx_ImageView_info_sender">{senderName}</div>;
|
||||
const messageTimestamp = (
|
||||
<a
|
||||
|
@ -491,7 +489,7 @@ export default class ImageView extends React.Component<IProps, IState> {
|
|||
info = <div />;
|
||||
}
|
||||
|
||||
let contextMenuButton;
|
||||
let contextMenuButton: JSX.Element | undefined;
|
||||
if (this.props.mxEvent) {
|
||||
contextMenuButton = (
|
||||
<ContextMenuTooltipButton
|
||||
|
@ -519,7 +517,7 @@ export default class ImageView extends React.Component<IProps, IState> {
|
|||
/>
|
||||
);
|
||||
|
||||
let title: JSX.Element;
|
||||
let title: JSX.Element | undefined;
|
||||
if (this.props.mxEvent?.getContent()) {
|
||||
title = (
|
||||
<div className="mx_ImageView_title">
|
||||
|
|
|
@ -293,7 +293,7 @@ interface IProps {
|
|||
}
|
||||
|
||||
interface IState {
|
||||
contentRect: DOMRect;
|
||||
contentRect?: DOMRect;
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
|
@ -312,7 +312,6 @@ export default class InteractiveTooltip extends React.Component<IProps, IState>
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
contentRect: null,
|
||||
visible: false,
|
||||
};
|
||||
}
|
||||
|
@ -331,7 +330,7 @@ export default class InteractiveTooltip extends React.Component<IProps, IState>
|
|||
document.removeEventListener("mousemove", this.onMouseMove);
|
||||
}
|
||||
|
||||
private collectContentRect = (element: HTMLElement): void => {
|
||||
private collectContentRect = (element: HTMLElement | null): void => {
|
||||
// We don't need to clean up when unmounting, so ignore
|
||||
if (!element) return;
|
||||
|
||||
|
@ -354,7 +353,7 @@ export default class InteractiveTooltip extends React.Component<IProps, IState>
|
|||
} else {
|
||||
const targetRight = targetRect.right + window.scrollX;
|
||||
const spaceOnRight = UIStore.instance.windowWidth - targetRight;
|
||||
return contentRect && spaceOnRight - contentRect.width < MIN_SAFE_DISTANCE_TO_WINDOW_EDGE;
|
||||
return !!contentRect && spaceOnRight - contentRect.width < MIN_SAFE_DISTANCE_TO_WINDOW_EDGE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -368,7 +367,7 @@ export default class InteractiveTooltip extends React.Component<IProps, IState>
|
|||
} else {
|
||||
const targetBottom = targetRect.bottom + window.scrollY;
|
||||
const spaceBelow = UIStore.instance.windowHeight - targetBottom;
|
||||
return contentRect && spaceBelow - contentRect.height < MIN_SAFE_DISTANCE_TO_WINDOW_EDGE;
|
||||
return !!contentRect && spaceBelow - contentRect.height < MIN_SAFE_DISTANCE_TO_WINDOW_EDGE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,7 +415,7 @@ export default class InteractiveTooltip extends React.Component<IProps, IState>
|
|||
document.removeEventListener("mousemove", this.onMouseMove);
|
||||
}
|
||||
|
||||
private renderTooltip(): JSX.Element {
|
||||
private renderTooltip(): ReactNode {
|
||||
const { contentRect, visible } = this.state;
|
||||
if (!visible) {
|
||||
ReactDOM.unmountComponentAtNode(getOrCreateContainer());
|
||||
|
@ -435,7 +434,7 @@ export default class InteractiveTooltip extends React.Component<IProps, IState>
|
|||
// tooltip content would extend past the safe area towards the window
|
||||
// edge, flip around to below the target.
|
||||
const position: Partial<IRect> = {};
|
||||
let chevronFace: ChevronFace = null;
|
||||
let chevronFace: ChevronFace | null = null;
|
||||
if (this.isOnTheSide) {
|
||||
if (this.onLeftOfTarget()) {
|
||||
position.left = targetLeft;
|
||||
|
@ -461,8 +460,7 @@ export default class InteractiveTooltip extends React.Component<IProps, IState>
|
|||
|
||||
const chevron = <div className={"mx_InteractiveTooltip_chevron_" + chevronFace} />;
|
||||
|
||||
const menuClasses = classNames({
|
||||
mx_InteractiveTooltip: true,
|
||||
const menuClasses = classNames("mx_InteractiveTooltip", {
|
||||
mx_InteractiveTooltip_withChevron_top: chevronFace === ChevronFace.Top,
|
||||
mx_InteractiveTooltip_withChevron_left: chevronFace === ChevronFace.Left,
|
||||
mx_InteractiveTooltip_withChevron_right: chevronFace === ChevronFace.Right,
|
||||
|
|
|
@ -40,7 +40,7 @@ interface IProps {
|
|||
|
||||
interface IState {
|
||||
searchQuery: string;
|
||||
langs: Languages;
|
||||
langs: Languages | null;
|
||||
}
|
||||
|
||||
export default class LanguageDropdown extends React.Component<IProps, IState> {
|
||||
|
@ -103,8 +103,8 @@ export default class LanguageDropdown extends React.Component<IProps, IState> {
|
|||
|
||||
// default value here too, otherwise we need to handle null / undefined
|
||||
// values between mounting and the initial value propagating
|
||||
let language = SettingsStore.getValue("language", null, /*excludeDefault:*/ true);
|
||||
let value = null;
|
||||
let language = SettingsStore.getValue<string | undefined>("language", null, /*excludeDefault:*/ true);
|
||||
let value: string | undefined;
|
||||
if (language) {
|
||||
value = this.props.value || language;
|
||||
} else {
|
||||
|
|
|
@ -76,7 +76,7 @@ interface IProps<T> {
|
|||
}
|
||||
|
||||
interface IState {
|
||||
renderRange: ItemRange;
|
||||
renderRange: ItemRange | null;
|
||||
}
|
||||
|
||||
export default class LazyRenderList<T = any> extends React.Component<IProps<T>, IState> {
|
||||
|
@ -93,7 +93,7 @@ export default class LazyRenderList<T = any> extends React.Component<IProps<T>,
|
|||
};
|
||||
}
|
||||
|
||||
public static getDerivedStateFromProps(props: IProps<unknown>, state: IState): Partial<IState> {
|
||||
public static getDerivedStateFromProps(props: IProps<unknown>, state: IState): Partial<IState> | null {
|
||||
const range = LazyRenderList.getVisibleRangeFromProps(props);
|
||||
const intersectRange = range.expand(props.overflowMargin);
|
||||
const renderRange = range.expand(props.overflowItems);
|
||||
|
|
|
@ -64,7 +64,8 @@ const MiniAvatarUploader: React.FC<IProps> = ({
|
|||
const label = hasAvatar || busy ? hasAvatarLabel : noAvatarLabel;
|
||||
|
||||
const { room } = useContext(RoomContext);
|
||||
const canSetAvatar = isUserAvatar || room?.currentState?.maySendStateEvent(EventType.RoomAvatar, cli.getUserId());
|
||||
const canSetAvatar =
|
||||
isUserAvatar || room?.currentState?.maySendStateEvent(EventType.RoomAvatar, cli.getSafeUserId());
|
||||
if (!canSetAvatar) return <React.Fragment>{children}</React.Fragment>;
|
||||
|
||||
const visible = !!label && (hover || show);
|
||||
|
|
|
@ -50,7 +50,7 @@ export default class PersistentApp extends React.Component<IProps> {
|
|||
app={app}
|
||||
fullWidth={true}
|
||||
room={this.room}
|
||||
userId={this.context.credentials.userId}
|
||||
userId={this.context.getSafeUserId()}
|
||||
creatorUserId={app.creatorUserId}
|
||||
widgetPageTitle={WidgetUtils.getWidgetDataTitle(app)}
|
||||
waitForIframeLoad={app.waitForIframeLoad}
|
||||
|
|
|
@ -163,7 +163,12 @@ export default class PollCreateDialog extends ScrollableBaseModal<IProps, IState
|
|||
doMaybeLocalRoomAction(
|
||||
this.props.room.roomId,
|
||||
(actualRoomId: string) =>
|
||||
this.matrixClient.sendEvent(actualRoomId, this.props.threadId, pollEvent.type, pollEvent.content),
|
||||
this.matrixClient.sendEvent(
|
||||
actualRoomId,
|
||||
this.props.threadId ?? null,
|
||||
pollEvent.type,
|
||||
pollEvent.content,
|
||||
),
|
||||
this.matrixClient,
|
||||
)
|
||||
.then(() => this.props.onFinished(true))
|
||||
|
|
|
@ -48,7 +48,7 @@ interface IProps {
|
|||
parentEv?: MatrixEvent;
|
||||
// called when the ReplyChain contents has changed, including EventTiles thereof
|
||||
onHeightChanged: () => void;
|
||||
permalinkCreator: RoomPermalinkCreator;
|
||||
permalinkCreator?: RoomPermalinkCreator;
|
||||
// Specifies which layout to use.
|
||||
layout?: Layout;
|
||||
// Whether to always show a timestamp
|
||||
|
|
|
@ -71,7 +71,7 @@ export default class RoomAliasField extends React.PureComponent<IProps, IState>
|
|||
const postfix = domain ? <span title={`:${domain}`}>{`:${domain}`}</span> : <span />;
|
||||
const maxlength = domain ? 255 - domain.length - 2 : 255 - 1; // 2 for # and :
|
||||
const value = domain
|
||||
? this.props.value.substring(1, this.props.value.length - this.props.domain.length - 1)
|
||||
? this.props.value.substring(1, this.props.value.length - domain.length - 1)
|
||||
: this.props.value.substring(1);
|
||||
|
||||
return { prefix, postfix, value, maxlength };
|
||||
|
@ -104,7 +104,7 @@ export default class RoomAliasField extends React.PureComponent<IProps, IState>
|
|||
|
||||
private onValidate = async (fieldState: IFieldState): Promise<IValidationResult> => {
|
||||
const result = await this.validationRules(fieldState);
|
||||
this.setState({ isValid: result.valid });
|
||||
this.setState({ isValid: !!result.valid });
|
||||
return result;
|
||||
};
|
||||
|
||||
|
@ -225,8 +225,9 @@ export default class RoomAliasField extends React.PureComponent<IProps, IState>
|
|||
return this.state.isValid;
|
||||
}
|
||||
|
||||
public validate(options: IValidateOpts): Promise<boolean> {
|
||||
return this.fieldRef.current?.validate(options);
|
||||
public async validate(options: IValidateOpts): Promise<boolean> {
|
||||
const val = await this.fieldRef.current?.validate(options);
|
||||
return val ?? false;
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
|
|
|
@ -33,7 +33,7 @@ import TooltipTarget from "./TooltipTarget";
|
|||
import { Linkify, topicToHtml } from "../../../HtmlUtils";
|
||||
|
||||
interface IProps extends React.HTMLProps<HTMLDivElement> {
|
||||
room?: Room;
|
||||
room: Room;
|
||||
}
|
||||
|
||||
export default function RoomTopic({ room, ...props }: IProps): JSX.Element {
|
||||
|
@ -62,7 +62,7 @@ export default function RoomTopic({ room, ...props }: IProps): JSX.Element {
|
|||
|
||||
useDispatcher(dis, (payload) => {
|
||||
if (payload.action === Action.ShowRoomTopic) {
|
||||
const canSetTopic = room.currentState.maySendStateEvent(EventType.RoomTopic, client.getUserId());
|
||||
const canSetTopic = room.currentState.maySendStateEvent(EventType.RoomTopic, client.getSafeUserId());
|
||||
const body = topicToHtml(topic?.text, topic?.html, ref, true);
|
||||
|
||||
const modal = Modal.createDialog(InfoDialog, {
|
||||
|
|
|
@ -71,7 +71,7 @@ export default function SearchWarning({ isRoomEncrypted, kind }: IProps): JSX.El
|
|||
|
||||
let text: ReactNode | undefined;
|
||||
let logo: JSX.Element | undefined;
|
||||
if (desktopBuilds.get("available")) {
|
||||
if (desktopBuilds?.get("available")) {
|
||||
logo = <img src={desktopBuilds.get("logo")} />;
|
||||
const buildUrl = desktopBuilds.get("url");
|
||||
switch (kind) {
|
||||
|
|
|
@ -33,7 +33,7 @@ interface IProps {
|
|||
}
|
||||
|
||||
const showPickerDialog = (
|
||||
title: string,
|
||||
title: string | undefined,
|
||||
serverConfig: ValidatedServerConfig,
|
||||
onFinished: (config: ValidatedServerConfig) => void,
|
||||
): void => {
|
||||
|
|
|
@ -69,14 +69,14 @@ export default class SettingsFlag extends React.Component<IProps, IState> {
|
|||
private save = async (val?: boolean): Promise<void> => {
|
||||
await SettingsStore.setValue(
|
||||
this.props.name,
|
||||
this.props.roomId,
|
||||
this.props.roomId ?? null,
|
||||
this.props.level,
|
||||
val !== undefined ? val : this.state.value,
|
||||
);
|
||||
};
|
||||
|
||||
public render(): React.ReactNode {
|
||||
const canChange = SettingsStore.canSetValue(this.props.name, this.props.roomId, this.props.level);
|
||||
const canChange = SettingsStore.canSetValue(this.props.name, this.props.roomId ?? null, this.props.level);
|
||||
|
||||
if (!canChange && this.props.hideIfCannotSet) return null;
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ interface SpellCheckLanguagesDropdownIProps {
|
|||
|
||||
interface SpellCheckLanguagesDropdownIState {
|
||||
searchQuery: string;
|
||||
languages: Languages;
|
||||
languages?: Languages;
|
||||
}
|
||||
|
||||
export default class SpellCheckLanguagesDropdown extends React.Component<
|
||||
|
@ -51,7 +51,6 @@ export default class SpellCheckLanguagesDropdown extends React.Component<
|
|||
|
||||
this.state = {
|
||||
searchQuery: "",
|
||||
languages: null,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -59,7 +58,7 @@ export default class SpellCheckLanguagesDropdown extends React.Component<
|
|||
const plaf = PlatformPeg.get();
|
||||
if (plaf) {
|
||||
plaf.getAvailableSpellCheckLanguages()
|
||||
.then((languages) => {
|
||||
?.then((languages) => {
|
||||
languages.sort(function (a, b) {
|
||||
if (a < b) return -1;
|
||||
if (a > b) return 1;
|
||||
|
@ -92,11 +91,11 @@ export default class SpellCheckLanguagesDropdown extends React.Component<
|
|||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
if (this.state.languages === null) {
|
||||
if (!this.state.languages) {
|
||||
return <Spinner />;
|
||||
}
|
||||
|
||||
let displayedLanguages;
|
||||
let displayedLanguages: Languages;
|
||||
if (this.state.searchQuery) {
|
||||
displayedLanguages = this.state.languages.filter((lang) => {
|
||||
return languageMatchesSearchQuery(this.state.searchQuery, lang);
|
||||
|
@ -111,8 +110,8 @@ export default class SpellCheckLanguagesDropdown extends React.Component<
|
|||
|
||||
// default value here too, otherwise we need to handle null / undefined;
|
||||
// values between mounting and the initial value propagating
|
||||
let language = SettingsStore.getValue("language", null, /*excludeDefault:*/ true);
|
||||
let value = null;
|
||||
let language = SettingsStore.getValue<string | undefined>("language", null, /*excludeDefault:*/ true);
|
||||
let value: string | undefined;
|
||||
if (language) {
|
||||
value = this.props.value || language;
|
||||
} else {
|
||||
|
|
|
@ -24,7 +24,7 @@ interface IProps extends HTMLAttributes<HTMLSpanElement> {
|
|||
tooltipClass?: string;
|
||||
tooltip: React.ReactNode;
|
||||
tooltipProps?: Omit<React.ComponentProps<typeof TooltipTarget>, "label" | "tooltipClassName" | "className">;
|
||||
onClick?: (ev?: React.MouseEvent) => void;
|
||||
onClick?: (ev: React.MouseEvent) => void;
|
||||
}
|
||||
|
||||
export default class TextWithTooltip extends React.Component<IProps> {
|
||||
|
|
|
@ -40,7 +40,7 @@ export function UseCaseSelection({ onFinished }: Props): JSX.Element {
|
|||
onFinished(selection);
|
||||
}, TIMEOUT);
|
||||
return () => {
|
||||
clearTimeout(handler);
|
||||
if (handler !== null) clearTimeout(handler);
|
||||
handler = null;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ interface Props {
|
|||
}
|
||||
|
||||
export function UseCaseSelectionButton({ useCase, onClick, selected }: Props): JSX.Element {
|
||||
let label: string;
|
||||
let label: string | undefined;
|
||||
switch (useCase) {
|
||||
case UseCase.PersonalMessaging:
|
||||
label = _t("Friends and family");
|
||||
|
|
|
@ -43,7 +43,7 @@ interface IArgs<T, D = void> {
|
|||
}
|
||||
|
||||
export interface IFieldState {
|
||||
value: string;
|
||||
value: string | null;
|
||||
focused: boolean;
|
||||
allowEmpty?: boolean;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue