{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "responsive-resizable-preview", "type": "registry:component", "registryDependencies": [ "button", "badge", "resizable" ], "files": [ { "path": "components/domain-ui/responsive-resizable-preview/index.tsx", "content": "\"use client\";\nimport { useState, useEffect, useRef, useMemo } from \"react\";\nimport type { ImperativePanelHandle } from \"react-resizable-panels\";\nimport {\n ResizableHandle,\n ResizablePanel,\n ResizablePanelGroup,\n} from \"@/components/ui/resizable\";\nimport { defaultBreakpoints, getBreakpoint } from \"./breakpoints\";\nimport type { Breakpoint, BreakpointConfig } from \"./breakpoints\";\nimport { Toolbar, ScaleBar, Settings } from \"./settings\";\nimport { cn } from \"@/lib/utils\";\n\n// Types\nexport interface PreviewConfig {\n darkMode?: boolean;\n showToolbar?: boolean;\n showScale?: boolean;\n showLabels?: boolean;\n}\n\ninterface BasePreviewProps {\n className?: string;\n breakpoints?: BreakpointConfig[];\n config?: PreviewConfig;\n}\n\ninterface ResponsiveResizablePreviewProps extends BasePreviewProps {\n children?: React.ReactNode;\n}\n\ninterface RRChildPreviewProps extends BasePreviewProps {\n children?: React.ReactNode;\n}\n\ninterface RRIFramePreviewProps extends BasePreviewProps {\n srcUrl: string;\n height?: number;\n}\n\nconst defaultConfig = {\n darkMode: false,\n showToolbar: true,\n showScale: true,\n showLabels: true,\n};\n\n// PreviewPanel component - the core resizable container\ninterface PreviewPanelProps {\n children: React.ReactNode;\n className?: string;\n panelRef: React.RefObject;\n contentRef: React.RefObject;\n}\n\nfunction PreviewPanel({\n children,\n className,\n panelRef,\n contentRef,\n}: PreviewPanelProps) {\n const [isHandleResizing, setIsHandleResizing] = useState(false);\n\n const bgPattern = `url(\"data:image/svg+xml,%3Csvg width='6' height='6' viewBox='0 0 6 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%239C92AC' fill-opacity='0.2' fill-rule='evenodd'%3E%3Cpath d='M5 0h1L0 6V5zM6 5v1H5z'/%3E%3C/g%3E%3C/svg%3E\")`;\n\n return (\n \n \n
{children}
\n \n setIsHandleResizing(e)}\n />\n \n \n );\n}\n\nexport function ResponsiveResizablePreview({\n children,\n className,\n breakpoints = defaultBreakpoints,\n config: initialConfig = defaultConfig,\n}: ResponsiveResizablePreviewProps) {\n const [config, setConfig] = useState(initialConfig);\n\n const {\n darkMode = false,\n showToolbar = true,\n showScale = true,\n showLabels = true,\n } = config;\n\n const resizablePanelRef = useRef(null);\n const [width, setWidth] = useState(0);\n const [maxWidth, setMaxWidth] = useState(0);\n const panelContentRef = useRef(null);\n const rprRef = useRef(null);\n\n useEffect(() => {\n if (width > maxWidth) {\n setMaxWidth(width);\n }\n }, [width, maxWidth]);\n\n useEffect(() => {\n if (!panelContentRef.current) {\n return;\n }\n\n const observer = new ResizeObserver((entries) => {\n if (entries[0]) {\n const entryWidth = entries[0].contentRect.width;\n setWidth(Math.round(entryWidth));\n }\n });\n\n observer.observe(panelContentRef.current);\n return () => observer.disconnect();\n }, []);\n\n useEffect(() => {\n setConfig(initialConfig);\n }, [initialConfig]);\n\n const availableBreakpoints = useMemo(() => {\n return breakpoints.map((breakpoint: Breakpoint) => {\n breakpoint.percentage = (breakpoint.minWidthPx * 100) / maxWidth;\n\n if (breakpoint.percentage > 100) {\n breakpoint.percentage = 100;\n breakpoint.show = false;\n } else {\n breakpoint.show = true;\n }\n return breakpoint;\n });\n }, [maxWidth, breakpoints]);\n\n const currentBreakpoint = getBreakpoint(width, breakpoints);\n\n return (\n
\n \n \n {showToolbar && (\n <>\n
\n
\n {\n if (resizablePanelRef?.current) {\n resizablePanelRef.current.resize(\n Number.parseFloat(value)\n );\n }\n }}\n panelRef={panelContentRef} // Add this line\n />\n
\n\n
\n {\n setConfig(newConfig);\n }}\n rprRef={rprRef}\n />\n
\n
\n\n \n \n )}\n\n \n {children}\n \n
\n \n \n );\n}\n\n// RRChildPreview component - renders children directly\nexport function RRChildPreview({\n children,\n breakpoints,\n config,\n className,\n}: RRChildPreviewProps) {\n return (\n \n {children}\n \n );\n}\n\n// RRIFramePreview component - renders content in an iframe\nexport function RRIFramePreview({\n srcUrl,\n height,\n breakpoints,\n config,\n className,\n}: RRIFramePreviewProps) {\n return (\n \n