@kumodefe/rc-smart-layout
Version:
A flexible and customizable layout component for React that supports resizing, collapsing, and persistent size. It allows you to manage layout sections with horizontal and vertical orientations, with the ability to adjust sizes and remember them across se
1 lines • 10.5 kB
Source Map (JSON)
{"version":3,"sources":["../src/SmartLayout.tsx"],"sourcesContent":["/* eslint-disable react-hooks/exhaustive-deps */\n// SmartLayoutPro.tsx\nimport React, {\n createContext,\n CSSProperties,\n JSX,\n MouseEvent,\n ReactNode,\n useContext,\n useEffect,\n useRef,\n useState,\n} from 'react';\n\nimport clsx from 'clsx';\nimport {\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n ChevronUp,\n} from 'lucide-react';\n\n/**\n * Types\n */\nexport type Direction = \"vertical\" | \"horizontal\";\n\nexport interface LayoutContextType {\n\tdirection: Direction;\n}\n\nconst LayoutContext = createContext<LayoutContextType>({\n\tdirection: \"vertical\",\n});\n\nexport interface SectionBase {\n\tchildren: ReactNode;\n\tscroll?: boolean;\n\tgrow?: boolean;\n\tshrink?: boolean;\n\tminSize?: string;\n\tmaxSize?: string;\n\tsticky?: boolean;\n\tclassName?: string;\n\tas?: keyof JSX.IntrinsicElements;\n\tresizable?: boolean;\n\tcollapsible?: boolean;\n\tcollapsed?: boolean;\n\tonResize?: (size: number) => void;\n\tinitialSize?: number;\n\tpersistKey?: string;\n\tanimated?: boolean;\n\tonToggleCollapse?: (collapsed: boolean) => void;\n\tshowToggle?: boolean;\n\tminSnapSize?: number;\n\tresizeBarClass?: (props: any) => string;\n}\n\nexport interface SmartLayoutProps {\n\tdirection?: Direction;\n\tchildren: ReactNode;\n\tclassName?: string;\n\tpreset?: \"modal\" | \"card\" | \"split\" | \"sidebar\";\n\tresponsive?: boolean;\n\tas?: keyof JSX.IntrinsicElements;\n}\n\nconst getStyle = (isVertical: boolean, section: SectionBase, size?: number): CSSProperties => {\n\tconst baseStyle = size ? (isVertical ? {height: size} : {width: size}) : {};\n\n\treturn {\n\t\t...baseStyle,\n\t\t...(section.maxSize\n\t\t\t? isVertical\n\t\t\t\t? {maxHeight: section.maxSize}\n\t\t\t\t: {maxWidth: section.maxSize}\n\t\t\t: {}),\n\t\t...(section.minSize\n\t\t\t? isVertical\n\t\t\t\t? {minHeight: section.minSize}\n\t\t\t\t: {minWidth: section.minSize}\n\t\t\t: {}),\n\t};\n};\n\nconst getClass = (section: SectionBase, isVertical: boolean) =>\n\tclsx(\n\t\tsection.className,\n\t\tsection.grow && \"flex-1\",\n\t\tsection.shrink && \"shrink-0\",\n\t\tsection.scroll ? \"overflow-auto\" : \"overflow-hidden\",\n\t\tsection.sticky &&\n\t\t\t(isVertical ? \"sticky top-0 z-10 bg-inherit\" : \"sticky left-0 z-10 bg-inherit\"),\n\t\tsection.collapsible && section.collapsed && isVertical && \" h-fit\",\n\t\tsection.collapsible && section.collapsed && !isVertical && \" w-fit\",\n\t\tsection.animated && \"transition-all duration-300 ease-in-out\",\n\t\t\"relative\"\n\t);\n\nconst usePersistentSize = (\n\tkey?: string,\n\tinitial?: number\n): [number | undefined, (v: number) => void] => {\n\tconst [size, setSize] = useState<number | undefined>(() => {\n\t\tif (key) {\n\t\t\tconst stored = localStorage.getItem(`layout-size-${key}`);\n\t\t\treturn stored ? Number(stored) : initial;\n\t\t}\n\t\treturn initial;\n\t});\n\n\tconst setAndPersist = (v: number) => {\n\t\tif (key) localStorage.setItem(`layout-size-${key}`, String(v));\n\t\tsetSize(v);\n\t};\n\n\treturn [size, setAndPersist];\n};\n\nconst Section = ({\n\tchildren,\n\tas = \"div\",\n\tresizable,\n\tresizeBarClass,\n\tcollapsible,\n\tcollapsed: propCollapsed,\n\tonResize,\n\tinitialSize,\n\tpersistKey,\n\tonToggleCollapse,\n\tshowToggle,\n\tminSnapSize = 50,\n\t...props\n}: any) => {\n\tconst Tag = as;\n\tconst {direction} = useContext(LayoutContext);\n\tconst isVertical = direction === \"vertical\";\n\tconst ref = useRef<HTMLDivElement | null>(null);\n\n\tconst [size, setSize] = usePersistentSize(persistKey, initialSize);\n\tconst [collapsed, setCollapsed] = useState(propCollapsed ?? false);\n\tconst resizing = useRef(false);\n\n\tconst onMouseMove = (e: MouseEvent<Document>) => {\n\t\tif (!resizing.current || !ref.current) return;\n\t\tconst rect = ref.current.getBoundingClientRect();\n\t\tlet newSize = isVertical ? e.clientY - rect.top : e.clientX - rect.left;\n\t\tnewSize = Math.max(newSize, minSnapSize); // Ensures the minimum size\n\t\tsetSize(newSize);\n\t\tonResize?.(newSize);\n\t};\n\n\tconst onMouseUp = () => {\n\t\tresizing.current = false;\n\t\tdocument.removeEventListener(\"mousemove\", onMouseMove as any);\n\t\tdocument.removeEventListener(\"mouseup\", onMouseUp);\n\t};\n\n\tconst handleMouseDown = (e: MouseEvent<HTMLDivElement>) => {\n\t\te.preventDefault();\n\t\tresizing.current = true;\n\t\tdocument.addEventListener(\"mousemove\", onMouseMove as any);\n\t\tdocument.addEventListener(\"mouseup\", onMouseUp);\n\t};\n\n\tconst toggleCollapsed = () => {\n\t\tconst newState = !collapsed;\n\t\tsetCollapsed(newState);\n\t\tonToggleCollapse?.(newState);\n\t};\n\n\tuseEffect(() => {\n\t\treturn () => onMouseUp();\n\t}, []);\n\n\treturn (\n\t\t<Tag\n\t\t\tref={ref as any}\n\t\t\tclassName={getClass({...props, collapsible, collapsed}, isVertical)}\n\t\t\tstyle={getStyle(isVertical, props, collapsed ? 0 : size)}\n\t\t>\n\t\t\t{showToggle && collapsible && (\n\t\t\t\t<button\n\t\t\t\t\tonClick={toggleCollapsed}\n\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\"fixed z-30 rounded p-1 text-sm text-muted-foreground hover:bg-muted\",\n\t\t\t\t\t\tisVertical ? \"right-2 top-2\" : \"left-2 top-2\"\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t{collapsed ? (\n\t\t\t\t\t\tisVertical ? (\n\t\t\t\t\t\t\t<ChevronDown size={16} />\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<ChevronRight size={16} />\n\t\t\t\t\t\t)\n\t\t\t\t\t) : isVertical ? (\n\t\t\t\t\t\t<ChevronUp size={16} />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<ChevronLeft size={16} />\n\t\t\t\t\t)}\n\t\t\t\t</button>\n\t\t\t)}\n\t\t\t{!collapsed && children}\n\t\t\t{resizable && (\n\t\t\t\t<div\n\t\t\t\t\tonMouseDown={handleMouseDown}\n\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\"absolute z-20\",\n\t\t\t\t\t\tisVertical\n\t\t\t\t\t\t\t? \"-bottom-1 left-0 right-0 h-2 hover:bg-black cursor-row-resize\"\n\t\t\t\t\t\t\t: \"right-0 top-0 bottom-0 w-2 hover:bg-black cursor-col-resize\",\n\t\t\t\t\t\tresizeBarClass?.({resizable, isVertical}) || \"\"\n\t\t\t\t\t)}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</Tag>\n\t);\n};\n\n/**\n * Main Layout Component\n */\nconst SmartLayout = ({\n\tchildren,\n\tdirection = \"vertical\",\n\tclassName,\n\tpreset,\n\tresponsive,\n\tas = \"div\",\n}: SmartLayoutProps) => {\n\tconst isVertical = direction === \"vertical\";\n\n\tconst layoutClass = clsx(\n\t\t\"w-full h-full overflow-hidden relative\",\n\t\tisVertical ? \"flex flex-col\" : \"flex flex-row\",\n\t\tpreset === \"modal\" && \"rounded-xl border shadow-lg\",\n\t\tpreset === \"card\" && \"rounded-md border\",\n\t\tpreset === \"sidebar\" && \"border-r\",\n\t\tpreset === \"split\" && (isVertical ? \"divide-y\" : \"divide-x\"),\n\t\tresponsive && \"sm:flex-col md:flex-row\",\n\t\tclassName\n\t);\n\n\tconst Tag = as;\n\n\treturn (\n\t\t<LayoutContext.Provider value={{direction}}>\n\t\t\t<Tag className={layoutClass}>{children}</Tag>\n\t\t</LayoutContext.Provider>\n\t);\n};\n\nexport default SmartLayout;\n\nSmartLayout.Header = (props: SectionBase) => <Section {...props} />;\nSmartLayout.Body = (props: SectionBase) => <Section grow scroll {...props} />;\nSmartLayout.Footer = (props: SectionBase) => <Section {...props} />;\n\n\n// example in readme"],"mappings":"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","names":[]}