115 lines
3.5 KiB
TypeScript
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;
|