CAL-1664: Improve flash of toggle group when rerendering (#8900)

* CAL-1664: Improve flash of toggle group when rerendering, because active element moves into position.

* Added back newline
This commit is contained in:
Jeroen Reumkens 2023-05-15 16:38:02 +02:00 committed by GitHub
parent 2147cc82a5
commit 4137f63ec7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,6 +1,6 @@
import * as RadixToggleGroup from "@radix-ui/react-toggle-group";
import type { ReactNode } from "react";
import { useEffect, useState } from "react";
import { useEffect, useRef, useState } from "react";
import { classNames } from "@calcom/lib";
import { Tooltip } from "@calcom/ui";
@ -29,7 +29,7 @@ const OptionalTooltipWrapper = ({
export const ToggleGroup = ({ options, onValueChange, isFullWidth, ...props }: ToggleGroupProps) => {
const [value, setValue] = useState<string | undefined>(props.defaultValue);
const [activeToggleElement, setActiveToggleElement] = useState<null | HTMLButtonElement>(null);
const activeRef = useRef<HTMLSpanElement>(null);
useEffect(() => {
if (value && onValueChange) onValueChange(value);
@ -48,9 +48,15 @@ export const ToggleGroup = ({ options, onValueChange, isFullWidth, ...props }: T
)}>
{/* Active toggle. It's a separate element so we can animate it nicely. */}
<span
ref={activeRef}
aria-hidden
className="bg-emphasis absolute top-[4px] bottom-[4px] left-0 z-[0] rounded-[4px] transition-all"
style={{ left: activeToggleElement?.offsetLeft, width: activeToggleElement?.offsetWidth }}
className={classNames(
"bg-emphasis absolute top-[4px] bottom-[4px] left-0 z-[0] rounded-[4px]",
// Disable the animation until after initial render, that way when the component would
// rerender the styles are immediately set and we don't see a flash moving the element
// into position because of the animation.
activeRef?.current && "transition-all"
)}
/>
{options.map((option) => (
<OptionalTooltipWrapper key={option.value} tooltipText={option.tooltip}>
@ -65,8 +71,12 @@ export const ToggleGroup = ({ options, onValueChange, isFullWidth, ...props }: T
isFullWidth && "w-full"
)}
ref={(node) => {
if (node && value === option.value && activeToggleElement !== node) {
setActiveToggleElement(node);
if (node && value === option.value) {
// Sets position of active toggle element with inline styles.
// This way we trigger as little rerenders as possible.
if (!activeRef.current || activeRef?.current.style.left === `${node.offsetLeft}px`) return;
activeRef.current.style.left = `${node.offsetLeft}px`;
activeRef.current.style.width = `${node.offsetWidth}px`;
}
return node;
}}>