File size: 3,262 Bytes
8c96555 308bca9 1fe47b1 a88e9cf 308bca9 a88e9cf e9e1da2 1fe47b1 a88e9cf 8c96555 a88e9cf 8c96555 1fe47b1 a88e9cf 1fe47b1 0a795e1 308bca9 1fe47b1 8c96555 1fe47b1 0a795e1 8c96555 a88e9cf 8c96555 a88e9cf 8c96555 308bca9 a88e9cf 308bca9 a88e9cf 308bca9 a88e9cf 308bca9 a88e9cf 8c96555 a88e9cf 8c96555 1fe47b1 0970991 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
import React, { useState, useEffect, useRef } from "react"
import { Replacement } from "../interfaces";
interface WordChipProps {
word: string;
logprob: number;
threshold: number;
replacements: Replacement[];
onReplace: (newWord: string) => Promise<void>;
}
export function WordChip({
word,
logprob,
threshold,
replacements,
onReplace
}: WordChipProps) {
const [isExpanded, setIsExpanded] = useState(false);
const [selectedIndex, setSelectedIndex] = useState(-1);
const dropdownRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
setIsExpanded(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, []);
const handleClick = () => {
if (logprob < threshold && replacements.length > 0) {
setIsExpanded(true);
}
}
const handleReplacement = async (newWord: string) => {
console.log("handleReplacement", newWord);
await onReplace(newWord);
setIsExpanded(false); // Close the dropdown
};
console.log(`word: ->${word}<-`);
let w1;
let w2;
let w3;
// if word contains a newline, render a <br />
if (word.includes("\n")) {
[w1, w3] = word.split("\n");
w2 = "\n";
console.log(`split: ${w1} | ${w2} | ${w3}`);
} else {
w1 = word;
w2 = "";
w3 = "";
}
// sort replacements by logprob (make sure not to mutate the original array)
const sortedReplacements = [...replacements].sort((a, b) => b.logprob - a.logprob)
// convert logprobs to probabilities
const withProbabilities = sortedReplacements.map(r => ({ ...r, probability: Math.exp(r.logprob)*100 }))
return (
<span
title={logprob.toFixed(2)}
className={`word-chip ${logprob < threshold ? "flagged" : ""}`}
style={{ position: "relative", cursor: logprob < threshold ? "pointer" : "default" }}
onClick={handleClick}
>
{w1}
{w2 && <br />}
{w3}
{isExpanded && (
<div
ref={dropdownRef}
style={{
position: "absolute",
top: "100%",
left: 0,
zIndex: 100,
maxHeight: "400px",
overflowY: "auto",
backgroundColor: "white",
border: "1px solid #ccc",
borderRadius: "4px",
boxShadow: "0 2px 4px rgba(0,0,0,0.1)"
}}
>
{withProbabilities.map((option, index) => (
<div
key={index}
onClick={() => handleReplacement(option.text)}
onMouseEnter={() => setSelectedIndex(index)}
style={{
padding: "5px 10px",
cursor: "pointer",
color: "black",
backgroundColor: selectedIndex === index ? "#f0f0f0" : "white",
whiteSpace: "nowrap"
}}
>
{option.text} <small style={{ fontSize: "0.7em", color: "#666" }}>{option.probability.toFixed(1)}%</small>
</div>
))}
</div>
)}
</span>
)
}
|