|
1 | 1 | <script lang="ts">
|
2 |
| - import type { ItemPF2e } from "@item"; |
3 |
| - import { ErrorPF2e, htmlQuery } from "@util"; |
| 2 | + import { ErrorPF2e } from "@util"; |
| 3 | + import type { KeyboardEventHandler, MouseEventHandler } from "svelte/elements"; |
4 | 4 | import type { ABCPickerContext } from "./app.ts";
|
5 | 5 |
|
6 | 6 | const { actor, foundryApp, state: data }: ABCPickerContext = $props();
|
|
11 | 11 |
|
12 | 12 | let selection: string | null = $state(null);
|
13 | 13 | /** Show the confirmation button. */
|
14 |
| - function showConfirmation(button: HTMLButtonElement): void { |
15 |
| - const row = button.closest("li"); |
| 14 | + const showConfirmation: MouseEventHandler<HTMLButtonElement> = (event): void => { |
| 15 | + const row = event.currentTarget.closest("li"); |
16 | 16 | selection = selection === row?.dataset.uuid ? null : (row?.dataset.uuid ?? null);
|
17 |
| - } |
| 17 | + }; |
18 | 18 |
|
19 | 19 | /** Open an item sheet to show additional details. */
|
20 |
| - async function viewItemSheet(uuid: ItemUUID): Promise<void> { |
21 |
| - const item = await fromUuid<ItemPF2e>(uuid); |
| 20 | + const viewItemSheet: MouseEventHandler<HTMLButtonElement> = async (event): Promise<void> => { |
| 21 | + const uuid = event.currentTarget.closest("li")?.dataset?.uuid ?? ""; |
| 22 | + const item = await fromUuid(uuid); |
22 | 23 | item?.sheet.render(true);
|
23 |
| - } |
| 24 | + }; |
24 | 25 |
|
25 | 26 | /** Create a new embedded ABC item on the character. */
|
26 |
| - async function saveSelection(uuid: ItemUUID): Promise<void> { |
27 |
| - const item = await fromUuid<ItemPF2e>(uuid); |
28 |
| - if (!item) throw ErrorPF2e(`Unexpected error retrieving ${data.itemType}`); |
29 |
| - actor.createEmbeddedDocuments("Item", [item.clone().toObject()]); |
| 27 | + const saveSelection: MouseEventHandler<HTMLButtonElement> = async (event): Promise<void> => { |
| 28 | + const uuid = event.currentTarget.closest("li")?.dataset?.uuid ?? ""; |
| 29 | + const item = await fromUuid(uuid); |
| 30 | + if (!(item instanceof Item) || item.type !== data.itemType) { |
| 31 | + throw ErrorPF2e(`Unexpected error retrieving ${data.itemType}`); |
| 32 | + } |
| 33 | + actor.createEmbeddedDocuments("Item", [{ ...item.toObject(), _id: null }]); |
30 | 34 | foundryApp.close();
|
31 |
| - } |
| 35 | + }; |
32 | 36 |
|
33 | 37 | /** Search list and show or hide according to match result. */
|
34 |
| - const searchItems = fu.debounce((query: string) => { |
| 38 | + const searchItems: KeyboardEventHandler<HTMLInputElement> = (event) => debouncedSearch(event.currentTarget.value); |
| 39 | + const debouncedSearch = fu.debounce((query: string) => { |
35 | 40 | const regexp = new RegExp(RegExp.escape(query.trim()), "i");
|
36 | 41 | for (const row of foundryApp.element.getElementsByTagName("li")) {
|
37 |
| - row.hidden = !regexp.test(htmlQuery(row, "[data-name]")?.innerText ?? ""); |
| 42 | + row.hidden = !regexp.test(row.innerText ?? ""); |
38 | 43 | }
|
39 | 44 | }, 200);
|
40 | 45 | </script>
|
41 | 46 |
|
42 | 47 | <header class="search">
|
43 | 48 | <i class="fa-solid fa-search"></i>
|
44 |
| - <input |
45 |
| - type="search" |
46 |
| - spellcheck="false" |
47 |
| - placeholder={searchPlaceholder} |
48 |
| - onkeyup={(event) => searchItems(event.currentTarget.value)} |
49 |
| - /> |
| 49 | + <input type="search" spellcheck="false" placeholder={searchPlaceholder} onkeyup={searchItems} /> |
50 | 50 | </header>
|
51 | 51 |
|
52 | 52 | <ul>
|
53 | 53 | {#each data.items as item}
|
54 |
| - <li data-uuid={item.uuid}> |
| 54 | + <li class:selected={selection === item.uuid} data-uuid={item.uuid}> |
55 | 55 | <img src={item.img} loading="lazy" alt="Class icon" />
|
56 |
| - <button type="button" class="flat name-source" onclick={(e) => showConfirmation(e.currentTarget)}> |
57 |
| - <div class="name" data-name>{item.name}</div> |
| 56 | + <button type="button" class="flat name-source" onclick={showConfirmation}> |
| 57 | + <div class="name">{item.name}</div> |
58 | 58 | <div class="source" class:publication={item.source.publication}>{item.source.name}</div>
|
59 | 59 | </button>
|
60 | 60 | <div class="buttons">
|
61 | 61 | <button
|
62 | 62 | type="button"
|
63 | 63 | class="confirm"
|
64 |
| - class:selected={selection === item.uuid} |
65 | 64 | data-tooltip="PF2E.Actor.Character.ABCPicker.Tooltip.ConfirmSelection"
|
66 |
| - onclick={() => saveSelection(item.uuid)}><i class="fa-solid fa-check"></i></button |
| 65 | + onclick={saveSelection}><i class="fa-solid fa-check"></i></button |
67 | 66 | >
|
68 | 67 | <button
|
69 | 68 | type="button"
|
70 | 69 | data-tooltip="PF2E.Actor.Character.ABCPicker.Tooltip.ViewSheet"
|
71 |
| - onclick={() => viewItemSheet(item.uuid)}><i class="fa-solid fa-info fa-fw"></i></button |
| 70 | + onclick={viewItemSheet}><i class="fa-solid fa-info fa-fw"></i></button |
72 | 71 | >
|
73 | 72 | </div>
|
74 | 73 | </li>
|
|
129 | 128 | font-style: italic;
|
130 | 129 | }
|
131 | 130 | }
|
132 |
| -
|
133 |
| - &:hover + .buttons button.confirm:not(.selected) { |
134 |
| - opacity: 0.33; |
135 |
| - visibility: visible; |
136 |
| - } |
137 | 131 | }
|
138 | 132 |
|
139 | 133 | .buttons {
|
|
159 | 153 | &:not(:hover) {
|
160 | 154 | color: darkgreen;
|
161 | 155 | }
|
162 |
| -
|
163 |
| - &.selected { |
164 |
| - opacity: 1; |
165 |
| - visibility: visible; |
166 |
| - } |
167 | 156 | }
|
168 | 157 | }
|
169 | 158 | }
|
| 159 | +
|
| 160 | + &:hover:not(.selected) button.confirm { |
| 161 | + opacity: 0.33; |
| 162 | + visibility: visible; |
| 163 | + } |
| 164 | +
|
| 165 | + &.selected button.confirm { |
| 166 | + opacity: 1; |
| 167 | + visibility: visible; |
| 168 | + } |
170 | 169 | }
|
171 | 170 | }
|
172 | 171 | </style>
|
0 commit comments