@crockery/fellowship-components 0.4.1 → 1.0.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 (64) hide show
  1. package/README.md +31 -17
  2. package/RELEASING.md +2 -2
  3. package/THIRD_PARTY_LICENSES.md +12 -0
  4. package/dist/assets/dm-mono-latin-400-normal-4GdczIuU.woff2 +0 -0
  5. package/dist/assets/dm-mono-latin-500-normal-DRMDZjhP.woff2 +0 -0
  6. package/dist/assets/syne-latin-700-normal-AF3Rs61n.woff2 +0 -0
  7. package/dist/assets/syne-latin-800-normal-EehdNYzx.woff2 +0 -0
  8. package/dist/chunks/decorate-DyMgX_Uh.js +9 -0
  9. package/dist/chunks/{dungeon-cast-browser-CSnu3gC5.js → dungeon-cast-browser-DdG8klca.js} +62 -58
  10. package/dist/chunks/{dungeon-map-CutIcCVP.js → dungeon-map-D0-DAjZ9.js} +130 -131
  11. package/dist/chunks/{decorate-B_ZTN9li.js → field-manual-fonts-DTFloVFe.js} +18 -23
  12. package/dist/chunks/gear-planner-Bgt77Ovf.js +1696 -0
  13. package/dist/chunks/{talent-calculator-Dxuc2dZ8.js → talent-calculator-DbU6P1AP.js} +36 -35
  14. package/dist/chunks/tooltip-C3SSJw-t.js +482 -0
  15. package/dist/data/cast-data-source.d.ts +1 -1
  16. package/dist/data/data-source.d.ts +1 -1
  17. package/dist/data/package-cast-data-source.d.ts +1 -5
  18. package/dist/data/package-data-source.d.ts +1 -5
  19. package/dist/data/package-talent-data-source.d.ts +1 -5
  20. package/dist/data/talent-data-source.d.ts +1 -1
  21. package/dist/dungeon-cast-browser/dungeon-cast-browser.d.ts +2 -1
  22. package/dist/dungeon-cast-browser/render-model.d.ts +3 -2
  23. package/dist/dungeon-cast-browser/types.d.ts +2 -2
  24. package/dist/dungeon-cast-browser.js +1 -1
  25. package/dist/dungeon-map/dungeon-map.d.ts +2 -1
  26. package/dist/dungeon-map/render-model.d.ts +3 -3
  27. package/dist/dungeon-map/types.d.ts +2 -2
  28. package/dist/dungeon-map.js +1 -1
  29. package/dist/gear-planner/gear-planner.d.ts +36 -0
  30. package/dist/gear-planner/gear-planner.styles.d.ts +1 -0
  31. package/dist/gear-planner/gear-position.d.ts +19 -0
  32. package/dist/gear-planner/index.d.ts +2 -0
  33. package/dist/gear-planner/item-workbench.d.ts +18 -0
  34. package/dist/gear-planner/item-workbench.styles.d.ts +1 -0
  35. package/dist/gear-planner/types.d.ts +24 -0
  36. package/dist/gear-planner.js +5 -0
  37. package/dist/index.d.ts +6 -5
  38. package/dist/index.js +9 -7
  39. package/dist/react/dungeon-cast-browser.d.ts +8 -3
  40. package/dist/react/dungeon-cast-browser.js +11 -4
  41. package/dist/react/dungeon-map.d.ts +3 -1
  42. package/dist/react/dungeon-map.js +1 -1
  43. package/dist/react/gear-planner.d.ts +14 -0
  44. package/dist/react/gear-planner.js +23 -0
  45. package/dist/react/index.d.ts +2 -0
  46. package/dist/react/talent-calculator.d.ts +3 -1
  47. package/dist/react/talent-calculator.js +1 -1
  48. package/dist/react/tooltip.js +1 -1
  49. package/dist/react.js +2 -1
  50. package/dist/styles/dungeon-poster-fonts.d.ts +2 -0
  51. package/dist/styles/dungeon-poster.styles.d.ts +7 -0
  52. package/dist/talent-calculator/render-model.d.ts +3 -2
  53. package/dist/talent-calculator/talent-calculator.d.ts +2 -1
  54. package/dist/talent-calculator/types.d.ts +2 -2
  55. package/dist/talent-calculator.js +1 -1
  56. package/dist/tooltip.js +3 -3
  57. package/package.json +15 -2
  58. package/src/dungeon-cast-browser/README.md +10 -4
  59. package/src/dungeon-map/README.md +5 -6
  60. package/src/gear-planner/README.md +44 -0
  61. package/src/talent-calculator/README.md +5 -6
  62. package/src/tooltip/README.md +5 -6
  63. package/dist/chunks/data-source-XbksqUrw.js +0 -7
  64. package/dist/chunks/tooltip-DoQVSnOn.js +0 -410
@@ -66,10 +66,11 @@ map loading, canvas drawing, positioning, and viewport interactions.
66
66
 
67
67
  ## Data and assets
68
68
 
69
- Set `assetBaseUrl` to self-host package images:
69
+ Provide the application-owned image resolver separately from the data source:
70
70
 
71
71
  ```ts
72
- map.assetBaseUrl = "https://static.example.com/fellowship-data/v1.0.0/";
72
+ map.resolveAssetUrl = (asset) =>
73
+ new URL(asset.path, "https://static.example.com/fellowship/").href;
73
74
  ```
74
75
 
75
76
  Replace `dataSource` for filtered, experimental, remote, or application-owned data:
@@ -83,9 +84,6 @@ const source: FellowshipDataSource = {
83
84
  async loadDungeon(dungeonId, signal) {
84
85
  return applicationData.loadDungeon(dungeonId, signal);
85
86
  },
86
- resolveAssetUrl(asset) {
87
- return new URL(asset.path, "https://static.example.com/").href;
88
- },
89
87
  };
90
88
 
91
89
  map.dataSource = source;
@@ -97,7 +95,8 @@ map.dataSource = source;
97
95
 
98
96
  - `dungeonId: string`
99
97
  - `mapImageId: string | null`
100
- - `assetBaseUrl: string | null` — `null` uses the package-pinned CDN.
98
+ - `resolveAssetUrl: ImageAssetUrlResolver` — required and assigned as a
99
+ JavaScript property.
101
100
  - `dataSource: FellowshipDataSource | null` — `null` uses the package provider.
102
101
  - `renderEnemy: LitEnemyRenderer | null`
103
102
  - `renderGroup: LitGroupRenderer | null`
@@ -0,0 +1,44 @@
1
+ # Gear Planner
2
+
3
+ `<fellowship-gear-planner>` is a controlled, responsive editor for serializable
4
+ Fellowship loadouts.
5
+
6
+ ```ts
7
+ import gearPlannerData, {
8
+ createEmptyGearPlannerBuild,
9
+ } from "@crockery/fellowship-data/gear-planner";
10
+ import "@crockery/fellowship-components/gear-planner";
11
+
12
+ const planner = document.querySelector("fellowship-gear-planner");
13
+ planner.data = gearPlannerData;
14
+ planner.build = createEmptyGearPlannerBuild(
15
+ gearPlannerData,
16
+ gearPlannerData.heroes[0].hero.id,
17
+ );
18
+ planner.resolveAssetUrl = (asset) =>
19
+ new URL(asset.path, "https://static.example.com/fellowship/").href;
20
+ planner.addEventListener("fellowship-gear-build-change", (event) => {
21
+ planner.build = event.detail.build;
22
+ });
23
+ ```
24
+
25
+ The element never persists or mutates `build`. Its public properties are
26
+ `data`, `build`, `loading`, `error`, and the required `resolveAssetUrl`
27
+ callback.
28
+ `fellowship-gear-build-change` bubbles and is composed; its detail includes the
29
+ complete proposed build, change source, and affected position.
30
+ `fellowship-gear-planner-error` reports recoverable presentation failures.
31
+
32
+ The React wrapper is exported from
33
+ `@crockery/fellowship-components/react/gear-planner` as `GearPlanner`, with
34
+ `onBuildChange` and `onPlannerError` event props.
35
+
36
+ At 1200px and above, the component renders summary and slot rails around a
37
+ persistent workbench. Below 1200px it uses Traits & gems, Gear, and Bonuses tabs,
38
+ with configuration in a full-height focus-contained editor. Item choices are
39
+ filtered by the Data package, all changes are immediate, and unsupported
40
+ mechanics remain visibly excluded from exact totals.
41
+
42
+ The planner uses the public `--fellowship-poster-*` Dungeon Poster tokens and
43
+ bundled Syne/DM Mono faces. It maintains 44px controls, visible focus, reduced
44
+ motion, canonical mobile position order, and accessible equipped-item tooltips.
@@ -102,22 +102,20 @@ continues to own button semantics and selection state.
102
102
 
103
103
  ## Data and assets
104
104
 
105
- Self-host images with `assetBaseUrl`, or replace the complete provider:
105
+ Provide an image resolver and optionally replace the data provider:
106
106
 
107
107
  ```ts
108
108
  import type { FellowshipTalentDataSource } from "@crockery/fellowship-components/talent-calculator";
109
109
 
110
110
  declare const applicationTalentData: FellowshipTalentDataSource;
111
111
 
112
- calculator.assetBaseUrl = "https://static.example.com/fellowship-data/v1.0.0/";
112
+ calculator.resolveAssetUrl = (asset) =>
113
+ new URL(asset.path, "https://static.example.com/fellowship/").href;
113
114
 
114
115
  const source: FellowshipTalentDataSource = {
115
116
  async loadHeroTalents(heroId, signal) {
116
117
  return applicationTalentData.loadHeroTalents(heroId, signal);
117
118
  },
118
- resolveAssetUrl(asset) {
119
- return new URL(asset.path, "https://static.example.com/").href;
120
- },
121
119
  };
122
120
 
123
121
  calculator.dataSource = source;
@@ -131,7 +129,8 @@ calculator.dataSource = source;
131
129
  - `talentPoints: number` — defaults to `14`, normalized from `0` through
132
130
  `MAX_TALENT_POINTS`.
133
131
  - `selectedTalentIds: readonly string[]`
134
- - `assetBaseUrl: string | null`
132
+ - `resolveAssetUrl: ImageAssetUrlResolver` required and assigned as a
133
+ JavaScript property.
135
134
  - `dataSource: FellowshipTalentDataSource | null`
136
135
  - `renderTalent: LitTalentRenderer | null`
137
136
  - `showPointControls: boolean` — defaults to `true`.
@@ -48,8 +48,9 @@ Pass a React node to the wrapper's `content` prop to fill the named content slot
48
48
  - Positioning maintains an 8px trigger gap and viewport collision margin.
49
49
  - The native Popover API is used when available, with a fixed-position fallback.
50
50
 
51
- Tooltip content is noninteractive and uses `role="tooltip"`. The first slotted trigger receives a
52
- plain-text `aria-description` while connected; any existing value is restored afterward.
51
+ Tooltip content is noninteractive and uses `role="tooltip"`. The first slotted
52
+ trigger receives a stable `aria-describedby` relationship to the tooltip
53
+ surface while connected; any existing relationship is preserved and restored.
53
54
 
54
55
  ## API
55
56
 
@@ -101,10 +102,8 @@ import {
101
102
 
102
103
  ## Theming
103
104
 
104
- The tooltip inherits the shared `--fellowship-field-*` theme and exposes the established
105
- `--fellowship-tooltip-*` overrides. Its desaturated semantic defaults are ability `#76C5D2`,
106
- warning `#D4A761`, effect `#AFA1CA`, resource `#7CB2C2`, healing `#82B997`, Meiko primary
107
- `#C892A0`, and Meiko secondary `#8DBAB7`.
105
+ The tooltip inherits the shared `--fellowship-poster-*` Dungeon Poster
106
+ foundation and exposes the established `--fellowship-tooltip-*` overrides.
108
107
 
109
108
  CSS parts: `trigger`, `surface`, `arrow`, `heading`, `content`, and `paragraph`.
110
109
 
@@ -1,7 +0,0 @@
1
- import { FellowshipDataError as e } from "@crockery/fellowship-data/client";
2
- //#region src/data/data-source.ts
3
- var t = 2, n = (n) => {
4
- if (n !== t) throw new e("unsupported-schema", `Unsupported fellowship-data schema version: ${String(n)}.`);
5
- };
6
- //#endregion
7
- export { n, e as t };
@@ -1,410 +0,0 @@
1
- import { n as e, r as t, t as n } from "./decorate-B_ZTN9li.js";
2
- import { LitElement as r, css as i, html as a, nothing as o } from "lit";
3
- import { customElement as s, property as c, query as l, state as u } from "lit/decorators.js";
4
- import { repeat as d } from "lit/directives/repeat.js";
5
- import { styleMap as f } from "lit/directives/style-map.js";
6
- //#region src/tooltip/rich-text.ts
7
- var p = {
8
- bold: "strong",
9
- "rt.bold": "strong",
10
- "rt.absorb": "ability",
11
- "rt.warning": "warning",
12
- "rt.effect": "effect",
13
- "rt.mana": "resource",
14
- "rt.heal": "healing",
15
- "rt.meikoability1": "meiko-primary",
16
- "rt.meikoability2": "meiko-secondary"
17
- }, m = (e, t, n) => {
18
- let r = t.replace(/\r\n?/g, "\n").split(/\n{2,}/);
19
- r.forEach((t, i) => {
20
- let a = e.at(-1);
21
- if (t.length > 0) {
22
- let e = a.at(-1);
23
- e?.tone === n ? a[a.length - 1] = {
24
- text: `${e.text}${t}`,
25
- tone: n
26
- } : a.push({
27
- text: t,
28
- tone: n
29
- });
30
- }
31
- i < r.length - 1 && e.push([]);
32
- });
33
- }, h = (e) => {
34
- let t = [[]], n = ["default"], r = e.split(/(<\/?[^>]+>|<\/>)/g);
35
- for (let e of r) {
36
- if (!e) continue;
37
- if (e === "</>") {
38
- n.length > 1 && n.pop();
39
- continue;
40
- }
41
- if (e.match(/^<\/\s*([^>\s]+)\s*>$/)) {
42
- n.length > 1 && n.pop();
43
- continue;
44
- }
45
- let r = e.match(/^<\s*([^/][^>\s]*)\s*>$/);
46
- if (r) {
47
- let e = r[1]?.toLowerCase() ?? "";
48
- n.push(p[e] ?? "default");
49
- continue;
50
- }
51
- m(t, e, n.at(-1) ?? "default");
52
- }
53
- return t;
54
- }, g = (e) => h(e).map((e) => e.map(({ text: e }) => e).join("")).join("\n\n").trim(), _ = (e, t, n) => Math.min(Math.max(e, t), Math.max(t, n)), v = (e, t, n) => {
55
- let r = n.gap ?? 8, i = n.margin ?? 8, a = {
56
- top: e.top - i,
57
- bottom: n.viewportHeight - e.bottom - i,
58
- right: n.viewportWidth - e.right - i,
59
- left: e.left - i
60
- }, o = {
61
- top: t.height + r,
62
- bottom: t.height + r,
63
- right: t.width + r,
64
- left: t.width + r
65
- }, s = [
66
- "top",
67
- "bottom",
68
- "right",
69
- "left"
70
- ], c = n.placement ?? "auto", l = c === "auto" ? s.find((e) => a[e] >= o[e]) ?? [...s].sort((e, t) => a[t] - a[e])[0] : c, u = e.left + e.width / 2 - t.width / 2, d = e.top + e.height / 2 - t.height / 2, f = l === "left" ? e.left - t.width - r : l === "right" ? e.right + r : u, p = l === "top" ? e.top - t.height - r : l === "bottom" ? e.bottom + r : d;
71
- return {
72
- placement: l,
73
- x: Math.round(_(f, i, n.viewportWidth - t.width - i)),
74
- y: Math.round(_(p, i, n.viewportHeight - t.height - i))
75
- };
76
- }, y = i`
77
- :host {
78
- --fellowship-tooltip-void: var(--_fellowship-field-surface-raised);
79
- --fellowship-tooltip-ink: var(--_fellowship-field-ink);
80
- --fellowship-tooltip-muted-ink: var(--_fellowship-field-muted);
81
- --fellowship-tooltip-border: var(--_fellowship-field-border-strong);
82
- --fellowship-tooltip-focus: var(--_fellowship-field-focus);
83
- --fellowship-tooltip-ability: #76c5d2;
84
- --fellowship-tooltip-warning: #d4a761;
85
- --fellowship-tooltip-effect: #afa1ca;
86
- --fellowship-tooltip-resource: #7cb2c2;
87
- --fellowship-tooltip-healing: #82b997;
88
- --fellowship-tooltip-meiko-primary: #c892a0;
89
- --fellowship-tooltip-meiko-secondary: #8dbab7;
90
- --fellowship-tooltip-font-family: var(--_fellowship-field-font-family);
91
- --fellowship-tooltip-radius: var(--_fellowship-field-radius);
92
- --fellowship-tooltip-max-width: 360px;
93
-
94
- display: inline-block;
95
- min-width: 0;
96
- color: var(--fellowship-tooltip-ink);
97
- font-family: var(--fellowship-tooltip-font-family);
98
- -webkit-font-smoothing: antialiased;
99
- }
100
-
101
- :host([hidden]) {
102
- display: none;
103
- }
104
-
105
- .trigger {
106
- display: contents;
107
- }
108
-
109
- .surface {
110
- position: fixed;
111
- z-index: 2147483647;
112
- box-sizing: border-box;
113
- display: none;
114
- overflow: visible;
115
- width: max-content;
116
- max-width: min(var(--fellowship-tooltip-max-width), calc(100vw - 16px));
117
- margin: 0;
118
- padding: 12px 14px 14px;
119
- border: 1px solid var(--fellowship-tooltip-border);
120
- border-radius: var(--fellowship-tooltip-radius);
121
- background: var(--fellowship-tooltip-void);
122
- color: var(--fellowship-tooltip-ink);
123
- box-shadow: 0 8px 24px rgb(0 0 0 / 34%);
124
- opacity: 0;
125
- transform: translateY(4px) scale(0.98);
126
- transform-origin: bottom center;
127
- transition:
128
- opacity 140ms cubic-bezier(0.23, 1, 0.32, 1),
129
- transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
130
- pointer-events: none;
131
- }
132
-
133
- .surface[data-open="true"] {
134
- display: block;
135
- opacity: 1;
136
- transform: translateY(0) scale(1);
137
- }
138
-
139
- .surface[data-placement="bottom"] {
140
- transform-origin: top center;
141
- }
142
-
143
- .surface[data-placement="left"] {
144
- transform-origin: center right;
145
- }
146
-
147
- .surface[data-placement="right"] {
148
- transform-origin: center left;
149
- }
150
-
151
- .heading {
152
- position: relative;
153
- margin: 0 0 6px;
154
- padding-left: 12px;
155
- color: var(--fellowship-tooltip-ink);
156
- font-size: 14px;
157
- font-weight: 600;
158
- line-height: 20px;
159
- text-wrap: balance;
160
- }
161
-
162
- .heading::before {
163
- position: absolute;
164
- inset: 4px auto 4px 0;
165
- width: 2px;
166
- background: var(--_fellowship-field-accent);
167
- content: "";
168
- }
169
-
170
- .content {
171
- color: var(--fellowship-tooltip-muted-ink);
172
- font-size: 13px;
173
- font-weight: 400;
174
- line-height: 20px;
175
- text-wrap: pretty;
176
- }
177
-
178
- .paragraph {
179
- margin: 0;
180
- white-space: pre-line;
181
- }
182
-
183
- .paragraph + .paragraph {
184
- margin-top: 8px;
185
- }
186
-
187
- [data-tone="strong"] {
188
- color: var(--fellowship-tooltip-ink);
189
- font-weight: 600;
190
- }
191
-
192
- [data-tone="ability"] {
193
- color: var(--fellowship-tooltip-ability);
194
- }
195
-
196
- [data-tone="warning"] {
197
- color: var(--fellowship-tooltip-warning);
198
- }
199
-
200
- [data-tone="effect"] {
201
- color: var(--fellowship-tooltip-effect);
202
- }
203
-
204
- [data-tone="resource"] {
205
- color: var(--fellowship-tooltip-resource);
206
- }
207
-
208
- [data-tone="healing"] {
209
- color: var(--fellowship-tooltip-healing);
210
- }
211
-
212
- [data-tone="meiko-primary"] {
213
- color: var(--fellowship-tooltip-meiko-primary);
214
- }
215
-
216
- [data-tone="meiko-secondary"] {
217
- color: var(--fellowship-tooltip-meiko-secondary);
218
- }
219
-
220
- .arrow {
221
- position: absolute;
222
- width: 8px;
223
- height: 8px;
224
- border: solid var(--fellowship-tooltip-border);
225
- background: var(--fellowship-tooltip-void);
226
- transform: rotate(45deg);
227
- }
228
-
229
- .surface[data-placement="top"] .arrow {
230
- bottom: -5px;
231
- left: calc(50% - 4px);
232
- border-width: 0 1px 1px 0;
233
- }
234
-
235
- .surface[data-placement="bottom"] .arrow {
236
- top: -5px;
237
- left: calc(50% - 4px);
238
- border-width: 1px 0 0 1px;
239
- }
240
-
241
- .surface[data-placement="left"] .arrow {
242
- top: calc(50% - 4px);
243
- right: -5px;
244
- border-width: 1px 1px 0 0;
245
- }
246
-
247
- .surface[data-placement="right"] .arrow {
248
- top: calc(50% - 4px);
249
- left: -5px;
250
- border-width: 0 0 1px 1px;
251
- }
252
-
253
- @media (prefers-reduced-motion: reduce) {
254
- .surface {
255
- transition: opacity 100ms linear;
256
- transform: none;
257
- }
258
- }
259
- `, b = {
260
- bubbles: !0,
261
- composed: !0
262
- }, x = class extends r {
263
- constructor(...e) {
264
- super(...e), this.heading = null, this.text = null, this.placement = "auto", this.openDelay = 250, this.disabled = !1, this._open = !1, this._position = {
265
- x: 0,
266
- y: 0
267
- }, this._resolvedPlacement = "top", this._paragraphs = [], this.#e = null, this.#t = null, this.#n = null, this.#r = !1, this.#i = null, this.#o = () => {
268
- if (!this._open || !this.#t || !this._surface) return;
269
- let e = v(this.#t.getBoundingClientRect(), this._surface.getBoundingClientRect(), {
270
- placement: this.placement,
271
- viewportWidth: window.innerWidth,
272
- viewportHeight: window.innerHeight
273
- });
274
- e.x === this._position.x && e.y === this._position.y && e.placement === this._resolvedPlacement || (this._position = {
275
- x: e.x,
276
- y: e.y
277
- }, this._resolvedPlacement = e.placement);
278
- }, this.#l = () => {
279
- this.disabled || this._open || (this.#_(), this.#e = window.setTimeout(() => {
280
- this.#e = null, this.#a(!0, "pointer");
281
- }, Math.max(0, this.openDelay)));
282
- }, this.#u = () => {
283
- this.#_(), this._open && this.#a(!1, "pointer");
284
- }, this.#d = () => {
285
- this.#_(), !this.disabled && !this._open && this.#a(!0, "focus");
286
- }, this.#f = (e) => {
287
- !this.contains(e.relatedTarget) && this._open && this.#a(!1, "focus");
288
- }, this.#p = (e) => {
289
- e.key === "Escape" && this._open && (e.stopPropagation(), this.#a(!1, "escape"));
290
- }, this.#m = (e) => {
291
- let t = e.currentTarget.assignedElements({ flatten: !0 })[0];
292
- this.#g(), this.#t = t instanceof HTMLElement ? t : null, this.#h();
293
- };
294
- }
295
- static {
296
- this.styles = [t, y];
297
- }
298
- #e;
299
- #t;
300
- #n;
301
- #r;
302
- #i;
303
- connectedCallback() {
304
- super.connectedCallback(), e(this.ownerDocument), this.#i ??= new ResizeObserver(() => this.#o());
305
- }
306
- disconnectedCallback() {
307
- this.#_(), this.#c(), this.#g(), super.disconnectedCallback();
308
- }
309
- updated(e) {
310
- super.updated(e), (e.has("text") || e.has("heading")) && this.#h(), e.has("disabled") && this.disabled && this._open && this.#a(!1, "disabled"), e.has("placement") && this._open && this.#o();
311
- }
312
- willUpdate(e) {
313
- super.willUpdate(e), e.has("text") && (this._paragraphs = h(this.text ?? ""));
314
- }
315
- show() {
316
- this.disabled || this._open || this.#a(!0, "programmatic");
317
- }
318
- hide() {
319
- this.#_(), this._open && this.#a(!1, "programmatic");
320
- }
321
- render() {
322
- let e = {
323
- left: `${this._position.x}px`,
324
- top: `${this._position.y}px`
325
- };
326
- return a`
327
- <span
328
- class="trigger"
329
- part="trigger"
330
- @pointerenter=${this.#l}
331
- @pointerleave=${this.#u}
332
- @focusin=${this.#d}
333
- @focusout=${this.#f}
334
- @keydown=${this.#p}
335
- >
336
- <slot @slotchange=${this.#m}></slot>
337
- </span>
338
- <div
339
- class="surface"
340
- part="surface"
341
- role="tooltip"
342
- popover="manual"
343
- data-open=${String(this._open)}
344
- data-placement=${this._resolvedPlacement}
345
- style=${f(e)}
346
- >
347
- <span class="arrow" part="arrow" aria-hidden="true"></span>
348
- <slot name="content">
349
- ${this.heading ? a`<p class="heading" part="heading">${this.heading}</p>` : o}
350
- <div class="content" part="content">
351
- ${d(this._paragraphs, (e, t) => t, (e, t) => a`
352
- <p class="paragraph" part="paragraph">
353
- ${d(e, (e, n) => `${t}:${n}:${e.tone}:${e.text}`, (e) => a`<span data-tone=${e.tone}>${e.text}</span>`)}
354
- </p>
355
- `)}
356
- </div>
357
- </slot>
358
- </div>
359
- `;
360
- }
361
- #a(e, t) {
362
- e !== this._open && (this._open = e, this.updateComplete.then(() => {
363
- let t = this._surface;
364
- t && (e ? ("showPopover" in t && !t.matches(":popover-open") && t.showPopover(), this.#s(), this.#o()) : ("hidePopover" in t && t.matches(":popover-open") && t.hidePopover(), this.#c()));
365
- }), this.dispatchEvent(new CustomEvent("fellowship-tooltip-toggle", {
366
- ...b,
367
- detail: {
368
- open: e,
369
- reason: t
370
- }
371
- })));
372
- }
373
- #o;
374
- #s() {
375
- window.addEventListener("resize", this.#o), window.addEventListener("scroll", this.#o, !0), this.#t && this.#i?.observe(this.#t), this._surface && this.#i?.observe(this._surface);
376
- }
377
- #c() {
378
- window.removeEventListener("resize", this.#o), window.removeEventListener("scroll", this.#o, !0), this.#i?.disconnect();
379
- }
380
- #l;
381
- #u;
382
- #d;
383
- #f;
384
- #p;
385
- #m;
386
- #h() {
387
- if (!this.#t) return;
388
- this.#r ||= (this.#n = this.#t.getAttribute("aria-description"), !0);
389
- let e = [this.heading, g(this.text ?? "")].filter(Boolean).join(". ");
390
- e ? this.#t.setAttribute("aria-description", e) : this.#n === null && this.#t.removeAttribute("aria-description");
391
- }
392
- #g() {
393
- this.#t && (this.#n === null ? this.#t.removeAttribute("aria-description") : this.#t.setAttribute("aria-description", this.#n), this.#t = null, this.#n = null, this.#r = !1);
394
- }
395
- #_() {
396
- this.#e !== null && (window.clearTimeout(this.#e), this.#e = null);
397
- }
398
- };
399
- n([c({ type: String })], x.prototype, "heading", void 0), n([c({ type: String })], x.prototype, "text", void 0), n([c({ type: String })], x.prototype, "placement", void 0), n([c({
400
- type: Number,
401
- attribute: "open-delay"
402
- })], x.prototype, "openDelay", void 0), n([c({
403
- type: Boolean,
404
- reflect: !0
405
- })], x.prototype, "disabled", void 0), n([u()], x.prototype, "_open", void 0), n([u()], x.prototype, "_position", void 0), n([u()], x.prototype, "_resolvedPlacement", void 0), n([u()], x.prototype, "_paragraphs", void 0), n([l(".surface")], x.prototype, "_surface", void 0), x = n([s("fellowship-tooltip")], x);
406
- var S = () => {
407
- customElements.get("fellowship-tooltip") || customElements.define("fellowship-tooltip", x);
408
- };
409
- //#endregion
410
- export { g as a, h as i, S as n, v as r, x as t };