export function SegmentedControl()

in src/segmented-control/segmented-control.tsx [86:236]


export function SegmentedControl({
  activeKey = '0',
  disabled = false,
  children,
  fill = FILL.intrinsic,
  activateOnFocus = true,
  onChange,
  overrides = {},
  // @ts-expect-error todo(ts-migration) TS2322 Type 'null' is not assignable to type 'string'.
  uid: customUid = null,
  width,
  height,
}: SegmentedControlProps) {
  // Create unique id prefix for this segments component
  const generatedUid = useUID();
  const uid = customUid || generatedUid;

  // Unpack overrides
  const { Root: RootOverrides, Active: ActiveOverrides } = overrides;
  const [Root, RootProps] = getOverrides(RootOverrides, StyledRoot);
  const [Active, ActiveProps] = getOverrides(ActiveOverrides, StyledActive);
  const [SegmentList, SegmentListProps] = getOverrides(overrides.SegmentList, StyledSegmentList);

  // Count key updates
  // We disable a few things until after first mount:
  // - the highlight animation, avoiding an initial slide-in
  // - smooth scrolling active segment into view
  const [keyUpdated, setKeyUpdated] = React.useState(0);
  React.useEffect(() => {
    setKeyUpdated(keyUpdated + 1);
  }, [activeKey]);

  // Positioning the highlight.
  const activeSegmentRef = React.useRef<HTMLElement>();
  const [highlightLayout, setHighlightLayout] = React.useState({
    length: 0,
    distance: 0,
  });

  // Create a shared, memoized callback for segments to call on resize.
  const updateHighlight = React.useCallback(() => {
    if (activeSegmentRef.current) {
      setHighlightLayout(getLayoutParams(activeSegmentRef.current));
    }
  }, [activeSegmentRef.current]);

  // Update highlight on key
  React.useEffect(updateHighlight, [activeSegmentRef.current]);

  // Scroll active segment into view when the parent has scrollbar on mount and
  // on key change (smooth scroll). Note, if the active key changes while
  // the segment is not in view, the page will scroll it into view.
  // TODO: replace with custom scrolling logic.
  React.useEffect(() => {
    // Flow needs this condition pulled out.
    if (activeSegmentRef.current) {
      if (
        // @ts-expect-error todo(flow->ts) maybe parentElement?
        activeSegmentRef.current.parentNode.scrollWidth >
        // @ts-expect-error todo(flow->ts) maybe parentElement?
        activeSegmentRef.current.parentNode.clientWidth
      ) {
        if (keyUpdated > 1) {
          activeSegmentRef.current.scrollIntoView({
            behavior: 'smooth',
            block: 'nearest',
            inline: 'nearest',
          });
        } else {
          scrollParentToCentreTarget(activeSegmentRef.current);
        }
      }
    }
  }, [activeSegmentRef.current]);

  // Collect shared styling props
  const sharedStylingProps = {
    $fill: fill,
  };

  // Helper for parsing directional keys
  // TODO(WPT-6473): move to universal keycode aliases
  const [, theme] = useStyletron();
  const parseKeyDown = React.useCallback(
    (event: { keyCode: number }) => {
      if (isRTL(theme.direction)) {
        switch (event.keyCode) {
          case 39:
            return KEYBOARD_ACTION.previous;
          case 37:
            return KEYBOARD_ACTION.next;
          default:
            return null;
        }
      } else {
        switch (event.keyCode) {
          case 37:
            return KEYBOARD_ACTION.previous;
          case 39:
            return KEYBOARD_ACTION.next;
          default:
            return null;
        }
      }
    },
    [theme.direction]
  );

  return (
    <Root {...sharedStylingProps} {...RootProps} $width={width} $height={height}>
      <SegmentList
        data-baseweb="segmented-list"
        role="listbox"
        aria-label="segmented control"
        {...SegmentListProps}
      >
        {React.Children.map(children, (child: React.ReactElement, index) => {
          if (!child) return;
          return (
            <InternalSegment
              childKey={child.key}
              childIndex={index}
              activeKey={activeKey}
              activeSegmentRef={activeSegmentRef}
              updateHighlight={updateHighlight}
              parseKeyDown={parseKeyDown}
              activateOnFocus={activateOnFocus}
              uid={uid}
              disabled={disabled}
              sharedStylingProps={sharedStylingProps}
              onChange={onChange}
              setKeyUpdated={setKeyUpdated}
              {...child.props}
            />
          );
        })}
        <Active
          data-baseweb="segment-highlight"
          $length={highlightLayout.length}
          $distance={highlightLayout.distance}
          // This avoids the segment sliding in from the side on mount
          $animate={keyUpdated > 1}
          aria-hidden="true"
          role="presentation"
          {...sharedStylingProps}
          {...ActiveProps}
        />
      </SegmentList>
    </Root>
  );
}