• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

boruei-chen / materials / #15

pending completion
#15

push

boruei-chen
Merge branch 'develop'

40 of 88 branches covered (45.45%)

Branch coverage included in aggregate %.

41 of 41 new or added lines in 3 files covered. (100.0%)

45 of 57 relevant lines covered (78.95%)

1.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

54.41
/src/lib/components/Form/Select/Select.component.tsx
1
import React, { useRef, useState, useEffect } from 'react';
2
import { Props, ChangeEvent } from './Select.types';
3
import Context from './Select.context';
4
import Option from './Option';
5
import { Props as OptionProps, OptionData } from './Option/Option.types';
6
import './Select.styles.scss';
7

8
const Select = React.forwardRef<HTMLInputElement, Props>((props, ref) => {
1✔
9
  const {
10
    variant = 'outline',
2✔
11
    label,
12
    className,
13
    value,
14
    placeholder,
15
    errorMessage,
16
    disabled,
17
    children,
18
    onChange,
19
    onFocus,
20
    ...restProps
21
  } = props;
2✔
22

23
  const isMountedRef = useRef<boolean>(false);
2✔
24
  const fieldElementRef = useRef<HTMLDivElement>(null);
2✔
25
  const virtualOptionPanelElementRef = useRef<HTMLDivElement>(null);
2✔
26
  const [virtualOptionPanelVisibleState, setVirtualOptionPanelVisibleState] = useState<boolean>(false);
2✔
27
  const [activeOptionDataState, setActiveOptionDataState] = useState<OptionData>();
2✔
28

29
  useEffect(() => {
2✔
30
    document.addEventListener('mousedown', handleVirtualOptionPanelOutsideClick);
2✔
31
    return () => {
2✔
32
      document.removeEventListener('mousedown', handleVirtualOptionPanelOutsideClick);
2✔
33
    };
34
  }, []);
35

36
  useEffect(() => {
2✔
37
    if (!isMountedRef.current) {
2!
38
      const virtualOptionElementList = React.Children.toArray(children).filter((element) => React.isValidElement(element) && (element as React.FunctionComponentElement<OptionProps>).type.displayName === 'Option');
6✔
39
      const activeVirtualOptionElement = virtualOptionElementList.find((element) => React.isValidElement<OptionProps>(element) && element.props.value === value);
6✔
40
      if (React.isValidElement<OptionProps>(activeVirtualOptionElement)) {
2!
41
        const activeOptionData: OptionData = {
×
42
          value: activeVirtualOptionElement.props.value,
43
          option: activeVirtualOptionElement.props.children
44
        };
45
        setActiveOptionDataState(activeOptionData);
×
46
      }
47
      isMountedRef.current = true;
2✔
48
    }
49
  }, [value, children]);
50

51
  const handleFieldFocus = (event: React.FocusEvent<HTMLInputElement>) => {
2✔
52
    setVirtualOptionPanelVisibleState(true);
×
53
    if (onFocus) onFocus(event);
×
54
  };
55

56
  const handleVirtualOptionPanelOutsideClick = (event: MouseEvent) => {
2✔
57
    if (
×
58
      (fieldElementRef.current && !fieldElementRef.current.contains(event.target as Node)) &&
×
59
      (virtualOptionPanelElementRef.current && !virtualOptionPanelElementRef.current.contains(event.target as Node))
60
    ) {
61
      setVirtualOptionPanelVisibleState(false);
×
62
    }
63
  };
64

65
  const handleVirtualOptionSelect = (event: ChangeEvent) => {
2✔
66
    const activeOptionData: OptionData = {
×
67
      value: event.value,
68
      option: event.option
69
    };
70
    setActiveOptionDataState(activeOptionData);
×
71
    setVirtualOptionPanelVisibleState(false);
×
72
    if (onChange) onChange(event);
×
73
  };
74

75
  return (
2✔
76
    <div className={'brcm-select' + (variant ? ` brcm-select--variant-${variant}` : '') + (disabled ? ' brcm-select--disabled' : '') + (errorMessage ? ' brcm-select--invalid' : '') + (className ? ` ${className}` : '')}>
8!
77
      <Context.Provider
78
        value={{
79
          activeOptionData: activeOptionDataState,
80
          onVirtualOptionSelect: handleVirtualOptionSelect
81
        }}
82
      >
83
        <label className="brcm-select__wrapper">
84
          {label && <span className="brcm-select__label">{label}</span>}
2!
85
          <div className="brcm-select__field" ref={fieldElementRef}>
86
            <input
87
              {...restProps}
88
              type="text"
89
              className="brcm-select__input"
90
              onFocus={handleFieldFocus}
91
              disabled={disabled}
92
              readOnly
93
              ref={ref}
94
            />
95
            <div className="brcm-select__virtual-input">
96
              {activeOptionDataState
2!
97
                ? <div className="brcm-select__virtual-input-value">{activeOptionDataState.option}</div>
98
                : <span className="brcm-select__virtual-input-placeholder">{placeholder}</span>}
99
            </div>
100
          </div>
101
        </label>
102
        <div className={'brcm-select__virtual-option-panel' + (virtualOptionPanelVisibleState ? ' brcm-select__virtual-option-panel--visible' : ' brcm-select__virtual-option-panel--hidden')} ref={virtualOptionPanelElementRef}>
2!
103
          <ul className="brcm-select__virtual-option-list">
104
            {children}
105
          </ul>
106
        </div>
107
        {(errorMessage && !disabled) && <span className="brcm-select__error-message">{errorMessage}</span>}
2!
108
      </Context.Provider>
109
    </div>
110
  );
111
});
112

113
Select.displayName = 'Select';
1✔
114

115
export default Object.assign(Select, { Option });
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc