AbilitySelector
Toggleable grid of AI capability chips (Web Search, Code Exec, etc.). Selected chips highlight with an animated checkmark.
Use and inspectUse this as a presentational interface around your own submit, stream, or state handlers. Reset preview only remounts the local example; it does not send a request or connect to a model.Next: inspect the source and wire its callback to a bounded backend action.
AbilitySelectorToggleable grid of AI capability chips (Web Search, Code Exec, etc.). Selected chips highlight with an animated checkmark.
"use client";
import { useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
const DEFAULT_ABILITIES = [
{ id: "web-search", label: "Web Search", icon: "🔍" },
{ id: "code-exec", label: "Code Exec", icon: "⚡" },
{ id: "file-read", label: "File Read", icon: "📄" },
{ id: "image-gen", label: "Image Gen", icon: "🎨" },
{ id: "memory", label: "Memory", icon: "🧠" },
{ id: "reasoning", label: "Reasoning", icon: "💡" },
];
type AbilitySelectorProps = {
selected: string[];
onChange: (abilities: string[]) => void;
};
export function AbilitySelector({ selected, onChange }: AbilitySelectorProps) {
function toggle(id: string) {
if (selected.includes(id)) {
onChange(selected.filter((s) => s !== id));
} else {
onChange([...selected, id]);
}
}
return (
<div className="pk-ability-sel">
<div className="pk-ability-sel-label">Abilities</div>
<div className="pk-ability-sel-grid">
{DEFAULT_ABILITIES.map((a) => {
const on = selected.includes(a.id);
return (
<motion.button
key={a.id}
className={"pk-ability-chip" + (on ? " pk-ability-chip--on" : "")}
onClick={() => toggle(a.id)}
whileTap={{ scale: 0.95 }}
transition={{ type: "spring", stiffness: 300, damping: 20 }}
aria-pressed={on}
>
<span className="pk-ability-chip-icon">{a.icon}</span>
<span className="pk-ability-chip-label">{a.label}</span>
<AnimatePresence>
{on && (
<motion.span
className="pk-ability-chip-check"
initial={{ opacity: 0, scale: 0.5 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.5 }}
transition={{ type: "spring", stiffness: 400, damping: 18 }}
>
✓
</motion.span>
)}
</AnimatePresence>
</motion.button>
);
})}
</div>
</div>
);
}Install
npm install framer-motion
This component requires framer-motion.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
selected* | string[] | — | Array of active ability ids |
onChange* | (abilities: string[]) => void | — | Called when an ability is toggled |