{
  "name": "presentation",
  "type": "registry:ui",
  "dependencies": [
    "cn",
    "@diceui/pptx"
  ],
  "registryDependencies": [
    "button",
    "@diceui/use-mobile"
  ],
  "files": [
    {
      "path": "ui/presentation.tsx",
      "type": "registry:ui",
      "content": "\"use client\";\n\nimport { Presentation as PresentationPrimitive } from \"@diceui/pptx\";\nimport { cn } from \"cn\";\nimport * as React from \"react\";\n\nimport { useIsMobile } from \"@/registry/bases/radix/hooks/use-mobile\";\nimport { Button } from \"@/registry/bases/radix/ui/button\";\nimport { IconPlaceholder } from \"@/registry/icons/icon-placeholder\";\n\nfunction PresentationProvider({\n  ...props\n}: PresentationPrimitive.Provider.Props) {\n  return (\n    <PresentationPrimitive.Provider\n      data-slot=\"presentation-provider\"\n      {...props}\n    />\n  );\n}\n\nfunction Presentation({\n  className,\n  ...props\n}: PresentationPrimitive.Root.Props) {\n  return (\n    <PresentationPrimitive.Root\n      data-slot=\"presentation\"\n      className={cn(\"relative flex overflow-hidden\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction PresentationContent({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"presentation-content\"\n      className={cn(\n        \"relative isolate flex flex-1 flex-col overflow-hidden\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction PresentationViewport({\n  className,\n  autoFit = true,\n  autoFitPadding = 10,\n  ...props\n}: PresentationPrimitive.Viewport.Props) {\n  return (\n    <PresentationPrimitive.Viewport\n      autoFit={autoFit}\n      autoFitPadding={autoFitPadding}\n      data-slot=\"presentation-viewport\"\n      className={cn(\n        \"flex flex-1 items-center justify-center overflow-hidden bg-background\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction PresentationSlide({\n  className,\n  ...props\n}: PresentationPrimitive.Slide.Props) {\n  return (\n    <PresentationPrimitive.Slide\n      data-slot=\"presentation-slide\"\n      className={cn(\"border\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction PresentationSelection({\n  className,\n  ...props\n}: PresentationPrimitive.Selection.Props) {\n  return (\n    <PresentationPrimitive.Selection\n      data-slot=\"presentation-selection\"\n      className={cn(\"[--presentation-selection:var(--ring)]\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction PresentationLoading({\n  className,\n  children,\n  ...props\n}: PresentationPrimitive.Loading.Props) {\n  return (\n    <PresentationPrimitive.Loading\n      data-slot=\"presentation-loading\"\n      className={cn(\n        \"absolute inset-0 z-10 flex items-center justify-center text-sm text-muted-foreground\",\n        className,\n      )}\n      {...props}\n    >\n      {children ?? ((progress) => <span>Loading… {progress}%</span>)}\n    </PresentationPrimitive.Loading>\n  );\n}\n\nfunction PresentationError({\n  className,\n  children,\n  ...props\n}: PresentationPrimitive.Error.Props) {\n  return (\n    <PresentationPrimitive.Error\n      data-slot=\"presentation-error\"\n      className={cn(\n        \"absolute inset-0 z-10 flex items-center justify-center text-sm text-destructive\",\n        className,\n      )}\n      {...props}\n    >\n      {children ?? ((error: Error) => <span>{error.message}</span>)}\n    </PresentationPrimitive.Error>\n  );\n}\n\nfunction PresentationThumbnailItemPreview({\n  className,\n  ...props\n}: PresentationPrimitive.ThumbnailItemPreview.Props) {\n  return (\n    <PresentationPrimitive.ThumbnailItemPreview\n      data-slot=\"presentation-thumbnail-item-preview\"\n      className={cn(\n        \"w-full overflow-hidden rounded-sm data-pending:animate-pulse data-pending:bg-muted\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction PresentationThumbnailItemNumber({\n  className,\n  ...props\n}: PresentationPrimitive.ThumbnailItemNumber.Props) {\n  return (\n    <PresentationPrimitive.ThumbnailItemNumber\n      data-slot=\"presentation-thumbnail-item-number\"\n      className={cn(\n        \"block text-center font-mono text-xs leading-none text-muted-foreground tabular-nums\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction PresentationThumbnailItem({\n  className,\n  children,\n  ...props\n}: PresentationPrimitive.ThumbnailItem.Props) {\n  return (\n    <PresentationPrimitive.ThumbnailItem\n      data-slot=\"presentation-thumbnail-item\"\n      className={cn(\n        \"relative flex w-full cursor-pointer gap-1.5 rounded-md border p-1.5 outline-none hover:bg-accent\",\n        \"ring-2 ring-transparent transition-[color,ring] duration-100 focus:ring-ring data-active:bg-accent\",\n        className,\n      )}\n      {...props}\n    >\n      {children ?? (\n        <>\n          <PresentationThumbnailItemNumber />\n          <PresentationThumbnailItemPreview />\n        </>\n      )}\n    </PresentationPrimitive.ThumbnailItem>\n  );\n}\n\nfunction PresentationThumbnailList({\n  className,\n  children,\n  ...props\n}: PresentationPrimitive.ThumbnailList.Props) {\n  const isMobile = useIsMobile();\n  const id = React.useId();\n  const [open, setOpen] = React.useState(false);\n  const [wasMobile, setWasMobile] = React.useState(isMobile);\n  const listRef = React.useRef<HTMLDivElement | null>(null);\n  const triggerRef = React.useRef<HTMLButtonElement | null>(null);\n\n  const isHidden = isMobile && !open;\n\n  if (wasMobile !== isMobile) {\n    setWasMobile(isMobile);\n    setOpen(false);\n  }\n\n  React.useEffect(() => {\n    if (!isMobile || !open) return;\n\n    let pendingPointerId: number | null = null;\n\n    function isInside(target: Node) {\n      return (\n        !!listRef.current?.contains(target) ||\n        !!triggerRef.current?.contains(target)\n      );\n    }\n\n    function onPointerDown(event: PointerEvent) {\n      pendingPointerId = isInside(event.target as Node)\n        ? null\n        : event.pointerId;\n    }\n\n    function onPointerUp(event: PointerEvent) {\n      const isPendingPointer = pendingPointerId === event.pointerId;\n      pendingPointerId = null;\n      if (isPendingPointer && !isInside(event.target as Node)) setOpen(false);\n    }\n\n    function onPointerCancel() {\n      pendingPointerId = null;\n    }\n\n    function onKeyDown(event: KeyboardEvent) {\n      if (event.key === \"Escape\") setOpen(false);\n    }\n\n    document.addEventListener(\"pointerdown\", onPointerDown);\n    document.addEventListener(\"pointerup\", onPointerUp);\n    document.addEventListener(\"pointercancel\", onPointerCancel);\n    document.addEventListener(\"keydown\", onKeyDown);\n    return () => {\n      document.removeEventListener(\"pointerdown\", onPointerDown);\n      document.removeEventListener(\"pointerup\", onPointerUp);\n      document.removeEventListener(\"pointercancel\", onPointerCancel);\n      document.removeEventListener(\"keydown\", onKeyDown);\n    };\n  }, [isMobile, open]);\n\n  return (\n    <>\n      {isMobile && (\n        <Button\n          type=\"button\"\n          aria-controls={id}\n          aria-expanded={open}\n          aria-label=\"Toggle thumbnails\"\n          variant=\"outline\"\n          size=\"icon-sm\"\n          ref={triggerRef}\n          className=\"absolute top-2 left-2 z-10 bg-background/80 backdrop-blur-sm\"\n          onClick={() => setOpen((value) => !value)}\n        >\n          <IconPlaceholder\n            lucide=\"PanelLeftIcon\"\n            tabler=\"IconLayoutSidebar\"\n            hugeicons=\"SidebarLeftIcon\"\n            phosphor=\"SidebarIcon\"\n            remixicon=\"RiSideBarLine\"\n          />\n        </Button>\n      )}\n      <PresentationPrimitive.ThumbnailList\n        id={id}\n        aria-hidden={isHidden || undefined}\n        data-slot=\"presentation-thumbnail-list\"\n        data-mobile={isMobile || undefined}\n        inert={isHidden}\n        ref={listRef}\n        render={<aside />}\n        className={cn(\n          \"flex w-40 shrink-0 flex-col gap-2 overflow-y-auto border-r bg-background p-1.5\",\n          isMobile && \"absolute inset-y-0 left-0 z-20 transition-transform\",\n          isHidden && \"-translate-x-full\",\n          className,\n        )}\n        {...props}\n      >\n        {children ??\n          (({ slides }) =>\n            slides.map((slide) => (\n              <PresentationThumbnailItem key={slide.id} slideId={slide.id} />\n            )))}\n      </PresentationPrimitive.ThumbnailList>\n    </>\n  );\n}\n\nexport {\n  Presentation,\n  PresentationContent,\n  PresentationError,\n  PresentationLoading,\n  PresentationProvider,\n  PresentationSelection,\n  PresentationSlide,\n  PresentationThumbnailItem,\n  PresentationThumbnailItemNumber,\n  PresentationThumbnailItemPreview,\n  PresentationThumbnailList,\n  PresentationViewport,\n};\n",
      "target": ""
    }
  ]
}