clean presidio

This commit is contained in:
Biqoz
2026-01-29 00:19:50 +01:00
parent 050474e95b
commit 90b73080e0
11 changed files with 667 additions and 516 deletions

View File

@@ -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}