components/elements/CircleChain/CircleChain.jsxjavascript
import "./CircleChain.scss";
import { useElementSize } from "../../../hooks/elementSize";

// brand gradient endpoints (orange -> teal), matching the accent colors
// already used across the app (--uimc-color-orange, the teal story-icon)
// const FROM = [0xec, 0x66, 0x02];
// const TO = [0x00, 0x99, 0x99];

// const mix = (ratio) => {
//   const [r, g, b] = FROM.map((from, i) => Math.round(from + (TO[i] - from) * ratio));
//   return `rgb(${r} ${g} ${b})`;
// };

/**
 * N labeled circles overlapping in a horizontal row ("circleChain" element
 * type), brand-gradient colored left to right.
 *
 * @param {Object} props
 * @param {Array<{text: string}>} props.items - Circles, left to right.
 * @param {"landscape"|"portrait"} [props.orientation="landscape"] - Sizes each circle as a fraction of the measured ring diameter, per the Figma spec's portrait/landscape ratios.
 */
export const CircleChain = ({ items, orientation = "landscape" }) => {
  // Button positions are measured off the buttons-ring's own rendered size
  // rather than a hardcoded em constant - SelectWidget.scss's `--ring-size:
  // min(<em>, <N>cqmin)` can shrink that ring below its em value when space
  // is tight (e.g. the iPad Air's letterboxed portrait reference), and a
  // fixed em radius here would then place buttons outside the now-smaller
  // ring instead of on it. Measuring the actual box is the single source of
  // truth instead of duplicating that min() formula in JS.
  const [buttonsRingRef, { width: ringWidth, height: ringHeight }] = useElementSize();
  const ringDiameter = Math.min(ringWidth, ringHeight);

  // Figma spec's item diameter as a fraction of its buttons-ring diameter
  // (34.375/76.25 em portrait, 28/67 em landscape) rather than its own fixed
  // em value - same reasoning as ringDiameter above: an item sized in em
  // wouldn't shrink when the ring's `min(<em>, <N>cqmin)` cap shrinks it, so
  // buttons would end up too big for their own ring on a small enough
  // container (e.g. the iPad).
  const ITEM_DIAMETER_RATIO = orientation === "portrait" ? 34.375 / 76.25 : (28 / 67) * 1.5;
  const itemDiameter = ringDiameter * ITEM_DIAMETER_RATIO;
  return (
    <div className="circle-chain">
      <div className="circle-chain__ring circle-chain__ring--outer" />
      <div className="circle-chain__ring circle-chain__ring--dashed" />
      <div className="circle-chain__ring circle-chain__ring--buttons" ref={buttonsRingRef} />

      {items.map((item, index) => {
        // spread items evenly around the button ring, starting at the top
        // (-90deg) and going clockwise
        const angle = -90 + index * (360 / items.length);
        const radians = (angle * Math.PI) / 180;
        const x = (ringDiameter / 2) * Math.cos(radians);
        const y = (ringDiameter / 2) * Math.sin(radians);

        return (
          <button
            key={index}
            type="button"
            className="circle-chain__circle "
            style={{
              "--item-diameter": `${itemDiameter}px`,
              "--x": `${x}px`,
              "--y": `${y}px`,
            }}>
            <div className="circle-chain__text">{item.text}</div>
          </button>
        );
      })}
    </div>
  );
};