|
20 | 20 | .sort((a, b) => a.sort - b.sort) |
21 | 21 | .map(({ index }) => index), |
22 | 22 | ); |
| 23 | + const selectedWords = $derived( |
| 24 | + selectedIndexes.map((index) => recoveryPhrase[index]), |
| 25 | + ); |
23 | 26 | const isCheckingOrder = $derived( |
24 | | - selectedIndexes.length === recoveryPhrase.length, |
| 27 | + selectedWords.length === recoveryPhrase.length, |
25 | 28 | ); |
26 | 29 |
|
| 30 | + const handleSelect = (index: number) => { |
| 31 | + selectedIndexes = [...selectedIndexes, index]; |
| 32 | + }; |
| 33 | + const handleUndo = () => { |
| 34 | + selectedIndexes = selectedIndexes.slice(0, -1); |
| 35 | + }; |
| 36 | + const handleClear = () => { |
| 37 | + selectedIndexes = []; |
| 38 | + }; |
| 39 | +
|
27 | 40 | // Auto-submit after the last word has been selected |
28 | 41 | $effect(() => { |
29 | | - if (selectedIndexes.length !== recoveryPhrase.length) { |
| 42 | + if (!isCheckingOrder) { |
30 | 43 | return; |
31 | 44 | } |
32 | | - onCompleted(selectedIndexes.map((index) => recoveryPhrase[index])); |
| 45 | + onCompleted(selectedWords); |
33 | 46 | }); |
34 | 47 | </script> |
35 | 48 |
|
|
54 | 67 | <Trans>Select each word in the correct order</Trans> |
55 | 68 | {/if} |
56 | 69 | </p> |
57 | | -<div class={["mb-8 grid grid-cols-3 gap-3"]}> |
| 70 | +<ul class={["mb-8 grid grid-cols-3 gap-3"]}> |
58 | 71 | {#each shuffledIndexes as index} |
59 | 72 | {@const word = recoveryPhrase[index]} |
60 | 73 | {@const selectedPosition = selectedIndexes.indexOf(index)} |
61 | 74 | {@const isSelected = selectedPosition !== -1 && !isCheckingOrder} |
62 | 75 | {@const isLastSelected = selectedIndexes.slice(-1)[0] === index} |
63 | | - <button |
64 | | - onclick={() => |
65 | | - (selectedIndexes = isLastSelected |
66 | | - ? selectedIndexes.slice(0, -1) |
67 | | - : [...selectedIndexes, index])} |
68 | | - class={[ |
69 | | - "border-border-primary hover:not-disabled:bg-bg-primary_hover focus-visible:not-disabled:bg-bg-primary_hover flex h-7 flex-row items-center rounded-full border px-1.5 outline-none", |
70 | | - isSelected && "!border-fg-primary", |
71 | | - isCheckingOrder && "!bg-bg-disabled !border-border-disabled_subtle", |
72 | | - ]} |
73 | | - disabled={(isSelected && !isLastSelected) || isCheckingOrder} |
74 | | - > |
75 | | - <span |
76 | | - class={[ |
77 | | - "text-text-secondary w-4 text-center text-xs font-semibold tabular-nums select-none", |
78 | | - isSelected ? "!text-text-primary" : "-translate-y-0.25", |
79 | | - isCheckingOrder && "!text-text-disabled", |
80 | | - ]} |
81 | | - > |
82 | | - {isSelected || isCheckingOrder |
83 | | - ? `${selectedPosition + 1}`.padStart(2, "0") |
84 | | - : "_"} |
85 | | - </span> |
86 | | - <span |
| 76 | + <li class="contents"> |
| 77 | + <button |
| 78 | + onclick={isLastSelected ? handleUndo : () => handleSelect(index)} |
87 | 79 | class={[ |
88 | | - "border-border-secondary mx-1 h-full border-r", |
| 80 | + "border-border-primary hover:not-disabled:bg-bg-primary_hover focus-visible:not-disabled:bg-bg-primary_hover flex h-7 flex-row items-center rounded-full border px-1.5 outline-none", |
89 | 81 | isSelected && "!border-fg-primary", |
90 | | - isCheckingOrder && "!border-border-disabled_subtle", |
91 | | - ]} |
92 | | - ></span> |
93 | | - <span |
94 | | - class={[ |
95 | | - "text-text-secondary -translate-y-0.25 text-base select-none", |
96 | | - word.length > 7 && "tracking-tight", |
97 | | - isSelected && "!text-text-primary font-semibold", |
98 | | - isCheckingOrder && "!text-text-disabled", |
| 82 | + isCheckingOrder && "!bg-bg-disabled !border-border-disabled_subtle", |
99 | 83 | ]} |
| 84 | + disabled={(isSelected && !isLastSelected) || isCheckingOrder} |
| 85 | + aria-pressed={isSelected ? "true" : "false"} |
100 | 86 | > |
101 | | - {word} |
102 | | - </span> |
103 | | - </button> |
| 87 | + <span |
| 88 | + class={[ |
| 89 | + "text-text-secondary w-4 text-center text-xs font-semibold tabular-nums select-none", |
| 90 | + isSelected ? "!text-text-primary" : "-translate-y-0.25", |
| 91 | + isCheckingOrder && "!text-text-disabled", |
| 92 | + ]} |
| 93 | + aria-hidden="true" |
| 94 | + > |
| 95 | + {isSelected || isCheckingOrder |
| 96 | + ? `${selectedPosition + 1}`.padStart(2, "0") |
| 97 | + : "_"} |
| 98 | + </span> |
| 99 | + <span |
| 100 | + class={[ |
| 101 | + "border-border-secondary mx-1 h-full border-r", |
| 102 | + isSelected && "!border-fg-primary", |
| 103 | + isCheckingOrder && "!border-border-disabled_subtle", |
| 104 | + ]} |
| 105 | + ></span> |
| 106 | + <span |
| 107 | + class={[ |
| 108 | + "text-text-secondary -translate-y-0.25 text-base select-none", |
| 109 | + word.length > 7 && "tracking-tight", |
| 110 | + isSelected && "!text-text-primary font-semibold", |
| 111 | + isCheckingOrder && "!text-text-disabled", |
| 112 | + ]} |
| 113 | + > |
| 114 | + {word} |
| 115 | + </span> |
| 116 | + </button> |
| 117 | + </li> |
104 | 118 | {/each} |
105 | | -</div> |
| 119 | +</ul> |
106 | 120 | <Button |
107 | | - onclick={() => (selectedIndexes = [])} |
| 121 | + onclick={handleClear} |
108 | 122 | variant="secondary" |
109 | 123 | size="lg" |
110 | 124 | disabled={selectedIndexes.length === 0 || isCheckingOrder} |
|
0 commit comments