{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "column-node",
  "title": "Column Nodes",
  "description": "Resizable column components for layout.",
  "dependencies": [
    "@udecode/cn",
    "@platejs/layout"
  ],
  "registryDependencies": [
    "https://platejs.org/r/resize-handle.json"
  ],
  "files": [
    {
      "path": "src/registry/ui/column-node.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\n\nimport type { TColumnElement } from 'platejs';\nimport type { PlateElementProps } from 'platejs/react';\n\nimport { useDraggable, useDropLine } from '@platejs/dnd';\nimport { setColumns } from '@platejs/layout';\nimport { ResizableProvider } from '@platejs/resizable';\nimport { BlockSelectionPlugin } from '@platejs/selection/react';\nimport { useComposedRef } from '@udecode/cn';\nimport { type LucideProps, Trash2Icon } from 'lucide-react';\nimport { GripHorizontal } from 'lucide-react';\nimport { PathApi } from 'platejs';\nimport {\n  PlateElement,\n  useEditorRef,\n  useEditorSelector,\n  useElement,\n  useFocusedLast,\n  usePluginOption,\n  useReadOnly,\n  useRemoveNodeButton,\n  useSelected,\n  withHOC,\n} from 'platejs/react';\n\nimport { Button } from '@/components/ui/button';\nimport {\n  Popover,\n  PopoverAnchor,\n  PopoverContent,\n} from '@/components/ui/popover';\nimport { Separator } from '@/components/ui/separator';\nimport {\n  Tooltip,\n  TooltipContent,\n  TooltipProvider,\n  TooltipTrigger,\n} from '@/components/ui/tooltip';\nimport { cn } from '@/lib/utils';\n\nexport const ColumnElement = withHOC(\n  ResizableProvider,\n  function ColumnElement(props: PlateElementProps<TColumnElement>) {\n    const { width } = props.element;\n    const readOnly = useReadOnly();\n    const isSelectionAreaVisible = usePluginOption(\n      BlockSelectionPlugin,\n      'isSelectionAreaVisible'\n    );\n\n    const { isDragging, nodeRef, previewRef, handleRef } = useDraggable({\n      element: props.element,\n      orientation: 'horizontal',\n      type: 'column',\n      canDropNode: ({ dragEntry, dropEntry }) =>\n        PathApi.equals(\n          PathApi.parent(dragEntry[1]),\n          PathApi.parent(dropEntry[1])\n        ),\n    });\n\n    return (\n      <div className=\"group/column relative\" style={{ width: width ?? '100%' }}>\n        {!readOnly && !isSelectionAreaVisible && (\n          <div\n            ref={handleRef}\n            className={cn(\n              '-translate-x-1/2 -translate-y-1/2 absolute top-2 left-1/2 z-50',\n              'pointer-events-auto flex items-center',\n              'opacity-0 transition-opacity group-hover/column:opacity-100'\n            )}\n          >\n            <ColumnDragHandle />\n          </div>\n        )}\n\n        <PlateElement\n          {...props}\n          ref={useComposedRef(props.ref, previewRef, nodeRef)}\n          className=\"h-full px-2 pt-2 group-first/column:pl-0 group-last/column:pr-0\"\n        >\n          <div\n            className={cn(\n              'relative h-full border border-transparent p-1.5',\n              !readOnly && 'rounded-lg border-border border-dashed',\n              isDragging && 'opacity-50'\n            )}\n          >\n            {props.children}\n\n            {!readOnly && !isSelectionAreaVisible && <DropLine />}\n          </div>\n        </PlateElement>\n      </div>\n    );\n  }\n);\n\nconst ColumnDragHandle = React.memo(function ColumnDragHandle() {\n  return (\n    <TooltipProvider>\n      <Tooltip>\n        <TooltipTrigger asChild>\n          <Button variant=\"ghost\" className=\"!px-1 h-5\">\n            <GripHorizontal\n              className=\"text-muted-foreground\"\n              onClick={(event) => {\n                event.stopPropagation();\n                event.preventDefault();\n              }}\n            />\n          </Button>\n        </TooltipTrigger>\n\n        <TooltipContent>Drag to move column</TooltipContent>\n      </Tooltip>\n    </TooltipProvider>\n  );\n});\n\nfunction DropLine() {\n  const { dropLine } = useDropLine({ orientation: 'horizontal' });\n\n  if (!dropLine) return null;\n\n  return (\n    <div\n      className={cn(\n        'slate-dropLine',\n        'absolute bg-brand/50',\n        dropLine === 'left' &&\n          'group-first/column:-left-1 inset-y-0 left-[-10.5px] w-1',\n        dropLine === 'right' &&\n          'group-last/column:-right-1 inset-y-0 right-[-11px] w-1'\n      )}\n    />\n  );\n}\n\nexport function ColumnGroupElement(props: PlateElementProps) {\n  return (\n    <PlateElement className=\"mb-2\" {...props}>\n      <ColumnFloatingToolbar>\n        <div className=\"flex size-full rounded\">{props.children}</div>\n      </ColumnFloatingToolbar>\n    </PlateElement>\n  );\n}\n\nfunction ColumnFloatingToolbar({ children }: React.PropsWithChildren) {\n  const editor = useEditorRef();\n  const readOnly = useReadOnly();\n  const element = useElement<TColumnElement>();\n  const { props: buttonProps } = useRemoveNodeButton({ element });\n  const selected = useSelected();\n  const isCollapsed = useEditorSelector(\n    (editor) => editor.api.isCollapsed(),\n    []\n  );\n  const isFocusedLast = useFocusedLast();\n\n  const open = isFocusedLast && !readOnly && selected && isCollapsed;\n\n  const onColumnChange = (widths: string[]) => {\n    setColumns(editor, {\n      at: element,\n      widths,\n    });\n  };\n\n  return (\n    <Popover open={open} modal={false}>\n      <PopoverAnchor>{children}</PopoverAnchor>\n      <PopoverContent\n        className=\"w-auto p-1\"\n        onOpenAutoFocus={(e) => e.preventDefault()}\n        align=\"center\"\n        side=\"top\"\n        sideOffset={10}\n      >\n        <div className=\"box-content flex h-8 items-center\">\n          <Button\n            variant=\"ghost\"\n            className=\"size-8\"\n            onClick={() => onColumnChange(['50%', '50%'])}\n          >\n            <DoubleColumnOutlined />\n          </Button>\n          <Button\n            variant=\"ghost\"\n            className=\"size-8\"\n            onClick={() => onColumnChange(['33%', '33%', '33%'])}\n          >\n            <ThreeColumnOutlined />\n          </Button>\n          <Button\n            variant=\"ghost\"\n            className=\"size-8\"\n            onClick={() => onColumnChange(['70%', '30%'])}\n          >\n            <RightSideDoubleColumnOutlined />\n          </Button>\n          <Button\n            variant=\"ghost\"\n            className=\"size-8\"\n            onClick={() => onColumnChange(['30%', '70%'])}\n          >\n            <LeftSideDoubleColumnOutlined />\n          </Button>\n          <Button\n            variant=\"ghost\"\n            className=\"size-8\"\n            onClick={() => onColumnChange(['25%', '50%', '25%'])}\n          >\n            <DoubleSideDoubleColumnOutlined />\n          </Button>\n\n          <Separator orientation=\"vertical\" className=\"mx-1 h-6\" />\n          <Button variant=\"ghost\" className=\"size-8\" {...buttonProps}>\n            <Trash2Icon />\n          </Button>\n        </div>\n      </PopoverContent>\n    </Popover>\n  );\n}\n\nconst DoubleColumnOutlined = (props: LucideProps) => (\n  <svg\n    fill=\"none\"\n    height=\"16\"\n    viewBox=\"0 0 16 16\"\n    width=\"16\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    {...props}\n  >\n    <path\n      clipRule=\"evenodd\"\n      d=\"M8.5 3H13V13H8.5V3ZM7.5 2H8.5H13C13.5523 2 14 2.44772 14 3V13C14 13.5523 13.5523 14 13 14H8.5H7.5H3C2.44772 14 2 13.5523 2 13V3C2 2.44772 2.44772 2 3 2H7.5ZM7.5 13H3L3 3H7.5V13Z\"\n      fill=\"currentColor\"\n      fillRule=\"evenodd\"\n    />\n  </svg>\n);\n\nconst ThreeColumnOutlined = (props: LucideProps) => (\n  <svg\n    fill=\"none\"\n    height=\"16\"\n    viewBox=\"0 0 16 16\"\n    width=\"16\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    {...props}\n  >\n    <path\n      clipRule=\"evenodd\"\n      d=\"M9.25 3H6.75V13H9.25V3ZM9.25 2H6.75H5.75H3C2.44772 2 2 2.44772 2 3V13C2 13.5523 2.44772 14 3 14H5.75H6.75H9.25H10.25H13C13.5523 14 14 13.5523 14 13V3C14 2.44772 13.5523 2 13 2H10.25H9.25ZM10.25 3V13H13V3H10.25ZM3 13H5.75V3H3L3 13Z\"\n      fill=\"currentColor\"\n      fillRule=\"evenodd\"\n    />\n  </svg>\n);\n\nconst RightSideDoubleColumnOutlined = (props: LucideProps) => (\n  <svg\n    fill=\"none\"\n    height=\"16\"\n    viewBox=\"0 0 16 16\"\n    width=\"16\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    {...props}\n  >\n    <path\n      clipRule=\"evenodd\"\n      d=\"M11.25 3H13V13H11.25V3ZM10.25 2H11.25H13C13.5523 2 14 2.44772 14 3V13C14 13.5523 13.5523 14 13 14H11.25H10.25H3C2.44772 14 2 13.5523 2 13V3C2 2.44772 2.44772 2 3 2H10.25ZM10.25 13H3L3 3H10.25V13Z\"\n      fill=\"currentColor\"\n      fillRule=\"evenodd\"\n    />\n  </svg>\n);\n\nconst LeftSideDoubleColumnOutlined = (props: LucideProps) => (\n  <svg\n    fill=\"none\"\n    height=\"16\"\n    viewBox=\"0 0 16 16\"\n    width=\"16\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    {...props}\n  >\n    <path\n      clipRule=\"evenodd\"\n      d=\"M5.75 3H13V13H5.75V3ZM4.75 2H5.75H13C13.5523 2 14 2.44772 14 3V13C14 13.5523 13.5523 14 13 14H5.75H4.75H3C2.44772 14 2 13.5523 2 13V3C2 2.44772 2.44772 2 3 2H4.75ZM4.75 13H3L3 3H4.75V13Z\"\n      fill=\"currentColor\"\n      fillRule=\"evenodd\"\n    />\n  </svg>\n);\n\nconst DoubleSideDoubleColumnOutlined = (props: LucideProps) => (\n  <svg\n    fill=\"none\"\n    height=\"16\"\n    viewBox=\"0 0 16 16\"\n    width=\"16\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    {...props}\n  >\n    <path\n      clipRule=\"evenodd\"\n      d=\"M10.25 3H5.75V13H10.25V3ZM10.25 2H5.75H4.75H3C2.44772 2 2 2.44772 2 3V13C2 13.5523 2.44772 14 3 14H4.75H5.75H10.25H11.25H13C13.5523 14 14 13.5523 14 13V3C14 2.44772 13.5523 2 13 2H11.25H10.25ZM11.25 3V13H13V3H11.25ZM3 13H4.75V3H3L3 13Z\"\n      fill=\"currentColor\"\n      fillRule=\"evenodd\"\n    />\n  </svg>\n);\n",
      "type": "registry:ui"
    },
    {
      "path": "src/registry/ui/column-node-static.tsx",
      "content": "import * as React from 'react';\n\nimport type { TColumnElement } from 'platejs';\nimport type { SlateElementProps } from 'platejs/static';\n\nimport { SlateElement } from 'platejs/static';\n\nexport function ColumnElementStatic(props: SlateElementProps<TColumnElement>) {\n  const { width } = props.element;\n\n  return (\n    <div className=\"group/column relative\" style={{ width: width ?? '100%' }}>\n      <SlateElement\n        className=\"h-full px-2 pt-2 group-first/column:pl-0 group-last/column:pr-0\"\n        {...props}\n      >\n        <div className=\"relative h-full border border-transparent p-1.5\">\n          {props.children}\n        </div>\n      </SlateElement>\n    </div>\n  );\n}\n\nexport function ColumnGroupElementStatic(props: SlateElementProps) {\n  return (\n    <SlateElement className=\"mb-2\" {...props}>\n      <div className=\"flex size-full rounded\">{props.children}</div>\n    </SlateElement>\n  );\n}\n\n/**\n * DOCX-compatible column component using table cell.\n */\nexport function ColumnElementDocx(props: SlateElementProps<TColumnElement>) {\n  const { width } = props.element;\n\n  return (\n    <SlateElement\n      {...props}\n      as=\"td\"\n      style={{\n        width: width ?? 'auto',\n        verticalAlign: 'top',\n        padding: '4px 8px',\n        border: 'none',\n      }}\n    >\n      {props.children}\n    </SlateElement>\n  );\n}\n\n/**\n * DOCX-compatible column group component using table layout.\n */\nexport function ColumnGroupElementDocx(props: SlateElementProps) {\n  return (\n    <SlateElement {...props}>\n      <table\n        style={{\n          width: '100%',\n          borderCollapse: 'collapse',\n          border: 'none',\n          tableLayout: 'fixed',\n        }}\n      >\n        <tbody>\n          <tr>{props.children}</tr>\n        </tbody>\n      </table>\n    </SlateElement>\n  );\n}\n",
      "type": "registry:ui"
    }
  ],
  "meta": {
    "docs": [
      {
        "route": "/docs/column"
      },
      {
        "route": "https://pro.platejs.org/docs/components/column-node"
      }
    ],
    "examples": [
      "column-demo"
    ]
  },
  "type": "registry:ui"
}