UNPKG

now-design-organisms

Version:

Organism components for the Now Design System

154 lines (143 loc) 4.58 kB
import React from 'react'; import PropTypes from 'prop-types'; import AccordionSelectableListContainer from '../AccordionSelectableListContainer'; import { LogoMetalCloud } from 'now-design-atoms'; import './LeftPanel.css'; /** * LeftPanel Organism Component * A reusable left panel navigation organism using AccordionSelectableListContainer * * Props: * - items: array (required) - Array of accordion configurations * - onItemSelect: function (optional) - Enhanced callback when any item is selected * Receives: (itemId, parentAccordionId, selectedItemLabel) * - selectedItem: string (optional) - Selected item ID * - logo: element|component (optional) - Custom logo component or element to replace LogoMetalCloud * - logoSize: object (optional) - Logo dimensions {width, height} (default: {width: 64, height: 32}) * - onLogoClick: function (optional) - Callback when logo is clicked * - contentClassName: string (optional) - Additional CSS classes for content container * - contentStyle: object (optional) - Additional inline styles for content container * - className: string (optional) - Additional CSS classes * - style: object (optional) - Additional inline styles (includes layout, visual, and positioning styles) */ const LeftPanel = ({ items = [], onItemSelect, selectedItem, logo, logoSize = { width: 64, height: 32 }, onLogoClick, contentClassName = '', contentStyle = {}, className = '', style = {} }) => { // Warning for missing or empty items if (!items || items.length === 0) { console.warn('LeftPanel: items is empty or missing. Component may not render properly.'); } const handleItemSelect = (itemId) => { if (onItemSelect) { // Find the parent accordion for this item const parentAccordion = items.find(accordion => accordion.items.some(item => item.id === itemId) ); // Find the selected item details const selectedItemDetails = parentAccordion?.items.find(item => item.id === itemId); // Enhanced callback with essential data only onItemSelect( itemId, parentAccordion?.id || null, selectedItemDetails?.label || null ); } }; const handleLogoClick = (e) => { if (onLogoClick) { onLogoClick(e); } }; // Build content styles const contentStyles = { flex: 1, ...contentStyle }; // Render logo - handle both React elements and components const renderLogo = () => { if (logo) { // If logo is a React element (already rendered), return it as is if (React.isValidElement(logo)) { return logo; } // If logo is a component function, render it with props if (typeof logo === 'function') { const LogoComponent = logo; return <LogoComponent {...logoSize} />; } } // Default logo return <LogoMetalCloud {...logoSize} />; }; return ( <div className={`left-panel ${className}`} style={style} > {/* Logo Section */} <div className="left-panel-logo" style={{ cursor: onLogoClick ? 'pointer' : 'default' }} onClick={handleLogoClick} > {renderLogo()} </div> {/* Content Section */} <div className={`left-panel-content ${contentClassName}`} style={contentStyles}> <AccordionSelectableListContainer accordionData={items} onItemSelect={handleItemSelect} defaultSelectedItemId={selectedItem} /> </div> </div> ); }; LeftPanel.propTypes = { items: PropTypes.arrayOf( PropTypes.shape({ id: PropTypes.string.isRequired, triggerLabel: PropTypes.string.isRequired, triggerIcon: PropTypes.oneOfType([ PropTypes.string, PropTypes.element ]), items: PropTypes.arrayOf( PropTypes.shape({ id: PropTypes.string.isRequired, label: PropTypes.string.isRequired, icon: PropTypes.oneOfType([ PropTypes.string, PropTypes.element ]), disabled: PropTypes.bool }) ).isRequired }) ).isRequired, onItemSelect: PropTypes.func, selectedItem: PropTypes.string, logo: PropTypes.oneOfType([ PropTypes.element, PropTypes.func ]), logoSize: PropTypes.shape({ width: PropTypes.number, height: PropTypes.number }), onLogoClick: PropTypes.func, contentClassName: PropTypes.string, contentStyle: PropTypes.object, className: PropTypes.string, style: PropTypes.object }; export default LeftPanel;