39948-vm/frontend/src/components/UiElements/UiElementRenderer.tsx
2026-03-30 21:28:00 +04:00

115 lines
3.5 KiB
TypeScript

/**
* UiElementRenderer Component
*
* Unified UI Element Renderer - single source of truth for element rendering.
* Used by both CanvasElement (constructor) and RuntimeElement (presentation)
* to ensure WYSIWYG consistency.
*
* Renders any UI element with consistent styling by delegating to per-type components.
*/
import React from 'react';
import type { CanvasElement } from '../../types/constructor';
import { useElementWrapperStyle } from './shared/useElementWrapperStyle';
import {
isNavigationElementType,
isTooltipElementType,
isDescriptionElementType,
isGalleryElementType,
isCarouselElementType,
isVideoPlayerElementType,
isAudioPlayerElementType,
isLogoElementType,
isSpotElementType,
isPopupElementType,
} from '../../lib/elementDefaults';
// Import per-type components
import NavigationElement from './elements/NavigationElement';
import GalleryElement from './elements/GalleryElement';
import TooltipElement from './elements/TooltipElement';
import DescriptionElement from './elements/DescriptionElement';
import CarouselElement from './elements/CarouselElement';
import LogoElement from './elements/LogoElement';
import SpotElement from './elements/SpotElement';
import VideoPlayerElement from './elements/VideoPlayerElement';
import AudioPlayerElement from './elements/AudioPlayerElement';
import PopupElement from './elements/PopupElement';
export interface UiElementRendererProps {
element: CanvasElement;
resolveUrl?: (url: string | undefined) => string;
// Constructor-specific props (optional)
isSelected?: boolean;
isEditMode?: boolean;
isDisabled?: boolean;
// Gallery carousel callback
onGalleryCardClick?: (cardIndex: number) => void;
}
/**
* Unified UI Element Renderer
*
* Renders any UI element with consistent styling.
* Used by both CanvasElement (constructor) and RuntimeElement (presentation).
*/
export const UiElementRenderer: React.FC<UiElementRendererProps> = ({
element,
resolveUrl,
isSelected = false,
isEditMode = false,
isDisabled = false,
onGalleryCardClick,
}) => {
const { className, style } = useElementWrapperStyle({
element,
isSelected,
isEditMode,
isDisabled,
});
// Common props for all element types
const commonProps = { element, resolveUrl, className, style };
// Delegate to type-specific component
if (isNavigationElementType(element.type)) {
return <NavigationElement {...commonProps} />;
}
if (isGalleryElementType(element.type)) {
return <GalleryElement {...commonProps} onCardClick={onGalleryCardClick} />;
}
if (isTooltipElementType(element.type)) {
return <TooltipElement {...commonProps} />;
}
if (isDescriptionElementType(element.type)) {
return <DescriptionElement {...commonProps} />;
}
if (isCarouselElementType(element.type)) {
return <CarouselElement {...commonProps} />;
}
if (isVideoPlayerElementType(element.type)) {
return <VideoPlayerElement {...commonProps} />;
}
if (isAudioPlayerElementType(element.type)) {
return <AudioPlayerElement {...commonProps} />;
}
if (isLogoElementType(element.type)) {
return <LogoElement {...commonProps} />;
}
if (isSpotElementType(element.type)) {
return <SpotElement {...commonProps} />;
}
if (isPopupElementType(element.type)) {
return <PopupElement {...commonProps} />;
}
// Fallback for unknown types
return (
<div className={className} style={style}>
<span className='px-4 py-2 text-sm'>{element.label || element.type}</span>
</div>
);
};
export default UiElementRenderer;