# All files / src/tree TreeItemExpander.tsx

100% Statements 90/90
100% Branches 18/18
100% Functions 2/2
100% Lines 90/90

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    911x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    937x
    53x
    53x
    884x
    884x
    884x
    198x
    198x
    198x
    1140x
    64x
    64x
    3x
    3x
    3x
    3x
    3x
    3x
    64x
    64x
    198x
    198x
    198x
    198x
    1001x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
    1140x
     "use client";
    import { cnb } from "cnbuilder";
    import {
      cloneElement,
      isValidElement,
      type MouseEventHandler,
      type ReactElement,
      type ReactNode,
    } from "react";
    import { getIcon } from "../icon/iconConfig.js";
    import { IconRotator } from "../icon/IconRotator.js";
    import { useTreeContext } from "./TreeProvider.js";

    /**
     * @internal
     * @remarks \@since 6.0.0 Updated to use the latest API
     */
    export interface TreeItemExpanderProps {
      /** @defaultValue `false` */
      isLeft?: boolean;
      itemId: string;
      addon: ReactNode;
      disabled: boolean;
      expanded: boolean;
      isLeafNode: boolean;
      className?: string;
    }

    /**
     * **Client Component**
     *
     * @internal
     * @remarks \@since 6.0.0 Updated to support the new `expansionMode` behavior.
     */
    export function TreeItemExpander(props: TreeItemExpanderProps): ReactElement {
      const {
        itemId,
        isLeft = false,
        addon,
        expanded,
        disabled,
        isLeafNode,
        className,
      } = props;
      const {
        expanderIcon,
        expanderLeft,
        expansionMode,
        disableTransition,
        toggleTreeItemExpansion,
      } = useTreeContext();

      const icon = getIcon("dropdown", expanderIcon);
      if (isLeafNode || expanderLeft !== isLeft) {
        if (isValidElement<{ className?: string }>(addon)) {
          return cloneElement(addon, { className });
        }

        return <>{addon}</>;
      }

      const isCloneable = isValidElement(icon);
      let clickProps: { onClick: MouseEventHandler<Element> } | undefined;
      if (expansionMode === "manual" && !disabled) {
        clickProps = {
          onClick(event) {
            // do not select the tree item if the icon is clicked
            event.stopPropagation();
            event.preventDefault();

            toggleTreeItemExpansion(itemId);
          },
        };
      }

      return (
        <>
          <IconRotator
            className={cnb(!addon && className)}
            {...(!isCloneable ? clickProps : undefined)}
            rotated={expanded}
            forceIconWrap={!isCloneable}
            disableTransition={disableTransition}
          >
            {clickProps && isCloneable ? cloneElement(icon, clickProps) : icon}
          </IconRotator>
          {addon}
        </>
      );
    }