function InternalSegment()

in src/segmented-control/segmented-control.tsx [238:446]


function InternalSegment({
  childKey,
  childIndex,
  activeKey,
  activeSegmentRef,
  updateHighlight,
  parseKeyDown,
  activateOnFocus,
  uid,
  disabled,
  sharedStylingProps,
  onChange,
  setKeyUpdated,
  ...props
}) {
  const key = childKey || String(childIndex);
  const isActive = key == activeKey;
  const {
    artwork: Artwork,
    overrides = {},
    segmentRef,
    onClick,
    label,
    description,
    badge,
    badgeHint,
    ...restProps
  } = props;

  // A way to share our internal activeSegmentRef via the "segmentRef" prop.
  const ref = React.useRef();
  React.useImperativeHandle(segmentRef, () => {
    return isActive ? activeSegmentRef.current : ref.current;
  });

  // Track segment dimensions in a ref after each render
  // This is used to compare params when the resize observer fires
  const segmentLayoutParams = React.useRef({ length: 0, distance: 0 });
  React.useEffect(() => {
    segmentLayoutParams.current = getLayoutParams(
      isActive ? activeSegmentRef.current : ref.current
    );
  });

  // We need to potentially update the active segment highlight when the width or
  // placement changes for a segment so we listen for resize updates in each segment.
  React.useEffect(() => {
    if (window.ResizeObserver) {
      const observer = new window.ResizeObserver((entries) => {
        if (entries[0] && entries[0].target) {
          const segmentLayoutParamsAfterResize = getLayoutParams(entries[0].target);
          if (
            segmentLayoutParamsAfterResize.length !== segmentLayoutParams.current.length ||
            segmentLayoutParamsAfterResize.distance !== segmentLayoutParams.current.distance
          ) {
            setKeyUpdated(1);
            updateHighlight();
          }
        }
      });
      observer.observe(isActive ? activeSegmentRef.current : ref.current);
      return () => {
        observer.disconnect();
      };
    }
  }, [activeKey]);

  React.useEffect(updateHighlight, [label]);

  // Collect overrides
  const {
    Segment: SegmentOverrides,
    ArtworkContainer: ArtworkContainerOverrides,
    LabelBlock: LabelBlockContainerOverrides,
    Label: LabelOverrides,
    Description: DescriptionOverrides,
    Badge: BadgeOverrides,
    BadgeHint: BadgeHintOverrides,
  } = overrides;
  const [Segment, SegmentProps] = getOverrides(SegmentOverrides, StyledSegment);
  const [LabelBlockContainer, LabelBlockContainerProps] = getOverrides(
    LabelBlockContainerOverrides,
    StyledLabelBlock
  );
  const [ArtworkContainer, ArtworkContainerProps] = getOverrides(
    ArtworkContainerOverrides,
    StyledArtworkContainer
  );
  const [LabelContainer, LabelContainerProps] = getOverrides(LabelOverrides, StyledLabel);
  const [DescriptionContainer, DescriptionContainerProps] = getOverrides(
    DescriptionOverrides,
    StyledDescription
  );
  const [BadgeContainer, BadgeContainerProps] = getOverrides(BadgeOverrides, StyledBadge);
  const [BadgeHintContainer, BadgeHintContainerProps] = getOverrides(
    BadgeHintOverrides,
    StyledBadgeHint
  );

  // Keyboard focus styling
  const [focusVisible, setFocusVisible] = React.useState(false);
  const handleFocus = React.useCallback((event: SyntheticEvent) => {
    if (isFocusVisible(event)) {
      setFocusVisible(true);
    }
  }, []);
  const handleBlur = React.useCallback(
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    (event: SyntheticEvent) => {
      if (focusVisible !== false) {
        setFocusVisible(false);
      }
    },
    [focusVisible]
  );

  // Keyboard focus management
  // @ts-expect-error todo(flow->ts): deps are required
  const handleKeyDown = React.useCallback((event) => {
    // WAI-ARIA 1.1
    // https://www.w3.org/TR/wai-aria-practices-1.1/#segmentpanel
    // We use directional keys to iterate focus through SegmentedControl.

    // Find all segments eligible for focus
    const availableSegmentedControl = [...event.target.parentNode.childNodes].filter(
      (node) => !node.disabled && node.getAttribute('role') === 'option'
    );

    // Exit early if there are no other segments available
    if (availableSegmentedControl.length === 1) return;

    // Find segment to focus, looping to start/end of list if necessary
    const currentSegmentIndex = availableSegmentedControl.indexOf(event.target);
    const action = parseKeyDown(event);
    if (action) {
      let nextSegment: HTMLButtonElement | undefined | null;
      if (action === KEYBOARD_ACTION.previous) {
        if (availableSegmentedControl[currentSegmentIndex - 1]) {
          nextSegment = availableSegmentedControl[currentSegmentIndex - 1];
        } else {
          nextSegment = availableSegmentedControl[availableSegmentedControl.length - 1];
        }
      } else if (action === KEYBOARD_ACTION.next) {
        if (availableSegmentedControl[currentSegmentIndex + 1]) {
          nextSegment = availableSegmentedControl[currentSegmentIndex + 1];
        } else {
          nextSegment = availableSegmentedControl[0];
        }
      }
      if (nextSegment) {
        // Focus the segment
        nextSegment.focus();

        // Optionally activate the segment
        if (activateOnFocus) {
          nextSegment.click();
        }
      }
    }
  });

  return (
    <Segment
      data-baseweb="segment"
      key={key}
      id={getSegmentId(uid, key)}
      role="option"
      onKeyDown={handleKeyDown}
      aria-selected={isActive}
      tabIndex={isActive ? '0' : '-1'}
      ref={isActive ? activeSegmentRef : ref}
      disabled={!isActive && disabled}
      type="button" // so it doesn't trigger a submit when used inside forms
      $focusVisible={focusVisible}
      $isActive={isActive}
      $hasArtwork={!!Artwork}
      $hasLabel={!!label}
      {...sharedStylingProps}
      {...restProps}
      {...SegmentProps}
      onClick={(event) => {
        if (typeof onChange === 'function') onChange({ activeKey: key });
        if (typeof onClick === 'function') onClick(event);
      }}
      onFocus={forkFocus({ ...restProps, ...SegmentProps }, handleFocus)}
      onBlur={forkBlur({ ...restProps, ...SegmentProps }, handleBlur)}
    >
      <LabelBlockContainer {...LabelBlockContainerProps}>
        {!!Artwork && (
          <ArtworkContainer
            data-baseweb="artwork-container"
            {...sharedStylingProps}
            {...ArtworkContainerProps}
          >
            <Artwork size={20} color="contentPrimary" />
          </ArtworkContainer>
        )}
        {!!label && <LabelContainer {...LabelContainerProps}>{label ? label : key}</LabelContainer>}
        {!!badge && <BadgeContainer {...BadgeContainerProps}>{badge}</BadgeContainer>}
        {badgeHint && <BadgeHintContainer {...BadgeHintContainerProps} />}
      </LabelBlockContainer>
      {description ? (
        <DescriptionContainer {...DescriptionOverrides} {...DescriptionContainerProps}>
          {description}
        </DescriptionContainer>
      ) : null}
    </Segment>
  );
}