{"version":3,"file":"CopilotSidebarView.mjs","names":["CopilotChatView"],"sources":["../../../src/components/chat/CopilotSidebarView.tsx"],"sourcesContent":["import React, { useEffect, useLayoutEffect, useRef, useState } from \"react\";\n\nimport CopilotChatView, {\n  CopilotChatViewProps,\n  WelcomeScreenProps,\n} from \"./CopilotChatView\";\nimport {\n  CopilotChatConfigurationProvider,\n  useCopilotChatConfiguration,\n} from \"@/providers/CopilotChatConfigurationProvider\";\nimport CopilotChatToggleButton from \"./CopilotChatToggleButton\";\nimport { cn } from \"@/lib/utils\";\nimport { CopilotModalHeader } from \"./CopilotModalHeader\";\nimport { renderSlot, SlotValue } from \"@/lib/slots\";\n\nconst DEFAULT_SIDEBAR_WIDTH = 480;\nconst SIDEBAR_TRANSITION_MS = 260;\n\nexport type CopilotSidebarViewProps = CopilotChatViewProps & {\n  header?: SlotValue<typeof CopilotModalHeader>;\n  toggleButton?: SlotValue<typeof CopilotChatToggleButton>;\n  width?: number | string;\n  defaultOpen?: boolean;\n};\n\nexport function CopilotSidebarView({\n  header,\n  toggleButton,\n  width,\n  defaultOpen = true,\n  ...props\n}: CopilotSidebarViewProps) {\n  return (\n    <CopilotChatConfigurationProvider isModalDefaultOpen={defaultOpen}>\n      <CopilotSidebarViewInternal\n        header={header}\n        toggleButton={toggleButton}\n        width={width}\n        {...props}\n      />\n    </CopilotChatConfigurationProvider>\n  );\n}\n\nfunction CopilotSidebarViewInternal({\n  header,\n  toggleButton,\n  width,\n  ...props\n}: Omit<CopilotSidebarViewProps, \"defaultOpen\">) {\n  const configuration = useCopilotChatConfiguration();\n\n  const isSidebarOpen = configuration?.isModalOpen ?? false;\n\n  const sidebarRef = useRef<HTMLDivElement | null>(null);\n  const [sidebarWidth, setSidebarWidth] = useState<number | string>(\n    width ?? DEFAULT_SIDEBAR_WIDTH,\n  );\n\n  // Helper to convert width to CSS value\n  const widthToCss = (w: number | string): string => {\n    return typeof w === \"number\" ? `${w}px` : w;\n  };\n\n  // Helper to extract numeric value for body margin (only works with px values)\n  const widthToMargin = (w: number | string): string => {\n    if (typeof w === \"number\") {\n      return `${w}px`;\n    }\n    // For string values, use as-is (assumes valid CSS unit)\n    return w;\n  };\n\n  useEffect(() => {\n    // If width is explicitly provided, don't measure\n    if (width !== undefined) {\n      return;\n    }\n\n    if (typeof window === \"undefined\") {\n      return;\n    }\n\n    const element = sidebarRef.current;\n    if (!element) {\n      return;\n    }\n\n    const updateWidth = () => {\n      const rect = element.getBoundingClientRect();\n      if (rect.width > 0) {\n        setSidebarWidth(rect.width);\n      }\n    };\n\n    updateWidth();\n\n    if (typeof ResizeObserver !== \"undefined\") {\n      const observer = new ResizeObserver(() => updateWidth());\n      observer.observe(element);\n      return () => observer.disconnect();\n    }\n\n    window.addEventListener(\"resize\", updateWidth);\n    return () => window.removeEventListener(\"resize\", updateWidth);\n  }, [width]);\n\n  // Manage body margin for sidebar docking (desktop only).\n  // useLayoutEffect runs before paint, so defaultOpen={true} never causes a\n  // visible layout shift — the margin is already applied on the first frame.\n  const hasMounted = useRef(false);\n\n  useLayoutEffect(() => {\n    if (\n      typeof window === \"undefined\" ||\n      typeof window.matchMedia !== \"function\"\n    )\n      return;\n    if (!window.matchMedia(\"(min-width: 768px)\").matches) return;\n\n    if (isSidebarOpen) {\n      if (hasMounted.current) {\n        document.body.style.transition = `margin-inline-end ${SIDEBAR_TRANSITION_MS}ms ease`;\n      }\n      document.body.style.marginInlineEnd = widthToMargin(sidebarWidth);\n    } else if (hasMounted.current) {\n      document.body.style.transition = `margin-inline-end ${SIDEBAR_TRANSITION_MS}ms ease`;\n      document.body.style.marginInlineEnd = \"\";\n    }\n\n    hasMounted.current = true;\n\n    return () => {\n      document.body.style.marginInlineEnd = \"\";\n      document.body.style.transition = \"\";\n    };\n  }, [isSidebarOpen, sidebarWidth]);\n\n  const headerElement = renderSlot(header, CopilotModalHeader, {});\n  const toggleButtonElement = renderSlot(\n    toggleButton,\n    CopilotChatToggleButton,\n    {},\n  );\n\n  return (\n    <>\n      {toggleButtonElement}\n      <aside\n        ref={sidebarRef}\n        data-copilotkit\n        data-testid=\"copilot-sidebar\"\n        data-copilot-sidebar\n        className={cn(\n          \"copilotKitSidebar copilotKitWindow\",\n          \"cpk:fixed cpk:right-0 cpk:top-0 cpk:z-[1200] cpk:flex\",\n          // Height with dvh fallback and safe area support\n          \"cpk:h-[100vh] cpk:h-[100dvh] cpk:max-h-screen\",\n          // Responsive width: full on mobile, custom on desktop\n          \"cpk:w-full\",\n          \"cpk:border-l cpk:border-border cpk:bg-background cpk:text-foreground cpk:shadow-xl\",\n          \"cpk:transition-transform cpk:duration-300 cpk:ease-out\",\n          isSidebarOpen\n            ? \"cpk:translate-x-0\"\n            : \"cpk:translate-x-full cpk:pointer-events-none\",\n        )}\n        style={\n          {\n            // Use CSS custom property for responsive width\n            [\"--sidebar-width\" as string]: widthToCss(sidebarWidth),\n            // Safe area insets for iOS\n            paddingTop: \"env(safe-area-inset-top)\",\n            paddingBottom: \"env(safe-area-inset-bottom)\",\n          } as React.CSSProperties\n        }\n        aria-hidden={!isSidebarOpen}\n        aria-label=\"Copilot chat sidebar\"\n        role=\"complementary\"\n      >\n        <div className=\"cpk:flex cpk:h-full cpk:w-full cpk:flex-col cpk:overflow-hidden\">\n          {headerElement}\n          <div className=\"cpk:flex-1 cpk:overflow-hidden\" data-sidebar-chat>\n            <CopilotChatView {...props} />\n          </div>\n        </div>\n      </aside>\n    </>\n  );\n}\n\nCopilotSidebarView.displayName = \"CopilotSidebarView\";\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace CopilotSidebarView {\n  /**\n   * Sidebar-specific welcome screen layout:\n   * - Suggestions at the top\n   * - Welcome message in the middle\n   * - Input fixed at the bottom (like normal chat)\n   */\n  export const WelcomeScreen: React.FC<WelcomeScreenProps> = ({\n    welcomeMessage,\n    input,\n    suggestionView,\n    className,\n    children,\n    ...props\n  }) => {\n    // Render the welcomeMessage slot internally\n    const BoundWelcomeMessage = renderSlot(\n      welcomeMessage,\n      CopilotChatView.WelcomeMessage,\n      {},\n    );\n\n    if (children) {\n      return (\n        <div data-copilotkit style={{ display: \"contents\" }}>\n          {children({\n            welcomeMessage: BoundWelcomeMessage,\n            input,\n            suggestionView,\n            className,\n            ...props,\n          })}\n        </div>\n      );\n    }\n\n    return (\n      <div\n        className={cn(\"cpk:h-full cpk:flex cpk:flex-col\", className)}\n        {...props}\n      >\n        {/* Welcome message - centered vertically */}\n        <div className=\"cpk:flex-1 cpk:flex cpk:flex-col cpk:items-center cpk:justify-center cpk:px-4\">\n          {BoundWelcomeMessage}\n        </div>\n\n        {/* Suggestions and input at bottom */}\n        <div className=\"cpk:px-8 cpk:pb-4\">\n          <div className=\"cpk:max-w-3xl cpk:mx-auto\">\n            {/* Suggestions above input */}\n            <div className=\"cpk:mb-4 cpk:flex cpk:justify-center\">\n              {suggestionView}\n            </div>\n            {input}\n          </div>\n        </div>\n      </div>\n    );\n  };\n}\n\nexport default CopilotSidebarView;\n"],"mappings":"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"}