@crockery/fellowship-components 0.1.0 → 0.3.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.
- package/README.md +7 -2
- package/RELEASING.md +9 -45
- package/dist/chunks/data-source-C-Gs7kRl.js +2 -0
- package/dist/chunks/decorate-B_ZTN9li.js.map +1 -1
- package/dist/chunks/dungeon-cast-browser-Cyh519NI.js +705 -0
- package/dist/chunks/dungeon-cast-browser-Cyh519NI.js.map +1 -0
- package/dist/chunks/{dungeon-map-IPN6sEDj.js → dungeon-map-xFaPasVr.js} +113 -138
- package/dist/chunks/dungeon-map-xFaPasVr.js.map +1 -0
- package/dist/chunks/{talent-calculator-Ch1Pbbba.js → talent-calculator-CIPNbqK5.js} +84 -114
- package/dist/chunks/talent-calculator-CIPNbqK5.js.map +1 -0
- package/dist/data/cast-data-source.d.ts +5 -0
- package/dist/data/cast-data-source.d.ts.map +1 -0
- package/dist/data/data-source.d.ts +5 -16
- package/dist/data/data-source.d.ts.map +1 -1
- package/dist/data/package-cast-data-source.d.ts +8 -0
- package/dist/data/package-cast-data-source.d.ts.map +1 -0
- package/dist/data/package-data-source.d.ts +3 -1
- package/dist/data/package-data-source.d.ts.map +1 -1
- package/dist/data/package-talent-data-source.d.ts +2 -0
- package/dist/data/package-talent-data-source.d.ts.map +1 -1
- package/dist/data/talent-data-source.d.ts +4 -10
- package/dist/data/talent-data-source.d.ts.map +1 -1
- package/dist/dungeon-cast-browser/dungeon-cast-browser.d.ts +36 -0
- package/dist/dungeon-cast-browser/dungeon-cast-browser.d.ts.map +1 -0
- package/dist/dungeon-cast-browser/dungeon-cast-browser.styles.d.ts +2 -0
- package/dist/dungeon-cast-browser/dungeon-cast-browser.styles.d.ts.map +1 -0
- package/dist/dungeon-cast-browser/index.d.ts +4 -0
- package/dist/dungeon-cast-browser/index.d.ts.map +1 -0
- package/dist/dungeon-cast-browser/render-model.d.ts +5 -0
- package/dist/dungeon-cast-browser/render-model.d.ts.map +1 -0
- package/dist/dungeon-cast-browser/types.d.ts +60 -0
- package/dist/dungeon-cast-browser/types.d.ts.map +1 -0
- package/dist/dungeon-cast-browser.js +7 -0
- package/dist/dungeon-cast-browser.js.map +1 -0
- package/dist/dungeon-map.js +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -5
- package/dist/react/dungeon-cast-browser.d.ts +12 -0
- package/dist/react/dungeon-cast-browser.d.ts.map +1 -0
- package/dist/react/dungeon-cast-browser.js +19 -0
- package/dist/react/dungeon-cast-browser.js.map +1 -0
- package/dist/react/dungeon-map.js +1 -1
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/talent-calculator.js +1 -1
- package/dist/react.js +4 -3
- package/dist/talent-calculator.js +1 -1
- package/package.json +35 -25
- package/src/dungeon-cast-browser/README.md +22 -0
- package/dist/chunks/data-source-CoIFvV72.js +0 -10
- package/dist/chunks/data-source-CoIFvV72.js.map +0 -1
- package/dist/chunks/dungeon-map-IPN6sEDj.js.map +0 -1
- package/dist/chunks/talent-calculator-Ch1Pbbba.js.map +0 -1
|
@@ -1,115 +1,85 @@
|
|
|
1
|
-
import { t as e } from "./data-source-
|
|
1
|
+
import { t as e } from "./data-source-C-Gs7kRl.js";
|
|
2
2
|
import { n as t, r as n, t as r } from "./decorate-B_ZTN9li.js";
|
|
3
3
|
import { a as i, n as a } from "./tooltip-DoQVSnOn.js";
|
|
4
|
-
import {
|
|
5
|
-
import { LitElement as
|
|
6
|
-
import { customElement as
|
|
7
|
-
import { repeat as
|
|
4
|
+
import { createPackageFellowshipDataClient as o } from "@crockery/fellowship-data/client";
|
|
5
|
+
import { LitElement as s, css as c, html as l, nothing as u } from "lit";
|
|
6
|
+
import { customElement as d, property as f, state as p } from "lit/decorators.js";
|
|
7
|
+
import { repeat as m } from "lit/directives/repeat.js";
|
|
8
|
+
import { findImage as h } from "@crockery/fellowship-data";
|
|
8
9
|
//#region src/data/package-talent-data-source.ts
|
|
9
|
-
var g
|
|
10
|
-
|
|
11
|
-
}, v = () => (g ??= Promise.all([
|
|
12
|
-
import("@crockery/fellowship-data/heroes"),
|
|
13
|
-
import("@crockery/fellowship-data/talents"),
|
|
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)}.`);
|
|
18
|
-
let a = /* @__PURE__ */ new Map();
|
|
19
|
-
for (let e of n.default) {
|
|
20
|
-
let t = a.get(e.parentId) ?? [];
|
|
21
|
-
t.push(e), a.set(e.parentId, t);
|
|
22
|
-
}
|
|
10
|
+
var g = (e = {}) => {
|
|
11
|
+
let t = o(e);
|
|
23
12
|
return {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
talentsByHero: new Map([...a].map(([e, t]) => [e, t]))
|
|
13
|
+
loadHeroTalents: (e, n) => t.loadHeroTalents(e, n),
|
|
14
|
+
resolveAssetUrl: (e) => t.resolveAssetUrl(e)
|
|
27
15
|
};
|
|
28
|
-
}
|
|
29
|
-
throw g = void 0, t instanceof e ? t : new e("data-load-failed", "Unable to load hero talents from @crockery/fellowship-data.", t);
|
|
30
|
-
}), g), y = (t = {}) => ({
|
|
31
|
-
async loadHeroTalents(t, n) {
|
|
32
|
-
_(n);
|
|
33
|
-
let r = await v();
|
|
34
|
-
_(n);
|
|
35
|
-
let i = r.heroes.get(t);
|
|
36
|
-
if (!i) throw new e("hero-not-found", `No hero with ID “${t}” exists in @crockery/fellowship-data.`);
|
|
37
|
-
return {
|
|
38
|
-
manifest: r.manifest,
|
|
39
|
-
hero: i,
|
|
40
|
-
talents: r.talentsByHero.get(t) ?? []
|
|
41
|
-
};
|
|
42
|
-
},
|
|
43
|
-
resolveAssetUrl(e) {
|
|
44
|
-
return t.assetBaseUrl ? s(e, { baseUrl: t.assetBaseUrl }) : s(e);
|
|
45
|
-
}
|
|
46
|
-
}), b = [
|
|
16
|
+
}, _ = [
|
|
47
17
|
"I",
|
|
48
18
|
"II",
|
|
49
19
|
"III",
|
|
50
20
|
"IV",
|
|
51
21
|
"V",
|
|
52
22
|
"VI"
|
|
53
|
-
],
|
|
23
|
+
], v = (e) => _[e - 1] ?? String(e), y = (e, t, n) => ({
|
|
54
24
|
code: e,
|
|
55
25
|
message: n,
|
|
56
26
|
talentId: t.id
|
|
57
|
-
}),
|
|
27
|
+
}), b = (e, t) => {
|
|
58
28
|
let n = [], r = /* @__PURE__ */ new Set(), i = [];
|
|
59
29
|
for (let a of e.talents) {
|
|
60
30
|
if (a.row === null && a.column === null) continue;
|
|
61
31
|
if (!Number.isInteger(a.row) || !Number.isInteger(a.column) || a.row === null || a.column === null || a.row < 1 || a.row > 6 || a.column < 1 || a.column > 3) {
|
|
62
|
-
n.push(
|
|
32
|
+
n.push(y("invalid-position", a, `Talent “${a.id}” has an invalid row or column and was skipped.`));
|
|
63
33
|
continue;
|
|
64
34
|
}
|
|
65
35
|
let e = `${a.row}:${a.column}`;
|
|
66
36
|
if (r.has(e)) {
|
|
67
|
-
n.push(
|
|
37
|
+
n.push(y("duplicate-position", a, `Talent “${a.id}” duplicates row ${a.row}, column ${a.column} and was skipped.`));
|
|
68
38
|
continue;
|
|
69
39
|
}
|
|
70
40
|
r.add(e);
|
|
71
|
-
let
|
|
72
|
-
|
|
73
|
-
let
|
|
41
|
+
let o = Number.isInteger(a.pointCost) && (a.pointCost ?? 0) > 0 ? a.pointCost : null;
|
|
42
|
+
o === null && n.push(y("invalid-cost", a, `Talent “${a.id}” has an invalid point cost.`)), a.name || n.push(y("missing-name", a, `Talent “${a.id}” has no display name.`)), a.description || n.push(y("missing-description", a, `Talent “${a.id}” has no description.`));
|
|
43
|
+
let s = h(a.images, {
|
|
74
44
|
type: "talent",
|
|
75
45
|
size: "200"
|
|
76
|
-
}) ??
|
|
46
|
+
}) ?? h(a.images, {
|
|
77
47
|
type: "talent",
|
|
78
48
|
size: "full"
|
|
79
|
-
}),
|
|
80
|
-
if (!
|
|
49
|
+
}), c = null;
|
|
50
|
+
if (!s) n.push(y("missing-image", a, `Talent “${a.id}” has no icon.`));
|
|
81
51
|
else try {
|
|
82
|
-
|
|
52
|
+
c = t.resolveAssetUrl(s);
|
|
83
53
|
} catch (e) {
|
|
84
|
-
n.push(
|
|
54
|
+
n.push(y("asset-url-error", a, `The icon URL for talent “${a.id}” could not be resolved: ${String(e)}.`));
|
|
85
55
|
}
|
|
86
56
|
i.push({
|
|
87
57
|
talent: a,
|
|
88
58
|
row: a.row,
|
|
89
59
|
column: a.column,
|
|
90
|
-
pointCost:
|
|
91
|
-
imageUrl:
|
|
60
|
+
pointCost: o,
|
|
61
|
+
imageUrl: c
|
|
92
62
|
});
|
|
93
63
|
}
|
|
94
64
|
i.sort((e, t) => e.row - t.row || e.column - t.column);
|
|
95
|
-
let a = new Map(i.map((e) => [e.talent.id, e])),
|
|
65
|
+
let a = new Map(i.map((e) => [e.talent.id, e])), o = [...new Set(i.map(({ row: e }) => e))].map((e) => ({
|
|
96
66
|
row: e,
|
|
97
|
-
label:
|
|
67
|
+
label: v(e),
|
|
98
68
|
talents: i.filter((t) => t.row === e)
|
|
99
69
|
}));
|
|
100
70
|
return {
|
|
101
71
|
hero: e.hero,
|
|
102
|
-
rows:
|
|
72
|
+
rows: o,
|
|
103
73
|
talentById: a,
|
|
104
74
|
warnings: n
|
|
105
75
|
};
|
|
106
|
-
},
|
|
76
|
+
}, x = 14, S = (e) => Math.min(14, Math.max(0, Math.round(Number.isFinite(e) ? e : 14))), C = (e, t) => {
|
|
107
77
|
let n = new Set(t), r = [...e.talentById.values()].filter(({ talent: e }) => n.has(e.id)).map(({ talent: e }) => e.id), i = new Set(r);
|
|
108
78
|
return {
|
|
109
79
|
selectedTalentIds: r,
|
|
110
80
|
removedTalentIds: [...new Set(t)].filter((e) => !i.has(e))
|
|
111
81
|
};
|
|
112
|
-
},
|
|
82
|
+
}, w = (e, t, n) => {
|
|
113
83
|
let r = new Set(t), i = [...e.talentById.values()].reduce((e, t) => r.has(t.talent.id) && t.pointCost !== null ? e + t.pointCost : e, 0), a = n - i;
|
|
114
84
|
return {
|
|
115
85
|
selectedTalentIds: [...e.talentById.values()].filter(({ talent: e }) => r.has(e.id)).map(({ talent: e }) => e.id),
|
|
@@ -117,7 +87,7 @@ var g, _ = (t) => {
|
|
|
117
87
|
remainingPoints: a,
|
|
118
88
|
overBudget: a < 0
|
|
119
89
|
};
|
|
120
|
-
},
|
|
90
|
+
}, T = (e, t) => e !== null && !t.overBudget && e <= t.remainingPoints, E = c`
|
|
121
91
|
:host {
|
|
122
92
|
--fellowship-talent-background: var(--_fellowship-field-canvas);
|
|
123
93
|
--fellowship-talent-surface: var(--_fellowship-field-surface);
|
|
@@ -665,20 +635,20 @@ var g, _ = (t) => {
|
|
|
665
635
|
transform: none;
|
|
666
636
|
}
|
|
667
637
|
}
|
|
668
|
-
`,
|
|
638
|
+
`, D = {
|
|
669
639
|
bubbles: !0,
|
|
670
640
|
composed: !0
|
|
671
|
-
},
|
|
641
|
+
}, O = (e, t) => e.length !== t?.length || e.some((e, n) => e !== t[n]), k = (e) => `talent:${e}`, A = (e) => ({
|
|
672
642
|
selectedTalentIds: [],
|
|
673
643
|
spentPoints: 0,
|
|
674
644
|
remainingPoints: e,
|
|
675
645
|
overBudget: !1
|
|
676
|
-
}),
|
|
646
|
+
}), j = class extends s {
|
|
677
647
|
constructor(...e) {
|
|
678
|
-
super(...e), this.heroId = "", this.talentPoints = 14, this.selectedTalentIds = [], this.assetBaseUrl = null, this.dataSource = null, this.renderTalent = null, this.showPointControls = !0, this.showTooltips = !0, this._status = "empty", this._error = null, this._model = null, this._failedImages = /* @__PURE__ */ new Set(), this._announcement = "", this._renderSelectionState =
|
|
648
|
+
super(...e), this.heroId = "", this.talentPoints = 14, this.selectedTalentIds = [], this.assetBaseUrl = null, this.dataSource = null, this.renderTalent = null, this.showPointControls = !0, this.showTooltips = !0, this._status = "empty", this._error = null, this._model = null, this._failedImages = /* @__PURE__ */ new Set(), this._announcement = "", this._renderSelectionState = A(14), this._talentPresentation = /* @__PURE__ */ new Map(), this._talentRenderContent = /* @__PURE__ */ new Map(), this.#e = null, this.#t = 0, this.#n = null, this.#r = !1, this.#i = /* @__PURE__ */ new Set(), this.#a = [];
|
|
679
649
|
}
|
|
680
650
|
static {
|
|
681
|
-
this.styles = [n,
|
|
651
|
+
this.styles = [n, E];
|
|
682
652
|
}
|
|
683
653
|
#e;
|
|
684
654
|
#t;
|
|
@@ -700,7 +670,7 @@ var g, _ = (t) => {
|
|
|
700
670
|
return;
|
|
701
671
|
}
|
|
702
672
|
if (e.has("talentPoints")) {
|
|
703
|
-
let t =
|
|
673
|
+
let t = S(this.talentPoints);
|
|
704
674
|
if (t !== this.talentPoints) {
|
|
705
675
|
this.#r = !0, this.talentPoints = t, this.#v("normalization");
|
|
706
676
|
return;
|
|
@@ -712,20 +682,20 @@ var g, _ = (t) => {
|
|
|
712
682
|
willUpdate(e) {
|
|
713
683
|
super.willUpdate(e);
|
|
714
684
|
let t = e.has("_model") || e.has("selectedTalentIds") || e.has("talentPoints");
|
|
715
|
-
t && (this._renderSelectionState = this._model ?
|
|
685
|
+
t && (this._renderSelectionState = this._model ? w(this._model, this.selectedTalentIds, this.talentPoints) : A(this.talentPoints)), e.has("renderTalent") && this.#i.clear(), (t || e.has("renderTalent")) && this.#l(this._renderSelectionState);
|
|
716
686
|
}
|
|
717
687
|
get renderModel() {
|
|
718
688
|
return this._model;
|
|
719
689
|
}
|
|
720
690
|
get selectionState() {
|
|
721
|
-
return this._model ?
|
|
691
|
+
return this._model ? w(this._model, this.selectedTalentIds, this.talentPoints) : A(this.talentPoints);
|
|
722
692
|
}
|
|
723
693
|
reset() {
|
|
724
694
|
this.selectedTalentIds.length !== 0 && (this.selectedTalentIds = [], this.#_("reset"));
|
|
725
695
|
}
|
|
726
696
|
selectTalent(e) {
|
|
727
697
|
let t = this._model?.talentById.get(e), n = this.selectionState;
|
|
728
|
-
return !t || n.selectedTalentIds.includes(e) || !
|
|
698
|
+
return !t || n.selectedTalentIds.includes(e) || !T(t.pointCost, n) ? !1 : (this.selectedTalentIds = [...n.selectedTalentIds, e], this.#_("api"), !0);
|
|
729
699
|
}
|
|
730
700
|
deselectTalent(e) {
|
|
731
701
|
return this.selectionState.selectedTalentIds.includes(e) ? (this.selectedTalentIds = this.selectionState.selectedTalentIds.filter((t) => t !== e), this.#_("api"), !0) : !1;
|
|
@@ -735,7 +705,7 @@ var g, _ = (t) => {
|
|
|
735
705
|
}
|
|
736
706
|
render() {
|
|
737
707
|
let e = this._renderSelectionState;
|
|
738
|
-
return
|
|
708
|
+
return l`
|
|
739
709
|
<section
|
|
740
710
|
class="container"
|
|
741
711
|
part="container"
|
|
@@ -749,7 +719,7 @@ var g, _ = (t) => {
|
|
|
749
719
|
`;
|
|
750
720
|
}
|
|
751
721
|
#o(e) {
|
|
752
|
-
return
|
|
722
|
+
return l`
|
|
753
723
|
<header class="header" part="header">
|
|
754
724
|
<h2 class="heading" part="heading">Talent points</h2>
|
|
755
725
|
<div class="points-cluster">
|
|
@@ -764,7 +734,7 @@ var g, _ = (t) => {
|
|
|
764
734
|
<span class="points-separator" aria-hidden="true">/</span>
|
|
765
735
|
<span class="points-total" part="points-total">${this.talentPoints}</span>
|
|
766
736
|
</div>
|
|
767
|
-
${this.showPointControls ?
|
|
737
|
+
${this.showPointControls ? l`
|
|
768
738
|
<div
|
|
769
739
|
class="point-controls"
|
|
770
740
|
part="point-controls"
|
|
@@ -794,7 +764,7 @@ var g, _ = (t) => {
|
|
|
794
764
|
+
|
|
795
765
|
</button>
|
|
796
766
|
</div>
|
|
797
|
-
` :
|
|
767
|
+
` : u}
|
|
798
768
|
<button
|
|
799
769
|
class="clear-all"
|
|
800
770
|
part="clear-all"
|
|
@@ -809,7 +779,7 @@ var g, _ = (t) => {
|
|
|
809
779
|
`;
|
|
810
780
|
}
|
|
811
781
|
#s(e) {
|
|
812
|
-
return e.rows.length === 0 ?
|
|
782
|
+
return e.rows.length === 0 ? l`
|
|
813
783
|
<div class="status" part="empty-state" role="status">
|
|
814
784
|
<div class="status-card">
|
|
815
785
|
<div class="status-mark" aria-hidden="true">◇</div>
|
|
@@ -819,14 +789,14 @@ var g, _ = (t) => {
|
|
|
819
789
|
</p>
|
|
820
790
|
</div>
|
|
821
791
|
</div>
|
|
822
|
-
` :
|
|
792
|
+
` : l`
|
|
823
793
|
<div class="grid" part="grid" role="group" aria-label="Talent tiers">
|
|
824
|
-
${
|
|
794
|
+
${m(e.rows, (e) => e.row, (e) => l`
|
|
825
795
|
<fieldset class="row" part="row">
|
|
826
796
|
<legend class="visually-hidden">Talent tier ${e.label}</legend>
|
|
827
797
|
<span class="row-label" part="row-label" aria-hidden="true">${e.label}</span>
|
|
828
798
|
<div class="row-talents">
|
|
829
|
-
${
|
|
799
|
+
${m(e.talents, (e) => e.talent.id, (e) => this.#c(e))}
|
|
830
800
|
</div>
|
|
831
801
|
</fieldset>
|
|
832
802
|
`)}
|
|
@@ -835,8 +805,8 @@ var g, _ = (t) => {
|
|
|
835
805
|
}
|
|
836
806
|
#c(e) {
|
|
837
807
|
let t = this._talentPresentation.get(e.talent.id);
|
|
838
|
-
if (!t) return
|
|
839
|
-
let { context: n, name: r, descriptionId: i, affordability: a, description: o } = t, { selected: s, disabled: c } = n,
|
|
808
|
+
if (!t) return u;
|
|
809
|
+
let { context: n, name: r, descriptionId: i, affordability: a, description: o } = t, { selected: s, disabled: c } = n, d = l`
|
|
840
810
|
<button
|
|
841
811
|
class="talent"
|
|
842
812
|
part="talent"
|
|
@@ -851,22 +821,22 @@ var g, _ = (t) => {
|
|
|
851
821
|
<span class="talent-cost" part="talent-cost">${e.pointCost ?? "–"}</span>
|
|
852
822
|
</button>
|
|
853
823
|
`;
|
|
854
|
-
return
|
|
855
|
-
${this.showTooltips && (e.talent.description || c) ?
|
|
824
|
+
return l`
|
|
825
|
+
${this.showTooltips && (e.talent.description || c) ? l`
|
|
856
826
|
<fellowship-tooltip
|
|
857
827
|
.heading=${r}
|
|
858
828
|
.text=${e.talent.description ?? a}
|
|
859
829
|
>
|
|
860
|
-
${
|
|
830
|
+
${d}
|
|
861
831
|
</fellowship-tooltip>
|
|
862
|
-
` :
|
|
832
|
+
` : d}
|
|
863
833
|
<span class="visually-hidden" id=${i}>${o}</span>
|
|
864
834
|
`;
|
|
865
835
|
}
|
|
866
836
|
#l(e) {
|
|
867
837
|
let t = this.renderTalent, n = this._model, r = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map();
|
|
868
838
|
if (n) for (let o of n.talentById.values()) {
|
|
869
|
-
let s = e.selectedTalentIds.includes(o.talent.id), c =
|
|
839
|
+
let s = e.selectedTalentIds.includes(o.talent.id), c = T(o.pointCost, e), l = !s && !c, u = o.talent.name ?? o.talent.id, d = o.pointCost === null ? "This talent has no valid point cost." : l ? `Requires ${o.pointCost} talent points; ${Math.max(0, e.remainingPoints)} remaining.` : `${o.pointCost} talent ${o.pointCost === 1 ? "point" : "points"}.`, f = {
|
|
870
840
|
talent: o,
|
|
871
841
|
hero: n.hero,
|
|
872
842
|
selected: s,
|
|
@@ -895,17 +865,17 @@ var g, _ = (t) => {
|
|
|
895
865
|
this._talentPresentation = a, this._talentRenderContent = r;
|
|
896
866
|
}
|
|
897
867
|
#u(e) {
|
|
898
|
-
let t = e.talent, n = t.talent.name ?? t.talent.id, r = this.renderTalent && this._talentRenderContent.has(t.talent.id) ? this._talentRenderContent.get(t.talent.id) :
|
|
899
|
-
<slot name=${
|
|
868
|
+
let t = e.talent, n = t.talent.name ?? t.talent.id, r = this.renderTalent && this._talentRenderContent.has(t.talent.id) ? this._talentRenderContent.get(t.talent.id) : l`
|
|
869
|
+
<slot name=${k(t.talent.id)}>
|
|
900
870
|
<span class="talent-name" part="talent-name" title=${n}>${n}</span>
|
|
901
871
|
</slot>
|
|
902
872
|
`;
|
|
903
|
-
return
|
|
873
|
+
return l`
|
|
904
874
|
${this.#d(t, n)} ${r}
|
|
905
875
|
`;
|
|
906
876
|
}
|
|
907
877
|
#d(e, t) {
|
|
908
|
-
return e.imageUrl && !this._failedImages.has(e.talent.id) ?
|
|
878
|
+
return e.imageUrl && !this._failedImages.has(e.talent.id) ? l`
|
|
909
879
|
<img
|
|
910
880
|
class="talent-icon"
|
|
911
881
|
part="talent-icon"
|
|
@@ -914,11 +884,11 @@ var g, _ = (t) => {
|
|
|
914
884
|
draggable="false"
|
|
915
885
|
@error=${() => this.#b(e)}
|
|
916
886
|
/>
|
|
917
|
-
` :
|
|
887
|
+
` : l`<span class="talent-icon-fallback" part="talent-icon-fallback">${t.split(/\s+/).map((e) => e[0]).join("").slice(0, 2).toUpperCase()}</span>`;
|
|
918
888
|
}
|
|
919
889
|
#f() {
|
|
920
890
|
let e = this._status === "loading", t = this._status === "empty", n = e ? "Reading talent codex" : t ? "Choose a hero" : "Talents unavailable", r = e ? "Loading the hero and their available talents." : t ? "Set the hero-id attribute or heroId property to build a talent loadout." : this._error?.message ?? "An unexpected talent data error occurred.";
|
|
921
|
-
return
|
|
891
|
+
return l`
|
|
922
892
|
<div
|
|
923
893
|
class="status"
|
|
924
894
|
part=${this._status === "error" ? "error-state" : "status"}
|
|
@@ -928,7 +898,7 @@ var g, _ = (t) => {
|
|
|
928
898
|
<div class="status-mark" aria-hidden="true">${e ? "…" : "✦"}</div>
|
|
929
899
|
<p class="status-title">${n}</p>
|
|
930
900
|
<p class="status-copy">${r}</p>
|
|
931
|
-
${this._status === "error" ?
|
|
901
|
+
${this._status === "error" ? l`<button class="retry-button" type="button" @click=${this.retry}>Retry</button>` : u}
|
|
932
902
|
</div>
|
|
933
903
|
</div>
|
|
934
904
|
`;
|
|
@@ -940,18 +910,18 @@ var g, _ = (t) => {
|
|
|
940
910
|
return;
|
|
941
911
|
}
|
|
942
912
|
this._status = "loading";
|
|
943
|
-
let r = this.dataSource ??
|
|
913
|
+
let r = this.dataSource ?? g(this.assetBaseUrl ? { assetBaseUrl: this.assetBaseUrl } : {});
|
|
944
914
|
try {
|
|
945
915
|
let i = await r.loadHeroTalents(t, this.#e.signal);
|
|
946
916
|
if (n !== this.#t || this.#e.signal.aborted) return;
|
|
947
917
|
if (i.manifest.schemaVersion !== 1) throw new e("unsupported-schema", `Unsupported fellowship-data schema version: ${String(i.manifest.schemaVersion)}.`);
|
|
948
|
-
let a =
|
|
918
|
+
let a = b(i, r);
|
|
949
919
|
this._model = a, this._status = "ready";
|
|
950
920
|
let o = this.#m(!1);
|
|
951
921
|
await this.updateComplete;
|
|
952
922
|
let s = this.selectionState;
|
|
953
923
|
this.dispatchEvent(new CustomEvent("fellowship-talents-ready", {
|
|
954
|
-
...
|
|
924
|
+
...D,
|
|
955
925
|
detail: {
|
|
956
926
|
data: i,
|
|
957
927
|
model: a,
|
|
@@ -965,7 +935,7 @@ var g, _ = (t) => {
|
|
|
965
935
|
}
|
|
966
936
|
#m(e) {
|
|
967
937
|
if (!this._model) return !1;
|
|
968
|
-
let t =
|
|
938
|
+
let t = C(this._model, this.selectedTalentIds);
|
|
969
939
|
return t.selectedTalentIds.length !== this.selectedTalentIds.length || t.selectedTalentIds.some((e, t) => e !== this.selectedTalentIds[t]) ? (this.selectedTalentIds = t.selectedTalentIds, t.removedTalentIds.length > 0 && this.#x([{
|
|
970
940
|
code: "invalid-selection",
|
|
971
941
|
message: `Removed unavailable talent selections: ${t.removedTalentIds.join(", ")}.`,
|
|
@@ -984,13 +954,13 @@ var g, _ = (t) => {
|
|
|
984
954
|
this.selectedTalentIds = [...this.selectionState.selectedTalentIds, e.talent.id], this.#_("user");
|
|
985
955
|
}
|
|
986
956
|
#g(e, t) {
|
|
987
|
-
let n =
|
|
957
|
+
let n = S(e), r = this.selectionState;
|
|
988
958
|
n === this.talentPoints || n < r.spentPoints || (this.talentPoints = n, this.#r = !0, this.#v(t));
|
|
989
959
|
}
|
|
990
960
|
#_(e) {
|
|
991
|
-
let t = this._model ?
|
|
961
|
+
let t = this._model ? w(this._model, this.selectedTalentIds, this.talentPoints) : A(this.talentPoints);
|
|
992
962
|
this.dispatchEvent(new CustomEvent("fellowship-talent-selection-change", {
|
|
993
|
-
...
|
|
963
|
+
...D,
|
|
994
964
|
detail: {
|
|
995
965
|
...t,
|
|
996
966
|
source: e
|
|
@@ -1000,7 +970,7 @@ var g, _ = (t) => {
|
|
|
1000
970
|
#v(e) {
|
|
1001
971
|
let t = this.selectionState;
|
|
1002
972
|
this.dispatchEvent(new CustomEvent("fellowship-talent-points-change", {
|
|
1003
|
-
...
|
|
973
|
+
...D,
|
|
1004
974
|
detail: {
|
|
1005
975
|
...t,
|
|
1006
976
|
talentPoints: this.talentPoints,
|
|
@@ -1031,7 +1001,7 @@ var g, _ = (t) => {
|
|
|
1031
1001
|
}
|
|
1032
1002
|
#x(e) {
|
|
1033
1003
|
this.dispatchEvent(new CustomEvent("fellowship-talents-warning", {
|
|
1034
|
-
...
|
|
1004
|
+
...D,
|
|
1035
1005
|
detail: {
|
|
1036
1006
|
warnings: e,
|
|
1037
1007
|
model: this._model
|
|
@@ -1053,34 +1023,34 @@ var g, _ = (t) => {
|
|
|
1053
1023
|
message: t instanceof Error ? t.message : String(t)
|
|
1054
1024
|
};
|
|
1055
1025
|
this._error = n, this._status = "error", this.dispatchEvent(new CustomEvent("fellowship-talents-error", {
|
|
1056
|
-
...
|
|
1026
|
+
...D,
|
|
1057
1027
|
detail: n
|
|
1058
1028
|
}));
|
|
1059
1029
|
}
|
|
1060
1030
|
};
|
|
1061
|
-
r([
|
|
1031
|
+
r([f({
|
|
1062
1032
|
type: String,
|
|
1063
1033
|
attribute: "hero-id"
|
|
1064
|
-
})],
|
|
1034
|
+
})], j.prototype, "heroId", void 0), r([f({
|
|
1065
1035
|
type: Number,
|
|
1066
1036
|
attribute: "talent-points"
|
|
1067
|
-
})],
|
|
1037
|
+
})], j.prototype, "talentPoints", void 0), r([f({
|
|
1068
1038
|
attribute: !1,
|
|
1069
|
-
hasChanged:
|
|
1070
|
-
})],
|
|
1039
|
+
hasChanged: O
|
|
1040
|
+
})], j.prototype, "selectedTalentIds", void 0), r([f({
|
|
1071
1041
|
type: String,
|
|
1072
1042
|
attribute: "asset-base-url"
|
|
1073
|
-
})],
|
|
1043
|
+
})], j.prototype, "assetBaseUrl", void 0), r([f({ attribute: !1 })], j.prototype, "dataSource", void 0), r([f({ attribute: !1 })], j.prototype, "renderTalent", void 0), r([f({
|
|
1074
1044
|
type: Boolean,
|
|
1075
1045
|
attribute: "show-point-controls"
|
|
1076
|
-
})],
|
|
1046
|
+
})], j.prototype, "showPointControls", void 0), r([f({
|
|
1077
1047
|
type: Boolean,
|
|
1078
1048
|
attribute: "show-tooltips"
|
|
1079
|
-
})],
|
|
1080
|
-
var
|
|
1081
|
-
a(), customElements.get("fellowship-talent-calculator") || customElements.define("fellowship-talent-calculator",
|
|
1049
|
+
})], j.prototype, "showTooltips", void 0), r([p()], j.prototype, "_status", void 0), r([p()], j.prototype, "_error", void 0), r([p()], j.prototype, "_model", void 0), r([p()], j.prototype, "_failedImages", void 0), r([p()], j.prototype, "_announcement", void 0), r([p()], j.prototype, "_renderSelectionState", void 0), r([p()], j.prototype, "_talentPresentation", void 0), r([p()], j.prototype, "_talentRenderContent", void 0), j = r([d("fellowship-talent-calculator")], j);
|
|
1050
|
+
var M = () => {
|
|
1051
|
+
a(), customElements.get("fellowship-talent-calculator") || customElements.define("fellowship-talent-calculator", j);
|
|
1082
1052
|
};
|
|
1083
1053
|
//#endregion
|
|
1084
|
-
export {
|
|
1054
|
+
export { T as a, S as c, g as d, x as i, b as l, M as n, w as o, k as r, C as s, j as t, v as u };
|
|
1085
1055
|
|
|
1086
|
-
//# sourceMappingURL=talent-calculator-
|
|
1056
|
+
//# sourceMappingURL=talent-calculator-CIPNbqK5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"talent-calculator-CIPNbqK5.js","names":["#abortController","#flushRendererWarnings","#loadHeroTalents","#skipNextPropertyPointEvent","#emitPointsChange","#normalizeSelections","#reportOverBudget","#rendererFailures","#prepareTalentRenderContent","#emitSelectionChange","#renderHeader","#renderGrid","#renderStatus","#setTalentPoints","#renderTalent","#handleTalentActivation","#renderTalentContent","#pendingRendererWarnings","#renderDefaultTalentIcon","#handleImageError","#loadToken","#lastOverBudgetSignature","#reportWarnings","#setError"],"sources":["../../src/data/package-talent-data-source.ts","../../src/talent-calculator/render-model.ts","../../src/talent-calculator/selection-state.ts","../../src/talent-calculator/talent-calculator.styles.ts","../../src/talent-calculator/talent-calculator.ts"],"sourcesContent":["import { createPackageFellowshipDataClient } from \"@crockery/fellowship-data/client\";\n\nimport type { FellowshipTalentDataSource } from \"./talent-data-source.js\";\n\n/** @deprecated Create a package Fellowship data client instead. */\nexport interface PackageFellowshipTalentDataSourceOptions {\n readonly assetBaseUrl?: string;\n}\n\n/** @deprecated Use `createPackageFellowshipDataClient` from `@crockery/fellowship-data/client`. */\nexport const createPackageFellowshipTalentDataSource = (\n options: PackageFellowshipTalentDataSourceOptions = {},\n): FellowshipTalentDataSource => {\n const client = createPackageFellowshipDataClient(options);\n return {\n loadHeroTalents: (heroId, signal) => client.loadHeroTalents(heroId, signal),\n resolveAssetUrl: (asset) => client.resolveAssetUrl(asset),\n };\n};\n","import { findImage } from \"@crockery/fellowship-data\";\nimport type { Talent } from \"@crockery/fellowship-data\";\n\nimport type {\n FellowshipTalentDataSource,\n TalentCalculatorData,\n} from \"../data/talent-data-source.js\";\nimport type {\n TalentCalculatorRenderModel,\n TalentCalculatorTalentModel,\n TalentCalculatorWarning,\n} from \"./types.js\";\n\nconst romanNumerals = [\"I\", \"II\", \"III\", \"IV\", \"V\", \"VI\"] as const;\n\nexport const talentRowLabel = (row: number): string => romanNumerals[row - 1] ?? String(row);\n\nconst warning = (\n code: TalentCalculatorWarning[\"code\"],\n talent: Talent,\n message: string,\n): TalentCalculatorWarning => ({ code, message, talentId: talent.id });\n\nexport const createTalentCalculatorRenderModel = (\n data: TalentCalculatorData,\n source: FellowshipTalentDataSource,\n): TalentCalculatorRenderModel => {\n const warnings: TalentCalculatorWarning[] = [];\n const occupied = new Set<string>();\n const models: TalentCalculatorTalentModel[] = [];\n\n for (const talent of data.talents) {\n if (talent.row === null && talent.column === null) {\n continue;\n }\n if (\n !Number.isInteger(talent.row) ||\n !Number.isInteger(talent.column) ||\n talent.row === null ||\n talent.column === null ||\n talent.row < 1 ||\n talent.row > 6 ||\n talent.column < 1 ||\n talent.column > 3\n ) {\n warnings.push(\n warning(\n \"invalid-position\",\n talent,\n `Talent “${talent.id}” has an invalid row or column and was skipped.`,\n ),\n );\n continue;\n }\n\n const cell = `${talent.row}:${talent.column}`;\n if (occupied.has(cell)) {\n warnings.push(\n warning(\n \"duplicate-position\",\n talent,\n `Talent “${talent.id}” duplicates row ${talent.row}, column ${talent.column} and was skipped.`,\n ),\n );\n continue;\n }\n occupied.add(cell);\n\n const pointCost =\n Number.isInteger(talent.pointCost) && (talent.pointCost ?? 0) > 0 ? talent.pointCost : null;\n if (pointCost === null) {\n warnings.push(\n warning(\"invalid-cost\", talent, `Talent “${talent.id}” has an invalid point cost.`),\n );\n }\n if (!talent.name) {\n warnings.push(warning(\"missing-name\", talent, `Talent “${talent.id}” has no display name.`));\n }\n if (!talent.description) {\n warnings.push(\n warning(\"missing-description\", talent, `Talent “${talent.id}” has no description.`),\n );\n }\n\n const image =\n findImage(talent.images, { type: \"talent\", size: \"200\" }) ??\n findImage(talent.images, { type: \"talent\", size: \"full\" });\n let imageUrl: string | null = null;\n if (!image) {\n warnings.push(warning(\"missing-image\", talent, `Talent “${talent.id}” has no icon.`));\n } else {\n try {\n imageUrl = source.resolveAssetUrl(image);\n } catch (error: unknown) {\n warnings.push(\n warning(\n \"asset-url-error\",\n talent,\n `The icon URL for talent “${talent.id}” could not be resolved: ${String(error)}.`,\n ),\n );\n }\n }\n\n models.push({\n talent,\n row: talent.row,\n column: talent.column,\n pointCost,\n imageUrl,\n });\n }\n\n models.sort((a, b) => a.row - b.row || a.column - b.column);\n const talentById = new Map(models.map((model) => [model.talent.id, model]));\n const rows = [...new Set(models.map(({ row }) => row))].map((row) => ({\n row,\n label: talentRowLabel(row),\n talents: models.filter((talent) => talent.row === row),\n }));\n\n return { hero: data.hero, rows, talentById, warnings };\n};\n","import type { TalentCalculatorRenderModel, TalentCalculatorSelectionState } from \"./types.js\";\n\nexport const MAX_TALENT_POINTS = 14;\n\nexport const normalizeTalentPoints = (value: number): number =>\n Math.min(\n MAX_TALENT_POINTS,\n Math.max(0, Math.round(Number.isFinite(value) ? value : MAX_TALENT_POINTS)),\n );\n\nexport const normalizeSelectedTalentIds = (\n model: TalentCalculatorRenderModel,\n selectedTalentIds: readonly string[],\n): {\n readonly selectedTalentIds: readonly string[];\n readonly removedTalentIds: readonly string[];\n} => {\n const requested = new Set(selectedTalentIds);\n const selected = [...model.talentById.values()]\n .filter(({ talent }) => requested.has(talent.id))\n .map(({ talent }) => talent.id);\n const selectedSet = new Set(selected);\n const removed = [...new Set(selectedTalentIds)].filter((id) => !selectedSet.has(id));\n return { selectedTalentIds: selected, removedTalentIds: removed };\n};\n\nexport const createTalentCalculatorSelectionState = (\n model: TalentCalculatorRenderModel,\n selectedTalentIds: readonly string[],\n talentPoints: number,\n): TalentCalculatorSelectionState => {\n const selected = new Set(selectedTalentIds);\n const spentPoints = [...model.talentById.values()].reduce(\n (total, talent) =>\n selected.has(talent.talent.id) && talent.pointCost !== null\n ? total + talent.pointCost\n : total,\n 0,\n );\n const remainingPoints = talentPoints - spentPoints;\n return {\n selectedTalentIds: [...model.talentById.values()]\n .filter(({ talent }) => selected.has(talent.id))\n .map(({ talent }) => talent.id),\n spentPoints,\n remainingPoints,\n overBudget: remainingPoints < 0,\n };\n};\n\nexport const canSelectTalent = (\n pointCost: number | null,\n state: TalentCalculatorSelectionState,\n): boolean => pointCost !== null && !state.overBudget && pointCost <= state.remainingPoints;\n","import { css } from \"lit\";\n\nexport const talentCalculatorStyles = css`\n :host {\n --fellowship-talent-background: var(--_fellowship-field-canvas);\n --fellowship-talent-surface: var(--_fellowship-field-surface);\n --fellowship-talent-card-background: var(--_fellowship-field-surface);\n --fellowship-talent-card-selected-background: color-mix(\n in srgb,\n var(--_fellowship-field-surface-raised) 88%,\n var(--_fellowship-field-accent)\n );\n --fellowship-talent-foreground: var(--_fellowship-field-ink);\n --fellowship-talent-muted: var(--_fellowship-field-muted);\n --fellowship-talent-disabled: var(--_fellowship-field-tertiary);\n --fellowship-talent-border: var(--_fellowship-field-border);\n --fellowship-talent-selection: var(--_fellowship-field-accent);\n --fellowship-talent-focus: var(--_fellowship-field-focus);\n --fellowship-talent-points: var(--_fellowship-field-brass);\n --fellowship-talent-danger: var(--_fellowship-field-ember);\n --fellowship-talent-control-surface: var(--_fellowship-field-inset);\n --fellowship-talent-icon-size: 56px;\n --fellowship-talent-font-family: var(--_fellowship-field-font-family);\n --fellowship-talent-tactical-font-family: var(--_fellowship-field-mono-font-family);\n --fellowship-talent-radius: var(--_fellowship-field-radius);\n\n display: block;\n min-width: 0;\n container-type: inline-size;\n color: var(--fellowship-talent-foreground);\n font-family: var(--fellowship-talent-font-family);\n -webkit-font-smoothing: antialiased;\n }\n\n :host([hidden]) {\n display: none;\n }\n\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n }\n\n button {\n font: inherit;\n }\n\n .container {\n min-width: 0;\n padding: 16px;\n border-radius: calc(var(--fellowship-talent-radius) + 2px);\n background: var(--fellowship-talent-background);\n }\n\n .header {\n min-height: 72px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 24px;\n padding: 8px 8px 24px;\n }\n\n .heading {\n margin: 0;\n color: var(--fellowship-talent-muted);\n font-size: 12px;\n font-weight: 600;\n line-height: 16px;\n letter-spacing: 0.12em;\n text-transform: uppercase;\n }\n\n .points-cluster,\n .point-controls {\n display: flex;\n align-items: center;\n }\n\n .points-cluster {\n gap: 16px;\n }\n\n .points {\n display: flex;\n align-items: baseline;\n gap: 4px;\n color: var(--fellowship-talent-foreground);\n font-family: var(--fellowship-talent-tactical-font-family);\n font-size: 32px;\n font-weight: 600;\n line-height: 40px;\n letter-spacing: -0.04em;\n font-variant-numeric: tabular-nums;\n }\n\n .points-spent {\n color: var(--fellowship-talent-points);\n }\n\n .points-separator,\n .points-total {\n color: var(--_fellowship-field-tertiary);\n }\n\n .points-separator {\n font-size: 18px;\n font-weight: 500;\n }\n\n .points[data-invalid=\"true\"],\n .points[data-invalid=\"true\"] .points-spent {\n color: var(--fellowship-talent-danger);\n }\n\n .point-controls {\n gap: 4px;\n padding: 2px;\n border-radius: calc(var(--fellowship-talent-radius) + 2px);\n background: var(--fellowship-talent-control-surface);\n box-shadow: inset 0 0 0 1px var(--fellowship-talent-border);\n }\n\n .point-control {\n width: 40px;\n height: 40px;\n display: inline-grid;\n place-items: center;\n padding: 0;\n border: 0;\n border-radius: 4px;\n background: transparent;\n color: var(--fellowship-talent-muted);\n font-family: var(--fellowship-talent-tactical-font-family);\n font-size: 18px;\n font-weight: 500;\n line-height: 1;\n cursor: pointer;\n transition:\n background-color 120ms cubic-bezier(0.23, 1, 0.32, 1),\n color 120ms cubic-bezier(0.23, 1, 0.32, 1),\n transform 120ms cubic-bezier(0.23, 1, 0.32, 1);\n }\n\n .point-control:active:not(:disabled) {\n transform: scale(0.97);\n }\n\n .point-control:focus-visible,\n .clear-all:focus-visible,\n .talent:focus-visible,\n .retry-button:focus-visible {\n outline: 2px solid var(--fellowship-talent-focus);\n outline-offset: 2px;\n }\n\n .point-control:disabled {\n color: var(--fellowship-talent-disabled);\n cursor: not-allowed;\n opacity: 0.48;\n }\n\n .clear-all {\n min-height: 44px;\n padding: 0 8px;\n border: 0;\n border-radius: 4px;\n background: transparent;\n color: var(--fellowship-talent-muted);\n font-size: 12px;\n font-weight: 600;\n line-height: 1;\n letter-spacing: 0.04em;\n white-space: nowrap;\n cursor: pointer;\n transition:\n background-color 120ms cubic-bezier(0.23, 1, 0.32, 1),\n color 120ms cubic-bezier(0.23, 1, 0.32, 1),\n transform 120ms cubic-bezier(0.23, 1, 0.32, 1);\n }\n\n .clear-all:active:not(:disabled) {\n transform: scale(0.97);\n }\n\n .clear-all:disabled {\n color: var(--fellowship-talent-disabled);\n cursor: not-allowed;\n opacity: 0.42;\n }\n\n .grid {\n display: grid;\n gap: 16px;\n padding: 8px 0 0;\n }\n\n .row {\n min-width: 0;\n min-inline-size: 0;\n width: 100%;\n display: grid;\n grid-template-columns: 48px minmax(0, 1fr);\n align-items: stretch;\n gap: 8px;\n margin: 0;\n padding: 0;\n border: 0;\n }\n\n .row-label {\n position: relative;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 16px;\n color: var(--fellowship-talent-disabled);\n font-family: var(--fellowship-talent-tactical-font-family);\n font-size: 11px;\n font-weight: 600;\n line-height: 16px;\n text-align: center;\n letter-spacing: 0.08em;\n }\n\n .row-label::before {\n position: absolute;\n inset: 0 0 0 auto;\n width: 1px;\n background: var(--fellowship-talent-border);\n content: \"\";\n }\n\n .row-label::after {\n position: absolute;\n top: 23px;\n right: -3px;\n width: 7px;\n height: 1px;\n background: var(--fellowship-talent-selection);\n content: \"\";\n }\n\n .row-talents {\n min-width: 0;\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 8px;\n }\n\n fellowship-tooltip {\n display: block;\n min-width: 0;\n }\n\n .talent {\n position: relative;\n width: 100%;\n min-width: 0;\n min-height: 88px;\n display: grid;\n grid-template-columns: var(--fellowship-talent-icon-size) minmax(0, 1fr);\n align-items: center;\n gap: 16px;\n padding: 16px 36px 16px 16px;\n overflow: hidden;\n border: 1px solid transparent;\n border-radius: var(--fellowship-talent-radius);\n background: var(--fellowship-talent-card-background);\n color: var(--fellowship-talent-foreground);\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--fellowship-talent-border) 64%, transparent);\n text-align: left;\n cursor: pointer;\n transition:\n background-color 140ms cubic-bezier(0.23, 1, 0.32, 1),\n box-shadow 140ms cubic-bezier(0.23, 1, 0.32, 1),\n transform 120ms cubic-bezier(0.23, 1, 0.32, 1),\n opacity 140ms linear;\n }\n\n .talent::before {\n position: absolute;\n top: 16px;\n left: 0;\n width: 2px;\n height: 24px;\n background: transparent;\n content: \"\";\n }\n\n .talent:active:not([aria-disabled=\"true\"]) {\n transform: scale(0.99);\n }\n\n .talent[aria-pressed=\"true\"] {\n background: var(--fellowship-talent-card-selected-background);\n box-shadow: inset 0 0 0 1px\n color-mix(in srgb, var(--fellowship-talent-selection) 32%, transparent);\n }\n\n .talent[aria-pressed=\"true\"]::before {\n background: var(--fellowship-talent-selection);\n }\n\n .talent[aria-disabled=\"true\"] {\n color: var(--fellowship-talent-disabled);\n cursor: not-allowed;\n opacity: 0.46;\n }\n\n .talent-icon,\n .talent-icon-fallback {\n width: var(--fellowship-talent-icon-size);\n height: var(--fellowship-talent-icon-size);\n border-radius: calc(var(--fellowship-talent-radius) - 2px);\n box-shadow: inset 0 0 0 1px var(--fellowship-talent-border);\n }\n\n .talent-icon {\n display: block;\n object-fit: cover;\n }\n\n .talent-icon-fallback {\n display: grid;\n place-items: center;\n background: var(--fellowship-talent-control-surface);\n color: var(--fellowship-talent-muted);\n font-family: var(--fellowship-talent-tactical-font-family);\n font-size: 13px;\n font-weight: 600;\n letter-spacing: 0.08em;\n }\n\n .talent[aria-pressed=\"true\"] .talent-icon,\n .talent[aria-pressed=\"true\"] .talent-icon-fallback {\n box-shadow:\n inset 0 0 0 1px var(--fellowship-talent-border),\n 0 0 0 1px color-mix(in srgb, var(--fellowship-talent-selection) 60%, transparent);\n }\n\n .talent-name {\n min-width: 0;\n overflow: hidden;\n color: currentColor;\n font-size: 16px;\n font-weight: 600;\n line-height: 24px;\n text-overflow: ellipsis;\n text-wrap: balance;\n white-space: nowrap;\n }\n\n .talent-cost {\n position: absolute;\n top: 12px;\n right: 12px;\n color: var(--fellowship-talent-muted);\n font-family: var(--fellowship-talent-tactical-font-family);\n font-size: 11px;\n font-weight: 600;\n line-height: 16px;\n font-variant-numeric: tabular-nums;\n }\n\n .talent[aria-pressed=\"true\"] .talent-cost {\n color: var(--fellowship-talent-focus);\n }\n\n .status {\n min-height: 256px;\n display: grid;\n place-items: center;\n padding: 32px;\n color: var(--fellowship-talent-muted);\n text-align: center;\n }\n\n .status-card {\n max-width: 480px;\n }\n\n .status-mark {\n display: flex;\n width: 40px;\n height: 24px;\n align-items: center;\n justify-content: space-between;\n margin: 0 auto 16px;\n color: var(--fellowship-talent-points);\n font-family: var(--fellowship-talent-tactical-font-family);\n font-size: 16px;\n }\n\n .status-mark::before,\n .status-mark::after {\n width: 8px;\n height: 1px;\n background: var(--fellowship-talent-border);\n content: \"\";\n }\n\n .status-title {\n margin: 0;\n color: var(--fellowship-talent-foreground);\n font-size: 18px;\n font-weight: 600;\n line-height: 24px;\n text-wrap: balance;\n }\n\n .status-copy {\n margin: 8px 0 0;\n font-size: 14px;\n line-height: 24px;\n text-wrap: pretty;\n }\n\n .retry-button {\n min-height: 44px;\n margin-top: 24px;\n padding: 0 16px;\n border: 1px solid var(--fellowship-talent-border);\n border-radius: 4px;\n background: var(--fellowship-talent-control-surface);\n color: var(--fellowship-talent-foreground);\n font-weight: 600;\n cursor: pointer;\n }\n\n .visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n @media (hover: hover) {\n .point-control:hover:not(:disabled) {\n background: var(--fellowship-talent-surface);\n color: var(--fellowship-talent-foreground);\n }\n\n .clear-all:hover:not(:disabled) {\n background: color-mix(in srgb, var(--fellowship-talent-danger) 8%, transparent);\n color: var(--fellowship-talent-danger);\n }\n\n .talent:hover:not([aria-disabled=\"true\"]) {\n background: var(--_fellowship-field-surface-raised);\n box-shadow: inset 0 0 0 1px var(--fellowship-talent-border);\n }\n }\n\n @container (max-width: 719px) {\n .container {\n padding: 16px 12px;\n }\n\n .header {\n min-height: 80px;\n grid-template-columns: 1fr;\n display: grid;\n gap: 8px;\n padding: 4px 4px 20px;\n }\n\n .heading {\n font-size: 11px;\n }\n\n .points-cluster {\n width: 100%;\n flex-wrap: wrap;\n justify-content: flex-start;\n gap: 8px;\n }\n\n .points {\n font-size: 28px;\n line-height: 36px;\n }\n\n .grid {\n gap: 24px;\n }\n\n .row {\n grid-template-columns: 1fr;\n gap: 8px;\n }\n\n .row-label {\n min-height: 24px;\n align-items: center;\n justify-content: flex-start;\n padding: 0 0 0 16px;\n text-align: left;\n }\n\n .row-label::before {\n inset: 12px auto auto 0;\n width: 8px;\n height: 1px;\n }\n\n .row-label::after {\n top: 9px;\n right: auto;\n left: 0;\n width: 1px;\n height: 7px;\n }\n\n .row-talents {\n grid-template-columns: 1fr;\n gap: 8px;\n }\n\n .talent {\n --fellowship-talent-icon-size: 52px;\n\n min-height: 80px;\n padding-block: 12px;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .point-control,\n .clear-all,\n .talent {\n transition:\n background-color 100ms linear,\n box-shadow 100ms linear,\n color 100ms linear,\n opacity 100ms linear;\n }\n\n .point-control:active:not(:disabled),\n .clear-all:active:not(:disabled),\n .talent:active:not([aria-disabled=\"true\"]) {\n transform: none;\n }\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 { FellowshipDataError } from \"../data/data-source.js\";\nimport { createPackageFellowshipTalentDataSource } from \"../data/package-talent-data-source.js\";\nimport type { FellowshipTalentDataSource } from \"../data/talent-data-source.js\";\nimport { fieldManualStyles } from \"../styles/field-manual.styles.js\";\nimport { installFieldManualFonts } from \"../styles/field-manual-fonts.js\";\nimport { stripFellowshipRichText } from \"../tooltip/rich-text.js\";\nimport { defineFellowshipTooltip } from \"../tooltip/tooltip.js\";\nimport { createTalentCalculatorRenderModel } from \"./render-model.js\";\nimport {\n canSelectTalent,\n createTalentCalculatorSelectionState,\n MAX_TALENT_POINTS,\n normalizeSelectedTalentIds,\n normalizeTalentPoints,\n} from \"./selection-state.js\";\nimport { talentCalculatorStyles } from \"./talent-calculator.styles.js\";\nimport type {\n FellowshipTalentsErrorDetail,\n FellowshipTalentsReadyDetail,\n FellowshipTalentsWarningDetail,\n LitTalentRenderer,\n TalentCalculatorRenderModel,\n TalentCalculatorSelectionState,\n TalentCalculatorTalentModel,\n TalentCalculatorTalentRenderContext,\n TalentCalculatorWarning,\n TalentPointsChangeDetail,\n TalentPointsChangeSource,\n TalentSelectionChangeDetail,\n TalentSelectionChangeSource,\n} from \"./types.js\";\n\ntype ComponentStatus = \"empty\" | \"loading\" | \"ready\" | \"error\";\n\ninterface TalentPresentation {\n readonly context: TalentCalculatorTalentRenderContext;\n readonly name: string;\n readonly descriptionId: string;\n readonly affordability: string;\n readonly description: string;\n}\n\nconst eventOptions = { bubbles: true, composed: true } as const;\n\nconst stringArrayChanged = (\n value: readonly string[],\n previous: readonly string[] | undefined,\n): boolean =>\n value.length !== previous?.length || value.some((item, index) => item !== previous[index]);\n\nexport const talentSlotName = (talentId: string): string => `talent:${talentId}`;\n\nconst fallbackSelectionState = (talentPoints: number): TalentCalculatorSelectionState => ({\n selectedTalentIds: [],\n spentPoints: 0,\n remainingPoints: talentPoints,\n overBudget: false,\n});\n\nexport { MAX_TALENT_POINTS };\n\n/**\n * @fires fellowship-talents-ready - Fired after talent data is loaded and rendered.\n * @fires fellowship-talents-error - Fired when talent data cannot be loaded.\n * @fires fellowship-talents-warning - Fired for recoverable data and renderer issues.\n * @fires fellowship-talent-selection-change - Fired when selected talents change.\n * @fires fellowship-talent-points-change - Fired when the point budget changes.\n */\n@customElement(\"fellowship-talent-calculator\")\nexport class FellowshipTalentCalculatorElement extends LitElement {\n static override styles = [fieldManualStyles, talentCalculatorStyles];\n\n @property({ type: String, attribute: \"hero-id\" }) heroId = \"\";\n @property({ type: Number, attribute: \"talent-points\" }) talentPoints = MAX_TALENT_POINTS;\n @property({ attribute: false, hasChanged: stringArrayChanged })\n selectedTalentIds: readonly string[] = [];\n @property({ type: String, attribute: \"asset-base-url\" }) assetBaseUrl: string | null = null;\n @property({ attribute: false }) dataSource: FellowshipTalentDataSource | null = null;\n @property({ attribute: false }) renderTalent: LitTalentRenderer | null = null;\n @property({ type: Boolean, attribute: \"show-point-controls\" }) showPointControls = true;\n @property({ type: Boolean, attribute: \"show-tooltips\" }) showTooltips = true;\n\n @state() private _status: ComponentStatus = \"empty\";\n @state() private _error: FellowshipTalentsErrorDetail | null = null;\n @state() private _model: TalentCalculatorRenderModel | null = null;\n @state() private _failedImages = new Set<string>();\n @state() private _announcement = \"\";\n @state() private _renderSelectionState = fallbackSelectionState(MAX_TALENT_POINTS);\n @state() private _talentPresentation = new Map<string, TalentPresentation>();\n @state() private _talentRenderContent = new Map<string, unknown>();\n\n #abortController: AbortController | null = null;\n #loadToken = 0;\n #lastOverBudgetSignature: string | null = null;\n #skipNextPropertyPointEvent = false;\n #rendererFailures = new Set<string>();\n #pendingRendererWarnings: TalentCalculatorWarning[] = [];\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 this.#flushRendererWarnings();\n\n if (changed.has(\"heroId\") || changed.has(\"dataSource\") || changed.has(\"assetBaseUrl\")) {\n queueMicrotask(() => {\n if (this.isConnected) {\n void this.#loadHeroTalents();\n }\n });\n return;\n }\n\n if (changed.has(\"talentPoints\")) {\n const normalized = normalizeTalentPoints(this.talentPoints);\n if (normalized !== this.talentPoints) {\n this.#skipNextPropertyPointEvent = true;\n this.talentPoints = normalized;\n this.#emitPointsChange(\"normalization\");\n return;\n }\n if (this.#skipNextPropertyPointEvent) {\n this.#skipNextPropertyPointEvent = false;\n } else if (changed.get(\"talentPoints\") !== undefined) {\n this.#emitPointsChange(\"property\");\n }\n }\n\n if (changed.has(\"selectedTalentIds\") && this._model) {\n this.#normalizeSelections(true);\n }\n\n this.#reportOverBudget();\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n\n const selectionChanged =\n changed.has(\"_model\") || changed.has(\"selectedTalentIds\") || changed.has(\"talentPoints\");\n if (selectionChanged) {\n this._renderSelectionState = this._model\n ? createTalentCalculatorSelectionState(\n this._model,\n this.selectedTalentIds,\n this.talentPoints,\n )\n : fallbackSelectionState(this.talentPoints);\n }\n\n if (changed.has(\"renderTalent\")) {\n this.#rendererFailures.clear();\n }\n if (selectionChanged || changed.has(\"renderTalent\")) {\n this.#prepareTalentRenderContent(this._renderSelectionState);\n }\n }\n\n get renderModel(): TalentCalculatorRenderModel | null {\n return this._model;\n }\n\n get selectionState(): TalentCalculatorSelectionState {\n return this._model\n ? createTalentCalculatorSelectionState(this._model, this.selectedTalentIds, this.talentPoints)\n : fallbackSelectionState(this.talentPoints);\n }\n\n reset(): void {\n if (this.selectedTalentIds.length === 0) {\n return;\n }\n this.selectedTalentIds = [];\n this.#emitSelectionChange(\"reset\");\n }\n\n selectTalent(talentId: string): boolean {\n const model = this._model?.talentById.get(talentId);\n const state = this.selectionState;\n if (\n !model ||\n state.selectedTalentIds.includes(talentId) ||\n !canSelectTalent(model.pointCost, state)\n ) {\n return false;\n }\n this.selectedTalentIds = [...state.selectedTalentIds, talentId];\n this.#emitSelectionChange(\"api\");\n return true;\n }\n\n deselectTalent(talentId: string): boolean {\n if (!this.selectionState.selectedTalentIds.includes(talentId)) {\n return false;\n }\n this.selectedTalentIds = this.selectionState.selectedTalentIds.filter((id) => id !== talentId);\n this.#emitSelectionChange(\"api\");\n return true;\n }\n\n retry(): void {\n void this.#loadHeroTalents();\n }\n\n override render(): TemplateResult {\n const state = this._renderSelectionState;\n const label = this._model?.hero.name ?? this._model?.hero.id ?? \"Fellowship hero\";\n return html`\n <section\n class=\"container\"\n part=\"container\"\n aria-label=${`${label} talent calculator`}\n aria-invalid=${String(state.overBudget)}\n >\n ${this.#renderHeader(state)}\n ${\n this._status === \"ready\" && this._model\n ? this.#renderGrid(this._model)\n : this.#renderStatus()\n }\n <p class=\"visually-hidden\" role=\"status\" aria-live=\"polite\">${this._announcement}</p>\n </section>\n `;\n }\n\n #renderHeader(state: TalentCalculatorSelectionState): TemplateResult {\n return html`\n <header class=\"header\" part=\"header\">\n <h2 class=\"heading\" part=\"heading\">Talent points</h2>\n <div class=\"points-cluster\">\n <div\n class=\"points\"\n part=\"points\"\n data-invalid=${String(state.overBudget)}\n aria-label=${`${state.spentPoints} of ${this.talentPoints} talent points spent`}\n aria-live=\"polite\"\n >\n <span class=\"points-spent\" part=\"points-spent\">${state.spentPoints}</span>\n <span class=\"points-separator\" aria-hidden=\"true\">/</span>\n <span class=\"points-total\" part=\"points-total\">${this.talentPoints}</span>\n </div>\n ${\n this.showPointControls\n ? html`\n <div\n class=\"point-controls\"\n part=\"point-controls\"\n role=\"group\"\n aria-label=\"Talent points\"\n >\n <button\n class=\"point-control\"\n part=\"point-control\"\n type=\"button\"\n aria-label=\"Decrease available talent points\"\n title=\"Decrease available talent points\"\n ?disabled=${this.talentPoints <= state.spentPoints}\n @click=${() => this.#setTalentPoints(this.talentPoints - 1, \"decrement\")}\n >\n −\n </button>\n <button\n class=\"point-control\"\n part=\"point-control\"\n type=\"button\"\n aria-label=\"Increase available talent points\"\n title=\"Increase available talent points\"\n ?disabled=${this.talentPoints >= MAX_TALENT_POINTS}\n @click=${() => this.#setTalentPoints(this.talentPoints + 1, \"increment\")}\n >\n +\n </button>\n </div>\n `\n : nothing\n }\n <button\n class=\"clear-all\"\n part=\"clear-all\"\n type=\"button\"\n ?disabled=${state.selectedTalentIds.length === 0}\n @click=${this.reset}\n >\n Clear All\n </button>\n </div>\n </header>\n `;\n }\n\n #renderGrid(model: TalentCalculatorRenderModel): TemplateResult {\n if (model.rows.length === 0) {\n return html`\n <div class=\"status\" part=\"empty-state\" role=\"status\">\n <div class=\"status-card\">\n <div class=\"status-mark\" aria-hidden=\"true\">◇</div>\n <p class=\"status-title\">No active talents</p>\n <p class=\"status-copy\">\n ${model.hero.name ?? model.hero.id} has no positioned talents.\n </p>\n </div>\n </div>\n `;\n }\n\n return html`\n <div class=\"grid\" part=\"grid\" role=\"group\" aria-label=\"Talent tiers\">\n ${repeat(\n model.rows,\n (row) => row.row,\n (row) => html`\n <fieldset class=\"row\" part=\"row\">\n <legend class=\"visually-hidden\">Talent tier ${row.label}</legend>\n <span class=\"row-label\" part=\"row-label\" aria-hidden=\"true\">${row.label}</span>\n <div class=\"row-talents\">\n ${repeat(\n row.talents,\n (talent) => talent.talent.id,\n (talent) => this.#renderTalent(talent),\n )}\n </div>\n </fieldset>\n `,\n )}\n </div>\n `;\n }\n\n #renderTalent(talent: TalentCalculatorTalentModel): TemplateResult | typeof nothing {\n const presentation = this._talentPresentation.get(talent.talent.id);\n if (!presentation) {\n return nothing;\n }\n const { context, name, descriptionId, affordability, description } = presentation;\n const { selected, disabled } = context;\n const card = html`\n <button\n class=\"talent\"\n part=\"talent\"\n type=\"button\"\n aria-label=${`${name}, ${affordability}`}\n aria-describedby=${descriptionId}\n aria-pressed=${String(selected)}\n aria-disabled=${String(disabled)}\n @click=${() => this.#handleTalentActivation(talent, selected, disabled)}\n >\n ${this.#renderTalentContent(context)}\n <span class=\"talent-cost\" part=\"talent-cost\">${talent.pointCost ?? \"–\"}</span>\n </button>\n `;\n\n return html`\n ${\n this.showTooltips && (talent.talent.description || disabled)\n ? html`\n <fellowship-tooltip\n .heading=${name}\n .text=${talent.talent.description ?? affordability}\n >\n ${card}\n </fellowship-tooltip>\n `\n : card\n }\n <span class=\"visually-hidden\" id=${descriptionId}>${description}</span>\n `;\n }\n\n #prepareTalentRenderContent(state: TalentCalculatorSelectionState): void {\n const renderer = this.renderTalent;\n const model = this._model;\n const content = new Map<string, unknown>();\n const presentations = new Map<string, TalentPresentation>();\n\n if (model) {\n for (const talent of model.talentById.values()) {\n const selected = state.selectedTalentIds.includes(talent.talent.id);\n const affordable = canSelectTalent(talent.pointCost, state);\n const disabled = !selected && !affordable;\n const name = talent.talent.name ?? talent.talent.id;\n const affordability =\n talent.pointCost === null\n ? \"This talent has no valid point cost.\"\n : disabled\n ? `Requires ${talent.pointCost} talent points; ${Math.max(0, state.remainingPoints)} remaining.`\n : `${talent.pointCost} talent ${talent.pointCost === 1 ? \"point\" : \"points\"}.`;\n const context: TalentCalculatorTalentRenderContext = {\n talent,\n hero: model.hero,\n selected,\n affordable,\n disabled,\n spentPoints: state.spentPoints,\n remainingPoints: state.remainingPoints,\n talentPoints: this.talentPoints,\n };\n presentations.set(talent.talent.id, {\n context,\n name,\n descriptionId: `talent-description-${talent.row}-${talent.column}`,\n affordability,\n description: [stripFellowshipRichText(talent.talent.description ?? \"\"), affordability]\n .filter(Boolean)\n .join(\" \"),\n });\n if (!renderer) {\n continue;\n }\n try {\n content.set(talent.talent.id, renderer(context));\n } catch (error: unknown) {\n if (!this.#rendererFailures.has(talent.talent.id)) {\n this.#rendererFailures.add(talent.talent.id);\n this.#pendingRendererWarnings.push({\n code: \"renderer-error\",\n message: `The talent renderer failed for “${talent.talent.id}”: ${String(error)}.`,\n talentId: talent.talent.id,\n });\n }\n }\n }\n }\n\n this._talentPresentation = presentations;\n this._talentRenderContent = content;\n }\n\n #renderTalentContent(context: TalentCalculatorTalentRenderContext): unknown {\n const talent = context.talent;\n const name = talent.talent.name ?? talent.talent.id;\n const content =\n this.renderTalent && this._talentRenderContent.has(talent.talent.id)\n ? this._talentRenderContent.get(talent.talent.id)\n : html`\n <slot name=${talentSlotName(talent.talent.id)}>\n <span class=\"talent-name\" part=\"talent-name\" title=${name}>${name}</span>\n </slot>\n `;\n\n return html`\n ${this.#renderDefaultTalentIcon(talent, name)} ${content}\n `;\n }\n\n #renderDefaultTalentIcon(talent: TalentCalculatorTalentModel, name: string): TemplateResult {\n if (talent.imageUrl && !this._failedImages.has(talent.talent.id)) {\n return html`\n <img\n class=\"talent-icon\"\n part=\"talent-icon\"\n src=${talent.imageUrl}\n alt=\"\"\n draggable=\"false\"\n @error=${() => this.#handleImageError(talent)}\n />\n `;\n }\n const rune = name\n .split(/\\s+/)\n .map((part) => part[0])\n .join(\"\")\n .slice(0, 2)\n .toUpperCase();\n return html`<span class=\"talent-icon-fallback\" part=\"talent-icon-fallback\">${rune}</span>`;\n }\n\n #renderStatus(): TemplateResult {\n const loading = this._status === \"loading\";\n const empty = this._status === \"empty\";\n const title = loading\n ? \"Reading talent codex\"\n : empty\n ? \"Choose a hero\"\n : \"Talents unavailable\";\n const copy = loading\n ? \"Loading the hero and their available talents.\"\n : empty\n ? \"Set the hero-id attribute or heroId property to build a talent loadout.\"\n : (this._error?.message ?? \"An unexpected talent data error occurred.\");\n return html`\n <div\n class=\"status\"\n part=${this._status === \"error\" ? \"error-state\" : \"status\"}\n role=${this._status === \"error\" ? \"alert\" : \"status\"}\n >\n <div class=\"status-card\">\n <div class=\"status-mark\" aria-hidden=\"true\">${loading ? \"…\" : \"✦\"}</div>\n <p class=\"status-title\">${title}</p>\n <p class=\"status-copy\">${copy}</p>\n ${\n this._status === \"error\"\n ? html`<button class=\"retry-button\" type=\"button\" @click=${this.retry}>Retry</button>`\n : nothing\n }\n </div>\n </div>\n `;\n }\n\n async #loadHeroTalents(): Promise<void> {\n const heroId = this.heroId.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._failedImages = new Set();\n this.#rendererFailures.clear();\n this.#lastOverBudgetSignature = null;\n\n if (!heroId) {\n this._status = \"empty\";\n return;\n }\n\n this._status = \"loading\";\n const source =\n this.dataSource ??\n createPackageFellowshipTalentDataSource(\n this.assetBaseUrl ? { assetBaseUrl: this.assetBaseUrl } : {},\n );\n\n try {\n const data = await source.loadHeroTalents(heroId, this.#abortController.signal);\n if (token !== this.#loadToken || this.#abortController.signal.aborted) {\n return;\n }\n if (data.manifest.schemaVersion !== 1) {\n throw new FellowshipDataError(\n \"unsupported-schema\",\n `Unsupported fellowship-data schema version: ${String(data.manifest.schemaVersion)}.`,\n );\n }\n const model = createTalentCalculatorRenderModel(data, source);\n this._model = model;\n this._status = \"ready\";\n const normalized = this.#normalizeSelections(false);\n await this.updateComplete;\n const selection = this.selectionState;\n this.dispatchEvent(\n new CustomEvent<FellowshipTalentsReadyDetail>(\"fellowship-talents-ready\", {\n ...eventOptions,\n detail: { data, model, selection },\n }),\n );\n if (model.warnings.length > 0) {\n this.#reportWarnings(model.warnings);\n }\n if (normalized) {\n this.#emitSelectionChange(\"normalization\");\n }\n this.#reportOverBudget();\n } catch (error: unknown) {\n if (token !== this.#loadToken || this.#abortController.signal.aborted) {\n return;\n }\n this.#setError(error);\n }\n }\n\n #normalizeSelections(emit: boolean): boolean {\n if (!this._model) {\n return false;\n }\n const normalized = normalizeSelectedTalentIds(this._model, this.selectedTalentIds);\n const changed =\n normalized.selectedTalentIds.length !== this.selectedTalentIds.length ||\n normalized.selectedTalentIds.some((id, index) => id !== this.selectedTalentIds[index]);\n if (!changed) {\n return false;\n }\n this.selectedTalentIds = normalized.selectedTalentIds;\n if (normalized.removedTalentIds.length > 0) {\n this.#reportWarnings([\n {\n code: \"invalid-selection\",\n message: `Removed unavailable talent selections: ${normalized.removedTalentIds.join(\", \")}.`,\n talentId: null,\n },\n ]);\n }\n if (emit) {\n this.#emitSelectionChange(\"normalization\");\n }\n return true;\n }\n\n #handleTalentActivation(\n talent: TalentCalculatorTalentModel,\n selected: boolean,\n disabled: boolean,\n ): void {\n if (selected) {\n this.selectedTalentIds = this.selectionState.selectedTalentIds.filter(\n (id) => id !== talent.talent.id,\n );\n this.#emitSelectionChange(\"user\");\n return;\n }\n if (disabled) {\n this._announcement = this.selectionState.overBudget\n ? \"The current build exceeds the available talent points. Deselect a talent first.\"\n : `Not enough points for ${talent.talent.name ?? talent.talent.id}.`;\n return;\n }\n this.selectedTalentIds = [...this.selectionState.selectedTalentIds, talent.talent.id];\n this.#emitSelectionChange(\"user\");\n }\n\n #setTalentPoints(value: number, source: TalentPointsChangeSource): void {\n const normalized = normalizeTalentPoints(value);\n const state = this.selectionState;\n if (normalized === this.talentPoints || normalized < state.spentPoints) {\n return;\n }\n this.talentPoints = normalized;\n this.#skipNextPropertyPointEvent = true;\n this.#emitPointsChange(source);\n }\n\n #emitSelectionChange(source: TalentSelectionChangeSource): void {\n const state = this._model\n ? createTalentCalculatorSelectionState(this._model, this.selectedTalentIds, this.talentPoints)\n : fallbackSelectionState(this.talentPoints);\n this.dispatchEvent(\n new CustomEvent<TalentSelectionChangeDetail>(\"fellowship-talent-selection-change\", {\n ...eventOptions,\n detail: { ...state, source },\n }),\n );\n }\n\n #emitPointsChange(source: TalentPointsChangeSource): void {\n const state = this.selectionState;\n this.dispatchEvent(\n new CustomEvent<TalentPointsChangeDetail>(\"fellowship-talent-points-change\", {\n ...eventOptions,\n detail: { ...state, talentPoints: this.talentPoints, source },\n }),\n );\n }\n\n #reportOverBudget(): void {\n const state = this.selectionState;\n if (!state.overBudget) {\n this.#lastOverBudgetSignature = null;\n this.removeAttribute(\"aria-invalid\");\n return;\n }\n this.setAttribute(\"aria-invalid\", \"true\");\n const signature = `${this.talentPoints}:${state.selectedTalentIds.join(\",\")}`;\n if (signature === this.#lastOverBudgetSignature) {\n return;\n }\n this.#lastOverBudgetSignature = signature;\n this.#reportWarnings([\n {\n code: \"over-budget\",\n message: `The selected talents cost ${state.spentPoints} points, exceeding the ${this.talentPoints}-point budget.`,\n talentId: null,\n },\n ]);\n }\n\n #handleImageError(talent: TalentCalculatorTalentModel): void {\n if (this._failedImages.has(talent.talent.id)) {\n return;\n }\n this._failedImages = new Set(this._failedImages).add(talent.talent.id);\n this.#reportWarnings([\n {\n code: \"asset-image-error\",\n message: `The icon for talent “${talent.talent.id}” could not be loaded.`,\n talentId: talent.talent.id,\n },\n ]);\n }\n\n #reportWarnings(warnings: readonly TalentCalculatorWarning[]): void {\n this.dispatchEvent(\n new CustomEvent<FellowshipTalentsWarningDetail>(\"fellowship-talents-warning\", {\n ...eventOptions,\n detail: { warnings, model: this._model },\n }),\n );\n }\n\n #flushRendererWarnings(): void {\n if (this.#pendingRendererWarnings.length === 0) {\n return;\n }\n const warnings = this.#pendingRendererWarnings;\n this.#pendingRendererWarnings = [];\n this.#reportWarnings(warnings);\n }\n\n #setError(error: unknown): void {\n const detail: FellowshipTalentsErrorDetail =\n typeof error === \"object\" && error !== null && \"code\" in error && \"message\" in error\n ? {\n code: String(error.code),\n message: String(error.message),\n ...(error instanceof FellowshipDataError && error.cause !== undefined\n ? { cause: error.cause }\n : {}),\n }\n : { code: \"unknown\", message: error instanceof Error ? error.message : String(error) };\n this._error = detail;\n this._status = \"error\";\n this.dispatchEvent(\n new CustomEvent<FellowshipTalentsErrorDetail>(\"fellowship-talents-error\", {\n ...eventOptions,\n detail,\n }),\n );\n }\n}\n\nexport const defineFellowshipTalentCalculator = (): void => {\n defineFellowshipTooltip();\n if (!customElements.get(\"fellowship-talent-calculator\")) {\n customElements.define(\"fellowship-talent-calculator\", FellowshipTalentCalculatorElement);\n }\n};\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"fellowship-talent-calculator\": FellowshipTalentCalculatorElement;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { DungeonCastData } from "@crockery/fellowship-data/client";
|
|
2
|
+
import type { FellowshipDataClient } from "@crockery/fellowship-data/client";
|
|
3
|
+
/** @deprecated Use the corresponding `FellowshipDataClient` methods. */
|
|
4
|
+
export type FellowshipCastDataSource = Pick<FellowshipDataClient, "loadDungeonCasts" | "resolveAssetUrl">;
|
|
5
|
+
//# sourceMappingURL=cast-data-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cast-data-source.d.ts","sourceRoot":"","sources":["../../src/data/cast-data-source.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAExE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAE7E,wEAAwE;AACxE,MAAM,MAAM,wBAAwB,GAAG,IAAI,CACzC,oBAAoB,EACpB,kBAAkB,GAAG,iBAAiB,CACvC,CAAC"}
|