# All files / src/components/ui select.tsx

100% Statements 129/129
100% Branches 11/11
66.66% Functions 4/6
100% Lines 129/129

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
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    1301x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    66x
    66x
    66x
    66x
    66x
    66x
    66x
    66x
    1x
    1x
    1x
    66x
    66x
    66x
    66x
    66x
    66x
    66x
    66x
    66x
    66x
    66x
    66x
    66x
    66x
    66x
    66x
    66x
    66x
    1x
    1x
    1x
    1x
    66x
    66x
    66x
    1x
    1x
    1x
    66x
    66x
    66x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    4x
    1x
    1x
    1x
    1x
    1x
    76x
    76x
    76x
    76x
    76x
    76x
    76x
    76x
    76x
    76x
    76x
    76x
    76x
    1x
    1x
    1x
    76x
    76x
    76x
    76x
    76x
    76x
    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
     import { ComponentProps, forwardRef, useState, createContext, useContext } from "react"
    import { createPortal } from "react-dom"
    import { cn } from "@/lib/utils"

    interface SelectContextValue {
      value?: string
      onValueChange?: (value: string) => void
      open: boolean
      setOpen: (open: boolean) => void
    }

    const SelectContext = createContext<SelectContextValue | null>(null)

    interface SelectProps {
      value?: string
      onValueChange?: (value: string) => void
      children: React.ReactNode
    }

    export function Select({ value, onValueChange, children }: SelectProps) {
      const [open, setOpen] = useState(false)

      return (
        <SelectContext.Provider value={{ value, onValueChange, open, setOpen }}>
          {children}
        </SelectContext.Provider>
      )
    }

    export const SelectTrigger = forwardRef<HTMLButtonElement, ComponentProps<"button">>(
      ({ className, children, ...props }, ref) => {
        const context = useContext(SelectContext)

        return (
          <button
            ref={ref}
            className={cn("mat-mdc-select-trigger", className)}
            onClick={() => context?.setOpen(!context.open)}
            {...props}
          >
            <span className="mat-mdc-select-value">{children}</span>
            <span className="mat-mdc-select-arrow-wrapper">
              <svg className="mat-mdc-select-arrow" viewBox="0 0 10 5">
                <polygon points="0,0 5,5 10,0" />
              </svg>
            </span>
          </button>
        )
      }
    )
    SelectTrigger.displayName = "SelectTrigger"

    export const SelectValue = ({ placeholder }: { placeholder?: string }) => {
      const context = useContext(SelectContext)
      return <>{context?.value || placeholder}</>
    }

    export const SelectContent = forwardRef<HTMLDivElement, ComponentProps<"div">>(
      ({ className, children, ...props }, ref) => {
        const context = useContext(SelectContext)

        if (!context?.open) return null

        return createPortal(
          <div className="cdk-overlay-pane">
            <div
              ref={ref}
              className={cn("mat-mdc-select-panel", className)}
              {...props}
            >
              {children}
            </div>
          </div>,
          document.body
        )
      }
    )
    SelectContent.displayName = "SelectContent"

    export const SelectItem = forwardRef<HTMLDivElement, ComponentProps<"div"> & { value: string }>(
      ({ className, children, value, ...props }, ref) => {
        const context = useContext(SelectContext)
        const isSelected = context?.value === value

        return (
          <div
            ref={ref}
            className={cn(
              "mat-mdc-option",
              "mdc-list-item",
              isSelected && "mdc-list-item--selected",
              className
            )}
            onClick={() => {
              context?.onValueChange?.(value)
              context?.setOpen(false)
            }}
            {...props}
          >
            <span className="mdc-list-item__primary-text">{children}</span>
          </div>
        )
      }
    )
    SelectItem.displayName = "SelectItem"

    export const SelectGroup = forwardRef<HTMLDivElement, ComponentProps<"div">>(
      ({ className, ...props }, ref) => (
        <div ref={ref} className={cn("mat-mdc-optgroup", className)} {...props} />
      )
    )
    SelectGroup.displayName = "SelectGroup"

    export const SelectLabel = forwardRef<HTMLDivElement, ComponentProps<"div">>(
      ({ className, ...props }, ref) => (
        <div ref={ref} className={cn("mat-mdc-optgroup-label", className)} {...props} />
      )
    )
    SelectLabel.displayName = "SelectLabel"

    export const SelectSeparator = forwardRef<HTMLDivElement, ComponentProps<"div">>(
      ({ className, ...props }, ref) => (
        <div ref={ref} className={cn("mat-divider", className)} {...props} />
      )
    )
    SelectSeparator.displayName = "SelectSeparator"

    export const SelectScrollUpButton = () => null
    export const SelectScrollDownButton = () => null