import React , { useCallback , useContext , useEffect , useRef } from 'react' ; import PropTypes from 'prop-types' ; import { useUsingKeyboardContext } from '@leafygreen-ui/leafygreen-provider' ; import { css , cx } from '@leafygreen-ui/emotion' ; import { usePrevious } from '@leafygreen-ui/hooks' ; import { createDataProp } from '@leafygreen-ui/lib' ; import CheckmarkIcon from '@leafygreen-ui/icon/dist/Checkmark' ; import { LGGlyph } from '@leafygreen-ui/icon/src/types' ; import { colorSets } from './styleSets' ; import SelectContext from './SelectContext' ; const option = createDataProp ( 'option' ) ; type GlyphElement = React . ReactElement < LGGlyph . ComponentProps > & { type ? : { isGlyph ? : boolean ; } ; } ; export type ReactEmpty = null | undefined | false | '' ; const optionStyle = css `
  display: flex;
  width: 100%;
  padding: 10px 12px;
  outline: none;
  overflow-wrap: anywhere;
  transition: background-color 150ms ease-in-out;
  position: relative;

  &:before {
    content: '';
    position: absolute;
    transform: scaleY(0.3);
    top: 7px;
    bottom: 7px;
    left: 0;
    right: 0;
    width: 4px;
    border-radius: 0px 4px 4px 0px;
    opacity: 0;
    transition: all 150ms ease-in-out;
  }
` ; const optionTextStyle = css `
  display: flex;
  align-items: center;
` ; const iconStyle = css `
  min-width: 16px;
  margin-right: 6px;
` ; const glyphFocusStyle = css `
  ${ option . selector }:focus & {
    color: currentColor;
  }
` ; export interface InternalProps { children : React . ReactNode ; className : string | undefined ; glyph : GlyphElement | undefined ; selected : boolean ; focused : boolean ; disabled : boolean ; onClick : React . MouseEventHandler ; onFocus : React . FocusEventHandler ; isDeselection : boolean ; hasGlyphs : boolean ; triggerScrollIntoView : boolean ; } export function InternalOption ( { children , className , glyph , selected , focused , disabled , onClick , onFocus , isDeselection , triggerScrollIntoView , hasGlyphs , } ) { const { mode } = useContext ( SelectContext ) ; const { usingKeyboard : showFocus } = useUsingKeyboardContext ( ) ; const { option : colorSet } = colorSets [ mode ] ; const ref = useRef < HTMLLIElement > ( null ) ; const scrollIntoView = useCallback ( ( ) => { if ( ref . current == null ) { return null ; } const element = ref . current ; const parent = element ?. offsetParent ; if ( ! parent ) { return null ; } parent . scrollTop = element . offsetTop + ( element . clientHeight - parent . clientHeight ) / 2 ; } , [ ref ] ) ; const alreadyScrolledIntoView = usePrevious ( triggerScrollIntoView ) ; const shouldScrollIntoView = triggerScrollIntoView && ! alreadyScrolledIntoView ; useEffect ( ( ) => { if ( shouldScrollIntoView ) { scrollIntoView ( ) ; } } , [ scrollIntoView , shouldScrollIntoView ] ) ; const wasFocused = usePrevious ( focused ) ; const shouldFocus = focused && ! wasFocused ; useEffect ( ( ) => { if ( shouldFocus ) { ref . current ! . focus ( ) ; } } , [ shouldFocus ] ) ; const styledChildren = ( < span className = { cx ( optionTextStyle , { [ css `
          font-weight: bold;
        ` ] : selected && ! isDeselection , } ) } > { children } < /span>); const iconPlaceholder = ( < span className = { cx ( iconStyle , css `
          height: 100%;
        ` ) } / > ) ; let styledGlyph = iconPlaceholder ; if ( glyph ) { if ( ! glyph . type . isGlyph ) { console . error ( '`Option` instance did not render icon because it is not a known glyph element.' ) ; } else { styledGlyph = React . cloneElement ( glyph , { key : 'glyph' , className : cx ( iconStyle , css `
            color: ${ colorSet . icon . base };
          ` , { [ glyphFocusStyle ] : showFocus , [ css `
              color: ${ colorSet . icon . disabled };
            ` ] : disabled , } , glyph . props . className ) , } ) ; } } const checkmark = selected && ! isDeselection ? ( < CheckmarkIcon key = "checkmark" className = { cx ( iconStyle , css `
            color: ${ colorSet . icon . selected } ; `, {
            [glyphFocusStyle]: showFocus,
            [css ` color : $ { colorSet . icon . disabled } ; `]: disabled,
        })}/>) : (iconPlaceholder);
    let renderedChildren;
    if (hasGlyphs) {
        renderedChildren = (<span className={css ` display : flex ; justify - content : space - between ; width : 100 % ; `}>
        <span className={css ` display : flex ; `}>
          {styledGlyph}
          {styledChildren}
        </span>
        {checkmark}
      </span>);
    }
    else {
        renderedChildren = (<>
        {checkmark}
        {styledChildren}
      </>);
    }
    return (<li {...option.prop} role="option" aria-selected={selected} tabIndex={-1} ref={ref} className={cx(optionStyle, css ` cursor : pointer ; color : $ { colorSet . text . base } ; `, {
            [css ` & : hover { background - color : $ { colorSet . background . hovered } ; } `]: !disabled,
            [css ` & : focus { color : $ { colorSet . text . focused } ; background - color : $ { colorSet . background . focused } ; & : before { opacity : 1 ; transform : scaleY ( 1 ) ; background - color : $ { colorSet . indicator . focused } ; } } `]: showFocus && !disabled,
            [css ` cursor : not - allowed ; color : $ { colorSet . text . disabled } ; `]: disabled,
        }, className)} onClick={onClick} onFocus={onFocus} onKeyDown={undefined}>
      {renderedChildren}
    </li>);
}
InternalOption.displayName = 'Option';
interface Props {
    className?: string;
    glyph?: GlyphElement;
    disabled?: boolean;
    value?: string;
    children: React.ReactText | Array<React.ReactText | ReactEmpty>;
}
export default function Option(_) {
    throw Error('` Option ` must be a child of a ` Select ` instance');
}
Option.displayName = 'Option';
const textPropType = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
Option.propTypes = {
    children: PropTypes.oneOfType([
        textPropType,
        PropTypes.arrayOf(PropTypes.oneOfType([
            textPropType,
            PropTypes.oneOf([false, null, undefined, '']),
        ])),
    ]).isRequired,
    className: PropTypes.string,
    glyph: PropTypes.element,
    value: PropTypes.string,
    disabled: PropTypes.bool,
};
// React.ReactComponentElement messes up the original
// typing of props, so it is fixed up by overriding it.
export type OptionElement = Omit<React.ReactComponentElement<typeof Option>, 'props'> & {
    props: Props;
};
