diff --git a/src/client/CosmeticsModal.ts b/src/client/CosmeticsModal.ts
index 5925a5296..931433d62 100644
--- a/src/client/CosmeticsModal.ts
+++ b/src/client/CosmeticsModal.ts
@@ -18,6 +18,7 @@ import { modalHeader } from "./components/ui/ModalHeader";
import {
fetchCosmetics,
getPlayerCosmetics,
+ groupCosmeticVariants,
resolveCosmetics,
ResolvedCosmetic,
resolvedToPlayerPattern,
@@ -129,24 +130,24 @@ export class CosmeticsModal extends BaseModal {
- ${items.map((r) => {
- const isSelected =
+ ${groupCosmeticVariants(items).map((group) => {
+ const selectedVariant = group.find((r) =>
r.type === "pattern"
- ? (r.cosmetic === null && this.selectedPattern === null) ||
- (r.cosmetic !== null &&
- this.selectedPattern?.name === r.cosmetic.name &&
- (this.selectedPattern?.colorPalette?.name ?? null) ===
- (r.colorPalette?.name ?? null))
- : (() => {
- const skinName = (r.cosmetic as Skin | null)?.name ?? null;
- return (
- (skinName === null && this.selectedSkinName === null) ||
- (skinName !== null && this.selectedSkinName === skinName)
- );
- })();
+ ? r.cosmetic !== null &&
+ this.selectedPattern?.name === r.cosmetic.name &&
+ (this.selectedPattern?.colorPalette?.name ?? null) ===
+ (r.colorPalette?.name ?? null)
+ : (r.cosmetic as Skin | null)?.name === this.selectedSkinName,
+ );
+ const isSelected =
+ selectedVariant !== undefined ||
+ (group[0].cosmetic === null &&
+ this.selectedPattern === null &&
+ this.selectedSkinName === null);
return html`
this.selectCosmetic(rc)}
>
diff --git a/src/client/components/CosmeticButton.ts b/src/client/components/CosmeticButton.ts
index 9b78d40fb..0e2801d75 100644
--- a/src/client/components/CosmeticButton.ts
+++ b/src/client/components/CosmeticButton.ts
@@ -58,7 +58,7 @@ export class CosmeticButton extends LitElement {
const variants = this.variants;
if (variants && variants.length > 0) {
return (
- variants.find((v) => v.key === this.activeVariantKey) ?? variants[0]
+ variants.find((v) => v.key === this.activeVariantKey) ?? this.resolved
);
}
return this.resolved;
diff --git a/tests/client/CosmeticButton.test.ts b/tests/client/CosmeticButton.test.ts
new file mode 100644
index 000000000..4e1dfde5d
--- /dev/null
+++ b/tests/client/CosmeticButton.test.ts
@@ -0,0 +1,44 @@
+import { afterEach, describe, expect, it, vi } from "vitest";
+import { ResolvedCosmetic } from "../../src/client/Cosmetics";
+import { CosmeticButton } from "../../src/client/components/CosmeticButton";
+
+function patternVariant(name: string, palette: string): ResolvedCosmetic {
+ return {
+ type: "pattern",
+ cosmetic: { name, pattern: "AAAAAA" } as never,
+ colorPalette: {
+ name: palette,
+ primaryColor: "#ffffff",
+ secondaryColor: "#000000",
+ },
+ relationship: "owned",
+ key: `pattern:${name}:${palette}`,
+ };
+}
+
+describe("CosmeticButton variants", () => {
+ let button: CosmeticButton | undefined;
+
+ afterEach(() => {
+ button?.remove();
+ button = undefined;
+ });
+
+ it("uses the resolved variant until a swatch is selected", () => {
+ const red = patternVariant("stripes", "red");
+ const blue = patternVariant("stripes", "blue");
+ const onSelect = vi.fn();
+ button = new CosmeticButton();
+ button.resolved = blue;
+ button.variants = [red, blue];
+ button.onSelect = onSelect;
+
+ (
+ button as unknown as {
+ handleClick(): void;
+ }
+ ).handleClick();
+
+ expect(onSelect).toHaveBeenCalledWith(blue);
+ });
+});