mode-selector
agent-elements/mode-selectorFreeComponent
agent-elements publishes no description for this item.
Live preview
live · rendered by the registry
Rendered by agent-elements on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://agent-elements.21st.dev/r/mode-selector.jsonSource
1"use client";23import { memo, useCallback, useState } from "react";4import type { ComponentType } from "react";5import { IconCheck, IconChevronDown } from "@tabler/icons-react";6import { cn } from "../utils/cn";7import { Popover } from "./popover";89export type ModeOption = {10 id: string;11 label: string;12 icon?: ComponentType<{ className?: string }>;13 description?: string;14};1516export type ModeSelectorProps = {17 modes: ModeOption[];18 value?: string;19 defaultValue?: string;20 onChange?: (modeId: string) => void;21 className?: string;22};2324export const ModeSelector = memo(function ModeSelector({25 modes,26 value,27 defaultValue,28 onChange,29 className,30}: ModeSelectorProps) {31 const isControlled = value !== undefined;32 const [internalValue, setInternalValue] = useState(defaultValue);33 const activeId = isControlled ? value : internalValue;34 const activeMode = modes.find((m) => m.id === activeId) ?? modes[0];35 const [open, setOpen] = useState(false);3637 const handleSelect = useCallback(38 (id: string) => {39 if (!isControlled) setInternalValue(id);40 onChange?.(id);41 setOpen(false);42 },43 [isControlled, onChange],44 );4546 if (modes.length === 0) return null;47 const ActiveIcon = activeMode?.icon;48 const hasMultiple = modes.length > 1;4950 const trigger = (51 <button52 type="button"53 className={cn(54 "inline-flex h-7 items-center gap-1.5 rounded-[6px] px-2 text-[12px] leading-4 text-foreground/40 transition-colors hover:bg-foreground/6 cursor-pointer",55 !hasMultiple && "pointer-events-none",56 className,57 )}58 aria-label="Select mode"59 >60 {ActiveIcon && <ActiveIcon className="size-3.5 shrink-0" />}61 <span className="font-medium">{activeMode?.label}</span>62 {hasMultiple && <IconChevronDown className="size-3 text-foreground/40" />}63 </button>64 );6566 if (!hasMultiple) return trigger;6768 return (69 <Popover70 open={open}71 onOpenChange={setOpen}72 side="top"73 align="start"74 trigger={trigger}75 >76 {modes.map((mode) => {77 const isActive = mode.id === activeMode?.id;78 const Icon = mode.icon;79 return (80 <button81 key={mode.id}82 type="button"83 onClick={() => handleSelect(mode.id)}84 className={cn(85 "flex w-full items-start gap-2 rounded-[6px] px-2 py-1.5 text-left text-[12px] leading-4 text-an-foreground transition-colors hover:bg-foreground/6 cursor-pointer",86// … truncated
More from agent-elements
All 25 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| agent-chatagent-chat | agent-elements | Components | Free | no deps | |
| attachment-buttonattachment-button | agent-elements | Components | Free | no deps | |
| bash-toolbash-tool | agent-elements | Components | Free | no deps | |
| edit-tooledit-tool | agent-elements | Components | Free | no deps | |
| error-messageerror-message | agent-elements | Components | Free | no deps | |
| file-attachmentfile-attachment | agent-elements | Components | Free | no deps | |
| generic-toolgeneric-tool | agent-elements | Components | Free | no deps | |
| input-barinput-bar | agent-elements | Components | Free | no deps |
