File size: 1,652 Bytes
3201ca6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import FileIcon from "#/icons/file.svg?react";
import { useOptionalConversationId } from "#/hooks/use-conversation-id";
import { openWorkspaceFile } from "#/services/canvas-ui";

interface FilePathChipProps {
  path: string;
  /** Optional line-range suffix, e.g. "12-48". */
  range?: string;
  /**
   * Opens the referenced file when the surrounding visualizer can navigate.
   * Defaults to `openWorkspaceFile` so chips without a parent handler still
   * deep-link into the Files drawer.
   */
  onClick?: () => void;
}

/**
 * Monospace file-path pill with an optional navigation affordance.
 *
 * Passing `onClick` upgrades the same visual language to a custom handler
 * (e.g. markdown artifact View). Without it, click opens the Files drawer.
 */
export function FilePathChip({ path, range, onClick }: FilePathChipProps) {
  const { conversationId } = useOptionalConversationId();
  const content = (
    <>
      <FileIcon className="h-3.5 w-3.5 flex-shrink-0 text-muted" />
      <span className="break-all">{range ? `${path}:${range}` : path}</span>
    </>
  );
  const className =
    "inline-flex max-w-full cursor-pointer items-center gap-1.5 self-start rounded bg-surface-raised px-2 py-0.5 text-left font-mono text-xs text-foreground hover:bg-[var(--oh-interactive-hover)]";

  return (
    <button
      type="button"
      data-testid="file-path-chip"
      title={path}
      className={className}
      onClick={(event) => {
        event.stopPropagation();
        if (onClick) {
          onClick();
          return;
        }
        openWorkspaceFile(path, conversationId);
      }}
    >
      {content}
    </button>
  );
}