import { LitElement, html } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { Cosmetics } from "../core/CosmeticSchemas";
import { UserSettings } from "../core/game/UserSettings";
import { PlayerPattern } from "../core/Schemas";
import { renderPatternPreview } from "./components/PatternButton";
import { fetchCosmetics } from "./Cosmetics";
import { translateText } from "./Utils";
// Module-level cosmetics cache to avoid refetching on every component mount
let cosmeticsCache: Promise | null = null;
function getCachedCosmetics(): Promise {
if (!cosmeticsCache) {
const fetchPromise = fetchCosmetics();
cosmeticsCache = fetchPromise.catch((err) => {
cosmeticsCache = null;
throw err;
});
}
return cosmeticsCache;
}
@customElement("pattern-input")
export class PatternInput extends LitElement {
@state() public pattern: PlayerPattern | null = null;
@state() public selectedColor: string | null = null;
@state() private isLoading: boolean = true;
@property({ type: Boolean, attribute: "show-select-label" })
public showSelectLabel: boolean = false;
private userSettings = new UserSettings();
private cosmetics: Cosmetics | null = null;
private _abortController: AbortController | null = null;
private _onPatternSelected = () => {
this.updateFromSettings();
};
private updateFromSettings() {
this.selectedColor = this.userSettings.getSelectedColor() ?? null;
if (this.cosmetics) {
this.pattern = this.userSettings.getSelectedPatternName(this.cosmetics);
} else {
this.pattern = null;
}
}
private onInputClick(e: Event) {
e.preventDefault();
e.stopPropagation();
this.dispatchEvent(
new CustomEvent("pattern-input-click", {
bubbles: true,
composed: true,
}),
);
}
async connectedCallback() {
super.connectedCallback();
this._abortController = new AbortController();
this.isLoading = true;
const cosmetics = await getCachedCosmetics();
if (!this.isConnected) return;
this.cosmetics = cosmetics;
this.updateFromSettings();
if (!this.isConnected) return;
this.isLoading = false;
window.addEventListener("pattern-selected", this._onPatternSelected, {
signal: this._abortController.signal,
});
}
disconnectedCallback() {
super.disconnectedCallback();
if (this._abortController) {
this._abortController.abort();
this._abortController = null;
}
}
createRenderRoot() {
return this;
}
render() {
const isDefault = this.pattern === null && this.selectedColor === null;
const showSelect = this.showSelectLabel && isDefault;
const buttonTitle = translateText("territory_patterns.title");
// Show loading state
if (this.isLoading) {
return html`
`;
}
let previewContent;
if (this.pattern) {
previewContent = renderPatternPreview(this.pattern, 128, 128);
} else {
previewContent = renderPatternPreview(null, 128, 128);
}
return html`
`;
}
}