Enable some more oxlint rules (#34193)
* Enable some more oxlint rules * Iterate * Iterate * Update packages/shared-components/src/room/timeline/event-tile/EventTileView/E2ePadlock/E2ePadlock.tsx Co-authored-by: Hubert Chathi <hubert@uhoreg.ca> --------- Co-authored-by: Hubert Chathi <hubert@uhoreg.ca>
This commit is contained in:
co-authored by
Hubert Chathi
parent
4807ff1568
commit
d54cddcb1d
@@ -41,6 +41,7 @@ export default class NonUrgentToastContainer extends React.PureComponent<EmptyOb
|
|||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const toasts = this.state.toasts.map((t, i) => {
|
const toasts = this.state.toasts.map((t, i) => {
|
||||||
return (
|
return (
|
||||||
|
// oxlint-disable-next-line react/no-array-index-key
|
||||||
<div className="mx_NonUrgentToastContainer_toast" key={`toast-${i}`}>
|
<div className="mx_NonUrgentToastContainer_toast" key={`toast-${i}`}>
|
||||||
{React.createElement(t, {})}
|
{React.createElement(t, {})}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ export default class Waveform extends React.PureComponent<IProps> {
|
|||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
|
// oxlint-disable-next-line react/no-array-index-key
|
||||||
key={i}
|
key={i}
|
||||||
style={
|
style={
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -264,34 +264,50 @@ export default class LoginWithQRFlow extends React.Component<Props> {
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case Phase.ShowingQR: {
|
case Phase.ShowingQR: {
|
||||||
let steps: ReactNode[];
|
let steps: ReactNode;
|
||||||
if (this.props.intent === RendezvousIntent.LOGIN_ON_NEW_DEVICE) {
|
if (this.props.intent === RendezvousIntent.LOGIN_ON_NEW_DEVICE) {
|
||||||
steps = [
|
steps = (
|
||||||
_t("auth|qr_code_login|open_element_mobile_device", {
|
<>
|
||||||
brand: SdkConfig.get().brand,
|
<li>
|
||||||
}),
|
{_t("auth|qr_code_login|open_element_mobile_device", {
|
||||||
_t("auth|qr_code_login|tap_avatar_link_new_device", {
|
brand: SdkConfig.get().brand,
|
||||||
linkNewDevice: <strong>{_t("settings|sessions|sign_in_with_qr")}</strong>,
|
})}
|
||||||
}),
|
</li>
|
||||||
_t("auth|qr_code_login|choose_desktop_computer", {
|
<li>
|
||||||
desktopComputer: <strong>{_t("auth|qr_code_login|desktop_computer")}</strong>,
|
{_t("auth|qr_code_login|tap_avatar_link_new_device", {
|
||||||
}),
|
linkNewDevice: <strong>{_t("settings|sessions|sign_in_with_qr")}</strong>,
|
||||||
_t("auth|qr_code_login|select_ready_to_scan", {
|
})}
|
||||||
readyToScan: <strong>{_t("auth|qr_code_login|ready_to_scan")}</strong>,
|
</li>
|
||||||
}),
|
<li>
|
||||||
_t("auth|qr_code_login|follow_remaining_instructions"),
|
{_t("auth|qr_code_login|choose_desktop_computer", {
|
||||||
];
|
desktopComputer: <strong>{_t("auth|qr_code_login|desktop_computer")}</strong>,
|
||||||
|
})}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{_t("auth|qr_code_login|select_ready_to_scan", {
|
||||||
|
readyToScan: <strong>{_t("auth|qr_code_login|ready_to_scan")}</strong>,
|
||||||
|
})}
|
||||||
|
</li>
|
||||||
|
<li>{_t("auth|qr_code_login|follow_remaining_instructions")}</li>
|
||||||
|
</>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
steps = [
|
steps = (
|
||||||
_t("auth|qr_code_login|open_element_other_device", {
|
<>
|
||||||
brand: SdkConfig.get().brand,
|
<li>
|
||||||
}),
|
{_t("auth|qr_code_login|open_element_other_device", {
|
||||||
_t("auth|qr_code_login|select_qr_code", {
|
brand: SdkConfig.get().brand,
|
||||||
scanQRCode: <strong>{_t("auth|qr_code_login|scan_qr_code")}</strong>,
|
})}
|
||||||
}),
|
</li>
|
||||||
_t("auth|qr_code_login|point_the_camera"),
|
<li>
|
||||||
_t("auth|qr_code_login|follow_remaining_instructions"),
|
{_t("auth|qr_code_login|select_qr_code", {
|
||||||
];
|
scanQRCode: <strong>{_t("auth|qr_code_login|scan_qr_code")}</strong>,
|
||||||
|
})}
|
||||||
|
</li>
|
||||||
|
<li>{_t("auth|qr_code_login|point_the_camera")}</li>
|
||||||
|
<li>{_t("auth|qr_code_login|follow_remaining_instructions")}</li>
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
main = (
|
main = (
|
||||||
@@ -308,11 +324,7 @@ export default class LoginWithQRFlow extends React.Component<Props> {
|
|||||||
<Spinner />
|
<Spinner />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<ol>
|
<ol>{steps}</ol>
|
||||||
{steps.map((step, i) => (
|
|
||||||
<li key={this.props.intent + i}>{step}</li>
|
|
||||||
))}
|
|
||||||
</ol>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export default class ServerOfflineDialog extends React.PureComponent<IProps> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private renderTimeline(): ReactNode[] {
|
private renderTimeline(): ReactNode[] {
|
||||||
return EchoStore.instance.contexts.map((c, i) => {
|
return EchoStore.instance.contexts.map((c) => {
|
||||||
if (!c.firstFailedTime) return null; // not useful
|
if (!c.firstFailedTime) return null; // not useful
|
||||||
if (!(c instanceof RoomEchoContext))
|
if (!(c instanceof RoomEchoContext))
|
||||||
throw new Error("Cannot render unknown context: " + c.constructor.name);
|
throw new Error("Cannot render unknown context: " + c.constructor.name);
|
||||||
@@ -51,7 +51,7 @@ export default class ServerOfflineDialog extends React.PureComponent<IProps> {
|
|||||||
);
|
);
|
||||||
const entries = c.transactions
|
const entries = c.transactions
|
||||||
.filter((t) => t.status === TransactionStatus.Error || t.didPreviouslyFail)
|
.filter((t) => t.status === TransactionStatus.Error || t.didPreviouslyFail)
|
||||||
.map((t, j) => {
|
.map((t) => {
|
||||||
let button = <Spinner size={19} />;
|
let button = <Spinner size={19} />;
|
||||||
if (t.status === TransactionStatus.Error) {
|
if (t.status === TransactionStatus.Error) {
|
||||||
button = (
|
button = (
|
||||||
@@ -61,14 +61,14 @@ export default class ServerOfflineDialog extends React.PureComponent<IProps> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="mx_ServerOfflineDialog_content_context_txn" key={`txn-${j}`}>
|
<div className="mx_ServerOfflineDialog_content_context_txn" key={t.auditName}>
|
||||||
<span className="mx_ServerOfflineDialog_content_context_txn_desc">{t.auditName}</span>
|
<span className="mx_ServerOfflineDialog_content_context_txn_desc">{t.auditName}</span>
|
||||||
{button}
|
{button}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<div className="mx_ServerOfflineDialog_content_context" key={`context-${i}`}>
|
<div className="mx_ServerOfflineDialog_content_context" key={c.room.roomId}>
|
||||||
<div className="mx_ServerOfflineDialog_content_context_timestamp">
|
<div className="mx_ServerOfflineDialog_content_context_timestamp">
|
||||||
{formatTime(c.firstFailedTime, SettingsStore.getValue("showTwelveHourTimestamps"))}
|
{formatTime(c.firstFailedTime, SettingsStore.getValue("showTwelveHourTimestamps"))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -92,11 +92,11 @@ export default class WidgetCapabilitiesPromptDialog extends React.PureComponent<
|
|||||||
// Both are the same type (both timeline or both non-timeline), sort lexicographically
|
// Both are the same type (both timeline or both non-timeline), sort lexicographically
|
||||||
return lexicographicCompare(capA, capB);
|
return lexicographicCompare(capA, capB);
|
||||||
});
|
});
|
||||||
const checkboxRows = orderedCapabilities.map(([cap, isChecked], i) => {
|
const checkboxRows = orderedCapabilities.map(([cap, isChecked]) => {
|
||||||
const text = CapabilityText.for(cap, this.props.widgetKind);
|
const text = CapabilityText.for(cap, this.props.widgetKind);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_WidgetCapabilitiesPromptDialog_cap" key={cap + i}>
|
<div className="mx_WidgetCapabilitiesPromptDialog_cap" key={cap}>
|
||||||
<StyledCheckbox
|
<StyledCheckbox
|
||||||
checked={isChecked}
|
checked={isChecked}
|
||||||
onChange={() => this.onToggle(cap)}
|
onChange={() => this.onToggle(cap)}
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ export default class PollCreateDialog extends ScrollableBaseModal<IProps, IState
|
|||||||
/>
|
/>
|
||||||
<h2>{_t("poll|options_heading")}</h2>
|
<h2>{_t("poll|options_heading")}</h2>
|
||||||
{this.state.options.map((op, i) => (
|
{this.state.options.map((op, i) => (
|
||||||
|
// oxlint-disable-next-line react/no-array-index-key
|
||||||
<div key={`option_${i}`} className="mx_PollCreateDialog_option">
|
<div key={`option_${i}`} className="mx_PollCreateDialog_option">
|
||||||
<Field
|
<Field
|
||||||
id={`pollcreate_option_${i}`}
|
id={`pollcreate_option_${i}`}
|
||||||
|
|||||||
@@ -495,6 +495,7 @@ export class ImageBodyBaseInner extends React.Component<ImageBodyBaseProps, ISta
|
|||||||
<div
|
<div
|
||||||
className="mx_MImageBody_thumbnail_container"
|
className="mx_MImageBody_thumbnail_container"
|
||||||
style={{ maxHeight, maxWidth, aspectRatio: `${infoWidth}/${infoHeight}` }}
|
style={{ maxHeight, maxWidth, aspectRatio: `${infoWidth}/${infoHeight}` }}
|
||||||
|
// oxlint-disable-next-line jsx-a11y/no-noninteractive-tabindex
|
||||||
tabIndex={tooltipProps ? 0 : undefined}
|
tabIndex={tooltipProps ? 0 : undefined}
|
||||||
>
|
>
|
||||||
{placeholder}
|
{placeholder}
|
||||||
|
|||||||
@@ -347,10 +347,10 @@ export default class AliasSettings extends React.Component<IProps, IState> {
|
|||||||
<option value="" key="unset">
|
<option value="" key="unset">
|
||||||
{_t("room_settings|alias_not_specified")}
|
{_t("room_settings|alias_not_specified")}
|
||||||
</option>
|
</option>
|
||||||
{this.getAliases().map((alias, i) => {
|
{this.getAliases().map((alias) => {
|
||||||
if (alias === this.state.canonicalAlias) found = true;
|
if (alias === this.state.canonicalAlias) found = true;
|
||||||
return (
|
return (
|
||||||
<option value={alias} key={i}>
|
<option value={alias} key={alias}>
|
||||||
{alias}
|
{alias}
|
||||||
</option>
|
</option>
|
||||||
);
|
);
|
||||||
@@ -414,7 +414,7 @@ export default class AliasSettings extends React.Component<IProps, IState> {
|
|||||||
)}
|
)}
|
||||||
<datalist id="mx_AliasSettings_altRecommendations">
|
<datalist id="mx_AliasSettings_altRecommendations">
|
||||||
{this.getLocalNonAltAliases().map((alias) => {
|
{this.getLocalNonAltAliases().map((alias) => {
|
||||||
return <option value={alias} key={alias} />;
|
return <option value={alias} key={alias} aria-label={alias} />;
|
||||||
})}
|
})}
|
||||||
</datalist>
|
</datalist>
|
||||||
<EditableAliasesList
|
<EditableAliasesList
|
||||||
|
|||||||
@@ -314,7 +314,11 @@ export default class Autocomplete extends React.PureComponent<IProps, IState> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return completions.length > 0 ? (
|
return completions.length > 0 ? (
|
||||||
<div key={i} className="mx_Autocomplete_ProviderSection" role="presentation">
|
<div
|
||||||
|
key={completionResult.provider.getName()}
|
||||||
|
className="mx_Autocomplete_ProviderSection"
|
||||||
|
role="presentation"
|
||||||
|
>
|
||||||
<div className="mx_Autocomplete_provider_name">{completionResult.provider.getName()}</div>
|
<div className="mx_Autocomplete_provider_name">{completionResult.provider.getName()}</div>
|
||||||
{completionResult.provider.renderCompletions(completions)}
|
{completionResult.provider.renderCompletions(completions)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ function Indicators({ count, currentIndex }: IndicatorsProps): JSX.Element {
|
|||||||
return (
|
return (
|
||||||
<div className="mx_PinnedMessageBanner_Indicators">
|
<div className="mx_PinnedMessageBanner_Indicators">
|
||||||
{Array.from({ length: numberOfIndicators }).map((_, i) => (
|
{Array.from({ length: numberOfIndicators }).map((_, i) => (
|
||||||
|
// oxlint-disable-next-line react/no-array-index-key
|
||||||
<Indicator key={i} active={i === index} hidden={isLastCycle && lastCycleIndex <= i} />
|
<Indicator key={i} active={i === index} hidden={isLastCycle && lastCycleIndex <= i} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -655,6 +655,7 @@ class RoomPreviewBar extends React.Component<IProps, IState> {
|
|||||||
if (!Array.isArray(subTitle)) {
|
if (!Array.isArray(subTitle)) {
|
||||||
subTitle = [subTitle];
|
subTitle = [subTitle];
|
||||||
}
|
}
|
||||||
|
// oxlint-disable-next-line react/no-array-index-key
|
||||||
subTitleElements = subTitle.map((t, i) => <p key={`subTitle${i}`}>{t}</p>);
|
subTitleElements = subTitle.map((t, i) => <p key={`subTitle${i}`}>{t}</p>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import React, { type CSSProperties, memo, type RefObject, type ReactNode } from
|
|||||||
|
|
||||||
import { useIsExpanded } from "../hooks/useIsExpanded";
|
import { useIsExpanded } from "../hooks/useIsExpanded";
|
||||||
import { useSelection } from "../hooks/useSelection";
|
import { useSelection } from "../hooks/useSelection";
|
||||||
|
import { _t } from "../../../../../i18n";
|
||||||
|
|
||||||
const HEIGHT_BREAKING_POINT = 24;
|
const HEIGHT_BREAKING_POINT = 24;
|
||||||
|
|
||||||
@@ -38,6 +39,7 @@ export const Editor = memo(function Editor({ disabled, placeholder, leftComponen
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
contentEditable={!disabled}
|
contentEditable={!disabled}
|
||||||
role="textbox"
|
role="textbox"
|
||||||
|
aria-label={_t("a11y|message_composer")}
|
||||||
aria-multiline="true"
|
aria-multiline="true"
|
||||||
aria-autocomplete="list"
|
aria-autocomplete="list"
|
||||||
aria-haspopup="listbox"
|
aria-haspopup="listbox"
|
||||||
|
|||||||
@@ -124,10 +124,10 @@ const DeviceDetails: React.FC<Props> = ({
|
|||||||
{!accountManagementEndpoint && (
|
{!accountManagementEndpoint && (
|
||||||
<section className="mx_DeviceDetails_section">
|
<section className="mx_DeviceDetails_section">
|
||||||
<p className="mx_DeviceDetails_sectionHeading">{_t("settings|sessions|details_heading")}</p>
|
<p className="mx_DeviceDetails_sectionHeading">{_t("settings|sessions|details_heading")}</p>
|
||||||
{metadata.map(({ heading, values, id }, index) => (
|
{metadata.map(({ heading, values, id }) => (
|
||||||
<table
|
<table
|
||||||
className="mx_DeviceDetails_metadataTable"
|
className="mx_DeviceDetails_metadataTable"
|
||||||
key={index}
|
key={id}
|
||||||
data-testid={`device-detail-metadata-${id}`}
|
data-testid={`device-detail-metadata-${id}`}
|
||||||
>
|
>
|
||||||
{heading && (
|
{heading && (
|
||||||
|
|||||||
@@ -387,7 +387,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps, RolesR
|
|||||||
}
|
}
|
||||||
|
|
||||||
const powerSelectors = Object.keys(powerLevelDescriptors)
|
const powerSelectors = Object.keys(powerLevelDescriptors)
|
||||||
.map((key, index) => {
|
.map((key) => {
|
||||||
const descriptor = powerLevelDescriptors[key];
|
const descriptor = powerLevelDescriptors[key];
|
||||||
if (isSpaceRoom && descriptor.hideForSpace) {
|
if (isSpaceRoom && descriptor.hideForSpace) {
|
||||||
return null;
|
return null;
|
||||||
@@ -395,7 +395,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps, RolesR
|
|||||||
|
|
||||||
const value = parseIntWithDefault(get(plContent, key), descriptor.defaultValue);
|
const value = parseIntWithDefault(get(plContent, key), descriptor.defaultValue);
|
||||||
return (
|
return (
|
||||||
<div key={index} className="">
|
<div key={key}>
|
||||||
<PowerSelector
|
<PowerSelector
|
||||||
label={descriptor.desc}
|
label={descriptor.desc}
|
||||||
value={value}
|
value={value}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export const SpaceAvatar: React.FC<Pick<IProps, "avatarUrl" | "avatarDisabled" |
|
|||||||
if (avatar) {
|
if (avatar) {
|
||||||
avatarSection = (
|
avatarSection = (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
|
{/* oxlint-disable-next-line jsx-a11y/control-has-associated-label */}
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
className="mx_SpaceBasicSettings_avatar"
|
className="mx_SpaceBasicSettings_avatar"
|
||||||
onClick={() => avatarUploadRef.current?.click()}
|
onClick={() => avatarUploadRef.current?.click()}
|
||||||
|
|||||||
@@ -65,8 +65,13 @@ export default class VerificationShowSas extends React.Component<IProps, IState>
|
|||||||
? _t("encryption|verification|confirm_the_emojis")
|
? _t("encryption|verification|confirm_the_emojis")
|
||||||
: _t("encryption|verification|sas_emoji_caption_user");
|
: _t("encryption|verification|sas_emoji_caption_user");
|
||||||
} else if (this.props.sas.decimal) {
|
} else if (this.props.sas.decimal) {
|
||||||
const numberBlocks = this.props.sas.decimal.map((num, i) => <span key={i}>{num}</span>);
|
sasDisplay = (
|
||||||
sasDisplay = <div className="mx_VerificationShowSas_decimalSas">{numberBlocks}</div>;
|
<div className="mx_VerificationShowSas_decimalSas">
|
||||||
|
<span>{this.props.sas.decimal[0]}</span>
|
||||||
|
<span>{this.props.sas.decimal[1]}</span>
|
||||||
|
<span>{this.props.sas.decimal[2]}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
sasCaption = this.props.isSelf
|
sasCaption = this.props.isSelf
|
||||||
? _t("encryption|verification|sas_caption_self")
|
? _t("encryption|verification|sas_caption_self")
|
||||||
: _t("encryption|verification|sas_caption_user");
|
: _t("encryption|verification|sas_caption_user");
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ export default class AudioFeedArrayForLegacyCall extends React.Component<IProps,
|
|||||||
};
|
};
|
||||||
|
|
||||||
public render(): JSX.Element[] {
|
public render(): JSX.Element[] {
|
||||||
return this.state.feeds.map((feed, i) => {
|
return this.state.feeds.map((feed) => {
|
||||||
return <AudioFeed feed={feed} key={i} />;
|
return <AudioFeed feed={feed} key={feed.deviceId + feed.userId} />;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export function jsxJoin(array: ReactNode[], joiner?: string | JSX.Element): JSX.
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{array.map((element, index) => (
|
{array.map((element, index) => (
|
||||||
|
// oxlint-disable-next-line react/no-array-index-key
|
||||||
<React.Fragment key={index}>
|
<React.Fragment key={index}>
|
||||||
{element}
|
{element}
|
||||||
{index === array.length - 1 ? null : joiner}
|
{index === array.length - 1 ? null : joiner}
|
||||||
|
|||||||
@@ -16,18 +16,18 @@ describe("KeyboardLandmarkUtils", () => {
|
|||||||
it("Landmarks are cycled through correctly without an opened room", () => {
|
it("Landmarks are cycled through correctly without an opened room", () => {
|
||||||
render(
|
render(
|
||||||
<div>
|
<div>
|
||||||
<div tabIndex={0} className="mx_SpaceButton_active" data-testid="mx_SpaceButton_active">
|
<button className="mx_SpaceButton_active" data-testid="mx_SpaceButton_active">
|
||||||
SPACE_BUTTON
|
SPACE_BUTTON
|
||||||
</div>
|
</button>
|
||||||
<div tabIndex={0} id="room-list-search-button" data-testid="mx_RoomListSearch_search">
|
<button id="room-list-search-button" data-testid="mx_RoomListSearch_search">
|
||||||
ROOM_SEARCH
|
ROOM_SEARCH
|
||||||
</div>
|
</button>
|
||||||
<div tabIndex={0} className="mx_RoomListItemView" data-testid="mx_RoomListItemView">
|
<button className="mx_RoomListItemView" data-testid="mx_RoomListItemView">
|
||||||
ROOM_TILE
|
ROOM_TILE
|
||||||
</div>
|
</button>
|
||||||
<div tabIndex={0} className="mx_HomePage" data-testid="mx_HomePage">
|
<button className="mx_HomePage" data-testid="mx_HomePage">
|
||||||
HOME_PAGE
|
HOME_PAGE
|
||||||
</div>
|
</button>
|
||||||
</div>,
|
</div>,
|
||||||
);
|
);
|
||||||
// ACTIVE_SPACE_BUTTON <-> ROOM_SEARCH <-> ROOM_LIST <-> HOME <-> ACTIVE_SPACE_BUTTON
|
// ACTIVE_SPACE_BUTTON <-> ROOM_SEARCH <-> ROOM_LIST <-> HOME <-> ACTIVE_SPACE_BUTTON
|
||||||
@@ -69,21 +69,19 @@ describe("KeyboardLandmarkUtils", () => {
|
|||||||
defaultDispatcher.register(callback);
|
defaultDispatcher.register(callback);
|
||||||
render(
|
render(
|
||||||
<div>
|
<div>
|
||||||
<div tabIndex={0} className="mx_SpaceButton_active" data-testid="mx_SpaceButton_active">
|
<button className="mx_SpaceButton_active" data-testid="mx_SpaceButton_active">
|
||||||
SPACE_BUTTON
|
SPACE_BUTTON
|
||||||
</div>
|
</button>
|
||||||
<div tabIndex={0} id="room-list-search-button" data-testid="mx_RoomListSearch_search">
|
<button id="room-list-search-button" data-testid="mx_RoomListSearch_search">
|
||||||
ROOM_SEARCH
|
ROOM_SEARCH
|
||||||
</div>
|
</button>
|
||||||
<div tabIndex={0} className="mx_RoomListItemView_selected" data-testid="mx_RoomListItemView_selected">
|
<button className="mx_RoomListItemView_selected" data-testid="mx_RoomListItemView_selected">
|
||||||
ROOM_TILE
|
ROOM_TILE
|
||||||
</div>
|
</button>
|
||||||
<div tabIndex={0} className="mx_Room" data-testid="mx_Room">
|
<button className="mx_Room" data-testid="mx_Room">
|
||||||
ROOM
|
ROOM
|
||||||
<div tabIndex={0} className="mx_MessageComposer">
|
<div className="mx_MessageComposer">COMPOSER</div>
|
||||||
COMPOSER
|
</button>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>,
|
</div>,
|
||||||
);
|
);
|
||||||
// ACTIVE_SPACE_BUTTON <-> ROOM_SEARCH <-> ROOM_LIST <-> MESSAGE_COMPOSER <-> ACTIVE_SPACE_BUTTON
|
// ACTIVE_SPACE_BUTTON <-> ROOM_SEARCH <-> ROOM_LIST <-> MESSAGE_COMPOSER <-> ACTIVE_SPACE_BUTTON
|
||||||
|
|||||||
+10
-6
@@ -205,6 +205,14 @@ export default defineConfig({
|
|||||||
// Prevent unnecessary runtime dependencies between files
|
// Prevent unnecessary runtime dependencies between files
|
||||||
"typescript/consistent-type-imports": ["error", { fixStyle: "inline-type-imports" }],
|
"typescript/consistent-type-imports": ["error", { fixStyle: "inline-type-imports" }],
|
||||||
|
|
||||||
|
"jsx-a11y/control-has-associated-label": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
labelAttributes: ["label", "value"],
|
||||||
|
depth: 3,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
// Disable some perf rules
|
// Disable some perf rules
|
||||||
"no-await-in-loop": "off",
|
"no-await-in-loop": "off",
|
||||||
|
|
||||||
@@ -212,7 +220,7 @@ export default defineConfig({
|
|||||||
"unicorn/switch-case-braces": "off",
|
"unicorn/switch-case-braces": "off",
|
||||||
"sort-keys": "off",
|
"sort-keys": "off",
|
||||||
"typescript/require-array-sort-compare": "off",
|
"typescript/require-array-sort-compare": "off",
|
||||||
"eslint/no-extra-boolean-cast": "off",
|
"no-extra-boolean-cast": "off",
|
||||||
|
|
||||||
// These would be nice to enable at some point
|
// These would be nice to enable at some point
|
||||||
"unicorn/prefer-set-has": "off",
|
"unicorn/prefer-set-has": "off",
|
||||||
@@ -232,21 +240,17 @@ export default defineConfig({
|
|||||||
"typescript/no-implied-eval": "off",
|
"typescript/no-implied-eval": "off",
|
||||||
"typescript/no-misused-spread": "off",
|
"typescript/no-misused-spread": "off",
|
||||||
"promise/valid-params": "off",
|
"promise/valid-params": "off",
|
||||||
"no-extra-boolean-cast": "off",
|
|
||||||
"react-perf/jsx-no-new-function-as-prop": "off",
|
"react-perf/jsx-no-new-function-as-prop": "off",
|
||||||
"react-perf/jsx-no-new-object-as-prop": "off",
|
"react-perf/jsx-no-new-object-as-prop": "off",
|
||||||
"react-perf/jsx-no-jsx-as-prop": "off",
|
"react-perf/jsx-no-jsx-as-prop": "off",
|
||||||
"jsx-a11y/prefer-tag-over-role": "off",
|
"jsx-a11y/prefer-tag-over-role": "off",
|
||||||
"jsx-a11y/no-autofocus": "off",
|
"jsx-a11y/no-autofocus": "off",
|
||||||
"react/no-children-prop": "off",
|
"react/no-children-prop": "off",
|
||||||
"jsx-a11y/no-noninteractive-tabindex": "off",
|
|
||||||
"react-perf/jsx-no-new-array-as-prop": "off",
|
"react-perf/jsx-no-new-array-as-prop": "off",
|
||||||
"react/no-did-update-set-state": "off",
|
"react/no-did-update-set-state": "off",
|
||||||
"react/no-did-mount-set-state": "off",
|
"react/no-did-mount-set-state": "off",
|
||||||
"jsx-a11y/no-static-element-interactions": "off",
|
"jsx-a11y/no-static-element-interactions": "off",
|
||||||
"jsx-a11y/no-noninteractive-element-interactions": "off",
|
"jsx-a11y/no-noninteractive-element-interactions": "off",
|
||||||
"react/no-array-index-key": "off",
|
|
||||||
"jsx-a11y/control-has-associated-label": "off",
|
|
||||||
"jsx-a11y/media-has-caption": "off",
|
"jsx-a11y/media-has-caption": "off",
|
||||||
"jsx-a11y/no-noninteractive-element-to-interactive-role": "off",
|
"jsx-a11y/no-noninteractive-element-to-interactive-role": "off",
|
||||||
"jsx-a11y/aria-activedescendant-has-tabindex": "off",
|
"jsx-a11y/aria-activedescendant-has-tabindex": "off",
|
||||||
@@ -522,7 +526,6 @@ export default defineConfig({
|
|||||||
"typescript/no-empty-object-type": "off",
|
"typescript/no-empty-object-type": "off",
|
||||||
"typescript/unbound-method": "off",
|
"typescript/unbound-method": "off",
|
||||||
"typescript/no-floating-promises": "off",
|
"typescript/no-floating-promises": "off",
|
||||||
"typescript/no-misused-spread": "off",
|
|
||||||
"vitest/require-mock-type-parameters": "off",
|
"vitest/require-mock-type-parameters": "off",
|
||||||
"vitest/no-disabled-tests": "off",
|
"vitest/no-disabled-tests": "off",
|
||||||
"vitest/no-conditional-expect": "off",
|
"vitest/no-conditional-expect": "off",
|
||||||
@@ -565,6 +568,7 @@ export default defineConfig({
|
|||||||
"no-new": "off",
|
"no-new": "off",
|
||||||
"react/iframe-missing-sandbox": "off",
|
"react/iframe-missing-sandbox": "off",
|
||||||
"promise/no-promise-in-callback": "off",
|
"promise/no-promise-in-callback": "off",
|
||||||
|
|
||||||
// This would be good to enable in the future
|
// This would be good to enable in the future
|
||||||
"typescript/await-thenable": "off",
|
"typescript/await-thenable": "off",
|
||||||
"promise/no-callback-in-promise": "off",
|
"promise/no-callback-in-promise": "off",
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ const groupedVariant: ListTestVariant = {
|
|||||||
<div
|
<div
|
||||||
className="mx_group_header"
|
className="mx_group_header"
|
||||||
data-testid={`group-header-${header.id}`}
|
data-testid={`group-header-${header.id}`}
|
||||||
|
// oxlint-disable-next-line jsx-a11y/no-noninteractive-tabindex
|
||||||
tabIndex={context.tabIndexKey === header.id ? 0 : -1}
|
tabIndex={context.tabIndexKey === header.id ? 0 : -1}
|
||||||
onFocus={(e) => onFocus(header, e)}
|
onFocus={(e) => onFocus(header, e)}
|
||||||
>
|
>
|
||||||
|
|||||||
+2
-2
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
|||||||
Please see LICENSE files in the repository root for full details.
|
Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { type JSX } from "react";
|
import { type JSX } from "react";
|
||||||
import { Text, type HTMLReactParserOptions } from "html-react-parser";
|
import { Text, type HTMLReactParserOptions } from "html-react-parser";
|
||||||
|
|
||||||
type Replacer = HTMLReactParserOptions["replace"];
|
type Replacer = HTMLReactParserOptions["replace"];
|
||||||
@@ -28,7 +28,7 @@ export function applyReplacerOnString(
|
|||||||
const arr = Array.isArray(input) ? input : [input];
|
const arr = Array.isArray(input) ? input : [input];
|
||||||
return arr.map((item, index): JSX.Element => {
|
return arr.map((item, index): JSX.Element => {
|
||||||
if (typeof item === "string") {
|
if (typeof item === "string") {
|
||||||
return <React.Fragment key={index}>{(replacer(new Text(item), 0) as JSX.Element) || item}</React.Fragment>;
|
return (replacer(new Text(item), 0) as JSX.Element) || item;
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
@@ -31,6 +31,7 @@ export function SasEmoji({ emoji, className }: Props): JSX.Element {
|
|||||||
const { language } = useI18n();
|
const { language } = useI18n();
|
||||||
|
|
||||||
const emojiBlocks = emoji.map((emoji, i) => (
|
const emojiBlocks = emoji.map((emoji, i) => (
|
||||||
|
// oxlint-disable-next-line react/no-array-index-key
|
||||||
<div className={styles.segment} key={i}>
|
<div className={styles.segment} key={i}>
|
||||||
<div className={styles.emoji} aria-hidden={true}>
|
<div className={styles.emoji} aria-hidden={true}>
|
||||||
{emoji}
|
{emoji}
|
||||||
|
|||||||
+1
@@ -102,6 +102,7 @@ export const RoomListPrimaryFilters = memo(function RoomListPrimaryFilters({
|
|||||||
>
|
>
|
||||||
{visibleFilterIds.map((filterId, index) => (
|
{visibleFilterIds.map((filterId, index) => (
|
||||||
<ChatFilter
|
<ChatFilter
|
||||||
|
// oxlint-disable-next-line react/no-array-index-key
|
||||||
key={`${filterId}-${index}`}
|
key={`${filterId}-${index}`}
|
||||||
role="option"
|
role="option"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
|
|||||||
+2
@@ -69,6 +69,8 @@ export function E2ePadlock({ icon, title, className }: Readonly<E2ePadlockProps>
|
|||||||
data-testid="e2e-padlock"
|
data-testid="e2e-padlock"
|
||||||
className={classNames(styles.e2ePadlock, iconClasses[icon], className)}
|
className={classNames(styles.e2ePadlock, iconClasses[icon], className)}
|
||||||
role="img"
|
role="img"
|
||||||
|
// This is only tab indexed to act as a tooltip trigger
|
||||||
|
// oxlint-disable-next-line jsx-a11y/no-noninteractive-tabindex
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
aria-label={_t("timeline|e2e_state")}
|
aria-label={_t("timeline|e2e_state")}
|
||||||
>
|
>
|
||||||
|
|||||||
+1
@@ -257,6 +257,7 @@ export function FileBodyView({ vm, refIFrame, refLink, className }: Readonly<Fil
|
|||||||
* We'll use it to learn how the download button
|
* We'll use it to learn how the download button
|
||||||
* would have been styled if it was rendered inline.
|
* would have been styled if it was rendered inline.
|
||||||
* this violates multiple eslint rules so ignore it completely */}
|
* this violates multiple eslint rules so ignore it completely */}
|
||||||
|
{/* oxlint-disable-next-line jsx-a11y/control-has-associated-label */}
|
||||||
<Button size="md" kind="secondary" Icon={DownloadIcon} as="a" ref={refLink} />
|
<Button size="md" kind="secondary" Icon={DownloadIcon} as="a" ref={refLink} />
|
||||||
</div>
|
</div>
|
||||||
{/*
|
{/*
|
||||||
|
|||||||
Reference in New Issue
Block a user