Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 13 additions & 85 deletions biome.jsonc
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
{
"$schema": "https://biomejs.dev/schemas/2.4.2/schema.json",

// Code formatting and organization suggestions
"assist": {
"enabled": true,
Expand Down Expand Up @@ -33,92 +31,22 @@
"react": "all"
},
"rules": {
"a11y": "error",
"complexity": "error",
"correctness": "error",
"nursery": "off",
"performance": "error",
"recommended": true,
"security": "error",
"preset": "all",
"correctness": {
// Not a Qwik project - this rule produces false positives on ordinary
// React closures.
"useQwikValidLexicalScope": "off"
},
"style": {
"recommended": true,
// Too strict - hardcoded strings acceptable in this project
// Hardcoded UI strings are acceptable in this example app; no i18n layer.
"noJsxLiterals": "off"
},
"suspicious": "error"
}
},

// Override settings
"overrides": [
{
"includes": ["**/*.tsx", "**/*.jsx"],
"linter": {
"rules": {
"performance": {
// Next.js specific rule - not applicable to Vite/React projects
"noImgElement": "off"
},
"style": {
// Allow default exports in React components
"noDefaultExport": "off",
// Allow class components (converting to function components is a larger refactor)
"useReactFunctionComponents": "off"
},
"suspicious": {
// React specific rule - not applicable to Vite/React projects
"noReactSpecificProps": "off"
}
}
}
},
{
"includes": [
"**/*.spec.ts",
"**/*.spec.tsx",
"**/*.test.ts",
"**/*.test.tsx"
],
"linter": {
"rules": {
"complexity": {
// Test files can have longer functions with multiple test cases
"noExcessiveLinesPerFunction": "off"
},
"style": {
// HTTP headers follow spec casing (Authorization, not authorization)
"useNamingConvention": "off"
},
"suspicious": {
// Pact test executeTest callbacks are inherently async
"useAwait": "off"
}
}
}
},
{
"includes": ["*.config.ts", "*.config.js"],
"linter": {
"rules": {
"style": {
// Config files conventionally use default exports
"noDefaultExport": "off"
}
}
}
},
{
"includes": ["**/*.ts", "**/*.tsx"],
"linter": {
"rules": {
"correctness": {
// TypeScript handles this
"noUnresolvedImports": "off",
// False positive (we don't use Qwik)
"useQwikValidLexicalScope": "off"
}
}
"suspicious": {
// This is a React project - className/htmlFor are the correct props.
// The rule targets non-React JSX (e.g. Solid, Preact) where it would
// rewrite them to the HTML-standard names.
"noReactSpecificProps": "off"
}
}
]
}
}
72 changes: 36 additions & 36 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"check:fix": "biome check --write --unsafe ."
},
"devDependencies": {
"@biomejs/biome": "2.4.16",
"@biomejs/biome": "2.5.1",
"@pact-foundation/pact": "16.5.0",
"@testing-library/jest-dom": "6.9.1",
"@types/node": "25.9.4",
Expand Down
31 changes: 19 additions & 12 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useEffect, useId, useState } from "react";
import { useCallback, useEffect, useId, useState } from "react";
import { Link } from "react-router-dom";
import "spectre.css/dist/spectre.min.css";
import "spectre.css/dist/spectre-icons.min.css";
import "spectre.css/dist/spectre-exp.min.css";
import API from "./api.ts";
import Heading from "./Heading.tsx";
import Layout from "./Layout.tsx";
import { api } from "./api.ts";
import { Heading } from "./Heading.tsx";
import { Layout } from "./Layout.tsx";
import type { Product } from "./types/index.ts";

interface ProductTableRowProps {
Expand Down Expand Up @@ -53,15 +53,16 @@ function ProductTable(props: ProductTableProps) {
);
}

function App() {
export function App() {
const [loading, setLoading] = useState(true);
const [searchText, setSearchText] = useState("");
const [products, setProducts] = useState<Product[]>([]);
const [visibleProducts, setVisibleProducts] = useState<Product[]>([]);
const inputId = useId();

useEffect(() => {
API.getAllProducts()
api
.getAllProducts()
.then((r) => {
setLoading(false);
setProducts(r);
Expand All @@ -83,12 +84,19 @@ function App() {
);
};

setVisibleProducts(searchText ? findProducts(searchText) : products);
let visible = products;
if (searchText) {
visible = findProducts(searchText);
}
setVisibleProducts(visible);
}, [searchText, products]);

const onSearchTextChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearchText(e.target.value);
};
const onSearchTextChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
setSearchText(e.target.value);
},
[],
);

return (
<Layout>
Expand All @@ -105,6 +113,7 @@ function App() {
onChange={onSearchTextChange}
/>
</div>
{/* biome-ignore lint/style/noTernary: idiomatic JSX conditional rendering with an else branch */}
{loading ? (
<div className="loading loading-lg centered" />
) : (
Expand All @@ -113,5 +122,3 @@ function App() {
</Layout>
);
}

export default App;
7 changes: 4 additions & 3 deletions src/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ReactNode } from "react";
import React from "react";
import Heading from "./Heading.tsx";
import Layout from "./Layout.tsx";
import { Heading } from "./Heading.tsx";
import { Layout } from "./Layout.tsx";

interface ErrorBoundaryProps {
children: ReactNode;
Expand All @@ -11,7 +11,7 @@ interface ErrorBoundaryState {
hasError: boolean;
}

export default class ErrorBoundary extends React.Component<
export class ErrorBoundary extends React.Component<
ErrorBoundaryProps,
ErrorBoundaryState
> {
Expand All @@ -27,6 +27,7 @@ export default class ErrorBoundary extends React.Component<
<Layout>
<Heading text="Sad times :(" href="/" />
<div className="columns">
{/* biome-ignore lint/performance/noImgElement: Vite/React project — next/image is not applicable */}
<img
className="column col-6"
src="/sad_panda.gif"
Expand Down
4 changes: 1 addition & 3 deletions src/Heading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ interface HeadingProps {
text: string;
}

function Heading(props: HeadingProps) {
export function Heading(props: HeadingProps) {
return (
<div>
<h1>
Expand All @@ -23,5 +23,3 @@ function Heading(props: HeadingProps) {
</div>
);
}

export default Heading;
4 changes: 1 addition & 3 deletions src/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ interface LayoutProps {
children: ReactNode;
}

function Layout(props: LayoutProps) {
export function Layout(props: LayoutProps) {
return (
<div className="container">
<div className="columns">
Expand All @@ -13,5 +13,3 @@ function Layout(props: LayoutProps) {
</div>
);
}

export default Layout;
Loading