Upgrade Biome to 2.4.7 and enable 54 additional lint rules
Add rules covering bug prevention (noLeakedRender, noFloatingPromises, noImportCycles, noReactForwardRef), security (noScriptUrl, noAlert), performance (noAwaitInLoops, useTopLevelRegex), and code style (noNestedTernary, useGlobalThis, useNullishCoalescing, useSortedClasses, plus ~40 more). Fix all violations: extract top-level regex constants, guard React && renders with boolean coercion, refactor nested ternaries, replace window with globalThis, sort Tailwind classes, and introduce expectDomainError test helper to eliminate conditional expects. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -136,20 +136,18 @@ function EditableName({
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleClick}
|
||||
onTouchStart={handleTouchStart}
|
||||
onTouchEnd={cancelLongPress}
|
||||
onTouchCancel={cancelLongPress}
|
||||
onTouchMove={cancelLongPress}
|
||||
className="truncate text-left text-sm text-foreground cursor-text hover:text-hover-neutral transition-colors"
|
||||
style={color ? { color } : undefined}
|
||||
>
|
||||
{name}
|
||||
</button>
|
||||
</>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleClick}
|
||||
onTouchStart={handleTouchStart}
|
||||
onTouchEnd={cancelLongPress}
|
||||
onTouchCancel={cancelLongPress}
|
||||
onTouchMove={cancelLongPress}
|
||||
className="cursor-text truncate text-left text-foreground text-sm transition-colors hover:text-hover-neutral"
|
||||
style={color ? { color } : undefined}
|
||||
>
|
||||
{name}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -205,7 +203,7 @@ function MaxHpDisplay({
|
||||
<button
|
||||
type="button"
|
||||
onClick={startEditing}
|
||||
className="inline-block h-7 min-w-[3ch] text-center text-sm leading-7 tabular-nums text-muted-foreground transition-colors hover:text-hover-neutral"
|
||||
className="inline-block h-7 min-w-[3ch] text-center text-muted-foreground text-sm tabular-nums leading-7 transition-colors hover:text-hover-neutral"
|
||||
>
|
||||
{maxHp ?? "Max"}
|
||||
</button>
|
||||
@@ -230,7 +228,7 @@ function ClickableHp({
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"inline-block h-7 w-[4ch] text-center text-sm leading-7 tabular-nums text-muted-foreground",
|
||||
"inline-block h-7 w-[4ch] text-center text-muted-foreground text-sm tabular-nums leading-7",
|
||||
dimmed && "opacity-50",
|
||||
)}
|
||||
>
|
||||
@@ -245,7 +243,7 @@ function ClickableHp({
|
||||
type="button"
|
||||
onClick={() => setPopoverOpen(true)}
|
||||
className={cn(
|
||||
"inline-block h-7 min-w-[3ch] text-center text-sm font-medium leading-7 tabular-nums transition-colors hover:text-hover-neutral",
|
||||
"inline-block h-7 min-w-[3ch] text-center font-medium text-sm tabular-nums leading-7 transition-colors hover:text-hover-neutral",
|
||||
status === "bloodied" && "text-amber-400",
|
||||
status === "unconscious" && "text-red-400",
|
||||
status === "healthy" && "text-foreground",
|
||||
@@ -254,7 +252,7 @@ function ClickableHp({
|
||||
>
|
||||
{currentHp}
|
||||
</button>
|
||||
{popoverOpen && (
|
||||
{!!popoverOpen && (
|
||||
<HpAdjustPopover
|
||||
onAdjust={onAdjust}
|
||||
onClose={() => setPopoverOpen(false)}
|
||||
@@ -397,10 +395,10 @@ function InitiativeDisplay({
|
||||
type="button"
|
||||
onClick={startEditing}
|
||||
className={cn(
|
||||
"h-7 w-full text-center text-sm leading-7 tabular-nums transition-colors",
|
||||
initiative !== undefined
|
||||
? "font-medium text-foreground hover:text-hover-neutral"
|
||||
: "text-muted-foreground hover:text-hover-neutral",
|
||||
"h-7 w-full text-center text-sm tabular-nums leading-7 transition-colors",
|
||||
initiative === undefined
|
||||
? "text-muted-foreground hover:text-hover-neutral"
|
||||
: "font-medium text-foreground hover:text-hover-neutral",
|
||||
dimmed && "opacity-50",
|
||||
)}
|
||||
>
|
||||
@@ -491,6 +489,7 @@ export function CombatantRow({
|
||||
|
||||
return (
|
||||
/* biome-ignore lint/a11y/noStaticElementInteractions: role="button" is set conditionally when onShowStatBlock exists */
|
||||
/* biome-ignore lint/a11y/noNoninteractiveElementInteractions: role="button" is set conditionally when onShowStatBlock exists */
|
||||
<div
|
||||
ref={ref}
|
||||
role={onShowStatBlock ? "button" : undefined}
|
||||
@@ -517,7 +516,7 @@ export function CombatantRow({
|
||||
title="Concentrating"
|
||||
aria-label="Toggle concentration"
|
||||
className={cn(
|
||||
"flex w-full items-center justify-center self-stretch -my-2 -ml-[2px] pl-[14px] transition-opacity hover:text-hover-neutral hover:opacity-100",
|
||||
"-my-2 -ml-[2px] flex w-full items-center justify-center self-stretch pl-[14px] transition-opacity hover:text-hover-neutral hover:opacity-100",
|
||||
concentrationIconClass(combatant.isConcentrating, dimmed),
|
||||
)}
|
||||
>
|
||||
@@ -526,6 +525,7 @@ export function CombatantRow({
|
||||
|
||||
{/* Initiative */}
|
||||
{/* biome-ignore lint/a11y/noStaticElementInteractions: stopPropagation wrapper for interactive children */}
|
||||
{/* biome-ignore lint/a11y/noNoninteractiveElementInteractions: stopPropagation wrapper for interactive children */}
|
||||
<div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
@@ -542,22 +542,22 @@ export function CombatantRow({
|
||||
{/* Name + Conditions */}
|
||||
<div
|
||||
className={cn(
|
||||
"relative flex flex-wrap items-center gap-1 min-w-0",
|
||||
"relative flex min-w-0 flex-wrap items-center gap-1",
|
||||
dimmed && "opacity-50",
|
||||
)}
|
||||
>
|
||||
{combatant.icon &&
|
||||
combatant.color &&
|
||||
{!!combatant.icon &&
|
||||
!!combatant.color &&
|
||||
(() => {
|
||||
const PcIcon = PLAYER_ICON_MAP[combatant.icon as PlayerIcon];
|
||||
const pcColor =
|
||||
const iconColor =
|
||||
PLAYER_COLOR_HEX[
|
||||
combatant.color as keyof typeof PLAYER_COLOR_HEX
|
||||
];
|
||||
return PcIcon ? (
|
||||
<PcIcon
|
||||
size={14}
|
||||
style={{ color: pcColor }}
|
||||
style={{ color: iconColor }}
|
||||
className="shrink-0"
|
||||
/>
|
||||
) : null;
|
||||
@@ -574,7 +574,7 @@ export function CombatantRow({
|
||||
onRemove={(conditionId) => onToggleCondition(id, conditionId)}
|
||||
onOpenPicker={() => setPickerOpen((prev) => !prev)}
|
||||
/>
|
||||
{pickerOpen && (
|
||||
{!!pickerOpen && (
|
||||
<ConditionPicker
|
||||
activeConditions={combatant.conditions}
|
||||
onToggle={(conditionId) => onToggleCondition(id, conditionId)}
|
||||
@@ -585,6 +585,7 @@ export function CombatantRow({
|
||||
|
||||
{/* AC */}
|
||||
{/* biome-ignore lint/a11y/noStaticElementInteractions: stopPropagation wrapper for interactive children */}
|
||||
{/* biome-ignore lint/a11y/noNoninteractiveElementInteractions: stopPropagation wrapper for interactive children */}
|
||||
<div
|
||||
className={cn(dimmed && "opacity-50")}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
@@ -595,6 +596,7 @@ export function CombatantRow({
|
||||
|
||||
{/* HP */}
|
||||
{/* biome-ignore lint/a11y/noStaticElementInteractions: stopPropagation wrapper for interactive children */}
|
||||
{/* biome-ignore lint/a11y/noNoninteractiveElementInteractions: stopPropagation wrapper for interactive children */}
|
||||
<div
|
||||
className="flex items-center gap-1"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
@@ -609,7 +611,7 @@ export function CombatantRow({
|
||||
{maxHp !== undefined && (
|
||||
<span
|
||||
className={cn(
|
||||
"text-sm tabular-nums text-muted-foreground",
|
||||
"text-muted-foreground text-sm tabular-nums",
|
||||
dimmed && "opacity-50",
|
||||
)}
|
||||
>
|
||||
@@ -626,7 +628,7 @@ export function CombatantRow({
|
||||
icon={<X size={16} />}
|
||||
label="Remove combatant"
|
||||
onConfirm={() => onRemove(id)}
|
||||
className="h-7 w-7 text-muted-foreground opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto focus:opacity-100 focus:pointer-events-auto pointer-coarse:opacity-100 pointer-coarse:pointer-events-auto transition-opacity"
|
||||
className="pointer-events-none pointer-coarse:pointer-events-auto h-7 w-7 text-muted-foreground opacity-0 pointer-coarse:opacity-100 transition-opacity focus:pointer-events-auto focus:opacity-100 group-hover:pointer-events-auto group-hover:opacity-100"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user