import React, { useMemo } from 'react'; import { cn } from '@/lib/utils'; import { FlexibleContainer, RowDef, ColumnDef, WidgetInstance, } from '@/modules/layout/LayoutManager'; import { widgetRegistry } from '@/lib/widgetRegistry'; import { useLayout } from '@/modules/layout/LayoutContext'; import CollapsibleSection from '@/components/CollapsibleSection'; // --------------------------------------------------------------------------- // Helpers (shared with edit — kept small, duplicated for bundle isolation) // --------------------------------------------------------------------------- export function columnsToGridTemplate(columns: ColumnDef[]): string { return columns .map(c => { switch (c.unit) { case 'fr': return `${c.width}fr`; case 'px': return `${c.width}px`; case 'rem': return `${c.width}rem`; case '%': return `${c.width}%`; default: return `${c.width}fr`; } }) .join(' '); } export function getRowAlignItems(sizing?: 'constrained' | 'unconstrained'): string { return sizing === 'unconstrained' ? 'items-start' : 'items-stretch'; } // --------------------------------------------------------------------------- // View-only widget item // --------------------------------------------------------------------------- interface FlexWidgetViewProps { widget: WidgetInstance; pageId: string; contextVariables?: Record; pageContext?: Record; } const FlexWidgetView: React.FC = ({ widget, pageId, contextVariables, pageContext }) => { const { updateWidgetProps } = useLayout(); const widgetDef = widgetRegistry.get(widget.widgetId); if (!widgetDef) return null; const Component = widgetDef.component; return (
) => { try { await updateWidgetProps(pageId, widget.id, newProps); } catch (e) { console.error('Failed to update widget props', e); } }} onSave={() => { }} />
); }; // --------------------------------------------------------------------------- // Props (the view-only subset) // --------------------------------------------------------------------------- export interface FlexContainerViewProps { container: FlexibleContainer; isEditMode: boolean; pageId: string; isCompactMode?: boolean; contextVariables?: Record; pageContext?: Record; } // --------------------------------------------------------------------------- // Main View Component // --------------------------------------------------------------------------- const FlexContainerView: React.FC = ({ container, pageId, isCompactMode, contextVariables, pageContext, }) => { // ------- Widget grouping: per row + column ------- const widgetsByCell = useMemo(() => { const map = new Map(); for (const row of container.rows) { for (let colIdx = 0; colIdx < row.columns.length; colIdx++) { const key = `${row.id}:${colIdx}`; map.set(key, []); } } for (const w of container.widgets) { if (w.rowId && w.column !== undefined) { const key = `${w.rowId}:${w.column}`; const list = map.get(key); if (list) list.push(w); } } for (const list of map.values()) { list.sort((a, b) => (a.order ?? 0) - (b.order ?? 0)); } return map; }, [container.rows, container.widgets]); // ------- Render a single row ------- const renderRow = (row: RowDef) => { const gridTemplate = columnsToGridTemplate(row.columns); const alignClass = getRowAlignItems(row.sizing); return (
{row.columns.map((_col, colIdx) => { const key = `${row.id}:${colIdx}`; const cellWidgets = widgetsByCell.get(key) || []; return (
{cellWidgets.map(w => ( ))}
); })}
); }; // ------- Container wrapper ------- const title = container.settings?.title || 'Flexible Container'; const showTitle = container.settings?.showTitle; const isCollapsible = container.settings?.collapsible; const enabled = container.settings?.enabled !== false; if (!enabled) return null; const containerContent = (
{container.rows.map(row => renderRow(row))}
); if (isCollapsible && showTitle) { return ( {containerContent} ); } if (showTitle && !isCompactMode) { return (

{title}

{containerContent}
); } return containerContent; }; export default FlexContainerView;