fixed positioning
This commit is contained in:
parent
08365ca09e
commit
7dd3384a46
@ -10,11 +10,11 @@
|
||||
import React from 'react';
|
||||
import UiElementRenderer from '../UiElements/UiElementRenderer';
|
||||
import { useElementEffects } from '../../hooks/useElementEffects';
|
||||
import { useAppearAnimation } from '../../hooks/useAppearAnimation';
|
||||
import {
|
||||
buildTransitionStyle,
|
||||
buildAppearAnimationStyle,
|
||||
hasAnyEffects,
|
||||
extractEffectProperties,
|
||||
type ElementEffectProperties,
|
||||
} from '../../lib/elementEffects';
|
||||
import type { CanvasElement as CanvasElementType } from '../../types/constructor';
|
||||
import type { ResolvedTransitionSettings } from '../../types/transition';
|
||||
@ -57,66 +57,67 @@ const CanvasElement: React.FC<CanvasElementProps> = ({
|
||||
pageTransitionSettings,
|
||||
preloadCache,
|
||||
}) => {
|
||||
// Extract effect properties from element using helper
|
||||
const effectProperties = extractEffectProperties(
|
||||
element as unknown as Record<string, unknown>,
|
||||
);
|
||||
|
||||
// Use appear animation hook (removes animation after completion to unlock properties)
|
||||
const { animationStyle, onAnimationEnd, hasAnimationEnded } =
|
||||
useAppearAnimation(
|
||||
effectProperties,
|
||||
element.id, // Reset animation when element changes
|
||||
);
|
||||
// Extract effect properties from element
|
||||
const effectProperties: Partial<ElementEffectProperties> = {
|
||||
appearAnimation: element.appearAnimation,
|
||||
appearAnimationDuration: element.appearAnimationDuration,
|
||||
appearAnimationEasing: element.appearAnimationEasing,
|
||||
hoverScale: element.hoverScale,
|
||||
hoverOpacity: element.hoverOpacity,
|
||||
hoverBackgroundColor: element.hoverBackgroundColor,
|
||||
hoverColor: element.hoverColor,
|
||||
hoverBoxShadow: element.hoverBoxShadow,
|
||||
hoverTransitionDuration: element.hoverTransitionDuration,
|
||||
focusScale: element.focusScale,
|
||||
focusOpacity: element.focusOpacity,
|
||||
focusOutline: element.focusOutline,
|
||||
focusBoxShadow: element.focusBoxShadow,
|
||||
activeScale: element.activeScale,
|
||||
activeOpacity: element.activeOpacity,
|
||||
activeBackgroundColor: element.activeBackgroundColor,
|
||||
// Hover reveal effects
|
||||
hoverReveal: element.hoverReveal,
|
||||
hoverRevealInitialOpacity: element.hoverRevealInitialOpacity,
|
||||
hoverRevealTargetOpacity: element.hoverRevealTargetOpacity,
|
||||
hoverRevealDuration: element.hoverRevealDuration,
|
||||
hoverRevealDelay: element.hoverRevealDelay,
|
||||
hoverRevealPersist: element.hoverRevealPersist,
|
||||
hoverPersistOnClick: element.hoverPersistOnClick,
|
||||
};
|
||||
|
||||
// Use effects hook - disabled in edit mode to avoid interfering with dragging
|
||||
const { effectStyle, eventHandlers, onPersistClick } = useElementEffects(
|
||||
const { effectStyle, eventHandlers } = useElementEffects(
|
||||
isEditMode ? {} : effectProperties,
|
||||
isEditMode
|
||||
? undefined
|
||||
: {
|
||||
resetKey: element.id,
|
||||
appearAnimationCompleted:
|
||||
hasAnimationEnded || !effectProperties.appearAnimation,
|
||||
},
|
||||
);
|
||||
|
||||
// Combined click handler (only persist click in preview mode)
|
||||
const handleClick = () => {
|
||||
if (!isEditMode) {
|
||||
onPersistClick();
|
||||
}
|
||||
onClick();
|
||||
};
|
||||
|
||||
// Clamp position to canvas bounds (0-100%)
|
||||
const clamp = (value: number, min: number, max: number) =>
|
||||
Math.min(Math.max(value, min), max);
|
||||
const xClamped = clamp(element.xPercent ?? 50, 0, 100);
|
||||
const yClamped = clamp(element.yPercent ?? 50, 0, 100);
|
||||
|
||||
// Build base position style
|
||||
// Build base position style (outer div - handles positioning + animation)
|
||||
let positionStyle: React.CSSProperties = {
|
||||
left: `${xClamped}%`,
|
||||
top: `${yClamped}%`,
|
||||
transform: 'translate(-50%, -50%)',
|
||||
};
|
||||
|
||||
// Merge interactive effects (preview mode only)
|
||||
if (!isEditMode && effectStyle.transform) {
|
||||
// Preserve the translate, add effect transform
|
||||
positionStyle.transform = `translate(-50%, -50%) ${effectStyle.transform}`;
|
||||
// Remove transform from effectStyle to avoid double application
|
||||
const { transform, ...restEffectStyle } = effectStyle;
|
||||
positionStyle = { ...positionStyle, ...restEffectStyle };
|
||||
} else if (!isEditMode) {
|
||||
positionStyle = { ...positionStyle, ...effectStyle };
|
||||
}
|
||||
|
||||
// Add transition for interactive effects (preview mode only)
|
||||
if (!isEditMode && hasAnyEffects(effectProperties)) {
|
||||
// Add appear animation to outer div (ALWAYS - for WYSIWYG)
|
||||
// Animation is applied to outer div to keep positioning hack working
|
||||
if (effectProperties.appearAnimation) {
|
||||
positionStyle = {
|
||||
...positionStyle,
|
||||
...buildAppearAnimationStyle(effectProperties),
|
||||
};
|
||||
}
|
||||
|
||||
// Build inner wrapper style for hover/focus/active effects (preview mode only)
|
||||
// Using separate div so animation on outer div doesn't block these effects
|
||||
let innerEffectStyle: React.CSSProperties = {};
|
||||
if (!isEditMode && hasAnyEffects(effectProperties)) {
|
||||
innerEffectStyle = {
|
||||
...effectStyle,
|
||||
...buildTransitionStyle(effectProperties),
|
||||
};
|
||||
}
|
||||
@ -129,51 +130,8 @@ const CanvasElement: React.FC<CanvasElementProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
// Check if appear animation uses transform (slide/scale need separate wrapper)
|
||||
const needsAnimationWrapper =
|
||||
effectProperties.appearAnimation &&
|
||||
effectProperties.appearAnimation !== 'fade';
|
||||
|
||||
// Render content
|
||||
const content = (
|
||||
<UiElementRenderer
|
||||
element={element}
|
||||
resolveUrl={resolveUrl}
|
||||
isSelected={isSelected}
|
||||
isEditMode={isEditMode}
|
||||
onGalleryCardClick={onGalleryCardClick}
|
||||
onCarouselButtonPositionChange={onCarouselButtonPositionChange}
|
||||
letterboxStyles={letterboxStyles}
|
||||
pageTransitionSettings={pageTransitionSettings}
|
||||
preloadCache={preloadCache}
|
||||
/>
|
||||
);
|
||||
|
||||
// For slide/scale (uses transform), use separate wrapper to avoid conflict with positioning
|
||||
if (needsAnimationWrapper) {
|
||||
return (
|
||||
<div
|
||||
role='button'
|
||||
tabIndex={0}
|
||||
data-constructor-element-id={element.id}
|
||||
className='absolute cursor-pointer'
|
||||
style={positionStyle}
|
||||
onMouseDown={isEditMode ? onMouseDown : undefined}
|
||||
onClick={handleClick}
|
||||
onKeyDown={handleKeyDown}
|
||||
{...(!isEditMode ? eventHandlers : {})}
|
||||
>
|
||||
<div style={animationStyle} onAnimationEnd={onAnimationEnd}>
|
||||
{content}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Fade or no animation: apply animation to positioning div
|
||||
const combinedStyle = effectProperties.appearAnimation
|
||||
? { ...positionStyle, ...animationStyle }
|
||||
: positionStyle;
|
||||
// Check if we need the inner wrapper for effects
|
||||
const needsEffectWrapper = !isEditMode && hasAnyEffects(effectProperties);
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -181,16 +139,40 @@ const CanvasElement: React.FC<CanvasElementProps> = ({
|
||||
tabIndex={0}
|
||||
data-constructor-element-id={element.id}
|
||||
className='absolute cursor-pointer'
|
||||
style={combinedStyle}
|
||||
style={positionStyle}
|
||||
onMouseDown={isEditMode ? onMouseDown : undefined}
|
||||
onClick={handleClick}
|
||||
onClick={onClick}
|
||||
onKeyDown={handleKeyDown}
|
||||
onAnimationEnd={
|
||||
effectProperties.appearAnimation ? onAnimationEnd : undefined
|
||||
}
|
||||
{...(!isEditMode ? eventHandlers : {})}
|
||||
{...(!isEditMode && !needsEffectWrapper ? eventHandlers : {})}
|
||||
>
|
||||
{content}
|
||||
{needsEffectWrapper ? (
|
||||
// Inner wrapper handles hover/focus/active effects independently from animation
|
||||
<div style={innerEffectStyle} {...eventHandlers}>
|
||||
<UiElementRenderer
|
||||
element={element}
|
||||
resolveUrl={resolveUrl}
|
||||
isSelected={isSelected}
|
||||
isEditMode={isEditMode}
|
||||
onGalleryCardClick={onGalleryCardClick}
|
||||
onCarouselButtonPositionChange={onCarouselButtonPositionChange}
|
||||
letterboxStyles={letterboxStyles}
|
||||
pageTransitionSettings={pageTransitionSettings}
|
||||
preloadCache={preloadCache}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<UiElementRenderer
|
||||
element={element}
|
||||
resolveUrl={resolveUrl}
|
||||
isSelected={isSelected}
|
||||
isEditMode={isEditMode}
|
||||
onGalleryCardClick={onGalleryCardClick}
|
||||
onCarouselButtonPositionChange={onCarouselButtonPositionChange}
|
||||
letterboxStyles={letterboxStyles}
|
||||
pageTransitionSettings={pageTransitionSettings}
|
||||
preloadCache={preloadCache}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -277,18 +277,24 @@
|
||||
@-webkit-keyframes element-fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes element-fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user