Tesseract / studio /src /components /SlashMenu.jsx
rkbosamia's picture
Tesseract major version upgrade - v2
9c49532
Raw
History Blame Contribute Delete
2.19 kB
/**
* SlashMenu — autocomplete popover that floats above the composer when the
* input starts with "/". Renders filtered slash commands; the parent owns
* cursor state and Enter / arrow handling (so the textarea keeps focus).
*/
export default function SlashMenu({ items, cursor, onPick }) {
if (!items.length) return null
return (
<div
className="fade-in"
style={{
position: 'absolute',
bottom: 'calc(100% + 6px)',
left: 8,
right: 8,
maxHeight: 240,
overflowY: 'auto',
background: 'var(--surface-3)',
border: '1px solid var(--border-2)',
borderRadius: 10,
padding: 4,
boxShadow: '0 12px 28px rgba(0,0,0,0.4)',
zIndex: 20,
}}
>
{items.map((item, idx) => {
const active = idx === cursor
return (
<button
key={item.id}
type="button"
onMouseDown={(e) => {
// Prevent the textarea from losing focus on click.
e.preventDefault()
if (!item.disabled) onPick(idx)
}}
disabled={item.disabled}
className="w-full flex items-center justify-between px-3 py-1.5 rounded-md text-left"
style={{
background: active ? 'var(--accent-bg)' : 'transparent',
color: item.disabled ? 'var(--text-faint)' : 'var(--text)',
cursor: item.disabled ? 'not-allowed' : 'pointer',
opacity: item.disabled ? 0.45 : 1,
transition: 'background 0.1s',
}}
title={item.disabled ? 'Not available right now' : item.hint}
>
<span
className="mono text-[12px]"
style={{ color: active ? 'var(--accent-hi)' : 'var(--text-dim)' }}
>
{item.label}
</span>
<span
className="text-[10.5px] ml-3 truncate"
style={{ color: 'var(--text-faint)' }}
>
{item.hint}
</span>
</button>
)
})}
</div>
)
}