Switch from eslint to oxlint (#34166)
* Fix type imports * Fix jsdoc * Fixup types * Fix stray awaits on non-thenables * Fixup imports * Fix splats * Fix this-context on callbacks * Memoise react contexts * Prefer find/flatMap * Make oxlint happier about our React keys * Avoid unsafe default function params * Fixup jsdoc * Fixup contexts * Switch from eslint to oxlint * Some oxlint-related tweaks * Iterate * Partial revert to defer some changes and shrink diff * Iterate * Add eslint-plugin-element-call and enable the copyright rule * Set strictStorePkgContentCheck * Iterate * Make sonar happy * Fix new lints
This commit is contained in:
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
Copyright 2025 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
plugins: ["matrix-org", "eslint-plugin-react-compiler"],
|
||||
extends: [
|
||||
"plugin:matrix-org/react",
|
||||
"plugin:matrix-org/a11y",
|
||||
"plugin:matrix-org/typescript",
|
||||
"plugin:matrix-org/react",
|
||||
"plugin:storybook/recommended",
|
||||
],
|
||||
parserOptions: {
|
||||
project: ["./tsconfig.json"],
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
},
|
||||
rules: {
|
||||
// Bind or arrow functions in props causes performance issues (but we
|
||||
// currently use them in some places).
|
||||
// It's disabled here, but we should using it sparingly.
|
||||
"react/jsx-no-bind": "off",
|
||||
"react/jsx-key": ["error"],
|
||||
"matrix-org/require-copyright-header": "error",
|
||||
"react-compiler/react-compiler": "error",
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
paths: [
|
||||
{
|
||||
name: "react",
|
||||
importNames: ["act"],
|
||||
message: "Please use @test-utils instead.",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
"@typescript-eslint/unbound-method": ["error", { ignoreStatic: true }],
|
||||
"@typescript-eslint/explicit-function-return-type": [
|
||||
"error",
|
||||
{
|
||||
allowExpressions: true,
|
||||
},
|
||||
],
|
||||
|
||||
// We're okay being explicit at the moment
|
||||
// "@typescript-eslint/no-empty-interface": "off",
|
||||
// We'd rather not do this but we do
|
||||
// "@typescript-eslint/ban-ts-comment": "off",
|
||||
// We're okay with assertion errors when we ask for them
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-empty-object-type": [
|
||||
"error",
|
||||
{
|
||||
// We do this sometimes to brand interfaces
|
||||
allowInterfaces: "with-single-extends",
|
||||
},
|
||||
],
|
||||
"storybook/meta-satisfies-type": "error",
|
||||
|
||||
"react/forbid-elements": [
|
||||
"error",
|
||||
{
|
||||
forbid: [
|
||||
{ element: "h1", message: "Use Compound <Heading> instead" },
|
||||
{ element: "h2", message: "Use Compound <Heading> instead" },
|
||||
{ element: "h3", message: "Use Compound <Heading> instead" },
|
||||
{ element: "h4", message: "Use Compound <Heading> instead" },
|
||||
{ element: "h5", message: "Use Compound <Heading> instead" },
|
||||
{ element: "h6", message: "Use Compound <Heading> instead" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["src/**/*.test.{ts,tsx}", "src/**/*.stories.tsx"],
|
||||
rules: {
|
||||
"@typescript-eslint/unbound-method": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"react/forbid-elements": "off",
|
||||
},
|
||||
},
|
||||
],
|
||||
settings: {
|
||||
react: {
|
||||
version: "detect",
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -5,7 +5,7 @@
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { Addon, types, useGlobals } from "storybook/manager-api";
|
||||
import { type Addon, types, useGlobals } from "storybook/manager-api";
|
||||
import { WithTooltip, IconButton, TooltipLinkList } from "storybook/internal/components";
|
||||
import React from "react";
|
||||
import { GlobeIcon } from "@storybook/icons";
|
||||
|
||||
@@ -19,7 +19,7 @@ import { TooltipProvider } from "@vector-im/compound-web";
|
||||
|
||||
import { EventPresentationProvider, type EventDensity, type EventLayout, I18nApi, I18nContext } from "../src";
|
||||
import { setLanguage } from "../src/core/i18n/i18n";
|
||||
import { StoryContext } from "storybook/internal/csf";
|
||||
import { type StoryContext } from "storybook/internal/csf";
|
||||
import { DragDropProvider } from "@dnd-kit/react";
|
||||
import { PointerActivationConstraints, PointerSensor } from "@dnd-kit/dom";
|
||||
|
||||
|
||||
@@ -58,8 +58,7 @@
|
||||
"storybook": "storybook dev -p 6007",
|
||||
"build:storybook": "nx storybook",
|
||||
"build:doc": "nx typedoc",
|
||||
"lint": "pnpm lint:types && pnpm lint:js",
|
||||
"lint:js": "eslint --max-warnings 0 src",
|
||||
"lint": "pnpm lint:types",
|
||||
"lint:types": "nx lint:types"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -98,7 +97,6 @@
|
||||
"@storybook/addon-vitest": "^10.1.11",
|
||||
"@storybook/icons": "^2.0.0",
|
||||
"@storybook/react-vite": "^10.0.7",
|
||||
"@stylistic/eslint-plugin": "^5.7.0",
|
||||
"@testing-library/dom": "^10.4.1",
|
||||
"@testing-library/react": "^16.3.2",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
@@ -106,22 +104,9 @@
|
||||
"@types/lodash": "^4.17.20",
|
||||
"@types/react": "catalog:",
|
||||
"@types/react-dom": "catalog:",
|
||||
"@typescript-eslint/eslint-plugin": "^8.53.1",
|
||||
"@typescript-eslint/parser": "^8.53.1",
|
||||
"@vector-im/compound-web": "catalog:",
|
||||
"@vitejs/plugin-react": "catalog:",
|
||||
"@vitest/browser-playwright": "catalog:",
|
||||
"eslint": "8",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-deprecate": "^0.9.0",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||
"eslint-plugin-matrix-org": "^3.0.0",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-compiler": "^19.1.0-rc.2",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-storybook": "^10.0.7",
|
||||
"eslint-plugin-unicorn": "^56.0.0",
|
||||
"oxfmt": "0.56.0",
|
||||
"storybook": "^10.0.7",
|
||||
"storybook-addon-vis": "^4.0.0",
|
||||
|
||||
@@ -18,7 +18,7 @@ const I18N_BASE_PATH = "./src/i18n/strings/";
|
||||
const I18N_DEST = "storybook-static/i18n/";
|
||||
|
||||
// List of languages to include
|
||||
const INCLUDE_LANGS = [...new Set([...fs.readdirSync(I18N_BASE_PATH)])]
|
||||
const INCLUDE_LANGS = [...new Set(fs.readdirSync(I18N_BASE_PATH))]
|
||||
.filter((fn) => fn.endsWith(".json"))
|
||||
.map((f) => f.slice(0, -5));
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ export interface VirtualizedListProps<Item, Context> extends Omit<
|
||||
/**
|
||||
* Function to get the key to use for focusing an item.
|
||||
* @param item - The item to get the key for
|
||||
* @return The key to use for focusing the item
|
||||
* @returns The key to use for focusing the item
|
||||
*/
|
||||
getItemKey: (item: Item) => string;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* you will end up with literal "<a>" in your output, rather than HTML. Note that you can also use variable
|
||||
* substitution to insert React components, but you can't use it to translate text between tags.
|
||||
*
|
||||
* @return a React <span> component if any non-strings were used in substitutions, otherwise a string
|
||||
* @returns a React <span> component if any non-strings were used in substitutions, otherwise a string
|
||||
*/
|
||||
import React from "react";
|
||||
import { KEY_SEPARATOR } from "matrix-web-i18n";
|
||||
@@ -204,7 +204,7 @@ export function lookupString(key: TranslationKey): string {
|
||||
* @param {object} variables Variable substitutions, e.g { foo: 'bar' }
|
||||
* @param {object} tags Tag substitutions e.g. { 'a': (sub) => <a>{sub}</a> }
|
||||
*
|
||||
* @return a React <span> component if any non-strings were used in substitutions
|
||||
* @returns a React <span> component if any non-strings were used in substitutions
|
||||
* or translation used a fallback locale, otherwise a string
|
||||
*/
|
||||
// eslint-next-line @typescript-eslint/naming-convention
|
||||
@@ -243,7 +243,7 @@ export function sanitizeForTranslation(text: string): string {
|
||||
* the substitution (e.g. return a React component). In case of a tag replacement, the function receives as
|
||||
* the argument the text inside the element corresponding to the tag.
|
||||
*
|
||||
* @return a React <span> component if any non-strings were used in substitutions, otherwise a string
|
||||
* @returns a React <span> component if any non-strings were used in substitutions, otherwise a string
|
||||
*/
|
||||
export function substitute(text: string, variables?: StringVariables): string;
|
||||
export function substitute(text: string, variables?: RichVariables): React.ReactNode;
|
||||
@@ -277,7 +277,7 @@ export function substitute(text: string, variables?: IVariables, tags?: Tags): s
|
||||
* function which will receive as the argument the capture groups defined in the regexp. E.g.
|
||||
* { 'Hello (.?) World': (sub) => sub.toUpperCase() }
|
||||
*
|
||||
* @return a React <span> component if any non-strings were used in substitutions, otherwise a string
|
||||
* @returns a React <span> component if any non-strings were used in substitutions, otherwise a string
|
||||
*/
|
||||
export function replaceByRegexes(text: string, mapping: IVariables): string;
|
||||
export function replaceByRegexes(text: string, mapping: Tags): React.ReactNode;
|
||||
|
||||
@@ -25,7 +25,7 @@ const Button = (props: HTMLAttributes<HTMLButtonElement>): React.JSX.Element =>
|
||||
return <button {...props} onFocus={onFocus} tabIndex={isActive ? 0 : -1} ref={ref} />;
|
||||
};
|
||||
|
||||
const checkTabIndexes = (buttons: NodeListOf<HTMLElement>, expectations: number[]): void => {
|
||||
const expectTabIndexes = (buttons: NodeListOf<HTMLElement>, expectations: number[]): void => {
|
||||
expect([...buttons].map((b) => b.tabIndex)).toStrictEqual(expectations);
|
||||
};
|
||||
|
||||
@@ -89,16 +89,16 @@ describe("RovingTabIndex", () => {
|
||||
</RovingTabIndexProvider>,
|
||||
);
|
||||
|
||||
checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
|
||||
act(() => container.querySelectorAll("button")[2].focus());
|
||||
checkTabIndexes(container.querySelectorAll("button"), [-1, -1, 0]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [-1, -1, 0]);
|
||||
|
||||
act(() => container.querySelectorAll("button")[1].focus());
|
||||
checkTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]);
|
||||
|
||||
act(() => container.querySelectorAll("button")[1].blur());
|
||||
checkTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]);
|
||||
|
||||
rerender(
|
||||
<RovingTabIndexProvider>
|
||||
@@ -112,7 +112,7 @@ describe("RovingTabIndex", () => {
|
||||
)}
|
||||
</RovingTabIndexProvider>,
|
||||
);
|
||||
checkTabIndexes(container.querySelectorAll("button"), [-1, -1, 0, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [-1, -1, 0, -1]);
|
||||
|
||||
rerender(
|
||||
<RovingTabIndexProvider>
|
||||
@@ -125,7 +125,7 @@ describe("RovingTabIndex", () => {
|
||||
)}
|
||||
</RovingTabIndexProvider>,
|
||||
);
|
||||
checkTabIndexes(container.querySelectorAll("button"), [-1, -1, 0]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [-1, -1, 0]);
|
||||
});
|
||||
|
||||
it("provides a ref to the dom element", () => {
|
||||
@@ -165,10 +165,10 @@ describe("RovingTabIndex", () => {
|
||||
</RovingTabIndexProvider>,
|
||||
);
|
||||
|
||||
checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
|
||||
act(() => container.querySelectorAll("button")[2].focus());
|
||||
checkTabIndexes(container.querySelectorAll("button"), [-1, -1, 0]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [-1, -1, 0]);
|
||||
});
|
||||
|
||||
describe("reducer functions as expected", () => {
|
||||
@@ -390,22 +390,22 @@ describe("RovingTabIndex", () => {
|
||||
);
|
||||
|
||||
act(() => container.querySelectorAll("button")[0].focus());
|
||||
checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
|
||||
await userEvent.keyboard("[ArrowDown]");
|
||||
checkTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]);
|
||||
|
||||
await userEvent.keyboard("[ArrowDown]");
|
||||
checkTabIndexes(container.querySelectorAll("button"), [-1, -1, 0]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [-1, -1, 0]);
|
||||
|
||||
await userEvent.keyboard("[ArrowUp]");
|
||||
checkTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]);
|
||||
|
||||
await userEvent.keyboard("[ArrowUp]");
|
||||
checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
|
||||
await userEvent.keyboard("[ArrowUp]");
|
||||
checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
});
|
||||
|
||||
it("handles left/right arrow keys when handleLeftRight=true", async () => {
|
||||
@@ -420,10 +420,10 @@ describe("RovingTabIndex", () => {
|
||||
|
||||
act(() => container.querySelectorAll("button")[0].focus());
|
||||
await userEvent.keyboard("[ArrowRight]");
|
||||
checkTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]);
|
||||
|
||||
await userEvent.keyboard("[ArrowLeft]");
|
||||
checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
});
|
||||
|
||||
it("moves between multiple toolbar containers in one roving group", async () => {
|
||||
@@ -446,15 +446,15 @@ describe("RovingTabIndex", () => {
|
||||
|
||||
const buttons = container.querySelectorAll("button");
|
||||
act(() => buttons[1].focus());
|
||||
checkTabIndexes(buttons, [-1, 0, -1, -1]);
|
||||
expectTabIndexes(buttons, [-1, 0, -1, -1]);
|
||||
|
||||
await userEvent.keyboard("[ArrowRight]");
|
||||
expect(buttons[2]).toHaveFocus();
|
||||
checkTabIndexes(buttons, [-1, -1, 0, -1]);
|
||||
expectTabIndexes(buttons, [-1, -1, 0, -1]);
|
||||
|
||||
await userEvent.keyboard("[ArrowLeft]");
|
||||
expect(buttons[1]).toHaveFocus();
|
||||
checkTabIndexes(buttons, [-1, 0, -1, -1]);
|
||||
expectTabIndexes(buttons, [-1, 0, -1, -1]);
|
||||
});
|
||||
|
||||
it("handles Home, End, and loop across multiple toolbar containers", async () => {
|
||||
@@ -477,19 +477,19 @@ describe("RovingTabIndex", () => {
|
||||
|
||||
const buttons = container.querySelectorAll("button");
|
||||
act(() => buttons[2].focus());
|
||||
checkTabIndexes(buttons, [-1, -1, 0, -1]);
|
||||
expectTabIndexes(buttons, [-1, -1, 0, -1]);
|
||||
|
||||
await userEvent.keyboard("[End]");
|
||||
expect(buttons[3]).toHaveFocus();
|
||||
checkTabIndexes(buttons, [-1, -1, -1, 0]);
|
||||
expectTabIndexes(buttons, [-1, -1, -1, 0]);
|
||||
|
||||
await userEvent.keyboard("[ArrowRight]");
|
||||
expect(buttons[0]).toHaveFocus();
|
||||
checkTabIndexes(buttons, [0, -1, -1, -1]);
|
||||
expectTabIndexes(buttons, [0, -1, -1, -1]);
|
||||
|
||||
await userEvent.keyboard("[Home]");
|
||||
expect(buttons[0]).toHaveFocus();
|
||||
checkTabIndexes(buttons, [0, -1, -1, -1]);
|
||||
expectTabIndexes(buttons, [0, -1, -1, -1]);
|
||||
});
|
||||
|
||||
it("handles Home and End when handleHomeEnd=true", async () => {
|
||||
@@ -503,13 +503,13 @@ describe("RovingTabIndex", () => {
|
||||
);
|
||||
|
||||
act(() => container.querySelectorAll("button")[1].focus());
|
||||
checkTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]);
|
||||
|
||||
await userEvent.keyboard("[End]");
|
||||
checkTabIndexes(container.querySelectorAll("button"), [-1, -1, 0]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [-1, -1, 0]);
|
||||
|
||||
await userEvent.keyboard("[Home]");
|
||||
checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
});
|
||||
|
||||
it("loops when handleLoop=true", async () => {
|
||||
@@ -524,10 +524,10 @@ describe("RovingTabIndex", () => {
|
||||
|
||||
act(() => container.querySelectorAll("button")[2].focus());
|
||||
await userEvent.keyboard("[ArrowDown]");
|
||||
checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
|
||||
await userEvent.keyboard("[ArrowUp]");
|
||||
checkTabIndexes(container.querySelectorAll("button"), [-1, -1, 0]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [-1, -1, 0]);
|
||||
});
|
||||
|
||||
it("uses a custom getAction mapper", async () => {
|
||||
@@ -552,7 +552,7 @@ describe("RovingTabIndex", () => {
|
||||
await userEvent.keyboard("j");
|
||||
|
||||
expect(getAction).toHaveBeenCalled();
|
||||
checkTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [-1, 0, -1]);
|
||||
});
|
||||
|
||||
it("handles input fields when handleInputFields=true", () => {
|
||||
@@ -569,7 +569,7 @@ describe("RovingTabIndex", () => {
|
||||
const input = getByRole("textbox", { name: "Search input" });
|
||||
|
||||
fireEvent.keyDown(input, { key: "ArrowDown" });
|
||||
checkTabIndexes(container.querySelectorAll("button"), [-1, 0]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [-1, 0]);
|
||||
});
|
||||
|
||||
it("moves from an input field with Tab when handleInputFields=false", () => {
|
||||
@@ -586,7 +586,7 @@ describe("RovingTabIndex", () => {
|
||||
act(() => (input as HTMLElement).focus());
|
||||
|
||||
fireEvent.keyDown(input, { key: "Tab" });
|
||||
checkTabIndexes(container.querySelectorAll("button"), [-1, 0]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [-1, 0]);
|
||||
});
|
||||
|
||||
it("stops provider processing when onKeyDown prevents default", () => {
|
||||
@@ -606,7 +606,7 @@ describe("RovingTabIndex", () => {
|
||||
fireEvent.keyDown(container.querySelector('[role="toolbar"]')!, { key: "ArrowDown" });
|
||||
|
||||
expect(onKeyDown).toHaveBeenCalled();
|
||||
checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
});
|
||||
|
||||
it("calls scrollIntoView if specified", async () => {
|
||||
@@ -620,7 +620,7 @@ describe("RovingTabIndex", () => {
|
||||
);
|
||||
|
||||
act(() => container.querySelectorAll("button")[0].focus());
|
||||
checkTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
expectTabIndexes(container.querySelectorAll("button"), [0, -1, -1]);
|
||||
|
||||
const button = container.querySelectorAll("button")[1];
|
||||
const mock = vi.spyOn(button, "scrollIntoView");
|
||||
|
||||
@@ -153,7 +153,7 @@ export interface LinkedTextOptions {
|
||||
* Generates a linkifyjs options object that is reasonably paired down
|
||||
* to just the essentials required for an Element client.
|
||||
*
|
||||
* @return A `linkifyjs` `Opts` object. Used by `linkifyString` and `linkifyHtml
|
||||
* @returns A `linkifyjs` `Opts` object. Used by `linkifyString` and `linkifyHtml
|
||||
* @see {@link linkifyHtml}
|
||||
* @see {@link linkifyString}
|
||||
*/
|
||||
|
||||
+6
-2
@@ -9,8 +9,12 @@ import React, { type JSX, useEffect } from "react";
|
||||
import { fn } from "storybook/test";
|
||||
|
||||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||
import type { Room } from "./RoomListItemView";
|
||||
import { RoomListItemView, type RoomListItemViewSnapshot, type RoomListItemViewActions } from "./RoomListItemView";
|
||||
import {
|
||||
type Room,
|
||||
RoomListItemView,
|
||||
type RoomListItemViewSnapshot,
|
||||
type RoomListItemViewActions,
|
||||
} from "./RoomListItemView";
|
||||
import { useMockedViewModel } from "../../../../core/viewmodel";
|
||||
import { withViewDocs } from "../../../../../.storybook/withViewDocs";
|
||||
import { defaultSnapshot } from "./default-snapshot";
|
||||
|
||||
+2
-1
@@ -17,9 +17,10 @@ import {
|
||||
FlatVirtualizedList,
|
||||
getContainerAccessibleProps,
|
||||
type VirtualizedListContext,
|
||||
GroupedVirtualizedList,
|
||||
type GroupedVirtualizedListProps,
|
||||
} from "../../core/VirtualizedList";
|
||||
import type { RoomListViewSnapshot, RoomListViewModel } from "../RoomListView";
|
||||
import { GroupedVirtualizedList, type GroupedVirtualizedListProps } from "../../core/VirtualizedList";
|
||||
import { RoomListSectionHeaderView, RoomListStickySectionHeaderView } from "./RoomListSectionHeaderView";
|
||||
import { RoomListSectionHeaderDragOverlayView } from "./RoomListSectionHeaderDragOverlayView";
|
||||
import { RoomListItemWrapper } from "./RoomListItemWrapper";
|
||||
|
||||
@@ -26,7 +26,7 @@ export interface UploadButtonViewSnapshot {
|
||||
}
|
||||
|
||||
export interface UploadButtonViewActions {
|
||||
onUploadOptionSelected(type: string): void;
|
||||
onUploadOptionSelected(this: void, type: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ export interface RoomAvatarEventViewActions {
|
||||
/**
|
||||
* Invoked when the user opens the avatar image.
|
||||
*/
|
||||
onAvatarClick(): void;
|
||||
onAvatarClick(this: void): void;
|
||||
}
|
||||
|
||||
export type RoomAvatarEventViewModel = ViewModel<RoomAvatarEventViewSnapshot, RoomAvatarEventViewActions>;
|
||||
|
||||
+2
-1
@@ -19,7 +19,6 @@ import {
|
||||
type ImageBodyViewSnapshot,
|
||||
} from "./ImageBodyView";
|
||||
import imageSrc from "../../../../../../static/image-body/install-spinner.png";
|
||||
import thumbnailSrc from "../../../../../../static/image-body/install-spinner.png";
|
||||
import animatedGifSrc from "../../../../../../static/image-body/install-spinner.gif";
|
||||
const demoBlurhash = "LEHV6nWB2yk8pyo0adR*.7kCMdnj";
|
||||
const imageBodyViewStateOptions = [ImageBodyViewState.ERROR, ImageBodyViewState.HIDDEN, ImageBodyViewState.READY];
|
||||
@@ -29,6 +28,8 @@ const imageBodyViewPlaceholderOptions = [
|
||||
ImageBodyViewPlaceholder.BLURHASH,
|
||||
];
|
||||
|
||||
const thumbnailSrc = imageSrc;
|
||||
|
||||
type ImageBodyViewProps = ImageBodyViewSnapshot &
|
||||
ImageBodyViewActions & {
|
||||
className?: string;
|
||||
|
||||
@@ -28,6 +28,8 @@ type SharedRenderOptions = RenderOptions & {
|
||||
presentation?: Partial<EventPresentation>;
|
||||
};
|
||||
|
||||
const i18nApi = new I18nApi();
|
||||
|
||||
const wrapWithTooltipProvider = (Wrapper: RenderOptions["wrapper"], presentation?: Partial<EventPresentation>) => {
|
||||
return ({ children }: { children: React.ReactNode }) => {
|
||||
const resolvedPresentation: EventPresentation | undefined = presentation
|
||||
@@ -43,12 +45,12 @@ const wrapWithTooltipProvider = (Wrapper: RenderOptions["wrapper"], presentation
|
||||
|
||||
if (Wrapper) {
|
||||
return (
|
||||
<I18nContext.Provider value={new I18nApi()}>
|
||||
<I18nContext.Provider value={i18nApi}>
|
||||
<Wrapper>{content}</Wrapper>
|
||||
</I18nContext.Provider>
|
||||
);
|
||||
} else {
|
||||
return <I18nContext.Provider value={new I18nApi()}>{content}</I18nContext.Provider>;
|
||||
return <I18nContext.Provider value={i18nApi}>{content}</I18nContext.Provider>;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
"strict": true,
|
||||
"paths": {
|
||||
"@test-utils": ["./src/test/utils/index"]
|
||||
}
|
||||
},
|
||||
"noEmit": true
|
||||
},
|
||||
"include": ["./src/**/*.ts", "./src/**/*.tsx", ".storybook/*.ts", ".storybook/*.tsx"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
|
||||
@@ -10,7 +10,7 @@ import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { storybookTest } from "@storybook/addon-vitest/vitest-plugin";
|
||||
import { storybookVis } from "storybook-addon-vis/vitest-plugin";
|
||||
import { playwright, PlaywrightProviderOptions } from "@vitest/browser-playwright";
|
||||
import { playwright, type PlaywrightProviderOptions } from "@vitest/browser-playwright";
|
||||
import { nodePolyfills } from "vite-plugin-node-polyfills";
|
||||
|
||||
import rootConfig from "../../vitest.config";
|
||||
|
||||
Reference in New Issue
Block a user