poe-custom-elements
Version:
Path of Exile custom elements
465 lines (460 loc) • 15.3 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { LitElement, html, css } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import './poe-item';
import { styleMap } from 'lit/directives/style-map.js';
import { appendFontinStyle } from '../lib/internal.js';
import { basePath } from '../lib/base_path.js';
import { classMap } from 'lit/directives/class-map.js';
const SUPPORTED_STASH_TYPES = [
'NormalStash',
'PremiumStash',
'QuadStash',
'EssenceStash',
'CurrencyStash',
'FragmentStash',
'BlightStash',
'DivinationCardStash',
];
/**
* PoE stash tab
*/
let PoeStashTabElement = class PoeStashTabElement extends LitElement {
constructor() {
super(...arguments);
/** The state of search input for DivinationStashType */
this.search_query_for_divination_stash = '';
this.#navigate_items_with_arrow_keys = async (e) => {
if (!['ArrowDown', 'ArrowRight', 'ArrowUp', 'ArrowLeft'].includes(e.code)) {
return;
}
const active_item = this.#focused_item_element?.item;
if (!active_item) {
return;
}
// Prevent outer scrolling when the arrow keys are pressed while focus is inside the stash tab.
e.preventDefault();
const direction = e.code.slice(5).toLowerCase();
const item = await find_closest_item_element({
active_item,
direction,
items: this.#tab.items,
stash_tab_element: this,
tab_cells_side_count: get_stash_tab_side_cell_count(this.#tab.type),
});
if (!item) {
return;
}
item.focus();
};
}
/** Mutable clone of tab */
#tab;
get #focused_item_element() {
return this.shadowRoot?.querySelector('poe-item:focus') ?? null;
}
willUpdate(map) {
if (map.has('tab') && this.tab) {
this.#tab = structuredClone(this.tab);
const cells = get_stash_tab_side_cell_count(this.#tab.type);
adjust_item_x_y_for_custom_tab(this.#tab, cells);
this.#tab.items = orderItems(this.#tab.items);
this.style.setProperty('--cells-side-count', cells.toString());
this.style.setProperty('--background-image', `url(${tabImageSrc(this.#tab.type)})`);
}
}
render() {
if (!this.tab) {
this.style.setProperty('border', '2px solid red');
return html `<p style="color: red">No Poe Api stash tab data (.tab)</p>`;
}
if (!SUPPORTED_STASH_TYPES.includes(this.tab.type)) {
this.style.setProperty('border', '2px solid red');
return html `<p style="color: red; font-size: 24px">
StashType ( ${this.tab.type} ) is not supported ( yet? ).
</p>`;
}
return html `
<ul>
${this.#tab.items.map(item => html `<li
style=${styleMap({
'grid-column': `${item.x + 1} / span ${item.w}`,
'grid-row': `${item.y + 1} / span ${item.h}`,
})}
>
<poe-item
data-x=${item.x}
data-y=${item.y}
tabindex="0"
placed
style="--cell-size: ${sizeOfCellPixels(this.#tab.type)}"
.item=${item}
class=${classMap({
'item--visible': item.baseType
.toLowerCase()
.includes(this.search_query_for_divination_stash),
})}
></poe-item>
</li>`)}
</ul>
${this.#tab.type === 'DivinationCardStash'
? html `<input
placeholder="Search cards"
autocomplete="off"
id="search-divination-stash-tab"
type="text"
.value=${this.search_query_for_divination_stash}
=${this.#handleDivinationCardsQueryInput}
/>`
: null}
`;
}
#handleDivinationCardsQueryInput(e) {
if (e.target instanceof HTMLInputElement) {
this.search_query_for_divination_stash = e.target.value.trim().toLowerCase();
}
}
connectedCallback() {
super.connectedCallback();
appendFontinStyle();
window.addEventListener('keydown', this.#navigate_items_with_arrow_keys);
}
disconnectedCallback() {
super.disconnectedCallback();
window.removeEventListener('keydown', this.#navigate_items_with_arrow_keys);
}
#navigate_items_with_arrow_keys;
static { this.styles = css `
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
:host {
display: block;
--size: 569px;
--size-of-all-inner-borders: 5px;
--cells-side-count: '(computed) Number of cells';
--background-image: '(computed)';
width: var(--size);
height: var(--size);
background-image: var(--background-image);
font-family: fontin;
position: relative;
}
ul {
width: var(--size);
height: var(--size);
list-style: none;
display: grid;
grid-template-rows: repeat(var(--cells-side-count), 1fr);
grid-template-columns: repeat(var(--cells-side-count), 1fr);
gap: calc(var(--size-of-all-inner-borders) / var(--cells-side-count));
}
poe-item:focus,
poe-item:focus-visible {
outline: 3px solid rgb(39, 186, 253);
}
:host(:focus-within) {
outline: 3px solid rgb(39, 186, 253);
}
poe-item {
visibility: hidden;
}
.item--visible {
visibility: visible;
}
#search-divination-stash-tab {
position: absolute;
bottom: 1.2rem;
right: 1.2rem;
font: inherit;
border: 1px solid currentColor;
color: #e2e2e2;
transition: border 0.1s ease;
background-color: transparent;
border-radius: 2px;
padding: 3px 7px;
width: 30ch;
}
`; }
};
__decorate([
property({ type: Object }),
__metadata("design:type", Object)
], PoeStashTabElement.prototype, "tab", void 0);
__decorate([
state(),
__metadata("design:type", Object)
], PoeStashTabElement.prototype, "search_query_for_divination_stash", void 0);
PoeStashTabElement = __decorate([
customElement('poe-stash-tab')
], PoeStashTabElement);
export { PoeStashTabElement };
/**
* Adjusts the (x, y) coordinates of items in stash tabs that have a custom, non-grid layout,
* rearranging them to fit into a grid layout.
*
* @param tab - The stash tab containing the items.
* @param cells_side_count - The number of cells on one side of the grid layout.
*/
function adjust_item_x_y_for_custom_tab(tab, cells_side_count) {
if (!cells_side_count) {
return;
}
if (tab.type === 'FragmentStash') {
let current_x_for_y1_group = 0;
const STARTING_Y_FOR_Y1_GROUP = 12;
const Y_OFFSET_FOR_Y2_GROUP = 13;
tab.items.forEach(item => {
switch (item.y) {
case 0: {
item.y = Math.floor(item.x / cells_side_count);
item.x = item.x % cells_side_count;
break;
}
case 1: {
item.y = STARTING_Y_FOR_Y1_GROUP + Math.floor(current_x_for_y1_group / cells_side_count);
item.x = current_x_for_y1_group % cells_side_count;
current_x_for_y1_group++;
break;
}
case 2: {
item.y += Y_OFFSET_FOR_Y2_GROUP;
break;
}
default: {
console.warn(`Fragments stash unexpected item Y-coordinate. Expected 0|1|2, got ${item.y}`);
}
}
});
}
if (tab.type === 'EssenceStash' ||
tab.type === 'CurrencyStash' ||
tab.type === 'BlightStash' ||
tab.type === 'DivinationCardStash') {
if (tab.type === 'DivinationCardStash') {
let x = 0;
tab.items.forEach(item => {
item.x = x++;
});
}
tab.items.forEach(item => {
item.y = Math.floor(item.x / cells_side_count);
item.x = item.x % cells_side_count;
});
}
}
/**
* Returns the number of cells on one side of the stash tab based on the stash type.
*
* @param stash_type - The type of the stash tab (e.g., PremiumStash, QuadStash, etc.).
* @returns The number of cells on one side of the stash tab.
*/
function get_stash_tab_side_cell_count(stash_type) {
switch (stash_type) {
case 'PremiumStash':
case 'NormalStash':
case 'BlightStash':
return 12;
case 'QuadStash':
case 'FragmentStash':
case 'DivinationCardStash':
return 24;
default:
return 12;
}
}
function tabImageSrc(stash_type) {
switch (stash_type) {
case 'PremiumStash':
case 'NormalStash':
case 'EssenceStash':
case 'CurrencyStash':
case 'BlightStash':
return `${basePath()}/poe-images/StashPanelGrid.png`;
case 'QuadStash':
case 'FragmentStash':
case 'DivinationCardStash':
return `${basePath()}/poe-images/QuadStashPanelGrid.png`;
default:
return `${basePath()}/poe-images/StashPanelGrid.png`;
}
}
function sizeOfCellPixels(stash_type) {
return `${564 / get_stash_tab_side_cell_count(stash_type)}px`;
}
function orderItems(items) {
return Object.values(Object.groupBy(items, ({ y }) => y)).flatMap((itemsByRow = []) => {
itemsByRow.sort((a, b) => a.x - b.x);
return itemsByRow;
});
}
/**
* Finds the item element closest to the active item based on the provided direction.
*/
async function find_closest_item_element({ active_item, direction, items, stash_tab_element, tab_cells_side_count, }) {
if (direction === 'down') {
let current_x = active_item.x;
let current_y = active_item.y + active_item.h;
let item = null;
if (current_y + 1 > tab_cells_side_count) {
return null;
}
while (!item) {
for (let dx = 0; dx < active_item.w; dx++) {
item = await item_element_from_x_y({
stash_tab_element,
items,
coordinates: { x: current_x + dx, y: current_y },
});
if (item) {
break;
}
}
if (current_y === tab_cells_side_count - 1 && current_x === tab_cells_side_count - 1) {
break;
}
if (current_y === tab_cells_side_count - 1) {
current_y = active_item.y;
current_x++;
}
else {
current_y++;
}
}
return item;
}
else if (direction === 'right') {
let current_x = active_item.x + active_item.w;
let current_y = active_item.y;
let item = null;
if (current_x + 1 > tab_cells_side_count) {
return null;
}
while (!item) {
for (let dy = 0; dy < active_item.h; dy++) {
item = await item_element_from_x_y({
stash_tab_element,
items,
coordinates: { x: current_x, y: current_y + dy },
});
if (item) {
break;
}
}
if (current_y === tab_cells_side_count - 1 && current_x === tab_cells_side_count - 1) {
break;
}
if (current_x === tab_cells_side_count - 1) {
current_x = active_item.x + active_item.w;
current_y++;
}
else {
current_x++;
}
}
return item;
}
else if (direction === 'up') {
let current_x = active_item.x;
let current_y = active_item.y - 1;
let item = null;
if (current_y < 0) {
return null;
}
while (!item) {
for (let dx = 0; dx < active_item.w; dx++) {
item = await item_element_from_x_y({
stash_tab_element,
items,
coordinates: { x: current_x + dx, y: current_y },
});
if (item) {
break;
}
}
if (current_y === 0 && current_x === tab_cells_side_count - 1) {
break;
}
if (current_y === 0) {
current_y = active_item.y;
current_x = current_x + 1;
}
else {
current_y--;
}
}
return item;
}
else if (direction === 'left') {
let current_x = active_item.x - 1;
let current_y = active_item.y;
let item = null;
if (current_x < 0) {
return null;
}
while (!item) {
for (let dy = 0; dy < active_item.h; dy++) {
item = await item_element_from_x_y({
stash_tab_element,
items,
coordinates: { x: current_x, y: current_y + dy },
});
if (item) {
break;
}
}
if (current_x === 0 && current_y === tab_cells_side_count - 1) {
break;
}
if (current_x === 0) {
current_x = active_item.x;
current_y = current_y + 1;
}
else {
current_x--;
}
}
return item;
}
return null;
}
function item_from_x_y({ coordinates, items, }) {
const itemOnExactXY = items.find(item => item.x === coordinates.x && item.y === coordinates.y);
if (itemOnExactXY) {
return itemOnExactXY;
}
for (const item of items) {
for (let y = item.y; y < item.y + item.h; y++) {
for (let x = item.x; x < item.x + item.w; x++) {
if (x === coordinates.x && y === coordinates.y) {
return item;
}
}
}
}
return null;
}
async function item_element_from_x_y({ stash_tab_element, coordinates, items, }) {
const item = item_from_x_y({
coordinates,
items,
});
if (!item) {
return null;
}
if (!stash_tab_element.shadowRoot.querySelector('poe-item')) {
await stash_tab_element.updateComplete;
}
return (stash_tab_element.shadowRoot?.querySelector(`poe-item[data-x="${item.x}"][data-y="${item.y}"]`) ?? null);
}
//# sourceMappingURL=poe-stash-tab.js.map