MCPcopy
hub / github.com/codeaashu/claude-code / FuzzyPicker

Function FuzzyPicker

src/components/design-system/FuzzyPicker.tsx:68–217  ·  view source on GitHub ↗
({
  title,
  placeholder = 'Type to search…',
  initialQuery,
  items,
  getKey,
  renderItem,
  renderPreview,
  previewPosition = 'bottom',
  visibleCount: requestedVisible = DEFAULT_VISIBLE,
  direction = 'down',
  onQueryChange,
  onSelect,
  onTab,
  onShiftTab,
  onFocus,
  onCancel,
  emptyMessage = 'No results',
  matchLabel,
  selectAction = 'select',
  extraHints
}: Props<T>)

Source from the content-addressed store, hash-verified

66const CHROME_ROWS = 10;
67const MIN_VISIBLE = 2;
68export function FuzzyPicker<T>({
69 title,
70 placeholder = 'Type to search…',
71 initialQuery,
72 items,
73 getKey,
74 renderItem,
75 renderPreview,
76 previewPosition = 'bottom',
77 visibleCount: requestedVisible = DEFAULT_VISIBLE,
78 direction = 'down',
79 onQueryChange,
80 onSelect,
81 onTab,
82 onShiftTab,
83 onFocus,
84 onCancel,
85 emptyMessage = 'No results',
86 matchLabel,
87 selectAction = 'select',
88 extraHints
89}: Props<T>): React.ReactNode {
90 const isTerminalFocused = useTerminalFocus();
91 const {
92 rows,
93 columns
94 } = useTerminalSize();
95 const [focusedIndex, setFocusedIndex] = useState(0);
96
97 // Cap visibleCount so the picker never exceeds the terminal height. When it
98 // overflows, each re-render (arrow key, ctrl+p) mis-positions the cursor-up
99 // by the overflow amount and a previously-drawn line flashes blank.
100 const visibleCount = Math.max(MIN_VISIBLE, Math.min(requestedVisible, rows - CHROME_ROWS - (matchLabel ? 1 : 0)));
101
102 // Full hint row with onTab+onShiftTab is ~100 chars and wraps inconsistently
103 // below that. Compact mode drops shift+tab and shortens labels.
104 const compact = columns < 120;
105 const step = (delta: 1 | -1) => {
106 setFocusedIndex(i => clamp(i + delta, 0, items.length - 1));
107 };
108
109 // onKeyDown fires after useSearchInput's useInput, so onExit must be a
110 // no-op — return/downArrow are handled by handleKeyDown below. onCancel
111 // still covers escape/ctrl+c/ctrl+d. Backspace-on-empty is disabled so
112 // a held backspace doesn't eject the user from the dialog.
113 const {
114 query,
115 cursorOffset
116 } = useSearchInput({
117 isActive: true,
118 onExit: () => {},
119 onCancel,
120 initialQuery,
121 backspaceExitsOnEmpty: false
122 });
123 const handleKeyDown = (e: KeyboardEvent) => {
124 if (e.key === 'up' || e.ctrl && e.key === 'p') {
125 e.preventDefault();

Callers

nothing calls this directly

Calls 6

useTerminalFocusFunction · 0.85
useTerminalSizeFunction · 0.85
useSearchInputFunction · 0.85
clampFunction · 0.85
firstWordFunction · 0.85
maxMethod · 0.80

Tested by

no test coverage detected