❇️ dismissal from intervention
This commit is contained in:
@@ -41,6 +41,27 @@ const rawAnnotationsField = StateField.define<TextAnnotation[]>({
|
|||||||
// Per-session cache: annotation id → { text, suggestion extracted from blockquote }
|
// Per-session cache: annotation id → { text, suggestion extracted from blockquote }
|
||||||
export const tooltipAnalysisCache = new Map<string, { text: string; suggestion: string | null }>()
|
export const tooltipAnalysisCache = new Map<string, { text: string; suggestion: string | null }>()
|
||||||
|
|
||||||
|
// Debounced auto-dismissal when the user edits text inside a highlighted range.
|
||||||
|
// Exported so FeedbackPanel can cancel a pending timer on manual dismiss.
|
||||||
|
const EDIT_DISMISS_MS = 1200
|
||||||
|
const dismissTimers = new Map<string, ReturnType<typeof setTimeout>>()
|
||||||
|
|
||||||
|
export function cancelPendingDismiss(id: string): void {
|
||||||
|
const t = dismissTimers.get(id)
|
||||||
|
if (t !== undefined) { clearTimeout(t); dismissTimers.delete(id) }
|
||||||
|
}
|
||||||
|
|
||||||
|
function schedulePendingDismiss(id: string): void {
|
||||||
|
const existing = dismissTimers.get(id)
|
||||||
|
if (existing !== undefined) clearTimeout(existing)
|
||||||
|
dismissTimers.set(id, setTimeout(() => {
|
||||||
|
dismissTimers.delete(id)
|
||||||
|
const { removeAnnotation } = useEditorStore.getState()
|
||||||
|
removeAnnotation(id)
|
||||||
|
tooltipAnalysisCache.delete(id)
|
||||||
|
}, EDIT_DISMISS_MS))
|
||||||
|
}
|
||||||
|
|
||||||
// Extract the first blockquote from a markdown string — used as the applicable rewrite
|
// Extract the first blockquote from a markdown string — used as the applicable rewrite
|
||||||
function extractBlockquote(md: string): string | null {
|
function extractBlockquote(md: string): string | null {
|
||||||
const lines = md.split('\n')
|
const lines = md.split('\n')
|
||||||
@@ -357,11 +378,36 @@ export function MarkdownEditor(): JSX.Element {
|
|||||||
tr => tr.isUserEvent('undo') || tr.isUserEvent('redo')
|
tr => tr.isUserEvent('undo') || tr.isUserEvent('redo')
|
||||||
)
|
)
|
||||||
if (hasUndoRedo) {
|
if (hasUndoRedo) {
|
||||||
|
// User is reverting edits — cancel any pending auto-dismissals so
|
||||||
|
// restored highlights aren't immediately removed.
|
||||||
|
dismissTimers.forEach((_, id) => cancelPendingDismiss(id))
|
||||||
const prev = update.startState.field(rawAnnotationsField)
|
const prev = update.startState.field(rawAnnotationsField)
|
||||||
const curr = update.state.field(rawAnnotationsField)
|
const curr = update.state.field(rawAnnotationsField)
|
||||||
if (prev !== curr) {
|
if (prev !== curr) {
|
||||||
useEditorStore.getState().setAnnotations(curr)
|
useEditorStore.getState().setAnnotations(curr)
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-dismiss annotations whose highlighted text the user edits.
|
||||||
|
// We check the pre-edit annotation positions (startState) against
|
||||||
|
// each changed range reported by the transaction.
|
||||||
|
if (update.docChanged) {
|
||||||
|
const preAnnotations = update.startState.field(rawAnnotationsField)
|
||||||
|
if (preAnnotations.length > 0) {
|
||||||
|
for (const tr of update.transactions) {
|
||||||
|
if (!tr.docChanged) continue
|
||||||
|
// Skip non-user events such as file loads (addToHistory=false).
|
||||||
|
if (tr.annotation(Transaction.addToHistory) === false) continue
|
||||||
|
tr.changes.iterChangedRanges((fromA, toA) => {
|
||||||
|
for (const ann of preAnnotations) {
|
||||||
|
if (fromA < ann.to && toA > ann.from) {
|
||||||
|
schedulePendingDismiss(ann.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useEditorStore } from '../../store/editorStore'
|
|||||||
import type { TextAnnotation } from '../../types/editor'
|
import type { TextAnnotation } from '../../types/editor'
|
||||||
import {
|
import {
|
||||||
tooltipAnalysisCache,
|
tooltipAnalysisCache,
|
||||||
|
cancelPendingDismiss,
|
||||||
analyseAnnotation,
|
analyseAnnotation,
|
||||||
scrollToAnnotation,
|
scrollToAnnotation,
|
||||||
applyAnnotation
|
applyAnnotation
|
||||||
@@ -189,7 +190,7 @@ export function FeedbackPanel(): JSX.Element {
|
|||||||
key={ann.id}
|
key={ann.id}
|
||||||
ann={ann}
|
ann={ann}
|
||||||
autoAnalyse={analyseAll}
|
autoAnalyse={analyseAll}
|
||||||
onDismiss={() => { removeAnnotation(ann.id); tooltipAnalysisCache.delete(ann.id) }}
|
onDismiss={() => { cancelPendingDismiss(ann.id); removeAnnotation(ann.id); tooltipAnalysisCache.delete(ann.id) }}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user