{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "document-splits",
  "title": "Document Splits",
  "description": "A split-group review panel for organizing pages into output documents.",
  "dependencies": [
    "@dnd-kit/core@^6.3.1",
    "@dnd-kit/sortable@^10.0.0",
    "@dnd-kit/utilities@^3.2.2",
    "@base-ui/react@^1.4.1"
  ],
  "registryDependencies": [
    "@extend/file-thumbnail",
    "utils",
    "button",
    "scroll-area"
  ],
  "files": [
    {
      "path": "components/extend/document-splits.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { ScrollArea as ScrollAreaPrimitive } from \"@base-ui/react/scroll-area\"\nimport {\n  closestCenter,\n  DndContext,\n  DragOverlay,\n  PointerSensor,\n  useDroppable,\n  useSensor,\n  useSensors,\n  type CollisionDetection,\n  type DragEndEvent,\n  type DragOverEvent,\n  type DragStartEvent,\n} from \"@dnd-kit/core\"\nimport {\n  arrayMove,\n  horizontalListSortingStrategy,\n  SortableContext,\n  useSortable,\n  verticalListSortingStrategy,\n} from \"@dnd-kit/sortable\"\nimport { CSS } from \"@dnd-kit/utilities\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\nimport {\n  ScrollArea as InlineScrollArea,\n  ScrollBar,\n} from \"@/components/ui/scroll-area\"\nimport { FileThumbnail } from \"@/components/extend/file-thumbnail\"\nimport { IconPlaceholder } from \"@/components/icon-placeholder\"\n\nexport type DocumentSplitPageId = `page-${number}`\nexport type DocumentSplit = {\n  id: string\n  title: string\n  pages: DocumentSplitPageId[]\n}\ntype PageId = DocumentSplitPageId\ntype SplitGroup = DocumentSplit\nconst THUMBNAIL_WIDTH = 72\nconst THUMBNAIL_HEIGHT = 92\nconst DRAG_OVERLAY_DROP_ANIMATION = null\nconst THUMBNAIL_SURFACE_CLASS_NAME =\n  \"relative overflow-hidden rounded-lg border border-border bg-background shadow-xs\"\nconst THUMBNAIL_BUTTON_CLASS_NAME = cn(\n  THUMBNAIL_SURFACE_CLASS_NAME,\n  \"cursor-grab text-left transition-[border-color,box-shadow,opacity] outline-none hover:border-ring/40 hover:ring-2 hover:ring-ring focus-visible:border-ring/40 focus-visible:ring-2 focus-visible:ring-ring active:cursor-grabbing\"\n)\nconst splitterCollisionDetection: CollisionDetection = (args) => {\n  const dragType = args.active.data.current?.type\n  if (dragType === \"page\") {\n    return closestCenter({\n      ...args,\n      droppableContainers: args.droppableContainers.filter(\n        (container) =>\n          container.data.current?.type === \"page\" ||\n          (container.data.current?.type === \"page-dropzone\" &&\n            container.data.current?.isEmpty)\n      ),\n    })\n  }\n  if (dragType === \"split\") {\n    return closestCenter({\n      ...args,\n      droppableContainers: args.droppableContainers.filter(\n        (container) => container.data.current?.type === \"split\"\n      ),\n    })\n  }\n  return closestCenter(args)\n}\nexport const INITIAL_SPLITS: DocumentSplit[] = [\n  {\n    id: \"split-1\",\n    title: \"Abstract and intro\",\n    pages: [\"page-1\", \"page-2\", \"page-3\"],\n  },\n  {\n    id: \"split-2\",\n    title: \"Model architecture\",\n    pages: [\"page-4\", \"page-5\", \"page-6\", \"page-7\"],\n  },\n  {\n    id: \"split-3\",\n    title: \"Training and results\",\n    pages: [\"page-8\", \"page-9\", \"page-10\"],\n  },\n]\nexport function createInitialSplits(pageCount: number) {\n  if (pageCount <= 0) return INITIAL_SPLITS\n  const pages = Array.from(\n    { length: pageCount },\n    (_, index) => `page-${index + 1}` as PageId\n  )\n  const chunkSize = Math.max(1, Math.ceil(pageCount / 3))\n  return Array.from(\n    { length: Math.ceil(pageCount / chunkSize) },\n    (_, index) => {\n      const startIndex = index * chunkSize\n      const groupPages = pages.slice(startIndex, startIndex + chunkSize)\n      const firstPage = getPageNumber(groupPages[0])\n      const lastPage = getPageNumber(groupPages[groupPages.length - 1])\n      return {\n        id: `split-${index + 1}`,\n        title:\n          firstPage === lastPage\n            ? `Page ${firstPage}`\n            : `Pages ${firstPage}-${lastPage}`,\n        pages: groupPages,\n      }\n    }\n  )\n}\nfunction getPageNumber(pageId: PageId) {\n  return Number(pageId.replace(\"page-\", \"\"))\n}\nfunction getSplitSortableId(groupId: string) {\n  return `split-sortable-${groupId}`\n}\nfunction findGroupId(groups: SplitGroup[], id: string) {\n  if (groups.some((group) => group.id === id)) return id\n  return groups.find((group) => group.pages.includes(id as PageId))?.id ?? null\n}\nfunction getGroupPages(groups: SplitGroup[], groupId: string | null) {\n  return groups.find((group) => group.id === groupId)?.pages ?? []\n}\nfunction movePageToGroup({\n  draggedPageId,\n  groups,\n  insertIndex,\n  targetGroupId,\n}: {\n  draggedPageId: PageId\n  groups: SplitGroup[]\n  insertIndex: number\n  targetGroupId: string\n}) {\n  return groups.map((group) => {\n    const pagesWithoutDragged = group.pages.filter(\n      (pageId) => pageId !== draggedPageId\n    )\n    if (group.id !== targetGroupId) {\n      return { ...group, pages: pagesWithoutDragged }\n    }\n    const nextPages = [...pagesWithoutDragged]\n    nextPages.splice(insertIndex, 0, draggedPageId)\n    return { ...group, pages: nextPages }\n  })\n}\nfunction areSplitGroupsEqual(left: SplitGroup[], right: SplitGroup[]) {\n  if (left === right) return true\n  if (left.length !== right.length) return false\n  return left.every((leftGroup, groupIndex) => {\n    const rightGroup = right[groupIndex]\n    if (!rightGroup) return false\n    return (\n      leftGroup.id === rightGroup.id &&\n      leftGroup.title === rightGroup.title &&\n      leftGroup.pages.length === rightGroup.pages.length &&\n      leftGroup.pages.every(\n        (pageId, pageIndex) => pageId === rightGroup.pages[pageIndex]\n      )\n    )\n  })\n}\nfunction reorderPageInGroup({\n  draggedPageId,\n  groups,\n  overPageId,\n}: {\n  draggedPageId: PageId\n  groups: SplitGroup[]\n  overPageId: PageId\n}) {\n  const groupId = findGroupId(groups, draggedPageId)\n  const pages = getGroupPages(groups, groupId)\n  const draggedIndex = pages.indexOf(draggedPageId)\n  const overIndex = pages.indexOf(overPageId)\n  if (!groupId || draggedIndex === -1 || overIndex === -1) return groups\n  return groups.map((group) =>\n    group.id === groupId\n      ? {\n          ...group,\n          pages: arrayMove(group.pages, draggedIndex, overIndex),\n        }\n      : group\n  )\n}\nfunction createPageRangeLabel(pageIds: PageId[]) {\n  if (pageIds.length === 0) return \"No pages\"\n  return `Pages ${pageIds.map(getPageNumber).join(\", \")}`\n}\nfunction SplitGroupDropzone({\n  children,\n  group,\n}: {\n  children: React.ReactNode\n  group: SplitGroup\n}) {\n  const { isOver, setNodeRef } = useDroppable({\n    id: group.id,\n    data: { type: \"page-dropzone\", isEmpty: group.pages.length === 0 },\n  })\n  return (\n    <div\n      ref={setNodeRef}\n      className={cn(\n        \"min-h-[116px] rounded-lg p-2 transition-[background-color,box-shadow]\",\n        isOver && \"bg-accent/30 shadow-[inset_0_0_0_1px_var(--border)]\"\n      )}\n    >\n      {children}\n    </div>\n  )\n}\nfunction PageThumbnail({\n  imageUrl,\n  onSelect,\n  pageId,\n}: {\n  imageUrl?: string\n  onSelect: (pageNumber: number) => void\n  pageId: PageId\n}) {\n  const pageNumber = getPageNumber(pageId)\n  const {\n    attributes,\n    isDragging,\n    listeners,\n    setNodeRef,\n    transform,\n    transition,\n  } = useSortable({\n    id: pageId,\n    data: { type: \"page\" },\n  })\n  return (\n    <button\n      ref={setNodeRef}\n      type=\"button\"\n      className={cn(\n        THUMBNAIL_BUTTON_CLASS_NAME,\n        \"shrink-0\",\n        isDragging && \"opacity-0\"\n      )}\n      style={{\n        width: THUMBNAIL_WIDTH,\n        height: THUMBNAIL_HEIGHT,\n        transform: CSS.Transform.toString(transform),\n        transition,\n      }}\n      onClick={() => onSelect(pageNumber)}\n      {...attributes}\n      {...listeners}\n    >\n      <FileThumbnail\n        file={{\n          name: `page-${pageNumber}.pdf`,\n          type: \"application/pdf\",\n        }}\n        previewImageUrl={imageUrl}\n        isLoading={!imageUrl}\n        previewClassName=\"h-full aspect-auto\"\n        className=\"size-full rounded-[inherit] border-0 bg-transparent\"\n      />\n      <span className=\"absolute right-1 bottom-1 rounded bg-background/95 px-1.5 py-0.5 text-[10px] font-semibold text-foreground shadow-xs ring-1 ring-border/80\">\n        {pageNumber}\n      </span>\n    </button>\n  )\n}\nfunction SplitGroupCard({\n  canRemove,\n  group,\n  dragHandleProps,\n  thumbnailImages,\n  onRemove,\n  onSelectPage,\n}: {\n  canRemove: boolean\n  group: SplitGroup\n  dragHandleProps?: React.ComponentPropsWithoutRef<\"button\">\n  thumbnailImages: Record<PageId, string>\n  onRemove: () => void\n  onSelectPage: (pageNumber: number) => void\n}) {\n  return (\n    <section className=\"w-full rounded-lg border bg-background\">\n      <div className=\"flex items-center justify-between gap-3 border-b p-3\">\n        <div className=\"flex min-w-0 items-center gap-2\">\n          <button\n            type=\"button\"\n            aria-label={`Reorder ${group.title}`}\n            className=\"inline-flex size-7 shrink-0 cursor-grab items-center justify-center rounded-md text-muted-foreground hover:bg-muted active:cursor-grabbing\"\n            {...dragHandleProps}\n          >\n            <IconPlaceholder\n              lucide=\"GripVertical\"\n              tabler=\"IconGripVertical\"\n              hugeicons=\"DragDropVerticalIcon\"\n              phosphor=\"DotsSixVerticalIcon\"\n              remixicon=\"RiDraggable\"\n              className=\"size-4\"\n            />\n          </button>\n          <div className=\"min-w-0\">\n            <div className=\"truncate text-sm font-medium\">{group.title}</div>\n            <div className=\"mt-1 text-xs text-muted-foreground\">\n              {createPageRangeLabel(group.pages)}\n            </div>\n          </div>\n        </div>\n        <div className=\"flex shrink-0 items-center gap-2\">\n          <div className=\"rounded-full bg-muted px-2 py-0.5 text-xs text-muted-foreground\">\n            {group.pages.length}\n          </div>\n          <Button\n            type=\"button\"\n            variant=\"ghost\"\n            size=\"icon-sm\"\n            aria-label={`Remove ${group.title}`}\n            disabled={!canRemove}\n            onClick={onRemove}\n          >\n            <IconPlaceholder\n              lucide=\"Trash2Icon\"\n              tabler=\"IconTrash\"\n              hugeicons=\"Delete02Icon\"\n              phosphor=\"TrashIcon\"\n              remixicon=\"RiDeleteBinLine\"\n              className=\"size-4\"\n            />\n          </Button>\n        </div>\n      </div>\n      <SplitGroupDropzone group={group}>\n        {group.pages.length ? (\n          <SortableContext\n            items={group.pages}\n            strategy={horizontalListSortingStrategy}\n          >\n            <InlineScrollArea2\n              className=\"h-[110px] w-full overflow-hidden\"\n              orientation=\"horizontal\"\n              scrollbarGutter\n              scrollbarOverflowOnly\n              viewportClassName=\"overflow-y-hidden\"\n            >\n              <div className=\"flex w-max gap-2 overflow-y-hidden py-1 pr-6\">\n                {group.pages.map((pageId) => (\n                  <PageThumbnail\n                    key={pageId}\n                    pageId={pageId}\n                    imageUrl={thumbnailImages[pageId]}\n                    onSelect={onSelectPage}\n                  />\n                ))}\n              </div>\n            </InlineScrollArea2>\n          </SortableContext>\n        ) : (\n          <div className=\"grid h-[104px] place-items-center rounded-lg bg-muted/35 text-xs text-muted-foreground\">\n            Drop pages here\n          </div>\n        )}\n      </SplitGroupDropzone>\n    </section>\n  )\n}\nfunction SortableSplitGroupCard({\n  canRemove,\n  group,\n  thumbnailImages,\n  onRemove,\n  onSelectPage,\n}: {\n  canRemove: boolean\n  group: SplitGroup\n  thumbnailImages: Record<PageId, string>\n  onRemove: () => void\n  onSelectPage: (pageNumber: number) => void\n}) {\n  const {\n    attributes,\n    isDragging,\n    listeners,\n    setNodeRef,\n    transform,\n    transition,\n  } = useSortable({\n    id: getSplitSortableId(group.id),\n    data: { type: \"split\", groupId: group.id },\n  })\n  return (\n    <div\n      ref={setNodeRef}\n      className={cn(\"w-full\", isDragging && \"opacity-0\")}\n      style={{\n        transform: CSS.Transform.toString(transform),\n        transition,\n      }}\n    >\n      <SplitGroupCard\n        canRemove={canRemove}\n        group={group}\n        thumbnailImages={thumbnailImages}\n        dragHandleProps={{ ...attributes, ...listeners }}\n        onRemove={onRemove}\n        onSelectPage={onSelectPage}\n      />\n    </div>\n  )\n}\nfunction SplitGroupDragOverlay({\n  group,\n  thumbnailImages,\n  width,\n  onSelectPage,\n}: {\n  group: SplitGroup\n  thumbnailImages: Record<PageId, string>\n  width?: number\n  onSelectPage: (pageNumber: number) => void\n}) {\n  return (\n    <div className=\"relative z-40 max-w-[calc(100vw-2rem)]\" style={{ width }}>\n      <SplitGroupCard\n        canRemove={false}\n        group={group}\n        thumbnailImages={thumbnailImages}\n        onRemove={() => {}}\n        onSelectPage={onSelectPage}\n      />\n    </div>\n  )\n}\nexport function DocumentSplits({\n  className,\n  splits,\n  thumbnailImages = {},\n  withFrameDivider = true,\n  onSelectPage,\n  onSplitsChange,\n}: {\n  className?: string\n  splits: SplitGroup[]\n  thumbnailImages?: Record<PageId, string>\n  withFrameDivider?: boolean\n  onSelectPage: (pageNumber: number) => void\n  onSplitsChange: (splits: SplitGroup[]) => void\n}) {\n  const [draggedPageId, setDraggedPageId] = React.useState<PageId | null>(null)\n  const [activeSplitGroupId, setActiveSplitGroupId] = React.useState<\n    string | null\n  >(null)\n  const [activeSplitGroupWidth, setActiveSplitGroupWidth] = React.useState<\n    number | undefined\n  >()\n  const dragStartGroupIdRef = React.useRef<string | null>(null)\n  const dragStartSplitsRef = React.useRef<SplitGroup[] | null>(null)\n  const sensors = useSensors(\n    useSensor(PointerSensor, { activationConstraint: { distance: 6 } })\n  )\n  const handleDragStart = React.useCallback(\n    (event: DragStartEvent) => {\n      const dragType = event.active.data.current?.type\n      if (dragType === \"split\") {\n        dragStartGroupIdRef.current = null\n        dragStartSplitsRef.current = null\n        setDraggedPageId(null)\n        setActiveSplitGroupId(\n          (event.active.data.current?.groupId as string | undefined) ?? null\n        )\n        setActiveSplitGroupWidth(event.active.rect.current.initial?.width)\n        return\n      }\n      if (dragType !== \"page\") {\n        dragStartGroupIdRef.current = null\n        dragStartSplitsRef.current = null\n        setDraggedPageId(null)\n        setActiveSplitGroupId(null)\n        setActiveSplitGroupWidth(undefined)\n        return\n      }\n      const pageId = String(event.active.id) as PageId\n      dragStartGroupIdRef.current = findGroupId(splits, pageId)\n      dragStartSplitsRef.current = splits\n      setDraggedPageId(pageId)\n      setActiveSplitGroupId(null)\n      setActiveSplitGroupWidth(undefined)\n    },\n    [splits]\n  )\n  const handleDragOver = React.useCallback(\n    (event: DragOverEvent) => {\n      if (event.active.data.current?.type !== \"page\" || !event.over) return\n      const pageId = String(event.active.id) as PageId\n      const overId = String(event.over.id)\n      const sourceGroupId = findGroupId(splits, pageId)\n      const targetGroupId = findGroupId(splits, overId)\n      if (!sourceGroupId || !targetGroupId || sourceGroupId === targetGroupId) {\n        return\n      }\n      const targetPages = getGroupPages(splits, targetGroupId)\n      const overIndex = targetPages.indexOf(overId as PageId)\n      const insertIndex = overIndex === -1 ? targetPages.length : overIndex\n      const nextSplits = movePageToGroup({\n        draggedPageId: pageId,\n        groups: splits,\n        insertIndex,\n        targetGroupId,\n      })\n      if (!areSplitGroupsEqual(splits, nextSplits)) {\n        onSplitsChange(nextSplits)\n      }\n    },\n    [onSplitsChange, splits]\n  )\n  const handleDragEnd = React.useCallback(\n    (event: DragEndEvent) => {\n      if (event.active.data.current?.type === \"split\" && event.over) {\n        const activeGroupId = event.active.data.current.groupId\n        const overGroupId = event.over.data.current?.groupId\n        const draggedIndex = splits.findIndex(\n          (group) => group.id === activeGroupId\n        )\n        const overIndex = splits.findIndex((group) => group.id === overGroupId)\n        if (draggedIndex !== -1 && overIndex !== -1) {\n          const nextSplits = arrayMove(splits, draggedIndex, overIndex)\n          if (!areSplitGroupsEqual(splits, nextSplits)) {\n            onSplitsChange(nextSplits)\n          }\n        }\n        dragStartGroupIdRef.current = null\n        dragStartSplitsRef.current = null\n        setDraggedPageId(null)\n        setActiveSplitGroupId(null)\n        setActiveSplitGroupWidth(undefined)\n        return\n      }\n      if (event.active.data.current?.type !== \"page\" || !event.over) {\n        dragStartGroupIdRef.current = null\n        dragStartSplitsRef.current = null\n        setDraggedPageId(null)\n        setActiveSplitGroupId(null)\n        setActiveSplitGroupWidth(undefined)\n        return\n      }\n      const pageId = String(event.active.id) as PageId\n      const overId = String(event.over.id) as PageId\n      const overGroupId = findGroupId(splits, overId)\n      if (dragStartGroupIdRef.current === overGroupId) {\n        const nextSplits = reorderPageInGroup({\n          draggedPageId: pageId,\n          groups: splits,\n          overPageId: overId,\n        })\n        if (!areSplitGroupsEqual(splits, nextSplits)) {\n          onSplitsChange(nextSplits)\n        }\n      }\n      dragStartGroupIdRef.current = null\n      dragStartSplitsRef.current = null\n      setDraggedPageId(null)\n      setActiveSplitGroupId(null)\n      setActiveSplitGroupWidth(undefined)\n    },\n    [onSplitsChange, splits]\n  )\n  const handleDragCancel = React.useCallback(() => {\n    if (dragStartSplitsRef.current) {\n      onSplitsChange(dragStartSplitsRef.current)\n    }\n    dragStartSplitsRef.current = null\n    dragStartGroupIdRef.current = null\n    setDraggedPageId(null)\n    setActiveSplitGroupId(null)\n    setActiveSplitGroupWidth(undefined)\n  }, [onSplitsChange])\n  const activeSplitGroup = activeSplitGroupId\n    ? splits.find((group) => group.id === activeSplitGroupId)\n    : null\n  return (\n    <aside\n      className={cn(\n        \"flex h-full min-h-0 flex-col bg-muted/20\",\n        withFrameDivider && \"border-t md:border-t-0 md:border-l\",\n        className\n      )}\n    >\n      <div className=\"flex min-h-12 items-center justify-end gap-3 border-b bg-background px-3\">\n        <Button\n          type=\"button\"\n          variant=\"outline\"\n          size=\"sm\"\n          onClick={() =>\n            onSplitsChange([\n              ...splits,\n              {\n                id: `split-${Date.now()}`,\n                title: `Split ${splits.length + 1}`,\n                pages: [],\n              },\n            ])\n          }\n        >\n          <IconPlaceholder\n            lucide=\"Plus\"\n            tabler=\"IconPlus\"\n            hugeicons=\"Add01Icon\"\n            phosphor=\"PlusIcon\"\n            remixicon=\"RiAddLine\"\n            className=\"size-4\"\n          />\n          Add split\n        </Button>\n      </div>\n      <DndContext\n        id=\"document-splits-dnd\"\n        sensors={sensors}\n        collisionDetection={splitterCollisionDetection}\n        onDragStart={handleDragStart}\n        onDragOver={handleDragOver}\n        onDragEnd={handleDragEnd}\n        onDragCancel={handleDragCancel}\n      >\n        <InlineScrollArea2 className=\"min-h-0 flex-1\" scrollFade>\n          <SortableContext\n            items={splits.map((group) => getSplitSortableId(group.id))}\n            strategy={verticalListSortingStrategy}\n          >\n            <div className=\"space-y-3 p-3\">\n              {splits.map((group) => (\n                <SortableSplitGroupCard\n                  key={group.id}\n                  canRemove={splits.length > 1}\n                  group={group}\n                  thumbnailImages={thumbnailImages}\n                  onRemove={() => {\n                    if (splits.length <= 1) return\n                    onSplitsChange(\n                      splits.filter((split) => split.id !== group.id)\n                    )\n                  }}\n                  onSelectPage={onSelectPage}\n                />\n              ))}\n            </div>\n          </SortableContext>\n        </InlineScrollArea2>\n        <DragOverlay dropAnimation={DRAG_OVERLAY_DROP_ANIMATION} zIndex={40}>\n          {draggedPageId ? (\n            <div\n              className={cn(\n                THUMBNAIL_SURFACE_CLASS_NAME,\n                \"shadow-lg shadow-black/10\"\n              )}\n              style={{ width: THUMBNAIL_WIDTH, height: THUMBNAIL_HEIGHT }}\n            >\n              <FileThumbnail\n                file={{ name: `${draggedPageId}.pdf`, type: \"application/pdf\" }}\n                previewImageUrl={thumbnailImages[draggedPageId]}\n                isLoading={!thumbnailImages[draggedPageId]}\n                previewClassName=\"h-full aspect-auto\"\n                className=\"size-full rounded-[inherit] border-0 bg-transparent\"\n              />\n            </div>\n          ) : activeSplitGroup ? (\n            <SplitGroupDragOverlay\n              group={activeSplitGroup}\n              thumbnailImages={thumbnailImages}\n              width={activeSplitGroupWidth}\n              onSelectPage={onSelectPage}\n            />\n          ) : null}\n        </DragOverlay>\n      </DndContext>\n    </aside>\n  )\n}\nfunction InlineScrollArea2({\n  className,\n  children,\n  orientation = \"both\",\n  scrollFade = false,\n  scrollbarGutter = false,\n  scrollbarOverflowOnly = false,\n  viewportClassName,\n  viewportProps,\n  viewportRef,\n  ...props\n}: InlineScrollAreaProps) {\n  const {\n    className: viewportPropsClassName,\n    ref: viewportPropsRef,\n    ...resolvedViewportProps\n  } = viewportProps ?? {}\n  const composedViewportRef = React.useMemo(\n    () => InlineComposeRefs(viewportPropsRef, viewportRef),\n    [viewportPropsRef, viewportRef]\n  )\n\n  if (\n    !viewportProps &&\n    !viewportRef &&\n    !viewportClassName &&\n    !scrollFade &&\n    !scrollbarGutter &&\n    !scrollbarOverflowOnly\n  ) {\n    return (\n      <InlineScrollArea\n        {...props}\n        className={cn(\n          \"size-full min-h-0\",\n          orientation === \"horizontal\" &&\n            \"[&>[data-orientation=vertical]]:hidden\",\n          className\n        )}\n      >\n        {children}\n        {orientation !== \"vertical\" ? (\n          <ScrollBar orientation=\"horizontal\" />\n        ) : null}\n      </InlineScrollArea>\n    )\n  }\n\n  return (\n    <ScrollAreaPrimitive.Root\n      className={cn(\n        \"size-full min-h-0\",\n        scrollbarOverflowOnly &&\n          \"[&:not(:has([data-slot=scroll-area-viewport][data-has-overflow-x]))_[data-orientation=horizontal]]:hidden [&:not(:has([data-slot=scroll-area-viewport][data-has-overflow-y]))_[data-orientation=vertical]]:hidden\",\n        className\n      )}\n      {...props}\n    >\n      <ScrollAreaPrimitive.Viewport\n        {...resolvedViewportProps}\n        ref={composedViewportRef}\n        className={cn(\n          \"h-full rounded-[inherit] outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n          scrollFade &&\n            \"mask-t-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-start)))] mask-r-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-end)))] mask-b-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-end)))] mask-l-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-start)))] [--fade-size:1.5rem]\",\n          scrollbarGutter && orientation !== \"vertical\" && \"pb-3.5\",\n          scrollbarGutter && orientation !== \"horizontal\" && \"pe-3.5\",\n          viewportPropsClassName,\n          viewportClassName\n        )}\n        data-slot=\"scroll-area-viewport\"\n      >\n        {children}\n      </ScrollAreaPrimitive.Viewport>\n      {orientation !== \"horizontal\" ? (\n        <ScrollBar orientation=\"vertical\" />\n      ) : null}\n      {orientation !== \"vertical\" ? (\n        <ScrollBar orientation=\"horizontal\" />\n      ) : null}\n      {orientation === \"both\" ? <ScrollAreaPrimitive.Corner /> : null}\n    </ScrollAreaPrimitive.Root>\n  )\n}\ntype InlineScrollAreaProps = ScrollAreaPrimitive.Root.Props & {\n  orientation?: \"vertical\" | \"horizontal\" | \"both\"\n  scrollFade?: boolean\n  scrollbarGutter?: boolean\n  scrollbarOverflowOnly?: boolean\n  viewportClassName?: string\n  viewportProps?: ScrollAreaPrimitive.Viewport.Props\n  viewportRef?: React.Ref<HTMLDivElement>\n}\nfunction InlineComposeRefs<T>(...refs: Array<React.Ref<T> | undefined>) {\n  return (node: T | null) => {\n    for (const ref of refs) {\n      if (!ref) continue\n      if (typeof ref === \"function\") ref(node)\n      else ref.current = node\n    }\n  }\n}\n",
      "type": "registry:ui",
      "target": "@components/extend/document-splits.tsx"
    }
  ],
  "categories": [
    "documents"
  ],
  "type": "registry:ui"
}
