update chatbox
This commit is contained in:
67
src/components/ai-assistant/PromptChips.jsx
Normal file
67
src/components/ai-assistant/PromptChips.jsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import * as React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
/**
|
||||
* PromptChips — suggested prompts.
|
||||
*
|
||||
* Clicking a chip runs it immediately. A chip is already a complete question, so
|
||||
* making the user press Enter afterwards adds a step that buys nothing.
|
||||
*
|
||||
* Chips always wrap onto as many lines as they need. The earlier horizontal-scroll
|
||||
* variant is gone: a scroller can always leave a chip half-visible at the edge,
|
||||
* and a half-visible button is a bug no amount of fade masking fixes. Wrapping
|
||||
* makes clipping structurally impossible instead of merely unlikely.
|
||||
*
|
||||
* `max` caps how many are offered in a conversation, where vertical space belongs
|
||||
* to the thread rather than to suggestions.
|
||||
*
|
||||
* Arrow keys move between chips, so the whole set is one tab stop.
|
||||
*/
|
||||
export function PromptChips({ prompts = [], onSelect, max, align = 'center', className }) {
|
||||
const chipRefs = React.useRef([]);
|
||||
const visible = max ? prompts.slice(0, max) : prompts;
|
||||
|
||||
const onKeyDown = (event, index) => {
|
||||
const delta = event.key === 'ArrowRight' ? 1 : event.key === 'ArrowLeft' ? -1 : 0;
|
||||
if (!delta) return;
|
||||
const next = chipRefs.current[index + delta];
|
||||
if (!next) return;
|
||||
event.preventDefault();
|
||||
next.focus();
|
||||
};
|
||||
|
||||
if (!visible.length) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
role="group"
|
||||
aria-label="Suggested prompts"
|
||||
className={cn(
|
||||
'flex flex-wrap gap-1.5',
|
||||
align === 'center' ? 'justify-center' : 'justify-start',
|
||||
className
|
||||
)}
|
||||
>
|
||||
{visible.map((prompt, i) => (
|
||||
<button
|
||||
key={prompt.label}
|
||||
ref={(el) => { chipRefs.current[i] = el; }}
|
||||
type="button"
|
||||
onClick={() => onSelect(prompt)}
|
||||
onKeyDown={(e) => onKeyDown(e, i)}
|
||||
title={prompt.prompt}
|
||||
className={cn(
|
||||
'rounded-full border border-border bg-surface px-2.5 py-1',
|
||||
'text-caption font-medium text-ink-2 shadow-xs',
|
||||
'transition-all duration-base ease-out',
|
||||
'hover:-translate-y-px hover:border-krow-blue/40 hover:bg-krow-blue-tint hover:text-krow-blue hover:shadow-sm',
|
||||
'active:translate-y-0 active:shadow-xs',
|
||||
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-krow-blue/60 focus-visible:ring-offset-1'
|
||||
)}
|
||||
>
|
||||
{prompt.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user