refactor: 大规模迁移原有组件到 ink 包内

This commit is contained in:
claude-code-best
2026-04-07 22:26:45 +08:00
parent 52a9cc0414
commit 91b9366f64
44 changed files with 563 additions and 2480 deletions

View File

@@ -1,62 +1,3 @@
// Creates a function that calls one function on the first call and another
// function on the second call within a certain timeout
import { useCallback, useEffect, useRef } from 'react'
export const DOUBLE_PRESS_TIMEOUT_MS = 800
export function useDoublePress(
setPending: (pending: boolean) => void,
onDoublePress: () => void,
onFirstPress?: () => void,
): () => void {
const lastPressRef = useRef<number>(0)
const timeoutRef = useRef<NodeJS.Timeout | undefined>(undefined)
const clearTimeoutSafe = useCallback(() => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current)
timeoutRef.current = undefined
}
}, [])
// Cleanup timeout on unmount
useEffect(() => {
return () => {
clearTimeoutSafe()
}
}, [clearTimeoutSafe])
return useCallback(() => {
const now = Date.now()
const timeSinceLastPress = now - lastPressRef.current
const isDoublePress =
timeSinceLastPress <= DOUBLE_PRESS_TIMEOUT_MS &&
timeoutRef.current !== undefined
if (isDoublePress) {
// Double press detected
clearTimeoutSafe()
setPending(false)
onDoublePress()
} else {
// First press
onFirstPress?.()
setPending(true)
// Clear any existing timeout and set new one
clearTimeoutSafe()
timeoutRef.current = setTimeout(
(setPending, timeoutRef) => {
setPending(false)
timeoutRef.current = undefined
},
DOUBLE_PRESS_TIMEOUT_MS,
setPending,
timeoutRef,
)
}
lastPressRef.current = now
}, [setPending, onDoublePress, onFirstPress, clearTimeoutSafe])
}
// Re-export from @anthropic/ink hooks module
export { useDoublePress } from '@anthropic/ink'
export { DOUBLE_PRESS_TIMEOUT_MS } from '@anthropic/ink'

View File

@@ -1,35 +1,2 @@
import { useEffect, useRef, useState } from 'react'
/**
* Throttles a value so each distinct value stays visible for at least `minMs`.
* Prevents fast-cycling progress text from flickering past before it's readable.
*
* Unlike debounce (wait for quiet) or throttle (limit rate), this guarantees
* each value gets its minimum screen time before being replaced.
*/
export function useMinDisplayTime<T>(value: T, minMs: number): T {
const [displayed, setDisplayed] = useState(value)
const lastShownAtRef = useRef(0)
useEffect(() => {
const elapsed = Date.now() - lastShownAtRef.current
if (elapsed >= minMs) {
lastShownAtRef.current = Date.now()
setDisplayed(value)
return
}
const timer = setTimeout(
(shownAtRef, setFn, v) => {
shownAtRef.current = Date.now()
setFn(v)
},
minMs - elapsed,
lastShownAtRef,
setDisplayed,
value,
)
return () => clearTimeout(timer)
}, [value, minMs])
return displayed
}
// Re-export from @anthropic/ink hooks module
export { useMinDisplayTime } from '@anthropic/ink'

View File

@@ -1,12 +1,2 @@
import { useContext } from 'react'
import { type TerminalSize, TerminalSizeContext } from '@anthropic/ink'
export function useTerminalSize(): TerminalSize {
const size = useContext(TerminalSizeContext)
if (!size) {
throw new Error('useTerminalSize must be used within an Ink App component')
}
return size
}
// Re-export from @anthropic/ink hooks module
export { useTerminalSize } from '@anthropic/ink'

View File

@@ -1,14 +1,2 @@
import { useEffect, useState } from 'react'
export function useTimeout(delay: number, resetTrigger?: number): boolean {
const [isElapsed, setIsElapsed] = useState(false)
useEffect(() => {
setIsElapsed(false)
const timer = setTimeout(setIsElapsed, delay, true)
return () => clearTimeout(timer)
}, [delay, resetTrigger])
return isElapsed
}
// Re-export from @anthropic/ink hooks module
export { useTimeout } from '@anthropic/ink'