clean presidio
This commit is contained in:
@@ -28,11 +28,10 @@ export const InteractiveTextEditor: React.FC<InteractiveTextEditorProps> = ({
|
||||
onRemoveMapping,
|
||||
}) => {
|
||||
const [selectedWords, setSelectedWords] = useState<Set<number>>(new Set());
|
||||
const [hoveredWord, setHoveredWord] = useState<number | null>(null);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { words } = useTextParsing(text, entityMappings);
|
||||
const { getCurrentColor } = useColorMapping(entityMappings); // CORRECTION: Passer entityMappings
|
||||
const { getCurrentColor } = useColorMapping(entityMappings);
|
||||
const {
|
||||
contextMenu,
|
||||
showContextMenu,
|
||||
@@ -42,7 +41,7 @@ export const InteractiveTextEditor: React.FC<InteractiveTextEditorProps> = ({
|
||||
getExistingLabels,
|
||||
} = useContextMenu({
|
||||
entityMappings,
|
||||
words, // NOUVEAU: passer les mots
|
||||
words,
|
||||
onUpdateMapping,
|
||||
onRemoveMapping,
|
||||
getCurrentColor,
|
||||
@@ -50,15 +49,10 @@ export const InteractiveTextEditor: React.FC<InteractiveTextEditorProps> = ({
|
||||
});
|
||||
|
||||
const handleWordClick = useCallback(
|
||||
(index: number, event: React.MouseEvent) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
// Support multi-sélection avec Ctrl, Cmd et Shift
|
||||
const isMultiSelect = event.ctrlKey || event.metaKey || event.shiftKey;
|
||||
|
||||
if (isMultiSelect) {
|
||||
setSelectedWords((prev) => {
|
||||
(index: number | null, event: React.MouseEvent) => {
|
||||
if (index !== null) {
|
||||
event.preventDefault();
|
||||
setSelectedWords(prev => {
|
||||
const newSet = new Set(prev);
|
||||
if (newSet.has(index)) {
|
||||
newSet.delete(index);
|
||||
@@ -67,53 +61,87 @@ export const InteractiveTextEditor: React.FC<InteractiveTextEditorProps> = ({
|
||||
}
|
||||
return newSet;
|
||||
});
|
||||
} else {
|
||||
setSelectedWords(new Set([index]));
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const handleContextMenu = useCallback(
|
||||
const handleContainerContextMenu = useCallback(
|
||||
(event: React.MouseEvent) => {
|
||||
event.preventDefault();
|
||||
if (selectedWords.size === 0) return;
|
||||
|
||||
// Priorité à la sélection de texte libre
|
||||
const selection = window.getSelection();
|
||||
if (selection && selection.toString().trim()) {
|
||||
const selectedText = selection.toString().trim();
|
||||
showContextMenu({
|
||||
x: event.clientX,
|
||||
y: event.clientY,
|
||||
selectedText,
|
||||
wordIndices: [], // Sélection libre, pas d'indices de mots
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback sur la sélection par mots si pas de sélection libre
|
||||
if (selectedWords.size > 0) {
|
||||
const selectedText = Array.from(selectedWords)
|
||||
.sort((a, b) => a - b)
|
||||
.map((index) => {
|
||||
const word = words[index];
|
||||
return word?.isEntity ? word.text : word?.text;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
|
||||
const selectedText = Array.from(selectedWords)
|
||||
.map((index) => {
|
||||
const word = words[index];
|
||||
return word?.isEntity ? word.text : word?.text;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
|
||||
showContextMenu({
|
||||
x: event.clientX,
|
||||
y: event.clientY,
|
||||
selectedText,
|
||||
wordIndices: Array.from(selectedWords),
|
||||
});
|
||||
showContextMenu({
|
||||
x: event.clientX,
|
||||
y: event.clientY,
|
||||
selectedText,
|
||||
wordIndices: Array.from(selectedWords),
|
||||
});
|
||||
}
|
||||
},
|
||||
[selectedWords, words, showContextMenu]
|
||||
);
|
||||
|
||||
const handleClearSelection = useCallback(() => {
|
||||
setSelectedWords(new Set());
|
||||
// Effacer la sélection de texte native
|
||||
const selection = window.getSelection();
|
||||
if (selection) {
|
||||
selection.removeAllRanges();
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className="relative">
|
||||
<div className="mb-2">
|
||||
<button
|
||||
onClick={handleClearSelection}
|
||||
className="px-3 py-1 bg-gray-200 hover:bg-gray-300 rounded text-sm"
|
||||
>
|
||||
Effacer la sélection
|
||||
</button>
|
||||
{selectedWords.size > 0 && (
|
||||
<span className="ml-2 text-sm text-gray-600">
|
||||
{selectedWords.size} mot(s) sélectionné(s)
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<TextDisplay
|
||||
words={words}
|
||||
text={text}
|
||||
selectedWords={selectedWords}
|
||||
hoveredWord={hoveredWord}
|
||||
onContextMenu={handleContainerContextMenu}
|
||||
onWordClick={handleWordClick}
|
||||
onContextMenu={handleContextMenu}
|
||||
onWordHover={setHoveredWord}
|
||||
/>
|
||||
|
||||
{contextMenu.visible && (
|
||||
<ContextMenu
|
||||
contextMenu={contextMenu}
|
||||
existingLabels={getExistingLabels()}
|
||||
// entityMappings={entityMappings} // SUPPRIMER cette ligne
|
||||
onApplyLabel={applyLabel}
|
||||
onApplyColor={applyColorDirectly}
|
||||
onRemoveLabel={removeLabel}
|
||||
|
||||
Reference in New Issue
Block a user