From 70c07c0a1af6884e4f69b52d0eec2edf13fed383 Mon Sep 17 00:00:00 2001
From: Kayla Glick <kayla-glick@github.com>
Date: Fri, 15 Mar 2024 23:53:05 -0400
Subject: [PATCH] fix mobile item picker rendering

---
 ui/core/components/gear_picker.tsx | 802 +++++++++++++++++------------
 1 file changed, 481 insertions(+), 321 deletions(-)

diff --git a/ui/core/components/gear_picker.tsx b/ui/core/components/gear_picker.tsx
index 0019807f59..f4c10925c6 100644
--- a/ui/core/components/gear_picker.tsx
+++ b/ui/core/components/gear_picker.tsx
@@ -1,4 +1,27 @@
+import { Tooltip } from 'bootstrap';
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+import { element, fragment, ref } from 'tsx-vanilla';
+
+import { setItemQualityCssClass } from '../css_utils';
+import { IndividualSimUI } from '../individual_sim_ui.js';
+import { Player } from '../player';
+import { Class, GemColor, ItemQuality, ItemSlot, ItemSpec, ItemType } from '../proto/common';
+import {
+	DatabaseFilters,
+	UIEnchant as Enchant,
+	UIGem as Gem,
+	UIItem as Item,
+} from '../proto/ui.js';
+import { ActionId } from '../proto_utils/action_id';
+import { getEnchantDescription, getUniqueEnchantString } from '../proto_utils/enchants';
+import { EquippedItem } from '../proto_utils/equipped_item';
+import { gemMatchesSocket, getEmptyGemSocketIconUrl } from '../proto_utils/gems';
 import { difficultyNames, professionNames, slotNames } from '../proto_utils/names.js';
+import { Stats } from '../proto_utils/stats';
+import { Sim } from '../sim.js';
+import { SimUI } from '../sim_ui';
+import { EventID, TypedEvent } from '../typed_event';
+import { formatDeltaTextElem } from '../utils';
 import { BaseModal } from './base_modal';
 import { Component } from './component';
 import { FiltersMenu } from './filters_menu';
@@ -9,67 +32,36 @@ import {
 	makeShowEPValuesSelector,
 	makeShowMatchingGemsSelector,
 } from './other_inputs';
-
-import { setItemQualityCssClass } from '../css_utils';
-import { Player } from '../player';
-import { Sim } from '../sim.js';
-import { SimUI } from '../sim_ui';
-import { EventID, TypedEvent } from '../typed_event';
-import { formatDeltaTextElem } from '../utils';
-
-import { ActionId } from '../proto_utils/action_id';
-import { getEnchantDescription, getUniqueEnchantString } from '../proto_utils/enchants';
-import { EquippedItem } from '../proto_utils/equipped_item';
-import { getEmptyGemSocketIconUrl, gemMatchesSocket } from '../proto_utils/gems';
-import { Stats } from '../proto_utils/stats';
-
-import {
-	Class,
-	GemColor,
-	ItemQuality,
-	ItemSlot,
-	ItemSpec,
-	ItemType,
-} from '../proto/common';
-import {
-	DatabaseFilters,
-	UIEnchant as Enchant,
-	UIGem as Gem,
-	UIItem as Item,
-} from '../proto/ui.js';
-import { IndividualSimUI } from '../individual_sim_ui.js';
-import { Tooltip } from 'bootstrap';
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-import { element, fragment, ref } from 'tsx-vanilla';
-
 import { Clusterize } from './virtual_scroll/clusterize.js';
 
 const EP_TOOLTIP = `
 	EP (Equivalence Points) is way of comparing items by multiplying the raw stats of an item with your current stat weights.
 	More EP does not necessarily mean more DPS, as EP doesn't take into account stat caps and non-linear stat calculations.
-`
+`;
 
 const createHeroicLabel = () => {
-	return (<span className='heroic-label'>[H]</span>);
-}
+	return <span className="heroic-label">[H]</span>;
+};
 
-const createGemContainer = (socketColor: GemColor ,gem : Gem|null) => {
+const createGemContainer = (socketColor: GemColor, gem: Gem | null) => {
 	const gemIconElem = ref<HTMLImageElement>();
 
-	let gemContainer = (
+	const gemContainer = (
 		<div className="gem-socket-container">
 			<img ref={gemIconElem} className={`gem-icon ${gem == null ? 'hide' : ''}`} />
-			<img className="socket-icon" src={getEmptyGemSocketIconUrl(socketColor)}/>
+			<img className="socket-icon" src={getEmptyGemSocketIconUrl(socketColor)} />
 		</div>
 	);
 
 	if (gem != null) {
-		ActionId.fromItemId(gem.id).fill().then(filledId => {
-			gemIconElem.value!.src = filledId.iconUrl;
-		});
+		ActionId.fromItemId(gem.id)
+			.fill()
+			.then(filledId => {
+				gemIconElem.value!.src = filledId.iconUrl;
+			});
 	}
 	return gemContainer;
-}
+};
 
 export class GearPicker extends Component {
 	// ItemSlot is used as the index
@@ -121,25 +113,37 @@ export class ItemRenderer extends Component {
 	readonly enchantElem: HTMLAnchorElement;
 	readonly socketsContainerElem: HTMLElement;
 
-	constructor(parent: HTMLElement, player: Player<any>) {
-		super(parent, 'item-picker-root');
+	constructor(parent: HTMLElement, root: HTMLElement, player: Player<any>) {
+		super(parent, 'item-picker-root', root);
 		this.player = player;
 
-		let iconElem = ref<HTMLAnchorElement>();
-		let nameElem = ref<HTMLAnchorElement>();
-		let enchantElem = ref<HTMLAnchorElement>();
-		let sce = ref<HTMLDivElement>();
+		const iconElem = ref<HTMLAnchorElement>();
+		const nameElem = ref<HTMLAnchorElement>();
+		const enchantElem = ref<HTMLAnchorElement>();
+		const sce = ref<HTMLDivElement>();
 		this.rootElem.appendChild(
 			<>
-				<a ref={iconElem} className="item-picker-icon" href="javascript:void(0)" attributes={{role:"button"}}>
+				<a
+					ref={iconElem}
+					className="item-picker-icon"
+					href="javascript:void(0)"
+					attributes={{ role: 'button' }}>
 					<div ref={sce} className="item-picker-sockets-container"></div>
 				</a>
 				<div className="item-picker-labels-container">
-					<a ref={nameElem} className="item-picker-name" href="javascript:void(0)" attributes={{role:"button"}}></a>
-					<br/>
-					<a ref={enchantElem} className="item-picker-enchant" href="javascript:void(0)" attributes={{role:"button"}}></a>
+					<a
+						ref={nameElem}
+						className="item-picker-name"
+						href="javascript:void(0)"
+						attributes={{ role: 'button' }}></a>
+					<br />
+					<a
+						ref={enchantElem}
+						className="item-picker-enchant"
+						href="javascript:void(0)"
+						attributes={{ role: 'button' }}></a>
 				</div>
-			</>
+			</>,
 		);
 
 		this.iconElem = iconElem.value!;
@@ -175,10 +179,13 @@ export class ItemRenderer extends Component {
 
 		this.player.setWowheadData(newItem, this.iconElem);
 		this.player.setWowheadData(newItem, this.nameElem);
-		newItem.asActionId().fill().then(filledId => {
-			filledId.setBackgroundAndHref(this.iconElem);
-			filledId.setWowheadHref(this.nameElem);
-		});
+		newItem
+			.asActionId()
+			.fill()
+			.then(filledId => {
+				filledId.setBackgroundAndHref(this.iconElem);
+				filledId.setWowheadHref(this.nameElem);
+			});
 
 		if (newItem.enchant) {
 			getEnchantDescription(newItem.enchant).then(description => {
@@ -196,9 +203,12 @@ export class ItemRenderer extends Component {
 		}
 
 		newItem.allSocketColors().forEach((socketColor, gemIdx) => {
-			let gemContainer = createGemContainer(socketColor, newItem.gems[gemIdx]);
+			const gemContainer = createGemContainer(socketColor, newItem.gems[gemIdx]);
 
-			if (gemIdx == newItem.numPossibleSockets - 1 && [ItemType.ItemTypeWrist, ItemType.ItemTypeHands].includes(newItem.item.type)) {
+			if (
+				gemIdx == newItem.numPossibleSockets - 1 &&
+				[ItemType.ItemTypeWrist, ItemType.ItemTypeHands].includes(newItem.item.type)
+			) {
 				const updateProfession = () => {
 					if (this.player.isBlacksmithing()) {
 						gemContainer.classList.remove('hide');
@@ -232,7 +242,7 @@ export class ItemPicker extends Component {
 		this.slot = slot;
 		this.simUI = simUI;
 		this.player = player;
-		this.itemElem = new ItemRenderer(this.rootElem, player);
+		this.itemElem = new ItemRenderer(parent, this.rootElem, player);
 
 		this.item = player.getEquippedItem(slot);
 		player.sim.waitForInit().then(() => {
@@ -280,7 +290,9 @@ export class ItemPicker extends Component {
 		if (newItem != null) {
 			this.itemElem.update(newItem);
 		} else {
-			this.itemElem.iconElem.style.backgroundImage = `url('${getEmptySlotIconUrl(this.slot)}')`;
+			this.itemElem.iconElem.style.backgroundImage = `url('${getEmptySlotIconUrl(
+				this.slot,
+			)}')`;
 		}
 
 		this._equippedItem = newItem;
@@ -293,13 +305,12 @@ export class ItemPicker extends Component {
 			equippedItem: this._equippedItem,
 			eligibleItems: this._items,
 			eligibleEnchants: this._enchants,
-			gearData: gearData
-		})
+			gearData: gearData,
+		});
 	}
 }
 
 export class IconItemSwapPicker extends Component {
-
 	private readonly iconAnchor: HTMLAnchorElement;
 	private readonly socketsContainerElem: HTMLElement;
 	private readonly player: Player<any>;
@@ -310,7 +321,7 @@ export class IconItemSwapPicker extends Component {
 	private _enchants: Array<Enchant> = [];
 
 	constructor(parent: HTMLElement, simUI: SimUI, player: Player<any>, slot: ItemSlot) {
-		super(parent, 'icon-picker-root')
+		super(parent, 'icon-picker-root');
 		this.rootElem.classList.add('icon-picker');
 		this.player = player;
 		this.slot = slot;
@@ -320,8 +331,8 @@ export class IconItemSwapPicker extends Component {
 		this.iconAnchor.target = '_blank';
 		this.rootElem.prepend(this.iconAnchor);
 
-		this.socketsContainerElem = document.createElement('div')
-		this.socketsContainerElem.classList.add('item-picker-sockets-container')
+		this.socketsContainerElem = document.createElement('div');
+		this.socketsContainerElem.classList.add('item-picker-sockets-container');
 		this.iconAnchor.appendChild(this.socketsContainerElem);
 
 		player.sim.waitForInit().then(() => {
@@ -329,11 +340,11 @@ export class IconItemSwapPicker extends Component {
 			this._enchants = this.player.getEnchants(slot);
 			const gearData = {
 				equipItem: (eventID: EventID, newItem: EquippedItem | null) => {
-					player.equipItemSwapitem(eventID, this.slot, newItem)
+					player.equipItemSwapitem(eventID, this.slot, newItem);
 				},
 				getEquippedItem: () => player.getItemSwapItem(this.slot),
 				changeEvent: player.itemSwapChangeEmitter,
-			}
+			};
 
 			this.iconAnchor.addEventListener('click', (event: Event) => {
 				event.preventDefault();
@@ -356,29 +367,30 @@ export class IconItemSwapPicker extends Component {
 	update(newItem: EquippedItem | null) {
 		this.iconAnchor.style.backgroundImage = `url('${getEmptySlotIconUrl(this.slot)}')`;
 		this.iconAnchor.removeAttribute('data-wowhead');
-		this.iconAnchor.href = "#";
+		this.iconAnchor.href = '#';
 		this.socketsContainerElem.innerText = '';
 
 		if (newItem) {
-			this.iconAnchor.classList.add("active")
+			this.iconAnchor.classList.add('active');
 
 			newItem.asActionId().fillAndSet(this.iconAnchor, true, true);
 			this.player.setWowheadData(newItem, this.iconAnchor);
 
 			newItem.allSocketColors().forEach((socketColor, gemIdx) => {
-				this.socketsContainerElem.appendChild(createGemContainer(socketColor, newItem.gems[gemIdx]));
+				this.socketsContainerElem.appendChild(
+					createGemContainer(socketColor, newItem.gems[gemIdx]),
+				);
 			});
 		} else {
-			this.iconAnchor.classList.remove("active")
+			this.iconAnchor.classList.remove('active');
 		}
 	}
-
 }
 
 export interface GearData {
-	equipItem: (eventID: EventID, equippedItem: EquippedItem | null) => void,
-	getEquippedItem: () => EquippedItem | null,
-	changeEvent: TypedEvent<any>,
+	equipItem: (eventID: EventID, equippedItem: EquippedItem | null) => void;
+	getEquippedItem: () => EquippedItem | null;
+	changeEvent: TypedEvent<any>;
 }
 
 export enum SelectorModalTabs {
@@ -390,12 +402,12 @@ export enum SelectorModalTabs {
 }
 
 interface SelectorModalConfig {
-	selectedTab: SelectorModalTabs
-	slot: ItemSlot,
-	equippedItem: EquippedItem | null,
-	eligibleItems: Array<Item>,
-	eligibleEnchants: Array<Enchant>,
-	gearData: GearData
+	selectedTab: SelectorModalTabs;
+	slot: ItemSlot;
+	equippedItem: EquippedItem | null;
+	eligibleItems: Array<Item>;
+	eligibleEnchants: Array<Enchant>;
+	gearData: GearData;
 }
 
 export class SelectorModal extends BaseModal {
@@ -407,7 +419,12 @@ export class SelectorModal extends BaseModal {
 	private readonly tabsElem: HTMLElement;
 	private readonly contentElem: HTMLElement;
 
-	constructor(parent: HTMLElement, simUI: SimUI, player: Player<any>, config: SelectorModalConfig) {
+	constructor(
+		parent: HTMLElement,
+		simUI: SimUI,
+		player: Player<any>,
+		config: SelectorModalConfig,
+	) {
 		super(parent, 'selector-modal');
 
 		this.simUI = simUI;
@@ -417,12 +434,17 @@ export class SelectorModal extends BaseModal {
 
 		window.scrollTo({ top: 0 });
 
-		this.header!.insertAdjacentElement('afterbegin', <ul className="nav nav-tabs selector-modal-tabs"></ul>);
+		this.header!.insertAdjacentElement(
+			'afterbegin',
+			<ul className="nav nav-tabs selector-modal-tabs"></ul>,
+		);
 
-		this.body.appendChild(<div className='tab-content selector-modal-tab-content'></div>);
+		this.body.appendChild(<div className="tab-content selector-modal-tab-content"></div>);
 
 		this.tabsElem = this.rootElem.querySelector('.selector-modal-tabs') as HTMLElement;
-		this.contentElem = this.rootElem.querySelector('.selector-modal-tab-content') as HTMLElement;
+		this.contentElem = this.rootElem.querySelector(
+			'.selector-modal-tab-content',
+		) as HTMLElement;
 
 		this.setData();
 
@@ -436,21 +458,23 @@ export class SelectorModal extends BaseModal {
 					<i className="fas fa-cog mx-1"></i>
 					to open your sim options, then click the "Restore Defaults".
 				</span>
-			</div>
-		)
+			</div>,
+		);
 	}
 
 	// Could be 'Items' 'Enchants' or 'Gem1'-'Gem3'
 	openTabName(name: string) {
-		Array.from(this.tabsElem.getElementsByClassName("selector-modal-item-tab")).forEach(elem => {
-			if (elem.getAttribute("data-content-id") == name + "-tab") {
-				(elem as HTMLElement).click();
-			}
-		});
+		Array.from(this.tabsElem.getElementsByClassName('selector-modal-item-tab')).forEach(
+			elem => {
+				if (elem.getAttribute('data-content-id') == name + '-tab') {
+					(elem as HTMLElement).click();
+				}
+			},
+		);
 	}
 
 	openTab(idx: number) {
-		const elems = this.tabsElem.getElementsByClassName("selector-modal-item-tab");
+		const elems = this.tabsElem.getElementsByClassName('selector-modal-item-tab');
 		(elems[idx] as HTMLElement).click();
 	}
 
@@ -489,7 +513,8 @@ export class SelectorModal extends BaseModal {
 			eventID => {
 				gearData.equipItem(eventID, null);
 				this.removeTabs('Gem');
-			});
+			},
+		);
 
 		this.addTab<Enchant>(
 			'Enchants',
@@ -497,7 +522,9 @@ export class SelectorModal extends BaseModal {
 				return {
 					item: enchant,
 					id: enchant.effectId,
-					actionId: enchant.spellId ? ActionId.fromSpellId(enchant.spellId) : ActionId.fromItemId(enchant.itemId),
+					actionId: enchant.spellId
+						? ActionId.fromSpellId(enchant.spellId)
+						: ActionId.fromItemId(enchant.itemId),
 					name: enchant.name,
 					quality: enchant.quality,
 					phase: enchant.phase || 1,
@@ -516,21 +543,20 @@ export class SelectorModal extends BaseModal {
 			GemColor.GemColorUnknown,
 			eventID => {
 				const equippedItem = gearData.getEquippedItem();
-				if (equippedItem)
-					gearData.equipItem(eventID, equippedItem.withEnchant(null));
-			});
+				if (equippedItem) gearData.equipItem(eventID, equippedItem.withEnchant(null));
+			},
+		);
 
 		this.addGemTabs(slot, equippedItem, gearData);
 	}
 
 	protected override onShow(e: Event) {
 		// Only refresh opened tab
-		let t = e.target! as HTMLElement;
-		let tab = t.querySelector<HTMLElement>('.active')!.dataset.contentId!;
+		const t = e.target! as HTMLElement;
+		const tab = t.querySelector<HTMLElement>('.active')!.dataset.contentId!;
 		if (tab.includes('Item')) {
 			this.ilists[0].sizeRefresh();
-		}
-		else if (tab.includes('Enchant')) {
+		} else if (tab.includes('Enchant')) {
 			this.ilists[1].sizeRefresh();
 		}
 	}
@@ -540,70 +566,80 @@ export class SelectorModal extends BaseModal {
 			return;
 		}
 
-		const socketBonusEP = this.player.computeStatsEP(new Stats(equippedItem.item.socketBonus)) / (equippedItem.item.gemSockets.length || 1);
-		equippedItem.curSocketColors(this.player.isBlacksmithing()).forEach((socketColor, socketIdx) => {
-			this.addTab<Gem>(
-				'Gem ' + (socketIdx + 1),
-				this.player.getGems(socketColor).map((gem: Gem) => {
-					return {
-						item: gem,
-						id: gem.id,
-						actionId: ActionId.fromItemId(gem.id),
-						name: gem.name,
-						quality: gem.quality,
-						phase: gem.phase,
-						heroic: false,
-						baseEP: this.player.computeStatsEP(new Stats(gem.stats)),
-						ignoreEPFilter: true,
-						onEquip: (eventID, gem: Gem) => {
-							const equippedItem = gearData.getEquippedItem();
-							if (equippedItem)
-								gearData.equipItem(eventID, equippedItem.withGem(gem, socketIdx));
-						},
-					};
-				}),
-				gem => {
-					let gemEP = this.player.computeGemEP(gem);
-					if (gemMatchesSocket(gem, socketColor)) {
-						gemEP += socketBonusEP;
-					}
-					return gemEP;
-				},
-				equippedItem => equippedItem?.gems[socketIdx],
-				socketColor,
-				eventID => {
-					const equippedItem = gearData.getEquippedItem();
-					if (equippedItem)
-						gearData.equipItem(eventID, equippedItem.withGem(null, socketIdx));
-				},
-				tabAnchor => {
-					let gemContainer = createGemContainer(socketColor, null);
-					tabAnchor.appendChild(gemContainer);
-					tabAnchor.classList.add('selector-modal-tab-gem');
-
-					const gemElem = tabAnchor.querySelector('.gem-icon') as HTMLElement;
-					const emptySocketUrl = getEmptyGemSocketIconUrl(socketColor)
-
-					const updateGemIcon = () => {
+		const socketBonusEP =
+			this.player.computeStatsEP(new Stats(equippedItem.item.socketBonus)) /
+			(equippedItem.item.gemSockets.length || 1);
+		equippedItem
+			.curSocketColors(this.player.isBlacksmithing())
+			.forEach((socketColor, socketIdx) => {
+				this.addTab<Gem>(
+					'Gem ' + (socketIdx + 1),
+					this.player.getGems(socketColor).map((gem: Gem) => {
+						return {
+							item: gem,
+							id: gem.id,
+							actionId: ActionId.fromItemId(gem.id),
+							name: gem.name,
+							quality: gem.quality,
+							phase: gem.phase,
+							heroic: false,
+							baseEP: this.player.computeStatsEP(new Stats(gem.stats)),
+							ignoreEPFilter: true,
+							onEquip: (eventID, gem: Gem) => {
+								const equippedItem = gearData.getEquippedItem();
+								if (equippedItem)
+									gearData.equipItem(
+										eventID,
+										equippedItem.withGem(gem, socketIdx),
+									);
+							},
+						};
+					}),
+					gem => {
+						let gemEP = this.player.computeGemEP(gem);
+						if (gemMatchesSocket(gem, socketColor)) {
+							gemEP += socketBonusEP;
+						}
+						return gemEP;
+					},
+					equippedItem => equippedItem?.gems[socketIdx],
+					socketColor,
+					eventID => {
 						const equippedItem = gearData.getEquippedItem();
-						const gem = equippedItem?.gems[socketIdx];
+						if (equippedItem)
+							gearData.equipItem(eventID, equippedItem.withGem(null, socketIdx));
+					},
+					tabAnchor => {
+						const gemContainer = createGemContainer(socketColor, null);
+						tabAnchor.appendChild(gemContainer);
+						tabAnchor.classList.add('selector-modal-tab-gem');
 
-						if (gem) {
-							gemElem.classList.remove('hide');
-							ActionId.fromItemId(gem.id).fill().then(filledId => {
-								gemElem.setAttribute('src', filledId.iconUrl);
-							});
-						} else {
-							gemElem.classList.add('hide');
-							gemElem.setAttribute('src', emptySocketUrl);
-						}
-					};
+						const gemElem = tabAnchor.querySelector('.gem-icon') as HTMLElement;
+						const emptySocketUrl = getEmptyGemSocketIconUrl(socketColor);
 
-					gearData.changeEvent.on(updateGemIcon);
-					this.addOnDisposeCallback(() => gearData.changeEvent.off(updateGemIcon));
-					updateGemIcon();
-				});
-		});
+						const updateGemIcon = () => {
+							const equippedItem = gearData.getEquippedItem();
+							const gem = equippedItem?.gems[socketIdx];
+
+							if (gem) {
+								gemElem.classList.remove('hide');
+								ActionId.fromItemId(gem.id)
+									.fill()
+									.then(filledId => {
+										gemElem.setAttribute('src', filledId.iconUrl);
+									});
+							} else {
+								gemElem.classList.add('hide');
+								gemElem.setAttribute('src', emptySocketUrl);
+							}
+						};
+
+						gearData.changeEvent.on(updateGemIcon);
+						this.addOnDisposeCallback(() => gearData.changeEvent.off(updateGemIcon));
+						updateGemIcon();
+					},
+				);
+			});
 	}
 
 	/**
@@ -616,10 +652,11 @@ export class SelectorModal extends BaseModal {
 		label: string,
 		itemData: Array<ItemData<T>>,
 		computeEP: (item: T) => number,
-		equippedToItemFn: (equippedItem: EquippedItem | null) => (T | null | undefined),
+		equippedToItemFn: (equippedItem: EquippedItem | null) => T | null | undefined,
 		socketColor: GemColor,
 		onRemove: (eventID: EventID) => void,
-		setTabContent?: (tabElem: HTMLAnchorElement) => void) {
+		setTabContent?: (tabElem: HTMLAnchorElement) => void,
+	) {
 		if (itemData.length == 0) {
 			return;
 		}
@@ -636,17 +673,16 @@ export class SelectorModal extends BaseModal {
 					className={`nav-link selector-modal-item-tab ${selected ? 'active' : ''}`}
 					dataset={{
 						label: label,
-						contentId:tabContentId,
-						bsToggle:'tab',
-						bsTarget:`#${tabContentId}`,
+						contentId: tabContentId,
+						bsToggle: 'tab',
+						bsTarget: `#${tabContentId}`,
 					}}
 					attributes={{
-						role:'tab',
-						'aria-selected':selected,
+						role: 'tab',
+						'aria-selected': selected,
 					}}
-					type="button"
-				></a>
-			</li>
+					type="button"></a>
+			</li>,
 		);
 
 		if (setTabContent) {
@@ -660,7 +696,7 @@ export class SelectorModal extends BaseModal {
 			return;
 		}
 
-		let ilist = new ItemList<T>(
+		const ilist = new ItemList<T>(
 			this.contentElem,
 			this.simUI,
 			this.config,
@@ -681,11 +717,17 @@ export class SelectorModal extends BaseModal {
 					this.addGemTabs(slot, gearData.getEquippedItem(), gearData);
 				}
 			},
-		)
+		);
 
-		let invokeUpdate = () => { ilist.updateSelected() }
-		let applyFilter = () => { ilist.applyFilters() }
-		let hideOrShowEPValues = () => { ilist.hideOrShowEPValues() }
+		const invokeUpdate = () => {
+			ilist.updateSelected();
+		};
+		const applyFilter = () => {
+			ilist.applyFilters();
+		};
+		const hideOrShowEPValues = () => {
+			ilist.hideOrShowEPValues();
+		};
 		// Add event handlers
 		gearData.changeEvent.on(invokeUpdate);
 
@@ -694,22 +736,23 @@ export class SelectorModal extends BaseModal {
 		this.player.sim.showEPValuesChangeEmitter.on(hideOrShowEPValues);
 
 		this.addOnDisposeCallback(() => {
-			gearData.changeEvent.off(invokeUpdate)
+			gearData.changeEvent.off(invokeUpdate);
 			this.player.sim.phaseChangeEmitter.off(applyFilter);
 			this.player.sim.filtersChangeEmitter.off(applyFilter);
 			this.player.sim.showEPValuesChangeEmitter.off(hideOrShowEPValues);
 			ilist.dispose();
 		});
 
-		tabAnchor.value!.addEventListener('shown.bs.tab', (event) => {
-			ilist.sizeRefresh()
+		tabAnchor.value!.addEventListener('shown.bs.tab', event => {
+			ilist.sizeRefresh();
 		});
 
 		this.ilists.push(ilist);
 	}
 
 	private removeTabs(labelSubstring: string) {
-		const tabElems = Array.prototype.slice.call(this.tabsElem.getElementsByClassName('selector-modal-item-tab'))
+		const tabElems = Array.prototype.slice
+			.call(this.tabsElem.getElementsByClassName('selector-modal-item-tab'))
 			.filter(tab => tab.dataset.label.includes(labelSubstring));
 
 		const contentElems = tabElems
@@ -722,21 +765,21 @@ export class SelectorModal extends BaseModal {
 }
 
 export interface ItemData<T> {
-	item: T,
-	name: string,
-	id: number,
-	actionId: ActionId,
-	quality: ItemQuality,
-	phase: number,
-	baseEP: number,
-	ignoreEPFilter: boolean,
-	heroic: boolean,
-	onEquip: (eventID: EventID, item: T) => void,
+	item: T;
+	name: string;
+	id: number;
+	actionId: ActionId;
+	quality: ItemQuality;
+	phase: number;
+	baseEP: number;
+	ignoreEPFilter: boolean;
+	heroic: boolean;
+	onEquip: (eventID: EventID, item: T) => void;
 }
 
 interface ItemDataWithIdx<T> {
-	idx: number,
-	data: ItemData<T>,
+	idx: number;
+	data: ItemData<T>;
 }
 
 const emptySlotIcons: Record<ItemSlot, string> = {
@@ -773,7 +816,7 @@ export class ItemList<T> {
 	private searchInput: HTMLInputElement;
 	private socketColor: GemColor;
 	private computeEP: (item: T) => number;
-	private equippedToItemFn: (equippedItem: EquippedItem | null) => (T | null | undefined);
+	private equippedToItemFn: (equippedItem: EquippedItem | null) => T | null | undefined;
 	private gearData: GearData;
 	private tabContent: Element;
 	private onItemClick: (itemData: ItemData<T>) => void;
@@ -787,10 +830,11 @@ export class ItemList<T> {
 		label: string,
 		itemData: Array<ItemData<T>>,
 		computeEP: (item: T) => number,
-		equippedToItemFn: (equippedItem: EquippedItem | null) => (T | null | undefined),
+		equippedToItemFn: (equippedItem: EquippedItem | null) => T | null | undefined,
 		socketColor: GemColor,
 		onRemove: (eventID: EventID) => void,
-		onItemClick: (itemData: ItemData<T>) => void) {
+		onItemClick: (itemData: ItemData<T>) => void,
+	) {
 		this.label = label;
 		this.player = player;
 		this.itemData = itemData;
@@ -811,28 +855,43 @@ export class ItemList<T> {
 		this.tabContent = (
 			<div
 				id={tabContentId}
-				className={`selector-modal-tab-pane tab-pane fade ${selected ? 'active show' : ''}`}
-			>
+				className={`selector-modal-tab-pane tab-pane fade ${
+					selected ? 'active show' : ''
+				}`}>
 				<div className="selector-modal-filters">
-					<input className="selector-modal-search form-control" type="text" placeholder="Search..."/>
-					{label == 'Items' && <button className="selector-modal-filters-button btn btn-primary">Filters</button>}
+					<input
+						className="selector-modal-search form-control"
+						type="text"
+						placeholder="Search..."
+					/>
+					{label == 'Items' && (
+						<button className="selector-modal-filters-button btn btn-primary">
+							Filters
+						</button>
+					)}
 					<div className="selector-modal-phase-selector"></div>
 					<div className="sim-input selector-modal-boolean-option selector-modal-show-1h-weapons"></div>
 					<div className="sim-input selector-modal-boolean-option selector-modal-show-2h-weapons"></div>
 					<div className="sim-input selector-modal-boolean-option selector-modal-show-matching-gems"></div>
 					<div className="sim-input selector-modal-boolean-option selector-modal-show-ep-values"></div>
-					<button className="selector-modal-simall-button btn btn-warning">Add to Batch Sim</button>
-					<button className="selector-modal-remove-button btn btn-danger">Unequip Item</button>
+					<button className="selector-modal-simall-button btn btn-warning">
+						Add to Batch Sim
+					</button>
+					<button className="selector-modal-remove-button btn btn-danger">
+						Unequip Item
+					</button>
 				</div>
 				<div className="selector-modal-list-labels">
-					<label className="item-label"><small>Item</small></label>
-					<label className="source-label"><small>Source</small></label>
+					<label className="item-label">
+						<small>Item</small>
+					</label>
+					<label className="source-label">
+						<small>Source</small>
+					</label>
 					<label className="ep-label">
 						<small>EP</small>
 						<i className="fa-solid fa-plus-minus fa-2xs"></i>
-						<button
-							ref={epButton}
-							className="btn btn-link p-0 ms-1">
+						<button ref={epButton} className="btn btn-link p-0 ms-1">
 							<i className="far fa-question-circle fa-lg"></i>
 						</button>
 					</label>
@@ -845,85 +904,148 @@ export class ItemList<T> {
 		parent.appendChild(this.tabContent);
 
 		new Tooltip(epButton.value!, {
-			title: EP_TOOLTIP
+			title: EP_TOOLTIP,
 		});
 
-		const show1hWeaponsSelector = makeShow1hWeaponsSelector(this.tabContent.getElementsByClassName('selector-modal-show-1h-weapons')[0] as HTMLElement, player.sim);
-		const show2hWeaponsSelector = makeShow2hWeaponsSelector(this.tabContent.getElementsByClassName('selector-modal-show-2h-weapons')[0] as HTMLElement, player.sim);
-		if (!(label == 'Items' && (slot == ItemSlot.ItemSlotMainHand || (slot == ItemSlot.ItemSlotOffHand && player.getClass() == Class.ClassWarrior)))) {
-			(this.tabContent.getElementsByClassName('selector-modal-show-1h-weapons')[0] as HTMLElement).style.display = 'none';
-			(this.tabContent.getElementsByClassName('selector-modal-show-2h-weapons')[0] as HTMLElement).style.display = 'none';
+		const show1hWeaponsSelector = makeShow1hWeaponsSelector(
+			this.tabContent.getElementsByClassName(
+				'selector-modal-show-1h-weapons',
+			)[0] as HTMLElement,
+			player.sim,
+		);
+		const show2hWeaponsSelector = makeShow2hWeaponsSelector(
+			this.tabContent.getElementsByClassName(
+				'selector-modal-show-2h-weapons',
+			)[0] as HTMLElement,
+			player.sim,
+		);
+		if (
+			!(
+				label == 'Items' &&
+				(slot == ItemSlot.ItemSlotMainHand ||
+					(slot == ItemSlot.ItemSlotOffHand && player.getClass() == Class.ClassWarrior))
+			)
+		) {
+			(
+				this.tabContent.getElementsByClassName(
+					'selector-modal-show-1h-weapons',
+				)[0] as HTMLElement
+			).style.display = 'none';
+			(
+				this.tabContent.getElementsByClassName(
+					'selector-modal-show-2h-weapons',
+				)[0] as HTMLElement
+			).style.display = 'none';
 		}
 
-		makeShowEPValuesSelector(this.tabContent.getElementsByClassName('selector-modal-show-ep-values')[0] as HTMLElement, player.sim);
+		makeShowEPValuesSelector(
+			this.tabContent.getElementsByClassName(
+				'selector-modal-show-ep-values',
+			)[0] as HTMLElement,
+			player.sim,
+		);
 
-		const showMatchingGemsSelector = makeShowMatchingGemsSelector(this.tabContent.getElementsByClassName('selector-modal-show-matching-gems')[0] as HTMLElement, player.sim);
+		const showMatchingGemsSelector = makeShowMatchingGemsSelector(
+			this.tabContent.getElementsByClassName(
+				'selector-modal-show-matching-gems',
+			)[0] as HTMLElement,
+			player.sim,
+		);
 		if (!label.startsWith('Gem')) {
-			(this.tabContent.getElementsByClassName('selector-modal-show-matching-gems')[0] as HTMLElement).style.display = 'none';
+			(
+				this.tabContent.getElementsByClassName(
+					'selector-modal-show-matching-gems',
+				)[0] as HTMLElement
+			).style.display = 'none';
 		}
 
-		const phaseSelector = makePhaseSelector(this.tabContent.getElementsByClassName('selector-modal-phase-selector')[0] as HTMLElement, player.sim);
+		const phaseSelector = makePhaseSelector(
+			this.tabContent.getElementsByClassName(
+				'selector-modal-phase-selector',
+			)[0] as HTMLElement,
+			player.sim,
+		);
 
 		if (label == 'Items') {
-			const filtersButton = this.tabContent.getElementsByClassName('selector-modal-filters-button')[0] as HTMLElement;
+			const filtersButton = this.tabContent.getElementsByClassName(
+				'selector-modal-filters-button',
+			)[0] as HTMLElement;
 			filtersButton.addEventListener('click', () => new FiltersMenu(parent, player, slot));
 		}
 
-		this.listElem = this.tabContent.getElementsByClassName('selector-modal-list')[0] as HTMLElement;
+		this.listElem = this.tabContent.getElementsByClassName(
+			'selector-modal-list',
+		)[0] as HTMLElement;
 
 		this.itemsToDisplay = [];
 
-		this.scroller = new Clusterize({
-			getNumberOfRows: () => { return this.itemsToDisplay.length },
-			generateRows: (startIdx, endIdx) => {
-				let items = [];
-				for (let i = startIdx; i < endIdx; ++i) {
-					if (i >= this.itemsToDisplay.length)
-						break;
-					items.push(this.createItemElem({idx:this.itemsToDisplay[i], data:this.itemData[this.itemsToDisplay[i]]}));
-				}
-				return items;
-			}
-		}, {
-			rows: [],
-			scroll_elem: this.listElem,
-			content_elem: this.listElem,
-			item_height: 56,
-			show_no_data_row: false,
-			no_data_text: '',
-			tag: 'li',
-			rows_in_block: 16,
-			blocks_in_cluster: 2,
-		});
+		this.scroller = new Clusterize(
+			{
+				getNumberOfRows: () => {
+					return this.itemsToDisplay.length;
+				},
+				generateRows: (startIdx, endIdx) => {
+					const items = [];
+					for (let i = startIdx; i < endIdx; ++i) {
+						if (i >= this.itemsToDisplay.length) break;
+						items.push(
+							this.createItemElem({
+								idx: this.itemsToDisplay[i],
+								data: this.itemData[this.itemsToDisplay[i]],
+							}),
+						);
+					}
+					return items;
+				},
+			},
+			{
+				rows: [],
+				scroll_elem: this.listElem,
+				content_elem: this.listElem,
+				item_height: 56,
+				show_no_data_row: false,
+				no_data_text: '',
+				tag: 'li',
+				rows_in_block: 16,
+				blocks_in_cluster: 2,
+			},
+		);
 
-		const removeButton = this.tabContent.getElementsByClassName('selector-modal-remove-button')[0] as HTMLButtonElement;
+		const removeButton = this.tabContent.getElementsByClassName(
+			'selector-modal-remove-button',
+		)[0] as HTMLButtonElement;
 		removeButton.addEventListener('click', event => {
 			onRemove(TypedEvent.nextEventID());
 		});
 
-		if (label.startsWith("Enchants")) {
+		if (label.startsWith('Enchants')) {
 			removeButton.textContent = 'Remove Enchant';
-		} else if (label.startsWith("Gem")) {
+		} else if (label.startsWith('Gem')) {
 			removeButton.textContent = 'Remove Gem';
 		}
 
 		this.updateSelected();
 
-		this.searchInput = this.tabContent.getElementsByClassName('selector-modal-search')[0] as HTMLInputElement;
+		this.searchInput = this.tabContent.getElementsByClassName(
+			'selector-modal-search',
+		)[0] as HTMLInputElement;
 		this.searchInput.addEventListener('input', () => this.applyFilters());
 
-		const simAllButton = this.tabContent.getElementsByClassName('selector-modal-simall-button')[0] as HTMLButtonElement;
-		if (label == "Items") {
-			simAllButton.hidden = !player.sim.getShowExperimental()
+		const simAllButton = this.tabContent.getElementsByClassName(
+			'selector-modal-simall-button',
+		)[0] as HTMLButtonElement;
+		if (label == 'Items') {
+			simAllButton.hidden = !player.sim.getShowExperimental();
 			player.sim.showExperimentalChangeEmitter.on(() => {
 				simAllButton.hidden = !player.sim.getShowExperimental();
 			});
-			simAllButton.addEventListener('click', (event) => {
+			simAllButton.addEventListener('click', event => {
 				if (simUI instanceof IndividualSimUI) {
-					let itemSpecs = Array<ItemSpec>();
-					const isRangedOrTrinket = this.slot == ItemSlot.ItemSlotRanged ||
+					const itemSpecs = Array<ItemSpec>();
+					const isRangedOrTrinket =
+						this.slot == ItemSlot.ItemSlotRanged ||
 						this.slot == ItemSlot.ItemSlotTrinket1 ||
-						this.slot == ItemSlot.ItemSlotTrinket2
+						this.slot == ItemSlot.ItemSlotTrinket2;
 
 					const curItem = this.equippedToItemFn(this.player.getEquippedItem(this.slot));
 					let curEP = 0;
@@ -931,9 +1053,9 @@ export class ItemList<T> {
 						curEP = this.computeEP(curItem);
 					}
 
-					for(let i of this.itemsToDisplay) {
+					for (const i of this.itemsToDisplay) {
 						const idata = this.itemData[i];
-						if (!isRangedOrTrinket && curEP > 0 && idata.baseEP < (curEP / 2)) {
+						if (!isRangedOrTrinket && curEP > 0 && idata.baseEP < curEP / 2) {
 							continue; // If we have EPs on current item, dont sim items with less than half the EP.
 						}
 
@@ -941,7 +1063,6 @@ export class ItemList<T> {
 						if (idata.baseEP > 0 || isRangedOrTrinket) {
 							itemSpecs.push(ItemSpec.create({ id: idata.id }));
 						}
-
 					}
 					simUI.bt.addItems(itemSpecs);
 					// TODO: should we open the bulk sim UI or should we run in the background showing progress, and then sort the items in the picker?
@@ -966,18 +1087,22 @@ export class ItemList<T> {
 		const newEquippedItem = this.gearData.getEquippedItem();
 		const newItem = this.equippedToItemFn(newEquippedItem);
 
-		const newItemId = newItem ? (this.label == 'Enchants' ? (newItem as unknown as Enchant).effectId : (newItem as unknown as Item | Gem).id) : 0;
+		const newItemId = newItem
+			? this.label == 'Enchants'
+				? (newItem as unknown as Enchant).effectId
+				: (newItem as unknown as Item | Gem).id
+			: 0;
 		const newEP = newItem ? this.computeEP(newItem) : 0;
 
-		this.scroller.elementUpdate((item) => {
-			let idx = (item as HTMLElement).dataset.idx!;
+		this.scroller.elementUpdate(item => {
+			const idx = (item as HTMLElement).dataset.idx!;
 			const itemData = this.itemData[parseFloat(idx)];
-			if (itemData.id == newItemId)
-				item.classList.add('active');
-			else
-				item.classList.remove('active');
+			if (itemData.id == newItemId) item.classList.add('active');
+			else item.classList.remove('active');
 
-			const epDeltaElem = item.getElementsByClassName('selector-modal-list-item-ep-delta')[0] as HTMLSpanElement;
+			const epDeltaElem = item.getElementsByClassName(
+				'selector-modal-list-item-ep-delta',
+			)[0] as HTMLSpanElement;
 			if (epDeltaElem) {
 				epDeltaElem.textContent = '';
 				if (itemData.item) {
@@ -993,7 +1118,7 @@ export class ItemList<T> {
 	public applyFilters() {
 		this.currentFilters = this.player.sim.getFilters();
 		let itemIdxs = new Array<number>(this.itemData.length);
-		for (let i = 0; i < this.itemData.length; ++i)  {
+		for (let i = 0; i < this.itemData.length; ++i) {
 			itemIdxs[i] = i;
 		}
 
@@ -1003,19 +1128,22 @@ export class ItemList<T> {
 			itemIdxs = this.player.filterItemData(
 				itemIdxs,
 				i => this.itemData[i].item as unknown as Item,
-				this.slot);
+				this.slot,
+			);
 		} else if (this.label == 'Enchants') {
 			itemIdxs = this.player.filterEnchantData(
 				itemIdxs,
 				i => this.itemData[i].item as unknown as Enchant,
 				this.slot,
-				currentEquippedItem);
+				currentEquippedItem,
+			);
 		} else if (this.label.startsWith('Gem')) {
 			itemIdxs = this.player.filterGemData(
 				itemIdxs,
 				i => this.itemData[i].item as unknown as Gem,
 				this.slot,
-				this.socketColor);
+				this.socketColor,
+			);
 		}
 
 		itemIdxs = itemIdxs.filter(i => {
@@ -1026,13 +1154,15 @@ export class ItemList<T> {
 			}
 
 			if (this.searchInput.value.length > 0) {
-				const searchQuery = this.searchInput.value.toLowerCase().replaceAll(/[^a-zA-Z0-9\s]/g, '').split(" ");
+				const searchQuery = this.searchInput.value
+					.toLowerCase()
+					.replaceAll(/[^a-zA-Z0-9\s]/g, '')
+					.split(' ');
 				const name = listItemData.name.toLowerCase().replaceAll(/[^a-zA-Z0-9\s]/g, '');
 
-				var include = true;
+				let include = true;
 				searchQuery.forEach(v => {
-					if (!name.includes(v))
-						include = false;
+					if (!name.includes(v)) include = false;
 				});
 				if (!include) {
 					return false;
@@ -1045,14 +1175,16 @@ export class ItemList<T> {
 		let sortFn: (itemA: T, itemB: T) => number;
 		if (this.slot == ItemSlot.ItemSlotTrinket1 || this.slot == ItemSlot.ItemSlotTrinket2) {
 			// Trinket EP is weird so just sort by ilvl instead.
-			sortFn = (itemA, itemB) => (itemB as unknown as Item).ilvl - (itemA as unknown as Item).ilvl;
+			sortFn = (itemA, itemB) =>
+				(itemB as unknown as Item).ilvl - (itemA as unknown as Item).ilvl;
 		} else {
 			sortFn = (itemA, itemB) => {
 				const diff = this.computeEP(itemB) - this.computeEP(itemA);
 				// if EP is same, sort by ilvl
-				if (Math.abs(diff) < 0.01) return (itemB as unknown as Item).ilvl - (itemA as unknown as Item).ilvl;
+				if (Math.abs(diff) < 0.01)
+					return (itemB as unknown as Item).ilvl - (itemA as unknown as Item).ilvl;
 				return diff;
-			}
+			};
 		}
 
 		itemIdxs = itemIdxs.sort((dataA, dataB) => {
@@ -1071,20 +1203,18 @@ export class ItemList<T> {
 	}
 
 	public hideOrShowEPValues() {
-		const labels = this.tabContent.getElementsByClassName("ep-label")
-		const container = this.tabContent.getElementsByClassName("selector-modal-list")
+		const labels = this.tabContent.getElementsByClassName('ep-label');
+		const container = this.tabContent.getElementsByClassName('selector-modal-list');
 		const show = this.player.sim.getShowEPValues();
-		const display = show ? "" : "none"
+		const display = show ? '' : 'none';
 
-		for (let label of labels) {
+		for (const label of labels) {
 			(label as HTMLElement).style.display = display;
 		}
 
-		for (let c of container) {
-			if (show)
-				c.classList.remove("hide-ep");
-			else
-				c.classList.add("hide-ep");
+		for (const c of container) {
+			if (show) c.classList.remove('hide-ep');
+			else c.classList.add('hide-ep');
 		}
 	}
 
@@ -1093,18 +1223,29 @@ export class ItemList<T> {
 		const itemEP = this.computeEP(itemData.item);
 
 		const equippedItem = this.equippedToItemFn(this.gearData.getEquippedItem());
-		const equippedItemID = equippedItem ? (this.label == 'Enchants' ? (equippedItem as unknown as Enchant).effectId : (equippedItem as unknown as Item).id) : 0;
-		const equippedItemEP = equippedItem ? this.computeEP(equippedItem) : 0
+		const equippedItemID = equippedItem
+			? this.label == 'Enchants'
+				? (equippedItem as unknown as Enchant).effectId
+				: (equippedItem as unknown as Item).id
+			: 0;
+		const equippedItemEP = equippedItem ? this.computeEP(equippedItem) : 0;
 
 		const nameElem = ref<HTMLLabelElement>();
 		const anchorElem = ref<HTMLAnchorElement>();
 		const iconElem = ref<HTMLImageElement>();
 		const listItemElem = (
-			<li className={`selector-modal-list-item ${equippedItemID == itemData.id ? 'active' : ''}`} dataset={{idx: item.idx.toString()}}>
-				<div className='selector-modal-list-label-cell'>
-					<a className='selector-modal-list-item-link' ref={anchorElem} dataset={{whtticon:'false'}}>
-						<img className='selector-modal-list-item-icon' ref={iconElem}></img>
-						<label className='selector-modal-list-item-name' ref={nameElem}>
+			<li
+				className={`selector-modal-list-item ${
+					equippedItemID == itemData.id ? 'active' : ''
+				}`}
+				dataset={{ idx: item.idx.toString() }}>
+				<div className="selector-modal-list-label-cell">
+					<a
+						className="selector-modal-list-item-link"
+						ref={anchorElem}
+						dataset={{ whtticon: 'false' }}>
+						<img className="selector-modal-list-item-icon" ref={iconElem}></img>
+						<label className="selector-modal-list-item-name" ref={nameElem}>
 							{itemData.name}
 							{itemData.heroic && createHeroicLabel()}
 						</label>
@@ -1115,37 +1256,42 @@ export class ItemList<T> {
 
 		if (this.label == 'Items') {
 			listItemElem.appendChild(
-				<div className='selector-modal-list-item-source-container'>
+				<div className="selector-modal-list-item-source-container">
 					{this.getSourceInfo(itemData.item as unknown as Item, this.player.sim)}
-				</div>
-			)
+				</div>,
+			);
 		}
 
-
 		if (this.slot != ItemSlot.ItemSlotTrinket1 && this.slot != ItemSlot.ItemSlotTrinket2) {
 			listItemElem.appendChild(
-				<div className='selector-modal-list-item-ep'>
-					<span className='selector-modal-list-item-ep-value'>
-						{itemEP < 9.95 ? itemEP.toFixed(1).toString() : Math.round(itemEP).toString()}
+				<div className="selector-modal-list-item-ep">
+					<span className="selector-modal-list-item-ep-value">
+						{itemEP < 9.95
+							? itemEP.toFixed(1).toString()
+							: Math.round(itemEP).toString()}
 					</span>
 					<span
-						className='selector-modal-list-item-ep-delta'
-						ref={e => itemData.item && equippedItemEP != itemEP && formatDeltaTextElem(e, equippedItemEP, itemEP, 0)}
-					></span>
-				</div>
+						className="selector-modal-list-item-ep-delta"
+						ref={e =>
+							itemData.item &&
+							equippedItemEP != itemEP &&
+							formatDeltaTextElem(e, equippedItemEP, itemEP, 0)
+						}></span>
+				</div>,
 			);
 		}
 
 		const favoriteElem = ref<HTMLButtonElement>();
 		listItemElem.appendChild(
 			<div>
-				<button className="selector-modal-list-item-favorite btn btn-link p-0"
-						ref={favoriteElem}
-						onclick={() => setFavorite(listItemElem.dataset.fav == 'false')}>
-					<i className='fa-star fa-xl'></i>
+				<button
+					className="selector-modal-list-item-favorite btn btn-link p-0"
+					ref={favoriteElem}
+					onclick={() => setFavorite(listItemElem.dataset.fav == 'false')}>
+					<i className="fa-star fa-xl"></i>
 				</button>
-			</div>
-		)
+			</div>,
+		);
 
 		anchorElem.value!.addEventListener('click', (event: Event) => {
 			event.preventDefault();
@@ -1161,7 +1307,7 @@ export class ItemList<T> {
 		setItemQualityCssClass(nameElem.value!, itemData.quality);
 
 		new Tooltip(favoriteElem.value!, {
-			title: 'Add to favorites'
+			title: 'Add to favorites',
 		});
 		const setFavorite = (isFavorite: boolean) => {
 			const filters = this.player.sim.getFilters();
@@ -1203,7 +1349,7 @@ export class ItemList<T> {
 			this.player.sim.setFilters(TypedEvent.nextEventID(), filters);
 		};
 
-		let isFavorite = this.isItemFavorited(itemData);
+		const isFavorite = this.isItemFavorited(itemData);
 
 		if (isFavorite) {
 			favoriteElem.value!.children[0].classList.add('fas');
@@ -1216,11 +1362,13 @@ export class ItemList<T> {
 		return listItemElem;
 	}
 
-	private isItemFavorited(itemData: ItemData<T>) : boolean {
+	private isItemFavorited(itemData: ItemData<T>): boolean {
 		if (this.label == 'Items') {
 			return this.currentFilters.favoriteItems.includes(itemData.id);
 		} else if (this.label == 'Enchants') {
-			return this.currentFilters.favoriteEnchants.includes(getUniqueEnchantString(itemData.item as unknown as Enchant));
+			return this.currentFilters.favoriteEnchants.includes(
+				getUniqueEnchantString(itemData.item as unknown as Enchant),
+			);
 		} else if (this.label.startsWith('Gem')) {
 			return this.currentFilters.favoriteGems.includes(itemData.id);
 		}
@@ -1232,14 +1380,21 @@ export class ItemList<T> {
 			return <></>;
 		}
 
-		const makeAnchor = (href:string, inner:string) => {
-			return <a href={href}><small>{inner}</small></a>;
-		}
+		const makeAnchor = (href: string, inner: string) => {
+			return (
+				<a href={href}>
+					<small>{inner}</small>
+				</a>
+			);
+		};
 
 		const source = item.sources[0];
 		if (source.source.oneofKind == 'crafted') {
 			const src = source.source.crafted;
-			return makeAnchor( ActionId.makeSpellUrl(src.spellId), professionNames.get(src.profession) ?? 'Unknown');
+			return makeAnchor(
+				ActionId.makeSpellUrl(src.spellId),
+				professionNames.get(src.profession) ?? 'Unknown',
+			);
 		} else if (source.source.oneofKind == 'drop') {
 			const src = source.source.drop;
 			const zone = sim.db.getZone(src.zoneId);
@@ -1248,12 +1403,17 @@ export class ItemList<T> {
 				throw new Error('No zone found for item: ' + item);
 			}
 
-			let rtnEl = makeAnchor( ActionId.makeZoneUrl(zone.id), `${zone.name} (${difficultyNames.get(src.difficulty) ?? 'Unknown'})`);
+			const rtnEl = makeAnchor(
+				ActionId.makeZoneUrl(zone.id),
+				`${zone.name} (${difficultyNames.get(src.difficulty) ?? 'Unknown'})`,
+			);
 
 			const category = src.category ? ` - ${src.category}` : '';
 			if (npc) {
 				rtnEl.appendChild(document.createElement('br'));
-				rtnEl.appendChild(makeAnchor(ActionId.makeNpcUrl(npc.id), `${npc.name + category}`));
+				rtnEl.appendChild(
+					makeAnchor(ActionId.makeNpcUrl(npc.id), `${npc.name + category}`),
+				);
 			} else if (src.otherName) {
 				/*innerHTML += `
 					<br>