fix(admin-panel): prevent layout shift when toggling feature flags (#12686)

Closes #12571
~~## What’s broken?~~
~~Toggling a feature flag in the admin panel re-renders the entire table
and uses a Framer Motion slide animation for the knob. Each animation
frame forces a layout recalculation all the way up, causing the page to
“jump.”~~

~~## What’s the fix?~~
~~Swap out the Framer Motion toggle for a pure-CSS version:~~
~~- Container is position: relative~~
~~- Knob is position: absolute and moves via left~~
~~- A transition: left 0.3s ease + will-change: left hint runs on the
compositor layer~~

~~This keeps the smooth slide effect but never triggers parent layout
reflows.~~

~~No changes to the public <Toggle> API or behavior.~~

~~TODO: test all toggles in app and stories if any~~

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
nitin
2025-06-18 15:26:19 +05:30
committed by GitHub
parent 657b87fd0c
commit fb6f2610c5
3 changed files with 113 additions and 11 deletions
@@ -12,28 +12,31 @@ type ContainerProps = {
};
const StyledContainer = styled.label<ContainerProps>`
flex-shrink: 0;
align-items: center;
background-color: ${({ theme, isOn, color }) =>
isOn ? (color ?? theme.color.blue) : theme.background.transparent.medium};
border-radius: 10px;
cursor: pointer;
display: flex;
flex-shrink: 0;
height: ${({ toggleSize }) => (toggleSize === 'small' ? 16 : 20)}px;
transition: background-color 0.3s ease;
width: ${({ toggleSize }) => (toggleSize === 'small' ? 24 : 32)}px;
opacity: ${({ 'data-disabled': disabled }) => (disabled ? 0.5 : 1)};
pointer-events: ${({ 'data-disabled': disabled }) =>
disabled ? 'none' : 'auto'};
position: relative;
transition: background-color 0.3s ease;
width: ${({ toggleSize }) => (toggleSize === 'small' ? 24 : 32)}px;
`;
const StyledCircle = styled(motion.span)<{
size: ToggleSize;
}>`
display: block;
background-color: ${({ theme }) => theme.background.primary};
border-radius: 50%;
display: block;
height: ${({ size }) => (size === 'small' ? 12 : 16)}px;
left: 0;
position: absolute;
width: ${({ size }) => (size === 'small' ? 12 : 16)}px;
`;
@@ -80,6 +83,7 @@ export const Toggle = ({
/>
<StyledCircle
initial="off"
animate={value ? 'on' : 'off'}
variants={circleVariants}
size={toggleSize}