fixed elements positioning

This commit is contained in:
Dmitri 2026-05-28 07:20:13 +02:00
parent c88f5d2a37
commit 69ddc59317
3 changed files with 61 additions and 11 deletions

View File

@ -274,16 +274,14 @@
============================================================= */ ============================================================= */
/* Element appear animation keyframes - Safari optimized */ /* Element appear animation keyframes - Safari optimized */
/* Note: element-fade-in must NOT include transform as it conflicts with
element positioning (translate(-50%, -50%)) causing position shift */
@-webkit-keyframes element-fade-in { @-webkit-keyframes element-fade-in {
from { from {
opacity: 0; opacity: 0;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
} }
to { to {
opacity: 1; opacity: 1;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
} }
} }

View File

@ -6,7 +6,7 @@
* handles state-based style application via JavaScript events. * handles state-based style application via JavaScript events.
*/ */
import { useCallback, useState, useEffect } from 'react'; import { useCallback, useState, useEffect, useRef } from 'react';
import type { CSSProperties } from 'react'; import type { CSSProperties } from 'react';
import { import {
buildHoverStyle, buildHoverStyle,
@ -83,13 +83,20 @@ export function useElementEffects(
isClickPersisted: false, isClickPersisted: false,
}); });
// Track previous resetKey to avoid running on initial mount
const prevResetKeyRef = useRef(resetKey);
// Reset reveal state and click-persisted state when resetKey changes (e.g., page navigation) // Reset reveal state and click-persisted state when resetKey changes (e.g., page navigation)
// Only run when resetKey actually CHANGES, not on initial mount (to avoid re-render during animation)
useEffect(() => { useEffect(() => {
setState((prev) => ({ if (prevResetKeyRef.current !== resetKey) {
...prev, setState((prev) => ({
isRevealed: false, ...prev,
isClickPersisted: false, isRevealed: false,
})); isClickPersisted: false,
}));
prevResetKeyRef.current = resetKey;
}
}, [resetKey]); }, [resetKey]);
const onMouseEnter = useCallback(() => { const onMouseEnter = useCallback(() => {

View File

@ -113,13 +113,58 @@ export type EffectPropName = (typeof EFFECT_PROPS)[number];
/** /**
* Build base transition style for smooth state changes. * Build base transition style for smooth state changes.
* Uses specific properties instead of 'all' to avoid affecting positioning transforms.
*/ */
export function buildTransitionStyle( export function buildTransitionStyle(
effects: Partial<ElementEffectProperties>, effects: Partial<ElementEffectProperties>,
): CSSProperties { ): CSSProperties {
const duration = normalizeDuration(effects.hoverTransitionDuration) || '0.2s'; const duration = normalizeDuration(effects.hoverTransitionDuration) || '0.2s';
// Build list of properties to transition based on what's configured
const transitionProps: string[] = [];
// Always include opacity if any effect might change it
if (
effects.hoverOpacity ||
effects.focusOpacity ||
effects.activeOpacity ||
effects.hoverReveal
) {
transitionProps.push('opacity');
}
// Include transform only for scale effects (not positioning)
if (effects.hoverScale || effects.focusScale || effects.activeScale) {
transitionProps.push('transform');
}
// Background color
if (effects.hoverBackgroundColor || effects.activeBackgroundColor) {
transitionProps.push('background-color');
}
// Text color
if (effects.hoverColor) {
transitionProps.push('color');
}
// Box shadow
if (effects.hoverBoxShadow || effects.focusBoxShadow) {
transitionProps.push('box-shadow');
}
// Outline
if (effects.focusOutline) {
transitionProps.push('outline');
}
// If no specific properties, return empty (no transition needed)
if (transitionProps.length === 0) {
return {};
}
return { return {
transition: `all ${duration} ease`, transition: transitionProps.map((p) => `${p} ${duration} ease`).join(', '),
}; };
} }