# All files / src/form selectUtils.ts

0% Statements 0/115
0% Branches 0/1
0% Functions 0/1
0% Lines 0/115

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
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116

     import { Children, isValidElement, type ReactNode } from "react";
    import { type MenuItemProps } from "../menu/MenuItem.js";

    /**
     * @internal
     * @remarks \@since 6.0.0
     */
    export interface SelectOption<Value extends string | number = string>
      extends MenuItemProps {
      value: Value;
    }

    /**
     * @internal
     * @remarks \@since 6.0.0
     */
    function getLabelFromChildren(children: ReactNode): string {
      if (!children) {
        return "";
      }

      if (typeof children === "string" || typeof children === "number") {
        return `${children}`;
      }

      if (isValidElement<{ children: ReactNode; hidden?: boolean }>(children)) {
        if (children.props.hidden) {
          return "";
        }

        return getLabelFromChildren(children.props.children);
      }

      const childList = Children.toArray(children);
      for (const child of childList) {
        if (typeof child === "string" || typeof child === "number") {
          return `${child}`[0].toUpperCase();
        }

        if (
          isValidElement<{ children: ReactNode; hidden?: boolean }>(child) &&
          !child.props.hidden
        ) {
          return getLabelFromChildren(child.props.children);
        }
      }

      return "";
    }

    /**
     * @internal
     * @remarks \@since 6.0.0
     */
    interface ExtractedOptions<Value extends string | number> {
      options: readonly SelectOption<Value>[];
      currentOption: SelectOption<Value> | undefined;
      searchValues: readonly string[];
      currentIndex: number;
    }

    /**
     * @internal
     * @remarks \@since 6.0.0
     */
    export function extractOptionsFromChildren<Value extends string | number>(
      children: ReactNode,
      currentValue: Value | undefined
    ): ExtractedOptions<Value> {
      let currentOption: SelectOption<Value> | undefined;
      let currentIndex = -1;

      const options: SelectOption<Value>[] = [];
      const searchValues: string[] = [];
      Children.forEach(children, (child) => {
        if (!isValidElement<SelectOption<Value>>(child)) {
          return;
        }

        const { value, disabled, children } = child.props;
        if (typeof value !== "undefined") {
          if (
            value === currentValue ||
            (!currentOption && typeof currentValue === "undefined")
          ) {
            currentOption = child.props;
            currentIndex = options.length;
          }

          if (!disabled) {
            options.push(child.props);
            searchValues.push(getLabelFromChildren(children));
          }
        } else if (children) {
          const result = extractOptionsFromChildren(children, currentValue);
          if (!currentOption) {
            ({ currentOption } = result);
          }

          if (result.currentIndex !== -1) {
            currentIndex = options.length + result.currentIndex;
          }

          options.push(...result.options);
          searchValues.push(...result.searchValues);
        }
      });

      return {
        options,
        searchValues,
        currentOption,
        currentIndex,
      };
    }