({
blockId,
subBlockId,
value,
enabled = true,
isReadOnly = false,
isStreaming = false,
debounceMs = 500,
}: UseCodeUndoRedoOptions)
| 20 | } |
| 21 | |
| 22 | export function useCodeUndoRedo({ |
| 23 | blockId, |
| 24 | subBlockId, |
| 25 | value, |
| 26 | enabled = true, |
| 27 | isReadOnly = false, |
| 28 | isStreaming = false, |
| 29 | debounceMs = 500, |
| 30 | }: UseCodeUndoRedoOptions) { |
| 31 | const { collaborativeSetSubblockValue } = useCollaborativeWorkflow() |
| 32 | const activeWorkflowId = useWorkflowRegistry((state) => state.activeWorkflowId) |
| 33 | const { isShowingDiff, hasActiveDiff } = useWorkflowDiffStore( |
| 34 | useShallow((state) => ({ |
| 35 | isShowingDiff: state.isShowingDiff, |
| 36 | hasActiveDiff: state.hasActiveDiff, |
| 37 | })) |
| 38 | ) |
| 39 | |
| 40 | const isBaselineView = hasActiveDiff && !isShowingDiff |
| 41 | const isEnabled = useMemo( |
| 42 | () => Boolean(enabled && activeWorkflowId && !isReadOnly && !isStreaming && !isBaselineView), |
| 43 | [enabled, activeWorkflowId, isReadOnly, isStreaming, isBaselineView] |
| 44 | ) |
| 45 | const isReplaceEnabled = useMemo( |
| 46 | () => Boolean(enabled && activeWorkflowId && !isReadOnly && !isBaselineView), |
| 47 | [enabled, activeWorkflowId, isReadOnly, isBaselineView] |
| 48 | ) |
| 49 | |
| 50 | const lastCommittedValueRef = useRef<string>(value ?? '') |
| 51 | const pendingBeforeRef = useRef<string | null>(null) |
| 52 | const pendingAfterRef = useRef<string | null>(null) |
| 53 | const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null) |
| 54 | const isApplyingRef = useRef(false) |
| 55 | |
| 56 | const clearTimer = useCallback(() => { |
| 57 | if (timeoutRef.current) { |
| 58 | clearTimeout(timeoutRef.current) |
| 59 | timeoutRef.current = null |
| 60 | } |
| 61 | }, []) |
| 62 | |
| 63 | const resetPending = useCallback(() => { |
| 64 | pendingBeforeRef.current = null |
| 65 | pendingAfterRef.current = null |
| 66 | }, []) |
| 67 | |
| 68 | const commitPending = useCallback(() => { |
| 69 | if (!isEnabled || !activeWorkflowId) { |
| 70 | clearTimer() |
| 71 | resetPending() |
| 72 | return |
| 73 | } |
| 74 | |
| 75 | const before = pendingBeforeRef.current |
| 76 | const after = pendingAfterRef.current |
| 77 | if (before === null || after === null) return |
| 78 | |
| 79 | if (before === after) { |
no test coverage detected