bigblocks
Version:
Complete Bitcoin UI component library - authentication, social, wallet, market, inscriptions, and blockchain interactions for React
15 lines • 17.4 kB
JSON
{
"name": "backup-recovery-mnemonicdisplay",
"type": "registry:component",
"dependencies": [],
"devDependencies": [],
"registryDependencies": [],
"files": [
{
"path": "components/backup-recovery/MnemonicDisplay.tsx",
"type": "registry:component",
"content": "\"use client\";\n\nimport {\n\tCheckIcon,\n\tCopyIcon,\n\tExclamationTriangleIcon,\n\tResetIcon,\n} from \"@radix-ui/react-icons\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { bip39words } from \"../../lib/bip39-words\";\nimport { cn } from \"../../lib/utils.js\";\nimport { Alert, AlertDescription } from \"../ui/alert.js\";\nimport { Badge } from \"../ui/badge.js\";\nimport { Button } from \"../ui/button.js\";\nimport { Card, CardContent } from \"../ui/card.js\";\nimport { Checkbox } from \"../ui/checkbox.js\";\nimport { Label } from \"../ui/label.js\";\nimport {\n\tSelect,\n\tSelectContent,\n\tSelectItem,\n\tSelectTrigger,\n\tSelectValue,\n} from \"../ui/select.js\";\n\nexport enum MnemonicMode {\n\tView = \"view\",\n\tVerify = \"verify\",\n\tImport = \"import\",\n}\n\nexport type MnemonicResult = {\n\tverified?: boolean;\n\timportedMnemonic?: string;\n\twords?: string[];\n};\n\nexport interface MnemonicDisplayProps {\n\tmnemonic?: string;\n\tmode?: MnemonicMode;\n\tonResult?: (result: MnemonicResult) => void;\n\tonContinue?: () => void;\n\tonBack?: () => void;\n\tshowCopyButton?: boolean;\n\trequireVerification?: boolean;\n\twordCount?: 12 | 24;\n\tautoCompleteLastWord?: boolean;\n\tclassName?: string;\n}\n\nexport function MnemonicDisplay({\n\tmnemonic = \"\",\n\tmode = MnemonicMode.View,\n\tonResult,\n\tonContinue,\n\tonBack,\n\tshowCopyButton = true,\n\trequireVerification = false,\n\twordCount = 12,\n\tautoCompleteLastWord = true,\n\tclassName = \"\",\n}: MnemonicDisplayProps) {\n\tconst [copied, setCopied] = useState(false);\n\tconst [acknowledged, setAcknowledged] = useState(false);\n\tconst [shuffledWords, setShuffledWords] = useState<string[]>([]);\n\tconst [selectedWords, setSelectedWords] = useState<string[]>([]);\n\tconst [importWords, setImportWords] = useState<string[]>(\n\t\tArray(wordCount).fill(\"\"),\n\t);\n\tconst [verificationError, setVerificationError] = useState(false);\n\n\tconst words = useMemo(() => mnemonic.split(\" \").filter(Boolean), [mnemonic]);\n\tconst isComplete =\n\t\tmode === MnemonicMode.Import\n\t\t\t? importWords.every((word) => word.length > 0)\n\t\t\t: true;\n\n\t// Shuffle words for verification mode\n\tconst shuffleWords = useCallback(() => {\n\t\tif (words.length === wordCount) {\n\t\t\tconst shuffled = [...words].sort(() => Math.random() - 0.5);\n\t\t\tsetShuffledWords(shuffled);\n\t\t}\n\t}, [words, wordCount]);\n\n\tuseEffect(() => {\n\t\tif (mode === MnemonicMode.Verify) {\n\t\t\tshuffleWords();\n\t\t}\n\t}, [mode, shuffleWords]);\n\n\tconst handleCopy = async () => {\n\t\ttry {\n\t\t\tawait navigator.clipboard.writeText(mnemonic);\n\t\t\tsetCopied(true);\n\t\t\tsetTimeout(() => setCopied(false), 2000);\n\t\t} catch (err) {\n\t\t\tconsole.error(\"Failed to copy:\", err);\n\t\t}\n\t};\n\n\tconst handleWordClick = (word: string, _index: number) => {\n\t\tif (mode !== MnemonicMode.Verify || selectedWords.includes(word)) return;\n\n\t\tlet newSelected = [...selectedWords, word];\n\n\t\t// Auto-complete last word if enabled and this is the second-to-last word\n\t\tif (autoCompleteLastWord && newSelected.length === wordCount - 1) {\n\t\t\tconst remainingWord = words.find((w) => !newSelected.includes(w));\n\t\t\tif (remainingWord) {\n\t\t\t\tnewSelected = [...newSelected, remainingWord];\n\t\t\t}\n\t\t}\n\n\t\tsetSelectedWords(newSelected);\n\n\t\t// Check if verification is complete\n\t\tif (newSelected.length === wordCount) {\n\t\t\tconst isCorrect = newSelected.every((w, i) => w === words[i]);\n\t\t\tif (isCorrect) {\n\t\t\t\tonResult?.({ verified: true });\n\t\t\t} else {\n\t\t\t\tsetVerificationError(true);\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tsetSelectedWords([]);\n\t\t\t\t\tsetVerificationError(false);\n\t\t\t\t\tshuffleWords();\n\t\t\t\t}, 1500);\n\t\t\t}\n\t\t}\n\t};\n\n\tconst handleImportWordChange = (index: number, word: string) => {\n\t\tconst newWords = [...importWords];\n\t\tnewWords[index] = word;\n\t\tsetImportWords(newWords);\n\n\t\tif (newWords.every((w) => w.length > 0)) {\n\t\t\tonResult?.({ importedMnemonic: newWords.join(\" \") });\n\t\t}\n\t};\n\n\tconst handlePaste = async (_index: number) => {\n\t\ttry {\n\t\t\tconst text = await navigator.clipboard.readText();\n\t\t\tconst pastedWords = text.trim().split(/\\s+/);\n\n\t\t\tif (\n\t\t\t\tpastedWords.length === wordCount &&\n\t\t\t\tpastedWords.every((w) => bip39words.includes(w.toLowerCase()))\n\t\t\t) {\n\t\t\t\tsetImportWords(pastedWords);\n\t\t\t\tonResult?.({ importedMnemonic: pastedWords.join(\" \") });\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconsole.error(\"Failed to paste:\", err);\n\t\t}\n\t};\n\n\tconst resetVerification = () => {\n\t\tsetSelectedWords([]);\n\t\tsetVerificationError(false);\n\t\tshuffleWords();\n\t};\n\n\tconst getTitle = () => {\n\t\tswitch (mode) {\n\t\t\tcase MnemonicMode.View:\n\t\t\t\treturn \"Recovery Phrase\";\n\t\t\tcase MnemonicMode.Verify:\n\t\t\t\treturn \"Verify Recovery Phrase\";\n\t\t\tcase MnemonicMode.Import:\n\t\t\t\treturn \"Import Recovery Phrase\";\n\t\t}\n\t};\n\n\tconst getDescription = () => {\n\t\tswitch (mode) {\n\t\t\tcase MnemonicMode.View:\n\t\t\t\treturn \"Write down these words in order. This is the ONLY way to recover your Bitcoin identity if you lose your password.\";\n\t\t\tcase MnemonicMode.Verify:\n\t\t\t\treturn \"Click the words in the correct order to verify you have saved your recovery phrase.\";\n\t\t\tcase MnemonicMode.Import:\n\t\t\t\treturn `Enter your ${wordCount}-word recovery phrase to restore your wallet.`;\n\t\t}\n\t};\n\n\treturn (\n\t\t<div className={cn(\"space-y-4\", className)}>\n\t\t\t<Card>\n\t\t\t\t<CardContent className=\"pt-6\">\n\t\t\t\t\t<div className=\"space-y-3\">\n\t\t\t\t\t\t<div className=\"flex justify-between items-center\">\n\t\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\t\twidth=\"20\"\n\t\t\t\t\t\t\t\t\theight=\"20\"\n\t\t\t\t\t\t\t\t\tfill=\"currentColor\"\n\t\t\t\t\t\t\t\t\tviewBox=\"0 0 20 20\"\n\t\t\t\t\t\t\t\t\taria-label=\"Key\"\n\t\t\t\t\t\t\t\t\tclassName=\"text-primary\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<title>Key</title>\n\t\t\t\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t\t\t\tfillRule=\"evenodd\"\n\t\t\t\t\t\t\t\t\t\td=\"M18 8a6 6 0 01-7.743 5.743L10 14l-1 1-1 1H6v2H2v-4l4.257-4.257A6 6 0 1118 8zm-6-4a1 1 0 100 2 2 2 0 012 2 1 1 0 102 0 4 4 0 00-4-4z\"\n\t\t\t\t\t\t\t\t\t\tclipRule=\"evenodd\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t\t<p className=\"font-medium text-base\">{getTitle()}</p>\n\t\t\t\t\t\t\t\t{mode === MnemonicMode.Verify && (\n\t\t\t\t\t\t\t\t\t<Badge\n\t\t\t\t\t\t\t\t\t\tvariant={\n\t\t\t\t\t\t\t\t\t\t\tselectedWords.length === wordCount\n\t\t\t\t\t\t\t\t\t\t\t\t? \"default\"\n\t\t\t\t\t\t\t\t\t\t\t\t: \"secondary\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{selectedWords.length}/{wordCount}\n\t\t\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{showCopyButton && mode === MnemonicMode.View && (\n\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\tvariant={copied ? \"secondary\" : \"outline\"}\n\t\t\t\t\t\t\t\t\tonClick={handleCopy}\n\t\t\t\t\t\t\t\t\tclassName={cn(copied && \"text-green-600\")}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{copied ? (\n\t\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t\t<CheckIcon className=\"h-4 w-4 mr-1\" aria-label=\"Copied\" />\n\t\t\t\t\t\t\t\t\t\t\tCopied!\n\t\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t\t<CopyIcon className=\"h-4 w-4 mr-1\" aria-label=\"Copy\" />\n\t\t\t\t\t\t\t\t\t\t\tCopy\n\t\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t{/* View Mode: Display numbered words */}\n\t\t\t\t\t\t{mode === MnemonicMode.View && (\n\t\t\t\t\t\t\t<div className=\"grid grid-cols-2 sm:grid-cols-3 gap-2\">\n\t\t\t\t\t\t\t\t{words.map((word, index) => (\n\t\t\t\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: The list is static and words can be duplicated.\n\t\t\t\t\t\t\t\t\t<Card key={`word-${index}`} className=\"bg-muted/50\">\n\t\t\t\t\t\t\t\t\t\t<CardContent className=\"p-2\">\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t\t\t\t<Badge variant=\"secondary\" className=\"text-xs\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t{index + 1}\n\t\t\t\t\t\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t\t\t\t\t\t\t<p className=\"text-sm font-medium font-mono\">{word}</p>\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t</CardContent>\n\t\t\t\t\t\t\t\t\t</Card>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t{/* Verify Mode: Click words in order */}\n\t\t\t\t\t\t{mode === MnemonicMode.Verify && (\n\t\t\t\t\t\t\t<div className=\"space-y-3\">\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\"min-h-[120px] p-2 border-2 border-dashed rounded-lg\",\n\t\t\t\t\t\t\t\t\t\t\"border-muted-foreground/25\",\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{selectedWords.length > 0 ? (\n\t\t\t\t\t\t\t\t\t\t<div className=\"flex flex-wrap gap-2\">\n\t\t\t\t\t\t\t\t\t\t\t{selectedWords.map((word) => (\n\t\t\t\t\t\t\t\t\t\t\t\t<Badge key={`selected-${word}`} variant=\"default\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t{word}\n\t\t\t\t\t\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t<div className=\"flex items-center justify-center h-full min-h-[100px]\">\n\t\t\t\t\t\t\t\t\t\t\t<p className=\"text-sm text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\tSelect words below\n\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t{verificationError && (\n\t\t\t\t\t\t\t\t\t<Alert variant=\"destructive\">\n\t\t\t\t\t\t\t\t\t\t<ExclamationTriangleIcon className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t\t\t<AlertDescription>\n\t\t\t\t\t\t\t\t\t\t\tIncorrect order. Please try again.\n\t\t\t\t\t\t\t\t\t\t</AlertDescription>\n\t\t\t\t\t\t\t\t\t</Alert>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t<div className=\"grid grid-cols-2 sm:grid-cols-3 gap-2\">\n\t\t\t\t\t\t\t\t\t{shuffledWords.map((word, index) => {\n\t\t\t\t\t\t\t\t\t\tconst isSelected = selectedWords.includes(word);\n\t\t\t\t\t\t\t\t\t\tconst isClickable = !isSelected;\n\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t<Card\n\t\t\t\t\t\t\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: The list is shuffled and words can be duplicated.\n\t\t\t\t\t\t\t\t\t\t\t\tkey={`shuffled-${word}-${index}`}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"cursor-pointer transition-all duration-150\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tisSelected &&\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"opacity-50 cursor-not-allowed bg-muted\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t!isSelected && \"hover:border-primary/50\",\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\tonClick={() =>\n\t\t\t\t\t\t\t\t\t\t\t\t\tisClickable && handleWordClick(word, index)\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<CardContent className=\"p-3\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<p className=\"text-sm font-medium font-mono text-center\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{word}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t\t</CardContent>\n\t\t\t\t\t\t\t\t\t\t\t</Card>\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\tonClick={resetVerification}\n\t\t\t\t\t\t\t\t\tclassName=\"text-muted-foreground\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<ResetIcon className=\"h-4 w-4 mr-1\" /> Reset Selection\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t{/* Import Mode: Text inputs for each word */}\n\t\t\t\t\t\t{mode === MnemonicMode.Import && (\n\t\t\t\t\t\t\t<div className=\"grid grid-cols-2 sm:grid-cols-3 gap-2\">\n\t\t\t\t\t\t\t\t{importWords.map((word, index) => (\n\t\t\t\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: The list of inputs is static.\n\t\t\t\t\t\t\t\t\t<div key={`import-${index}`}>\n\t\t\t\t\t\t\t\t\t\t<Label className=\"text-xs text-muted-foreground mb-1\">\n\t\t\t\t\t\t\t\t\t\t\tWord {index + 1}\n\t\t\t\t\t\t\t\t\t\t</Label>\n\t\t\t\t\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\t\t\t\t\tvalue={word}\n\t\t\t\t\t\t\t\t\t\t\tonValueChange={(value) =>\n\t\t\t\t\t\t\t\t\t\t\t\thandleImportWordChange(index, value)\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<SelectTrigger\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"w-full\"\n\t\t\t\t\t\t\t\t\t\t\t\tonDoubleClick={() => handlePaste(index)}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<SelectValue placeholder={`Word ${index + 1}`} />\n\t\t\t\t\t\t\t\t\t\t\t</SelectTrigger>\n\t\t\t\t\t\t\t\t\t\t\t<SelectContent>\n\t\t\t\t\t\t\t\t\t\t\t\t{bip39words\n\t\t\t\t\t\t\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t(w: string) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t!word || w.startsWith(word.toLowerCase()),\n\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t.slice(0, 10)\n\t\t\t\t\t\t\t\t\t\t\t\t\t.map((w: string) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<SelectItem key={w} value={w}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{w}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</SelectItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t\t</SelectContent>\n\t\t\t\t\t\t\t\t\t\t</Select>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t<Alert className=\"bg-amber-50 border-amber-200\">\n\t\t\t\t\t\t\t<ExclamationTriangleIcon className=\"h-4 w-4 text-amber-600\" />\n\t\t\t\t\t\t\t<AlertDescription className=\"text-amber-900\">\n\t\t\t\t\t\t\t\t{getDescription()}\n\t\t\t\t\t\t\t</AlertDescription>\n\t\t\t\t\t\t</Alert>\n\n\t\t\t\t\t\t{/* Action buttons for verification mode */}\n\t\t\t\t\t\t{mode === MnemonicMode.Verify &&\n\t\t\t\t\t\t\t(selectedWords.length > 0 || onBack) && (\n\t\t\t\t\t\t\t\t<div className=\"flex justify-between gap-2\">\n\t\t\t\t\t\t\t\t\t{onBack ? (\n\t\t\t\t\t\t\t\t\t\t<Button variant=\"outline\" onClick={onBack}>\n\t\t\t\t\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\t\t\t\t\twidth=\"16\"\n\t\t\t\t\t\t\t\t\t\t\t\theight=\"16\"\n\t\t\t\t\t\t\t\t\t\t\t\tfill=\"currentColor\"\n\t\t\t\t\t\t\t\t\t\t\t\tviewBox=\"0 0 20 20\"\n\t\t\t\t\t\t\t\t\t\t\t\taria-label=\"Back\"\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"mr-1\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<title>Back</title>\n\t\t\t\t\t\t\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t\t\t\t\t\t\tfillRule=\"evenodd\"\n\t\t\t\t\t\t\t\t\t\t\t\t\td=\"M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tclipRule=\"evenodd\"\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t\t\t\t\tView Recovery Phrase\n\t\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t<div />\n\t\t\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t\t\t{selectedWords.length > 0 && (\n\t\t\t\t\t\t\t\t\t\t<Button variant=\"outline\" onClick={resetVerification}>\n\t\t\t\t\t\t\t\t\t\t\t<ResetIcon className=\"h-4 w-4 mr-1\" aria-label=\"Reset\" />\n\t\t\t\t\t\t\t\t\t\t\tStart Over\n\t\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t</CardContent>\n\t\t\t</Card>\n\n\t\t\t{onContinue && mode === MnemonicMode.View && (\n\t\t\t\t<div className=\"space-y-3\">\n\t\t\t\t\t<div className=\"flex items-start gap-3\">\n\t\t\t\t\t\t<Checkbox\n\t\t\t\t\t\t\tid=\"acknowledge-checkbox\"\n\t\t\t\t\t\t\tchecked={acknowledged}\n\t\t\t\t\t\t\tonCheckedChange={(checked) => setAcknowledged(checked === true)}\n\t\t\t\t\t\t\tclassName=\"mt-0.5\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Label\n\t\t\t\t\t\t\thtmlFor=\"acknowledge-checkbox\"\n\t\t\t\t\t\t\tclassName=\"text-sm font-normal cursor-pointer\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tI have written down my recovery phrase and stored it in a safe\n\t\t\t\t\t\t\tplace\n\t\t\t\t\t\t</Label>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t{requireVerification ? (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tsize=\"lg\"\n\t\t\t\t\t\t\tonClick={() => onResult?.({ verified: false })}\n\t\t\t\t\t\t\tdisabled={!acknowledged}\n\t\t\t\t\t\t\tclassName=\"w-full\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tVerify Recovery Phrase\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tsize=\"lg\"\n\t\t\t\t\t\t\tonClick={onContinue}\n\t\t\t\t\t\t\tdisabled={!acknowledged}\n\t\t\t\t\t\t\tclassName=\"w-full\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tContinue\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{mode === MnemonicMode.Import && (\n\t\t\t\t<Button\n\t\t\t\t\tsize=\"lg\"\n\t\t\t\t\tonClick={() =>\n\t\t\t\t\t\tonResult?.({ importedMnemonic: importWords.join(\" \") })\n\t\t\t\t\t}\n\t\t\t\t\tdisabled={!isComplete}\n\t\t\t\t\tclassName=\"w-full\"\n\t\t\t\t>\n\t\t\t\t\tImport Wallet\n\t\t\t\t</Button>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\n// Note: MnemonicMode and MnemonicResult are already exported above\n",
"target": "<%- config.aliases.components %>/mnemonicdisplay.tsx"
}
]
}