/** * Web Component wrapper for AppSidebar (hand-crafted WC adapter). * Custom element: * * @generated by scripts/generate-wc-components.ts * DO NOT EDIT MANUALLY */ import { Calendar, Circle, FileText, Home, type LucideIcon, MessageCircle, Settings, Users, Workflow, } from 'lucide-react'; import React from 'react'; import { AppSidebar } from '../components'; import { SidebarInset, SidebarProvider } from '../components/ui/sidebar'; import { asArray, BaseCompoundWC, camelToKebab, dispatchEvent, installPropAccessors, type PropDefs, portalNode, registerWC, } from './_shared'; const PROP_DEFS: PropDefs = { navItems: 'json', activeNavItemId: 'string', account: 'json', logo: 'json', collapsible: 'string', connected: 'boolean', defaultOpen: 'boolean', side: 'string', compactedLogo: 'string', sidebarBgColor: 'string', rounded: 'boolean', logoSubtext: 'string', }; type NavSubItemDef = { label: string; badge?: string | number; href?: string; isActive?: boolean; }; type NavItemDef = { type?: 'item'; id: string; icon?: string; label: string; isActive?: boolean; badge?: string | number; href?: string; children?: NavSubItemDef[]; }; type NavSectionDef = { type: 'section'; id?: string; label: string; }; type NavEntryDef = NavItemDef | NavSectionDef; type LogoDef = { src?: string; alt?: string; }; const SIDEBAR_ICON_COMPONENTS: Record = { home: Home, users: Users, calendar: Calendar, 'file-text': FileText, settings: Settings, 'message-circle': MessageCircle, workflow: Workflow, }; const warnedUnsupportedIconNames = new Set(); function normalizeIconName(iconName: string | undefined): string | undefined { const normalizedIconName = iconName ?.trim() .replace(/([a-z0-9])([A-Z])/g, '$1-$2') .replace(/[\s_]+/g, '-') .toLowerCase(); return normalizedIconName || undefined; } function renderNavIcon(iconName: string | undefined): React.ReactElement { const normalizedIconName = normalizeIconName(iconName); if (normalizedIconName) { const Icon = SIDEBAR_ICON_COMPONENTS[normalizedIconName]; if (Icon) { return React.createElement(Icon, { 'aria-hidden': true }); } if (!warnedUnsupportedIconNames.has(normalizedIconName)) { warnedUnsupportedIconNames.add(normalizedIconName); console.warn( `[hf-app-sidebar] Unsupported nav item icon "${normalizedIconName}". Falling back to "circle".`, ); } } return React.createElement(Circle, { 'aria-hidden': true }); } function isNavSection(item: NavEntryDef): item is NavSectionDef { return item.type === 'section'; } function renderLogoImage( logo: LogoDef | undefined, fallbackAlt: string, ): React.ReactElement | null | undefined { if (!logo) { return undefined; } if (!logo.src) { return null; } return React.createElement('img', { src: logo.src, alt: logo.alt || fallbackAlt, }); } class AppSidebarWC extends BaseCompoundWC { get propDefs() { return PROP_DEFS; } static get observedAttributes() { return Object.keys(PROP_DEFS).map(camelToKebab); } protected _renderReact(): React.ReactElement { const props = this._readAllProps(); const contentSlot = this._getSlot('content'); const navItems = asArray(props.navItems); const account = props.account as | { name: string; subtitle: string; avatarSrc?: string; isOnline?: boolean; } | undefined; const logo = props.logo as LogoDef | undefined; const compactedLogo = props.compactedLogo ? renderLogoImage( { src: String(props.compactedLogo), alt: logo?.alt }, logo?.alt || 'Logo', ) : undefined; const host = this; function handleNavItemClick(item: { id: string; label: string }): void { dispatchEvent(host, 'nav-item-click', item); } function handleOpenChange(open: boolean): void { dispatchEvent(host, 'open-change', open); } const sidebarChildren: React.ReactElement[] = []; sidebarChildren.push( React.createElement( AppSidebar, { key: 'sidebar', collapsible: (props.collapsible as 'offcanvas' | 'icon' | 'none') || 'icon', side: (props.side as 'left' | 'right') || 'left', rounded: props.rounded as boolean, sidebarBgColor: props.sidebarBgColor as string, logoSubtext: props.logoSubtext as string, logo: renderLogoImage(logo, 'Logo'), compactedLogo, }, navItems.length > 0 && React.createElement( AppSidebar.Nav, { key: 'nav' }, ...navItems.map((item, index) => { if (isNavSection(item)) { return React.createElement(AppSidebar.NavSection, { key: item.id || `section-${index}`, label: item.label, }); } return React.createElement( AppSidebar.NavItem, { key: item.id, icon: renderNavIcon(item.icon), label: item.label, isActive: item.isActive || item.id === props.activeNavItemId, badge: item.badge, href: item.href, onClick: () => handleNavItemClick(item), }, ...(item.children ? item.children.map((child, idx) => React.createElement(AppSidebar.NavSub, { key: `${item.id}-sub-${idx}`, label: child.label, badge: child.badge, href: child.href, isActive: child.isActive, }), ) : []), ); }), ), account && React.createElement(AppSidebar.Account, { key: 'account', name: account.name, subtitle: account.subtitle, avatarSrc: account.avatarSrc, isOnline: account.isOnline, }), ), ); if (contentSlot) { sidebarChildren.push( React.createElement( SidebarInset, { key: 'inset', connected: props.connected as boolean }, portalNode(contentSlot), ), ); } return React.createElement( SidebarProvider, { defaultOpen: (props.defaultOpen as boolean) ?? false, onOpenChange: handleOpenChange, connected: props.connected as boolean, }, ...sidebarChildren, ); } } installPropAccessors(AppSidebarWC, PROP_DEFS); registerWC('hf-app-sidebar', AppSidebarWC); export { AppSidebarWC }; export default AppSidebarWC;