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 */
/* 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 {
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);
}
}

View File

@ -6,7 +6,7 @@
* 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 {
buildHoverStyle,
@ -83,13 +83,20 @@ export function useElementEffects(
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)
// Only run when resetKey actually CHANGES, not on initial mount (to avoid re-render during animation)
useEffect(() => {
setState((prev) => ({
...prev,
isRevealed: false,
isClickPersisted: false,
}));
if (prevResetKeyRef.current !== resetKey) {
setState((prev) => ({
...prev,
isRevealed: false,
isClickPersisted: false,
}));
prevResetKeyRef.current = resetKey;
}
}, [resetKey]);
const onMouseEnter = useCallback(() => {

View File

@ -113,13 +113,58 @@ export type EffectPropName = (typeof EFFECT_PROPS)[number];
/**
* Build base transition style for smooth state changes.
* Uses specific properties instead of 'all' to avoid affecting positioning transforms.
*/
export function buildTransitionStyle(
effects: Partial<ElementEffectProperties>,
): CSSProperties {
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 {
transition: `all ${duration} ease`,
transition: transitionProps.map((p) => `${p} ${duration} ease`).join(', '),
};
}