diff options
| author | Adam <[email protected]> | 2026-04-07 11:06:23 -0500 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-04-07 11:06:23 -0500 |
| commit | ec8b9810b4231cd6a5c69ccd930b6c50999fc997 (patch) | |
| tree | 562313d6dd3eda9891f3a4a3a2ef6ce3d36acd05 /packages/ui/src/components/basic-tool.tsx | |
| parent | 65318a80f7a3320ba77b749241f8de997dc65c82 (diff) | |
| download | opencode-ec8b9810b4231cd6a5c69ccd930b6c50999fc997.tar.gz opencode-ec8b9810b4231cd6a5c69ccd930b6c50999fc997.zip | |
feat(app): better subagent experience (#20708)
Diffstat (limited to 'packages/ui/src/components/basic-tool.tsx')
| -rw-r--r-- | packages/ui/src/components/basic-tool.tsx | 142 |
1 files changed, 86 insertions, 56 deletions
diff --git a/packages/ui/src/components/basic-tool.tsx b/packages/ui/src/components/basic-tool.tsx index a02fe941b..7d18dfacd 100644 --- a/packages/ui/src/components/basic-tool.tsx +++ b/packages/ui/src/components/basic-tool.tsx @@ -34,6 +34,9 @@ export interface BasicToolProps { locked?: boolean animated?: boolean onSubtitleClick?: () => void + onTriggerClick?: JSX.EventHandlerUnion<HTMLElement, MouseEvent> + triggerHref?: string + clickable?: boolean } const SPRING = { type: "spring" as const, visualDuration: 0.35, bounce: 0 } @@ -121,74 +124,101 @@ export function BasicTool(props: BasicToolProps) { setState("open", value) } - return ( - <Collapsible open={open()} onOpenChange={handleOpenChange} class="tool-collapsible"> - <Collapsible.Trigger> - <div data-component="tool-trigger"> - <div data-slot="basic-tool-tool-trigger-content"> - <div data-slot="basic-tool-tool-info"> - <Switch> - <Match when={isTriggerTitle(props.trigger) && props.trigger}> - {(trigger) => ( - <div data-slot="basic-tool-tool-info-structured"> - <div data-slot="basic-tool-tool-info-main"> + const trigger = () => ( + <div + data-component="tool-trigger" + data-clickable={props.clickable ? "true" : undefined} + data-hide-details={props.hideDetails ? "true" : undefined} + > + <div data-slot="basic-tool-tool-trigger-content"> + <div data-slot="basic-tool-tool-info"> + <Switch> + <Match when={isTriggerTitle(props.trigger) && props.trigger}> + {(title) => ( + <div data-slot="basic-tool-tool-info-structured"> + <div data-slot="basic-tool-tool-info-main"> + <span + data-slot="basic-tool-tool-title" + classList={{ + [title().titleClass ?? ""]: !!title().titleClass, + }} + > + <TextShimmer text={title().title} active={pending()} /> + </span> + <Show when={!pending()}> + <Show when={title().subtitle}> <span - data-slot="basic-tool-tool-title" + data-slot="basic-tool-tool-subtitle" classList={{ - [trigger().titleClass ?? ""]: !!trigger().titleClass, + [title().subtitleClass ?? ""]: !!title().subtitleClass, + clickable: !!props.onSubtitleClick, + }} + onClick={(e) => { + if (props.onSubtitleClick) { + e.stopPropagation() + props.onSubtitleClick() + } }} > - <TextShimmer text={trigger().title} active={pending()} /> + {title().subtitle} </span> - <Show when={!pending()}> - <Show when={trigger().subtitle}> + </Show> + <Show when={title().args?.length}> + <For each={title().args}> + {(arg) => ( <span - data-slot="basic-tool-tool-subtitle" + data-slot="basic-tool-tool-arg" classList={{ - [trigger().subtitleClass ?? ""]: !!trigger().subtitleClass, - clickable: !!props.onSubtitleClick, - }} - onClick={(e) => { - if (props.onSubtitleClick) { - e.stopPropagation() - props.onSubtitleClick() - } + [title().argsClass ?? ""]: !!title().argsClass, }} > - {trigger().subtitle} + {arg} </span> - </Show> - <Show when={trigger().args?.length}> - <For each={trigger().args}> - {(arg) => ( - <span - data-slot="basic-tool-tool-arg" - classList={{ - [trigger().argsClass ?? ""]: !!trigger().argsClass, - }} - > - {arg} - </span> - )} - </For> - </Show> - </Show> - </div> - <Show when={!pending() && trigger().action}> - <span data-slot="basic-tool-tool-action">{trigger().action}</span> + )} + </For> </Show> - </div> - )} - </Match> - <Match when={true}>{props.trigger as JSX.Element}</Match> - </Switch> - </div> - </div> - <Show when={props.children && !props.hideDetails && !props.locked && !pending()}> - <Collapsible.Arrow /> - </Show> + </Show> + </div> + <Show when={!pending() && title().action}> + <span data-slot="basic-tool-tool-action">{title().action}</span> + </Show> + </div> + )} + </Match> + <Match when={true}>{props.trigger as JSX.Element}</Match> + </Switch> </div> - </Collapsible.Trigger> + </div> + <Show when={props.children && !props.hideDetails && !props.locked && !pending()}> + <Collapsible.Arrow /> + </Show> + </div> + ) + + return ( + <Collapsible open={open()} onOpenChange={handleOpenChange} class="tool-collapsible"> + <Show + when={props.triggerHref} + fallback={ + <Collapsible.Trigger + data-hide-details={props.hideDetails ? "true" : undefined} + onClick={props.onTriggerClick} + > + {trigger()} + </Collapsible.Trigger> + } + > + {(href) => ( + <Collapsible.Trigger + as="a" + href={href()} + data-hide-details={props.hideDetails ? "true" : undefined} + onClick={props.onTriggerClick} + > + {trigger()} + </Collapsible.Trigger> + )} + </Show> <Show when={props.animated && props.children && !props.hideDetails}> <div ref={contentRef} |
