fixed elements positioning
This commit is contained in:
parent
c88f5d2a37
commit
69ddc59317
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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(() => {
|
||||
|
||||
@ -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(', '),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user