@crockery/fellowship-components 0.1.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +10 -3
  2. package/RELEASING.md +9 -45
  3. package/dist/chunks/data-source-XbksqUrw.js +9 -0
  4. package/dist/chunks/data-source-XbksqUrw.js.map +1 -0
  5. package/dist/chunks/decorate-B_ZTN9li.js.map +1 -1
  6. package/dist/chunks/dungeon-cast-browser-CSnu3gC5.js +705 -0
  7. package/dist/chunks/dungeon-cast-browser-CSnu3gC5.js.map +1 -0
  8. package/dist/chunks/{dungeon-map-IPN6sEDj.js → dungeon-map-CutIcCVP.js} +93 -119
  9. package/dist/chunks/dungeon-map-CutIcCVP.js.map +1 -0
  10. package/dist/chunks/{talent-calculator-Ch1Pbbba.js → talent-calculator-Dxuc2dZ8.js} +75 -105
  11. package/dist/chunks/talent-calculator-Dxuc2dZ8.js.map +1 -0
  12. package/dist/data/cast-data-source.d.ts +5 -0
  13. package/dist/data/cast-data-source.d.ts.map +1 -0
  14. package/dist/data/data-source.d.ts +7 -16
  15. package/dist/data/data-source.d.ts.map +1 -1
  16. package/dist/data/package-cast-data-source.d.ts +8 -0
  17. package/dist/data/package-cast-data-source.d.ts.map +1 -0
  18. package/dist/data/package-data-source.d.ts +3 -1
  19. package/dist/data/package-data-source.d.ts.map +1 -1
  20. package/dist/data/package-talent-data-source.d.ts +2 -0
  21. package/dist/data/package-talent-data-source.d.ts.map +1 -1
  22. package/dist/data/talent-data-source.d.ts +4 -10
  23. package/dist/data/talent-data-source.d.ts.map +1 -1
  24. package/dist/dungeon-cast-browser/dungeon-cast-browser.d.ts +36 -0
  25. package/dist/dungeon-cast-browser/dungeon-cast-browser.d.ts.map +1 -0
  26. package/dist/dungeon-cast-browser/dungeon-cast-browser.styles.d.ts +2 -0
  27. package/dist/dungeon-cast-browser/dungeon-cast-browser.styles.d.ts.map +1 -0
  28. package/dist/dungeon-cast-browser/index.d.ts +4 -0
  29. package/dist/dungeon-cast-browser/index.d.ts.map +1 -0
  30. package/dist/dungeon-cast-browser/render-model.d.ts +5 -0
  31. package/dist/dungeon-cast-browser/render-model.d.ts.map +1 -0
  32. package/dist/dungeon-cast-browser/types.d.ts +60 -0
  33. package/dist/dungeon-cast-browser/types.d.ts.map +1 -0
  34. package/dist/dungeon-cast-browser.js +7 -0
  35. package/dist/dungeon-cast-browser.js.map +1 -0
  36. package/dist/dungeon-map/dungeon-map.d.ts.map +1 -1
  37. package/dist/dungeon-map.js +1 -1
  38. package/dist/index.d.ts +6 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +8 -5
  41. package/dist/react/dungeon-cast-browser.d.ts +12 -0
  42. package/dist/react/dungeon-cast-browser.d.ts.map +1 -0
  43. package/dist/react/dungeon-cast-browser.js +19 -0
  44. package/dist/react/dungeon-cast-browser.js.map +1 -0
  45. package/dist/react/dungeon-map.js +1 -1
  46. package/dist/react/index.d.ts +2 -0
  47. package/dist/react/index.d.ts.map +1 -1
  48. package/dist/react/talent-calculator.js +1 -1
  49. package/dist/react.js +4 -3
  50. package/dist/talent-calculator/talent-calculator.d.ts.map +1 -1
  51. package/dist/talent-calculator.js +1 -1
  52. package/package.json +35 -25
  53. package/src/dungeon-cast-browser/README.md +22 -0
  54. package/dist/chunks/data-source-CoIFvV72.js +0 -10
  55. package/dist/chunks/data-source-CoIFvV72.js.map +0 -1
  56. package/dist/chunks/dungeon-map-IPN6sEDj.js.map +0 -1
  57. package/dist/chunks/talent-calculator-Ch1Pbbba.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dungeon-cast-browser-CSnu3gC5.js","names":["#abortController","#loadDungeonCasts","#renderStatus","#visibleEnemies","#handleSearch","#renderEnemy","#renderEmptySearch","#loadToken","#sameIdentity","#renderCast","#selectCast","#handleCastKeydown","#handleAbilityImageError","#statusCard"],"sources":["../../src/data/package-cast-data-source.ts","../../src/dungeon-cast-browser/dungeon-cast-browser.styles.ts","../../src/dungeon-cast-browser/render-model.ts","../../src/dungeon-cast-browser/dungeon-cast-browser.ts"],"sourcesContent":["import { createPackageFellowshipDataClient } from \"@crockery/fellowship-data/client\";\n\nimport type { FellowshipCastDataSource } from \"./cast-data-source.js\";\n\n/** @deprecated Create a package Fellowship data client instead. */\nexport interface PackageFellowshipCastDataSourceOptions {\n readonly assetBaseUrl?: string;\n}\n\n/** @deprecated Use `createPackageFellowshipDataClient` from `@crockery/fellowship-data/client`. */\nexport const createPackageFellowshipCastDataSource = (\n options: PackageFellowshipCastDataSourceOptions = {},\n): FellowshipCastDataSource => {\n const client = createPackageFellowshipDataClient(options);\n return {\n loadDungeonCasts: (dungeonId, signal) => client.loadDungeonCasts(dungeonId, signal),\n resolveAssetUrl: (asset) => client.resolveAssetUrl(asset),\n };\n};\n","import { css } from \"lit\";\n\nexport const dungeonCastBrowserStyles = css`\n :host {\n --fellowship-cast-canvas: var(--_fellowship-field-canvas);\n --fellowship-cast-surface: var(--_fellowship-field-surface);\n --fellowship-cast-raised: var(--_fellowship-field-surface-raised);\n --fellowship-cast-ink: var(--_fellowship-field-ink);\n --fellowship-cast-muted: var(--_fellowship-field-muted);\n --fellowship-cast-tertiary: var(--_fellowship-field-tertiary);\n --fellowship-cast-border: var(--_fellowship-field-border);\n --fellowship-cast-border-strong: var(--_fellowship-field-border-strong);\n --fellowship-cast-interrupt: var(--_fellowship-field-accent);\n --fellowship-cast-stop: var(--_fellowship-field-brass);\n --fellowship-cast-focus: var(--_fellowship-field-focus);\n --fellowship-cast-font-family: var(--_fellowship-field-font-family);\n --fellowship-cast-tactical-font-family: var(--_fellowship-field-mono-font-family);\n\n display: block;\n inline-size: 100%;\n min-block-size: 320px;\n color: var(--fellowship-cast-ink);\n font-family: var(--fellowship-cast-font-family);\n container-type: inline-size;\n -webkit-font-smoothing: antialiased;\n }\n\n :host([hidden]) {\n display: none;\n }\n\n :host([fill]) {\n min-block-size: 0;\n block-size: 100%;\n overflow: hidden;\n }\n\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n }\n\n .browser {\n min-block-size: inherit;\n overflow: hidden;\n border: 1px solid var(--fellowship-cast-border);\n border-radius: calc(var(--_fellowship-field-radius) + 2px);\n background: var(--fellowship-cast-canvas);\n }\n\n :host([fill]) .browser {\n display: grid;\n grid-template-rows: auto minmax(0, 1fr);\n min-block-size: 0;\n block-size: 100%;\n }\n\n .toolbar {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 12px;\n align-items: end;\n padding: 16px;\n border-block-end: 1px solid var(--fellowship-cast-border);\n background: var(--fellowship-cast-surface);\n }\n\n .eyebrow,\n .summary,\n .enemy-id,\n .ability-id,\n .capability,\n .marker {\n font-family: var(--fellowship-cast-tactical-font-family);\n }\n\n .eyebrow {\n margin: 0 0 4px;\n color: var(--fellowship-cast-interrupt);\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.12em;\n text-transform: uppercase;\n }\n\n h2 {\n margin: 0;\n font-size: clamp(18px, 3cqi, 24px);\n font-weight: 600;\n letter-spacing: 0.01em;\n line-height: 1.08;\n }\n\n .summary {\n margin: 6px 0 0;\n color: var(--fellowship-cast-tertiary);\n font-size: 11px;\n font-variant-numeric: tabular-nums;\n letter-spacing: 0.04em;\n }\n\n .search-label {\n display: grid;\n gap: 4px;\n min-inline-size: min(240px, 38cqi);\n color: var(--fellowship-cast-muted);\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.04em;\n }\n\n .search-input {\n min-block-size: 44px;\n inline-size: 100%;\n border: 1px solid var(--fellowship-cast-border-strong);\n border-radius: var(--_fellowship-field-radius);\n background: var(--_fellowship-field-inset);\n color: var(--fellowship-cast-ink);\n font: inherit;\n font-size: 14px;\n padding-inline: 12px;\n }\n\n .search-input::placeholder {\n color: var(--fellowship-cast-tertiary);\n }\n\n .search-input:focus-visible,\n .cast-row:focus-visible,\n .retry-button:focus-visible {\n outline: 2px solid var(--fellowship-cast-focus);\n outline-offset: 2px;\n }\n\n .enemy-list {\n display: grid;\n }\n\n :host([fill]) .enemy-list {\n min-block-size: 0;\n align-content: start;\n overflow-y: auto;\n overscroll-behavior: contain;\n }\n\n .enemy {\n min-inline-size: 0;\n border-block-end: 1px solid var(--fellowship-cast-border);\n }\n\n .enemy:last-child {\n border-block-end: 0;\n }\n\n .enemy-header {\n display: grid;\n grid-template-columns: 4px minmax(0, 1fr) auto;\n gap: 12px;\n align-items: center;\n min-block-size: 52px;\n padding: 8px 16px;\n background: color-mix(in srgb, var(--fellowship-cast-raised) 72%, transparent);\n }\n\n .enemy-rule {\n align-self: stretch;\n background: var(--fellowship-cast-interrupt);\n }\n\n .enemy-name {\n overflow: hidden;\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n line-height: 1.15;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .enemy-id {\n overflow: hidden;\n margin: 3px 0 0;\n color: var(--fellowship-cast-tertiary);\n font-size: 10px;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .enemy-count {\n color: var(--fellowship-cast-muted);\n font-family: var(--fellowship-cast-tactical-font-family);\n font-size: 10px;\n font-variant-numeric: tabular-nums;\n }\n\n .cast-list {\n display: grid;\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n .cast-list > li + li {\n border-block-start: 1px solid var(--fellowship-cast-border);\n }\n\n .cast-row {\n position: relative;\n display: grid;\n grid-template-columns: 40px minmax(0, 1fr) auto auto;\n gap: 12px;\n align-items: center;\n inline-size: 100%;\n min-block-size: 64px;\n padding: 8px 16px 8px 28px;\n border: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: start;\n cursor: pointer;\n transition: background-color 140ms cubic-bezier(0.23, 1, 0.32, 1);\n }\n\n .cast-row:not(:disabled):hover {\n background: color-mix(in srgb, var(--fellowship-cast-interrupt) 7%, transparent);\n }\n\n .cast-row[aria-pressed=\"true\"] {\n background: color-mix(in srgb, var(--fellowship-cast-interrupt) 11%, transparent);\n }\n\n .cast-row[aria-pressed=\"true\"]::before {\n position: absolute;\n inset: 12px auto 12px 0;\n inline-size: 3px;\n background: var(--fellowship-cast-interrupt);\n content: \"\";\n }\n\n .cast-row:disabled {\n color: var(--fellowship-cast-tertiary);\n cursor: not-allowed;\n }\n\n .ability-image,\n .ability-fallback {\n inline-size: 40px;\n block-size: 40px;\n border: 1px solid var(--fellowship-cast-border-strong);\n border-radius: 4px;\n background: var(--fellowship-cast-raised);\n }\n\n .ability-image {\n display: block;\n object-fit: cover;\n }\n\n .ability-fallback {\n display: grid;\n place-items: center;\n color: var(--fellowship-cast-muted);\n font-family: var(--fellowship-cast-tactical-font-family);\n font-size: 11px;\n font-weight: 600;\n }\n\n .ability-image[hidden],\n .ability-fallback[hidden] {\n display: none;\n }\n\n .ability-copy {\n min-inline-size: 0;\n }\n\n .ability-name {\n display: block;\n overflow: hidden;\n font-size: 14px;\n font-weight: 600;\n line-height: 1.15;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .ability-id {\n display: block;\n overflow: hidden;\n margin-block-start: 4px;\n color: var(--fellowship-cast-tertiary);\n font-size: 10px;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .capability {\n min-inline-size: 102px;\n padding: 5px 8px;\n border: 1px solid currentColor;\n border-radius: 999px;\n color: var(--fellowship-cast-interrupt);\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.04em;\n text-align: center;\n white-space: nowrap;\n }\n\n .capability[data-kind=\"varies\"] {\n border-style: dashed;\n }\n\n .capability[data-kind=\"stop\"] {\n color: var(--fellowship-cast-stop);\n }\n\n .capability[data-kind=\"none\"] {\n color: var(--fellowship-cast-tertiary);\n }\n\n .marker {\n min-inline-size: 72px;\n color: var(--fellowship-cast-stop);\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.06em;\n text-align: end;\n text-transform: uppercase;\n }\n\n .marker[data-empty=\"true\"] {\n visibility: hidden;\n }\n\n .status {\n display: grid;\n min-block-size: 280px;\n padding: 32px;\n place-items: center;\n text-align: center;\n }\n\n :host([fill]) .status {\n min-block-size: 0;\n }\n\n .status-card {\n display: grid;\n max-inline-size: 360px;\n gap: 8px;\n justify-items: center;\n }\n\n .status-mark {\n inline-size: 32px;\n block-size: 4px;\n margin-block-end: 8px;\n background: var(--fellowship-cast-interrupt);\n }\n\n .status-title {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n }\n\n .status-copy {\n margin: 0;\n color: var(--fellowship-cast-muted);\n font-size: 14px;\n line-height: 1.45;\n }\n\n .retry-button {\n min-block-size: 44px;\n margin-block-start: 8px;\n padding-inline: 16px;\n border: 1px solid var(--fellowship-cast-interrupt);\n border-radius: var(--_fellowship-field-radius);\n background: transparent;\n color: var(--fellowship-cast-ink);\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n }\n\n @container (max-width: 560px) {\n .toolbar {\n grid-template-columns: 1fr;\n }\n\n .search-label {\n min-inline-size: 0;\n }\n\n .cast-row {\n grid-template-columns: 40px minmax(0, 1fr) auto;\n padding-inline: 16px;\n }\n\n .marker {\n position: absolute;\n inset: 5px 8px auto auto;\n min-inline-size: 0;\n font-size: 8px;\n }\n\n .ability-id,\n .enemy-id {\n display: none;\n }\n\n .capability {\n min-inline-size: 0;\n padding-inline: 6px;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .cast-row {\n transition: none;\n }\n }\n`;\n","import type { Ability, ImageAssetRef } from \"@crockery/fellowship-data\";\n\nimport type { DungeonCastData, FellowshipCastDataSource } from \"../data/cast-data-source.js\";\nimport type {\n CastCapabilityLabel,\n DungeonCastBrowserModel,\n DungeonCastEnemyModel,\n DungeonCastModel,\n FellowshipCastIdentity,\n} from \"./types.js\";\n\nexport const castIdentityKey = ({ enemyId, abilityId }: FellowshipCastIdentity): string =>\n `${enemyId}\\u0000${abilityId}`;\n\nconst abilityImage = (ability: Ability): ImageAssetRef | null =>\n ability.images.find(({ size }) => size === \"200\") ?? ability.images[0] ?? null;\n\nconst capabilityLabel = (\n canInterrupt: boolean,\n interruptVaries: boolean,\n canStop: boolean,\n): CastCapabilityLabel => {\n if (interruptVaries) return \"Interrupt varies\";\n if (canInterrupt) return \"Interrupt\";\n if (canStop) return \"Stop\";\n return \"No response\";\n};\n\nexport const createDungeonCastBrowserModel = (\n data: DungeonCastData,\n source: FellowshipCastDataSource,\n): DungeonCastBrowserModel => {\n const seenEnemyIds = new Set<string>();\n const enemies: DungeonCastEnemyModel[] = [];\n\n for (const placement of data.dungeon.enemies) {\n if (seenEnemyIds.has(placement.id)) continue;\n seenEnemyIds.add(placement.id);\n\n const enemy = data.enemies.get(placement.id);\n if (!enemy) continue;\n\n const casts: DungeonCastModel[] = (data.abilitiesByEnemy.get(enemy.id) ?? [])\n .filter((ability) => ability.castInterruptibility !== undefined)\n .map((ability) => {\n const canInterrupt = ability.castInterruptibility !== \"never\";\n const interruptVaries = ability.castInterruptibility === \"sometimes\";\n const canStop = enemy.canBeControlled;\n const image = abilityImage(ability);\n let imageUrl: string | null = null;\n if (image) {\n try {\n imageUrl = source.resolveAssetUrl(image);\n } catch {\n imageUrl = null;\n }\n }\n return {\n identity: { enemyId: enemy.id, abilityId: ability.id },\n ability,\n enemy,\n canInterrupt,\n interruptVaries,\n canStop,\n actionable: canInterrupt || canStop,\n capabilityLabel: capabilityLabel(canInterrupt, interruptVaries, canStop),\n imageUrl,\n };\n });\n\n if (casts.some(({ actionable }) => actionable)) enemies.push({ enemy, casts });\n }\n\n return {\n dungeon: data.dungeon,\n enemies,\n castCount: enemies.reduce((total, enemy) => total + enemy.casts.length, 0),\n };\n};\n","import { html, LitElement, nothing, type PropertyValues, type TemplateResult } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { repeat } from \"lit/directives/repeat.js\";\n\nimport type { FellowshipCastDataSource } from \"../data/cast-data-source.js\";\nimport { assertSupportedFellowshipDataSchema, FellowshipDataError } from \"../data/data-source.js\";\nimport { createPackageFellowshipCastDataSource } from \"../data/package-cast-data-source.js\";\nimport { installFieldManualFonts } from \"../styles/field-manual-fonts.js\";\nimport { fieldManualStyles } from \"../styles/field-manual.styles.js\";\nimport { dungeonCastBrowserStyles } from \"./dungeon-cast-browser.styles.js\";\nimport { castIdentityKey, createDungeonCastBrowserModel } from \"./render-model.js\";\nimport type {\n ConfiguredCastFilter,\n DungeonCastBrowserModel,\n DungeonCastEnemyModel,\n DungeonCastModel,\n FellowshipCastBrowserErrorDetail,\n FellowshipCastBrowserReadyDetail,\n FellowshipCastIdentity,\n FellowshipCastSelectedDetail,\n} from \"./types.js\";\n\ntype ComponentStatus = \"empty\" | \"loading\" | \"ready\" | \"error\";\n\nconst eventOptions = { bubbles: true, composed: true } as const;\n\n/**\n * @fires fellowship-cast-browser-ready - Fired after dungeon casts have been loaded and joined.\n * @fires fellowship-cast-browser-error - Fired when dungeon cast data cannot be loaded.\n * @fires fellowship-cast-selected - Fired when a user selects an actionable cast.\n */\n@customElement(\"fellowship-dungeon-cast-browser\")\nexport class FellowshipDungeonCastBrowserElement extends LitElement {\n static override styles = [fieldManualStyles, dungeonCastBrowserStyles];\n\n @property({ type: String, attribute: \"dungeon-id\" }) dungeonId = \"\";\n @property({ attribute: false }) selectedCast: FellowshipCastIdentity | null = null;\n @property({ attribute: false }) configuredCasts: readonly FellowshipCastIdentity[] = [];\n @property({ type: String, attribute: \"configured-filter\" })\n configuredFilter: ConfiguredCastFilter = \"all\";\n @property({ type: Boolean, reflect: true }) fill = false;\n @property({ type: String, attribute: \"asset-base-url\" }) assetBaseUrl: string | null = null;\n @property({ attribute: false }) dataSource: FellowshipCastDataSource | null = null;\n\n @state() private _status: ComponentStatus = \"empty\";\n @state() private _error: FellowshipCastBrowserErrorDetail | null = null;\n @state() private _model: DungeonCastBrowserModel | null = null;\n @state() private _query = \"\";\n\n #abortController: AbortController | null = null;\n #loadToken = 0;\n\n override connectedCallback(): void {\n super.connectedCallback();\n installFieldManualFonts(this.ownerDocument);\n }\n\n override disconnectedCallback(): void {\n this.#abortController?.abort();\n super.disconnectedCallback();\n }\n\n protected override updated(changed: PropertyValues<this>): void {\n super.updated(changed);\n if (changed.has(\"dungeonId\") || changed.has(\"dataSource\") || changed.has(\"assetBaseUrl\")) {\n queueMicrotask(() => {\n if (this.isConnected) void this.#loadDungeonCasts();\n });\n }\n }\n\n retry(): void {\n void this.#loadDungeonCasts();\n }\n\n get renderModel(): DungeonCastBrowserModel | null {\n return this._model;\n }\n\n override render(): TemplateResult {\n if (this._status !== \"ready\" || !this._model) {\n return html`<section class=\"browser\" aria-label=\"Dungeon cast browser\">${this.#renderStatus()}</section>`;\n }\n\n const visibleEnemies = this.#visibleEnemies(this._model);\n return html`\n <section class=\"browser\" aria-label=${`${this._model.dungeon.name ?? this._model.dungeon.id} casts`}>\n <header class=\"toolbar\" part=\"toolbar\">\n <div>\n <p class=\"eyebrow\">Dungeon cast index</p>\n <h2>${this._model.dungeon.name ?? this._model.dungeon.id}</h2>\n <p class=\"summary\">\n ${this._model.enemies.length} enemies · ${this._model.castCount} cast-bearing abilities\n </p>\n </div>\n <label class=\"search-label\">\n Search casts\n <input\n class=\"search-input\"\n type=\"search\"\n placeholder=\"Enemy or ability\"\n .value=${this._query}\n @input=${this.#handleSearch}\n />\n </label>\n </header>\n ${\n visibleEnemies.length > 0\n ? html`<div class=\"enemy-list\" part=\"enemy-list\">${repeat(\n visibleEnemies,\n ({ enemy }) => enemy.id,\n (enemy) => this.#renderEnemy(enemy),\n )}</div>`\n : this.#renderEmptySearch()\n }\n </section>\n `;\n }\n\n async #loadDungeonCasts(): Promise<void> {\n const dungeonId = this.dungeonId.trim();\n const token = ++this.#loadToken;\n this.#abortController?.abort();\n this.#abortController = new AbortController();\n this._model = null;\n this._error = null;\n this._query = \"\";\n\n if (!dungeonId) {\n this._status = \"empty\";\n return;\n }\n\n this._status = \"loading\";\n const source =\n this.dataSource ??\n createPackageFellowshipCastDataSource(\n this.assetBaseUrl ? { assetBaseUrl: this.assetBaseUrl } : {},\n );\n\n try {\n const data = await source.loadDungeonCasts(dungeonId, this.#abortController.signal);\n if (token !== this.#loadToken || this.#abortController.signal.aborted) return;\n assertSupportedFellowshipDataSchema(data.manifest.schemaVersion);\n const model = createDungeonCastBrowserModel(data, source);\n this._model = model;\n this._status = \"ready\";\n this.dispatchEvent(\n new CustomEvent<FellowshipCastBrowserReadyDetail>(\"fellowship-cast-browser-ready\", {\n ...eventOptions,\n detail: { model, data },\n }),\n );\n } catch (error: unknown) {\n if (token !== this.#loadToken || this.#abortController.signal.aborted) return;\n const detail: FellowshipCastBrowserErrorDetail = {\n code:\n error instanceof FellowshipDataError\n ? error.code\n : ((error as { code?: string }).code ?? \"data-load-failed\"),\n message: error instanceof Error ? error.message : String(error),\n ...(error instanceof Error && error.cause !== undefined ? { cause: error.cause } : {}),\n };\n this._error = detail;\n this._status = \"error\";\n this.dispatchEvent(\n new CustomEvent<FellowshipCastBrowserErrorDetail>(\"fellowship-cast-browser-error\", {\n ...eventOptions,\n detail,\n }),\n );\n }\n }\n\n #visibleEnemies(model: DungeonCastBrowserModel): readonly DungeonCastEnemyModel[] {\n const query = this._query.trim().toLocaleLowerCase();\n const configuredFilter =\n this.configuredFilter === \"configured\" || this.configuredFilter === \"unconfigured\"\n ? this.configuredFilter\n : \"all\";\n return model.enemies.flatMap((enemy) => {\n const enemyMatches = `${enemy.enemy.name ?? \"\"} ${enemy.enemy.id}`\n .toLocaleLowerCase()\n .includes(query);\n const casts = enemy.casts.filter((cast) => {\n const queryMatches =\n !query ||\n enemyMatches ||\n `${cast.ability.name ?? \"\"} ${cast.ability.id}`.toLocaleLowerCase().includes(query);\n if (!queryMatches) return false;\n const configured = this.configuredCasts.some((identity) =>\n this.#sameIdentity(identity, cast.identity),\n );\n return (\n configuredFilter === \"all\" ||\n (configuredFilter === \"configured\" && configured) ||\n (configuredFilter === \"unconfigured\" && !configured)\n );\n });\n return casts.length > 0 ? [{ ...enemy, casts }] : [];\n });\n }\n\n #renderEnemy(model: DungeonCastEnemyModel): TemplateResult {\n return html`\n <article class=\"enemy\" part=\"enemy\">\n <header class=\"enemy-header\" part=\"enemy-header\">\n <span class=\"enemy-rule\" aria-hidden=\"true\"></span>\n <div>\n <h3 class=\"enemy-name\">${model.enemy.name ?? model.enemy.id}</h3>\n <p class=\"enemy-id\">${model.enemy.id}</p>\n </div>\n <span class=\"enemy-count\">${model.casts.length} ${model.casts.length === 1 ? \"cast\" : \"casts\"}</span>\n </header>\n <ul class=\"cast-list\">\n ${repeat(\n model.casts,\n ({ identity }) => castIdentityKey(identity),\n (cast) => html`<li>${this.#renderCast(cast)}</li>`,\n )}\n </ul>\n </article>\n `;\n }\n\n #renderCast(cast: DungeonCastModel): TemplateResult {\n const selected = this.#sameIdentity(this.selectedCast, cast.identity);\n const configured = this.configuredCasts.some((identity) =>\n this.#sameIdentity(identity, cast.identity),\n );\n const capabilityKind = cast.interruptVaries\n ? \"varies\"\n : cast.canInterrupt\n ? \"interrupt\"\n : cast.canStop\n ? \"stop\"\n : \"none\";\n const fallback = (cast.ability.name ?? cast.ability.id)\n .split(/\\s+/)\n .map((part) => part[0])\n .join(\"\")\n .slice(0, 2)\n .toUpperCase();\n\n return html`\n <button\n class=\"cast-row\"\n part=\"cast\"\n type=\"button\"\n ?disabled=${!cast.actionable}\n aria-pressed=${String(selected)}\n data-configured=${String(configured)}\n @click=${() => this.#selectCast(cast)}\n @keydown=${this.#handleCastKeydown}\n >\n ${\n cast.imageUrl\n ? html`<img\n class=\"ability-image\"\n part=\"cast-icon\"\n src=${cast.imageUrl}\n alt=\"\"\n @error=${this.#handleAbilityImageError}\n /><span\n class=\"ability-fallback\"\n part=\"cast-icon-fallback\"\n aria-hidden=\"true\"\n hidden\n >${fallback}</span\n >`\n : html`<span class=\"ability-fallback\" part=\"cast-icon-fallback\" aria-hidden=\"true\">${fallback}</span>`\n }\n <span class=\"ability-copy\">\n <span class=\"ability-name\">${cast.ability.name ?? cast.ability.id}</span>\n <span class=\"ability-id\">${cast.ability.id}</span>\n </span>\n <span class=\"capability\" data-kind=${capabilityKind}>${cast.capabilityLabel}</span>\n <span class=\"marker\" data-empty=${String(!configured)}>${configured ? \"Configured\" : nothing}</span>\n </button>\n `;\n }\n\n #renderStatus(): TemplateResult {\n if (this._status === \"loading\") {\n return this.#statusCard(\n \"Loading cast index\",\n \"Joining dungeon enemies with their cast data.\",\n );\n }\n if (this._status === \"error\") {\n return html`\n <div class=\"status\" role=\"alert\">\n <div class=\"status-card\">\n <span class=\"status-mark\" aria-hidden=\"true\"></span>\n <h2 class=\"status-title\">Cast data unavailable</h2>\n <p class=\"status-copy\">${this._error?.message ?? \"The dungeon cast index could not be loaded.\"}</p>\n <button class=\"retry-button\" type=\"button\" @click=${this.retry}>Retry</button>\n </div>\n </div>\n `;\n }\n if (this._status === \"ready\") {\n return this.#statusCard(\n \"No actionable casts\",\n \"This dungeon has no enemies with casts that can be interrupted or stopped.\",\n );\n }\n return this.#statusCard(\"Select a dungeon\", \"Choose a dungeon to inspect enemy casts.\");\n }\n\n #renderEmptySearch(): TemplateResult {\n return this.#statusCard(\n \"No matching casts\",\n `No enemy or ability matches “${this._query.trim()}”.`,\n );\n }\n\n #statusCard(title: string, copy: string): TemplateResult {\n return html`\n <div class=\"status\">\n <div class=\"status-card\">\n <span class=\"status-mark\" aria-hidden=\"true\"></span>\n <h2 class=\"status-title\">${title}</h2>\n <p class=\"status-copy\">${copy}</p>\n </div>\n </div>\n `;\n }\n\n #sameIdentity(left: FellowshipCastIdentity | null, right: FellowshipCastIdentity): boolean {\n return left?.enemyId === right.enemyId && left.abilityId === right.abilityId;\n }\n\n #selectCast(cast: DungeonCastModel): void {\n if (!cast.actionable) return;\n this.dispatchEvent(\n new CustomEvent<FellowshipCastSelectedDetail>(\"fellowship-cast-selected\", {\n ...eventOptions,\n detail: { cast },\n }),\n );\n }\n\n #handleSearch = (event: InputEvent): void => {\n this._query = (event.currentTarget as HTMLInputElement).value;\n };\n\n #handleAbilityImageError = (event: Event): void => {\n const image = event.currentTarget as HTMLImageElement;\n image.hidden = true;\n const fallback = image.nextElementSibling;\n if (fallback instanceof HTMLElement) fallback.hidden = false;\n };\n\n #handleCastKeydown = (event: KeyboardEvent): void => {\n const movement =\n event.key === \"ArrowDown\" || event.key === \"ArrowRight\"\n ? 1\n : event.key === \"ArrowUp\" || event.key === \"ArrowLeft\"\n ? -1\n : 0;\n if (movement === 0 && event.key !== \"Home\" && event.key !== \"End\") return;\n const buttons = [\n ...this.renderRoot.querySelectorAll<HTMLButtonElement>(\".cast-row:not(:disabled)\"),\n ];\n if (buttons.length === 0) return;\n const current = buttons.indexOf(event.currentTarget as HTMLButtonElement);\n const nextIndex =\n event.key === \"Home\"\n ? 0\n : event.key === \"End\"\n ? buttons.length - 1\n : (current + movement + buttons.length) % buttons.length;\n buttons[nextIndex]?.focus();\n event.preventDefault();\n };\n}\n\nexport const defineFellowshipDungeonCastBrowser = (): void => {\n if (\n typeof globalThis.customElements !== \"undefined\" &&\n !globalThis.customElements.get(\"fellowship-dungeon-cast-browser\")\n ) {\n globalThis.customElements.define(\n \"fellowship-dungeon-cast-browser\",\n FellowshipDungeonCastBrowserElement,\n );\n }\n};\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"fellowship-dungeon-cast-browser\": FellowshipDungeonCastBrowserElement;\n }\n}\n"],"mappings":"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"}
@@ -1,44 +1,19 @@
1
- import { t as e } from "./data-source-CoIFvV72.js";
2
- import { n as t, r as n, t as r } from "./decorate-B_ZTN9li.js";
3
- import { findImage as i, getAssetUrl as a } from "@crockery/fellowship-data";
1
+ import { n as e, t } from "./data-source-XbksqUrw.js";
2
+ import { n, r, t as i } from "./decorate-B_ZTN9li.js";
3
+ import { createPackageFellowshipDataClient as a } from "@crockery/fellowship-data/client";
4
4
  import { LitElement as o, css as s, html as c, nothing as l } from "lit";
5
5
  import { customElement as u, property as d, query as f, state as p } from "lit/decorators.js";
6
6
  import { repeat as m } from "lit/directives/repeat.js";
7
7
  import { styleMap as h } from "lit/directives/style-map.js";
8
+ import { findImage as g } from "@crockery/fellowship-data";
8
9
  //#region src/data/package-data-source.ts
9
- var g, _ = (t) => {
10
- if (t?.aborted) throw new e("aborted", "The dungeon data request was aborted.", t.reason);
11
- }, v = () => (g ??= Promise.all([
12
- import("@crockery/fellowship-data/dungeons"),
13
- import("@crockery/fellowship-data/enemies"),
14
- import("@crockery/fellowship-data/manifest")
15
- ]).then(([t, n, r]) => {
16
- let i = r.default;
17
- if (i.schemaVersion !== 1) throw new e("unsupported-schema", `Unsupported fellowship-data schema version: ${String(i.schemaVersion)}.`);
10
+ var _ = (e = {}) => {
11
+ let t = a(e);
18
12
  return {
19
- manifest: i,
20
- dungeons: new Map(t.default.map((e) => [e.id, e])),
21
- enemies: new Map(n.default.map((e) => [e.id, e]))
13
+ loadDungeon: (e, n) => t.loadDungeon(e, n),
14
+ resolveAssetUrl: (e) => t.resolveAssetUrl(e)
22
15
  };
23
- }).catch((t) => {
24
- throw g = void 0, t instanceof e ? t : new e("data-load-failed", "Unable to load @crockery/fellowship-data.", t);
25
- }), g), y = (t = {}) => ({
26
- async loadDungeon(t, n) {
27
- _(n);
28
- let r = await v();
29
- _(n);
30
- let i = r.dungeons.get(t);
31
- if (!i) throw new e("dungeon-not-found", `No dungeon with ID “${t}” exists in @crockery/fellowship-data.`);
32
- return {
33
- manifest: r.manifest,
34
- dungeon: i,
35
- enemies: r.enemies
36
- };
37
- },
38
- resolveAssetUrl(e) {
39
- return t.assetBaseUrl ? a(e, { baseUrl: t.assetBaseUrl }) : a(e);
40
- }
41
- }), b = s`
16
+ }, v = s`
42
17
  :host {
43
18
  --fellowship-map-soot: var(--_fellowship-field-canvas);
44
19
  --fellowship-map-ink: var(--_fellowship-field-ink);
@@ -484,7 +459,7 @@ var g, _ = (t) => {
484
459
  transform: none;
485
460
  }
486
461
  }
487
- `, x = .018, S = .036, C = .06, w = .12, T = (e, t, n) => Math.min(n, Math.max(t, e)), E = (e) => {
462
+ `, y = .018, b = .036, x = .06, S = .12, C = (e, t, n) => Math.min(n, Math.max(t, e)), w = (e) => {
488
463
  let t = e.map(({ position: e }) => e.x), n = e.map(({ position: e }) => e.y), r = Math.min(...t), i = Math.max(...t), a = Math.min(...n), o = Math.max(...n);
489
464
  return {
490
465
  x: r,
@@ -492,91 +467,91 @@ var g, _ = (t) => {
492
467
  width: i - r,
493
468
  height: o - a
494
469
  };
495
- }, D = (e) => {
496
- let t = e.x + e.width / 2, n = e.y + e.height / 2, r = Math.max(C, e.width + x * 2), i = Math.max(w, e.height + S * 2);
470
+ }, T = (e) => {
471
+ let t = e.x + e.width / 2, n = e.y + e.height / 2, r = Math.max(x, e.width + y * 2), i = Math.max(S, e.height + b * 2);
497
472
  return {
498
- x: T(t - r / 2, 0, Math.max(0, 1 - r)),
499
- y: T(n - i / 2, 0, Math.max(0, 1 - i)),
473
+ x: C(t - r / 2, 0, Math.max(0, 1 - r)),
474
+ y: C(n - i / 2, 0, Math.max(0, 1 - i)),
500
475
  width: Math.min(r, 1),
501
476
  height: Math.min(i, 1)
502
477
  };
503
- }, O = (e) => ({
478
+ }, E = (e) => ({
504
479
  x: e.reduce((e, t) => e + t.position.x, 0) / e.length,
505
480
  y: e.reduce((e, t) => e + t.position.y, 0) / e.length
506
- }), k = (e) => {
481
+ }), D = (e) => {
507
482
  let t = e.map(({ enemy: e }) => e?.dungeonScore).filter((e) => typeof e == "number");
508
483
  return t.length > 0 ? t.reduce((e, t) => e + t, 0) : null;
509
- }, A = (e, t) => {
510
- let n = E(t);
484
+ }, O = (e, t) => {
485
+ let n = w(t);
511
486
  return {
512
487
  id: e,
513
488
  enemies: t,
514
489
  enemyBounds: n,
515
- visualBounds: D(n),
516
- center: O(t),
517
- dungeonScore: k(t)
490
+ visualBounds: T(n),
491
+ center: E(t),
492
+ dungeonScore: D(t)
518
493
  };
519
- }, j = (e) => e !== null && Number.isFinite(e.x) && Number.isFinite(e.y) && e.x >= 0 && e.x <= 1 && e.y >= 0 && e.y <= 1, M = (e, t, n) => {
520
- let r = [], a = /* @__PURE__ */ new Map();
521
- return e.dungeon.enemies.forEach((o, s) => {
522
- if (o.mapImageId !== t.id) return;
523
- if (!j(o.mapPosition)) {
494
+ }, k = (e) => e !== null && Number.isFinite(e.x) && Number.isFinite(e.y) && e.x >= 0 && e.x <= 1 && e.y >= 0 && e.y <= 1, A = (e, t, n) => {
495
+ let r = [], i = /* @__PURE__ */ new Map();
496
+ return e.dungeon.enemies.forEach((a, o) => {
497
+ if (a.mapImageId !== t.id) return;
498
+ if (!k(a.mapPosition)) {
524
499
  r.push({
525
500
  code: "invalid-map-position",
526
- message: `Skipped ${o.id}: its map position is missing or outside the map.`,
527
- placementIndex: s,
528
- enemyId: o.id
501
+ message: `Skipped ${a.id}: its map position is missing or outside the map.`,
502
+ placementIndex: o,
503
+ enemyId: a.id
529
504
  });
530
505
  return;
531
506
  }
532
- let c = e.enemies.get(o.id) ?? null;
533
- c || r.push({
507
+ let s = e.enemies.get(a.id) ?? null;
508
+ s || r.push({
534
509
  code: "missing-enemy",
535
- message: `No enemy metadata exists for ${o.id}.`,
536
- placementIndex: s,
537
- enemyId: o.id
510
+ message: `No enemy metadata exists for ${a.id}.`,
511
+ placementIndex: o,
512
+ enemyId: a.id
538
513
  });
539
- let l = c ? i(c.images, {
514
+ let c = s ? g(s.images, {
540
515
  type: "enemy",
541
516
  size: "200"
542
- }) : null, u = null;
543
- if (l) try {
544
- u = n.resolveAssetUrl(l);
517
+ }) : null, l = null;
518
+ if (c) try {
519
+ l = n.resolveAssetUrl(c);
545
520
  } catch (e) {
546
521
  r.push({
547
522
  code: "asset-url-error",
548
- message: `Could not resolve the image URL for ${o.id}: ${String(e)}.`,
549
- placementIndex: s,
550
- enemyId: o.id
523
+ message: `Could not resolve the image URL for ${a.id}: ${String(e)}.`,
524
+ placementIndex: o,
525
+ enemyId: a.id
551
526
  });
552
527
  }
553
- else c && r.push({
528
+ else s && r.push({
554
529
  code: "missing-enemy-image",
555
- message: `No 200px enemy image exists for ${o.id}.`,
556
- placementIndex: s,
557
- enemyId: o.id
530
+ message: `No 200px enemy image exists for ${a.id}.`,
531
+ placementIndex: o,
532
+ enemyId: a.id
558
533
  });
559
- let d = {
560
- instanceId: `${e.dungeon.id}:${t.id}:${s}`,
561
- enemy: c,
562
- placement: o,
563
- position: o.mapPosition,
564
- imageUrl: u
565
- }, f = o.groupId === null ? `singleton:${s}` : `group:${o.groupId}`, p = a.get(f) ?? {
566
- id: o.groupId,
534
+ let u = {
535
+ instanceId: `${e.dungeon.id}:${t.id}:${o}`,
536
+ enemy: s,
537
+ placement: a,
538
+ position: a.mapPosition,
539
+ imageUrl: l
540
+ }, d = a.groupId === null ? `singleton:${o}` : `group:${a.groupId}`, f = i.get(d) ?? {
541
+ id: a.groupId,
567
542
  enemies: []
568
543
  };
569
- p.enemies.push(d), a.set(f, p);
544
+ f.enemies.push(u), i.set(d, f);
570
545
  }), {
571
546
  dungeon: e.dungeon,
572
547
  mapImage: t,
573
- groups: [...a.values()].map(({ id: e, enemies: t }) => A(e, t)),
548
+ groups: [...i.values()].map(({ id: e, enemies: t }) => O(e, t)),
574
549
  warnings: r
575
550
  };
576
- }, N = (e, t) => {
551
+ }, j = (e, t) => {
577
552
  let n = (e.id.split(":").at(-1) ?? e.id).replace(/^T_(?:Map_)?/i, "").replace(/^map[-_]/i, "").replaceAll(/[_-]+/g, " ").replace(/([a-z\d])([A-Z])/g, "$1 $2").trim(), r = t.id.split(".").at(-1)?.toLowerCase();
578
553
  return (n.split(/\s+/).filter((e) => e.toLowerCase() !== r).join(" ") || n || "Map").replace(/\b[a-z]/g, (e) => e.toUpperCase());
579
- }, P = (e, t, n) => Math.min(n, Math.max(t, e)), F = class {
554
+ }, M = (e, t, n) => Math.min(n, Math.max(t, e)), N = class {
580
555
  constructor() {
581
556
  this.#e = 0, this.#t = 0, this.#n = 0, this.#r = 0, this.#i = 1, this.#a = 0, this.#o = 0, this.maxZoom = 8;
582
557
  }
@@ -610,26 +585,26 @@ var g, _ = (t) => {
610
585
  }
611
586
  zoomAt(e, t = this.#e / 2, n = this.#t / 2) {
612
587
  let r = this.scale, i = (t - this.#a) / r, a = (n - this.#o) / r;
613
- return this.#i = P(this.#i * e, 1, Math.max(1, this.maxZoom)), this.#a = t - i * this.scale, this.#o = n - a * this.scale, this.#s(), this.state;
588
+ return this.#i = M(this.#i * e, 1, Math.max(1, this.maxZoom)), this.#a = t - i * this.scale, this.#o = n - a * this.scale, this.#s(), this.state;
614
589
  }
615
590
  panBy(e, t) {
616
591
  return this.#a += e, this.#o += t, this.#s(), this.state;
617
592
  }
618
593
  #s() {
619
594
  let e = this.#n * this.scale, t = this.#r * this.scale;
620
- this.#a = e <= this.#e ? (this.#e - e) / 2 : P(this.#a, this.#e - e, 0), this.#o = t <= this.#t ? (this.#t - t) / 2 : P(this.#o, this.#t - t, 0);
595
+ this.#a = e <= this.#e ? (this.#e - e) / 2 : M(this.#a, this.#e - e, 0), this.#o = t <= this.#t ? (this.#t - t) / 2 : M(this.#o, this.#t - t, 0);
621
596
  }
622
- }, I = {
597
+ }, P = {
623
598
  bubbles: !0,
624
599
  composed: !0
625
- }, L = class extends o {
600
+ }, F = class extends o {
626
601
  constructor(...e) {
627
602
  super(...e), this.dungeonId = "", this.mapImageId = null, this.assetBaseUrl = null, this.dataSource = null, this.renderEnemy = null, this.renderGroup = null, this.mapLabelFormatter = null, this.showControls = !0, this.showMapSelector = !0, this.maxZoom = 8, this.externalOverlay = !1, this._status = "empty", this._error = null, this._data = null, this._model = null, this._selectedMap = null, this._viewportState = {
628
603
  zoom: 1,
629
604
  scale: 1,
630
605
  x: 0,
631
606
  y: 0
632
- }, this._isPanning = !1, this._enemyRenderContent = /* @__PURE__ */ new Map(), this._groupRenderContent = /* @__PURE__ */ new Map(), this._mapLabels = /* @__PURE__ */ new Map(), this.#e = null, this.#t = null, this.#n = 0, this.#r = 0, this.#i = null, this.#a = new F(), this.#o = /* @__PURE__ */ new Map(), this.#s = null, this.#c = 0, this.#l = null, this.#u = /* @__PURE__ */ new Set(), this.#d = [], this.#j = (e) => {
607
+ }, this._isPanning = !1, this._enemyRenderContent = /* @__PURE__ */ new Map(), this._groupRenderContent = /* @__PURE__ */ new Map(), this._mapLabels = /* @__PURE__ */ new Map(), this.#e = null, this.#t = null, this.#n = 0, this.#r = 0, this.#i = null, this.#a = new N(), this.#o = /* @__PURE__ */ new Map(), this.#s = null, this.#c = 0, this.#l = null, this.#u = /* @__PURE__ */ new Set(), this.#d = [], this.#j = (e) => {
633
608
  if (![
634
609
  "ArrowLeft",
635
610
  "ArrowRight",
@@ -702,7 +677,7 @@ var g, _ = (t) => {
702
677
  };
703
678
  }
704
679
  static {
705
- this.styles = [n, b];
680
+ this.styles = [r, v];
706
681
  }
707
682
  #e;
708
683
  #t;
@@ -717,7 +692,7 @@ var g, _ = (t) => {
717
692
  #u;
718
693
  #d;
719
694
  connectedCallback() {
720
- super.connectedCallback(), t(this.ownerDocument), this.#i ??= new ResizeObserver(() => this.#R());
695
+ super.connectedCallback(), n(this.ownerDocument), this.#i ??= new ResizeObserver(() => this.#R());
721
696
  }
722
697
  disconnectedCallback() {
723
698
  this.#t?.abort(), this.#i?.disconnect(), super.disconnectedCallback();
@@ -827,13 +802,12 @@ var g, _ = (t) => {
827
802
  return;
828
803
  }
829
804
  this._status = "loading";
830
- let r = this.dataSource ?? y(this.assetBaseUrl ? { assetBaseUrl: this.assetBaseUrl } : {});
805
+ let r = this.dataSource ?? _(this.assetBaseUrl ? { assetBaseUrl: this.assetBaseUrl } : {});
831
806
  this.#e = r;
832
807
  try {
833
808
  let i = await r.loadDungeon(t, this.#t.signal);
834
809
  if (n !== this.#n || this.#t.signal.aborted) return;
835
- if (i.manifest.schemaVersion !== 1) throw new e("unsupported-schema", `Unsupported fellowship-data schema version: ${String(i.manifest.schemaVersion)}.`);
836
- this._data = i, await this.#h(!0);
810
+ e(i.manifest.schemaVersion), this._data = i, await this.#h(!0);
837
811
  } catch (e) {
838
812
  if (n !== this.#n || this.#t.signal.aborted) return;
839
813
  this.#_(e);
@@ -850,20 +824,20 @@ var g, _ = (t) => {
850
824
  });
851
825
  return;
852
826
  }
853
- let i = ++this.#r, a = M(t, r, n);
827
+ let i = ++this.#r, a = A(t, r, n);
854
828
  this._model = a, this._selectedMap = r, this._status = "loading", this._error = null, await this.updateComplete;
855
829
  let o = this._viewportElement;
856
830
  o && (this.#a.maxZoom = Math.max(1, this.maxZoom), this.#a.setDimensions(o.clientWidth, o.clientHeight, r.width, r.height), e && this.#a.fit(), this._viewportState = this.#a.state, await this.updateComplete);
857
831
  try {
858
832
  if (await this.#g(r, n, i), i !== this.#r) return;
859
833
  this._status = "ready", this.dispatchEvent(new CustomEvent("fellowship-map-ready", {
860
- ...I,
834
+ ...P,
861
835
  detail: {
862
836
  model: a,
863
837
  data: t
864
838
  }
865
839
  })), a.warnings.length > 0 && this.dispatchEvent(new CustomEvent("fellowship-map-warning", {
866
- ...I,
840
+ ...P,
867
841
  detail: {
868
842
  warnings: a.warnings,
869
843
  model: a
@@ -884,17 +858,17 @@ var g, _ = (t) => {
884
858
  if (!i || !a) throw Error("A 2D canvas context is unavailable.");
885
859
  a.clearRect(0, 0, i.width, i.height), a.drawImage(r, 0, 0, e.width, e.height);
886
860
  }
887
- #_(t) {
888
- let n = typeof t == "object" && t && "code" in t && "message" in t ? {
889
- code: String(t.code),
890
- message: String(t.message),
891
- ...t instanceof e && t.cause !== void 0 ? { cause: t.cause } : {}
861
+ #_(e) {
862
+ let n = typeof e == "object" && e && "code" in e && "message" in e ? {
863
+ code: String(e.code),
864
+ message: String(e.message),
865
+ ...e instanceof t && e.cause !== void 0 ? { cause: e.cause } : {}
892
866
  } : {
893
867
  code: "unknown",
894
- message: t instanceof Error ? t.message : String(t)
868
+ message: e instanceof Error ? e.message : String(e)
895
869
  };
896
870
  this._error = n, this._status = "error", this.dispatchEvent(new CustomEvent("fellowship-map-error", {
897
- ...I,
871
+ ...P,
898
872
  detail: n
899
873
  }));
900
874
  }
@@ -932,9 +906,9 @@ var g, _ = (t) => {
932
906
  #y() {
933
907
  let e = /* @__PURE__ */ new Map(), t = this._data?.dungeon;
934
908
  if (t) for (let n of t.mapImages) try {
935
- e.set(n.id, this.mapLabelFormatter?.(n, t) ?? N(n, t));
909
+ e.set(n.id, this.mapLabelFormatter?.(n, t) ?? j(n, t));
936
910
  } catch (r) {
937
- this.#B(`map-label:${n.id}`, "map-label-formatter-error", r), e.set(n.id, N(n, t));
911
+ this.#B(`map-label:${n.id}`, "map-label-formatter-error", r), e.set(n.id, j(n, t));
938
912
  }
939
913
  this._mapLabels = e;
940
914
  }
@@ -1067,7 +1041,7 @@ var g, _ = (t) => {
1067
1041
  }
1068
1042
  #A(e) {
1069
1043
  e.id !== this._selectedMap?.id && (this.mapImageId = e.id, this.dispatchEvent(new CustomEvent("fellowship-map-image-change", {
1070
- ...I,
1044
+ ...P,
1071
1045
  detail: {
1072
1046
  mapImageId: e.id,
1073
1047
  mapImage: e
@@ -1089,7 +1063,7 @@ var g, _ = (t) => {
1089
1063
  }
1090
1064
  #z(e) {
1091
1065
  this._viewportState = this.#a.state, this.dispatchEvent(new CustomEvent("fellowship-map-viewport-change", {
1092
- ...I,
1066
+ ...P,
1093
1067
  detail: {
1094
1068
  viewport: this.#a.state,
1095
1069
  source: e
@@ -1108,37 +1082,37 @@ var g, _ = (t) => {
1108
1082
  let e = this.#d;
1109
1083
  this.#d = [];
1110
1084
  for (let t of e) this.dispatchEvent(new CustomEvent("fellowship-map-error", {
1111
- ...I,
1085
+ ...P,
1112
1086
  detail: t
1113
1087
  }));
1114
1088
  }
1115
1089
  };
1116
- r([d({
1090
+ i([d({
1117
1091
  type: String,
1118
1092
  attribute: "dungeon-id"
1119
- })], L.prototype, "dungeonId", void 0), r([d({
1093
+ })], F.prototype, "dungeonId", void 0), i([d({
1120
1094
  type: String,
1121
1095
  attribute: "map-image-id"
1122
- })], L.prototype, "mapImageId", void 0), r([d({
1096
+ })], F.prototype, "mapImageId", void 0), i([d({
1123
1097
  type: String,
1124
1098
  attribute: "asset-base-url"
1125
- })], L.prototype, "assetBaseUrl", void 0), r([d({ attribute: !1 })], L.prototype, "dataSource", void 0), r([d({ attribute: !1 })], L.prototype, "renderEnemy", void 0), r([d({ attribute: !1 })], L.prototype, "renderGroup", void 0), r([d({ attribute: !1 })], L.prototype, "mapLabelFormatter", void 0), r([d({
1099
+ })], F.prototype, "assetBaseUrl", void 0), i([d({ attribute: !1 })], F.prototype, "dataSource", void 0), i([d({ attribute: !1 })], F.prototype, "renderEnemy", void 0), i([d({ attribute: !1 })], F.prototype, "renderGroup", void 0), i([d({ attribute: !1 })], F.prototype, "mapLabelFormatter", void 0), i([d({
1126
1100
  type: Boolean,
1127
1101
  attribute: "show-controls"
1128
- })], L.prototype, "showControls", void 0), r([d({
1102
+ })], F.prototype, "showControls", void 0), i([d({
1129
1103
  type: Boolean,
1130
1104
  attribute: "show-map-selector"
1131
- })], L.prototype, "showMapSelector", void 0), r([d({
1105
+ })], F.prototype, "showMapSelector", void 0), i([d({
1132
1106
  type: Number,
1133
1107
  attribute: "max-zoom"
1134
- })], L.prototype, "maxZoom", void 0), r([d({
1108
+ })], F.prototype, "maxZoom", void 0), i([d({
1135
1109
  type: Boolean,
1136
1110
  attribute: !1
1137
- })], L.prototype, "externalOverlay", void 0), r([p()], L.prototype, "_status", void 0), r([p()], L.prototype, "_error", void 0), r([p()], L.prototype, "_data", void 0), r([p()], L.prototype, "_model", void 0), r([p()], L.prototype, "_selectedMap", void 0), r([p()], L.prototype, "_viewportState", void 0), r([p()], L.prototype, "_isPanning", void 0), r([p()], L.prototype, "_enemyRenderContent", void 0), r([p()], L.prototype, "_groupRenderContent", void 0), r([p()], L.prototype, "_mapLabels", void 0), r([f(".viewport")], L.prototype, "_viewportElement", void 0), r([f("canvas")], L.prototype, "_canvasElement", void 0), L = r([u("fellowship-dungeon-map")], L);
1138
- var R = () => {
1139
- globalThis.customElements !== void 0 && !globalThis.customElements.get("fellowship-dungeon-map") && globalThis.customElements.define("fellowship-dungeon-map", L);
1111
+ })], F.prototype, "externalOverlay", void 0), i([p()], F.prototype, "_status", void 0), i([p()], F.prototype, "_error", void 0), i([p()], F.prototype, "_data", void 0), i([p()], F.prototype, "_model", void 0), i([p()], F.prototype, "_selectedMap", void 0), i([p()], F.prototype, "_viewportState", void 0), i([p()], F.prototype, "_isPanning", void 0), i([p()], F.prototype, "_enemyRenderContent", void 0), i([p()], F.prototype, "_groupRenderContent", void 0), i([p()], F.prototype, "_mapLabels", void 0), i([f(".viewport")], F.prototype, "_viewportElement", void 0), i([f("canvas")], F.prototype, "_canvasElement", void 0), F = i([u("fellowship-dungeon-map")], F);
1112
+ var I = () => {
1113
+ globalThis.customElements !== void 0 && !globalThis.customElements.get("fellowship-dungeon-map") && globalThis.customElements.define("fellowship-dungeon-map", F);
1140
1114
  };
1141
1115
  //#endregion
1142
- export { N as a, M as i, R as n, y as o, F as r, L as t };
1116
+ export { j as a, A as i, I as n, _ as o, N as r, F as t };
1143
1117
 
1144
- //# sourceMappingURL=dungeon-map-IPN6sEDj.js.map
1118
+ //# sourceMappingURL=dungeon-map-CutIcCVP.js.map