filteredItems: search()

in packages/fluentui/react-northstar/src/components/Dropdown/Dropdown.tsx [335:544]


        filteredItems: search(filteredItemsByValue, searchQuery),
        filteredItemStrings,
      };
    }

    return {
      filteredItems: filteredItemsByValue.filter(
        item => itemToString(item).toLowerCase().indexOf(searchQuery.toLowerCase()) !== -1,
      ),
      filteredItemStrings,
    };
  }

  return {
    filteredItems: filteredItemsByValue,
    filteredItemStrings,
  };
}

const isEmpty = prop => {
  return typeof prop === 'object' && !prop.props && !_.get(prop, 'children') && !_.get(prop, 'content');
};

/**
 * A Dropdown allows user to select one or more values from a list of options.
 * Can be created with search and multi-selection capabilities.
 *
 * @accessibility
 * Implements [ARIA Combo Box](https://www.w3.org/TR/wai-aria-practices-1.1/#combobox) design pattern, uses aria-live to announce state changes.
 * @accessibilityIssues
 * [Issue 991203: VoiceOver doesn't narrate properly elements in the input/combobox](https://bugs.chromium.org/p/chromium/issues/detail?id=991203)
 * [JAWS - ESC (ESCAPE) not closing collapsible listbox (dropdown) on first time #528](https://github.com/FreedomScientific/VFO-standards-support/issues/528)
 */
export const Dropdown = (React.forwardRef<HTMLDivElement, DropdownProps>((props, ref) => {
  const context = useFluentContext();
  const { setStart, setEnd } = useTelemetry(Dropdown.displayName, context.telemetry);

  setStart();

  const {
    'aria-labelledby': ariaLabelledby,
    'aria-invalid': ariaInvalid,
    clearable,
    clearIndicator,
    checkable,
    checkableIndicator,
    className,
    design,
    disabled,
    error,
    fluid,
    getA11ySelectionMessage,
    a11ySelectedItemsMessage,
    getA11yStatusMessage,
    inline,
    inverted,
    itemToString,
    itemToValue,
    items,
    highlightFirstItemOnOpen,
    multiple,
    headerMessage,
    moveFocusOnTab,
    noResultsMessage,
    loading,
    loadingMessage,
    placeholder,
    renderItem,
    renderSelectedItem,
    search,
    searchInput,
    styles,
    toggleIndicator,
    triggerButton,
    variables,
  } = props;

  const {
    align,
    flipBoundary,
    overflowBoundary,
    popperRef,
    position,
    positionFixed,
    offset,
    unstable_disableTether,
    unstable_pinned,
    autoSize,
  } = props; // PositioningProps passed directly to Dropdown
  const [list, positioningProps] = partitionPopperPropsFromShorthand(props.list); // PositioningProps passed to Dropdown `list` prop's `popper` key

  const buttonRef = React.useRef<HTMLElement>();
  const inputRef = React.useRef<HTMLInputElement | undefined>() as React.MutableRefObject<HTMLInputElement | undefined>;
  const listRef = React.useRef<HTMLElement>();
  const selectedItemsRef = React.useRef<HTMLDivElement>();
  const containerRef = React.useRef<HTMLDivElement>();

  const defaultTriggerButtonId = React.useMemo(() => _.uniqueId('dropdown-trigger-button-'), []);

  const ElementType = getElementType(props);
  const unhandledProps = useUnhandledProps(Dropdown.handledProps, props);

  const [activeSelectedIndex, setActiveSelectedIndex] = useAutoControlled<number | null | undefined>({
    defaultValue: props.defaultActiveSelectedIndex,
    initialValue: multiple ? null : undefined,
    value: props.activeSelectedIndex,
  });
  const [highlightedIndex, setHighlightedIndex] = useAutoControlled<number | null>({
    defaultValue: props.defaultHighlightedIndex,
    initialValue: highlightFirstItemOnOpen ? 0 : null,
    value: props.highlightedIndex,
  });
  const [open, setOpen] = useAutoControlled({
    defaultValue: props.defaultOpen,
    initialValue: false,
    value: props.open,
  });
  const [searchQuery, setSearchQuery] = useAutoControlled<string | undefined>({
    defaultValue: props.defaultSearchQuery,
    initialValue: search ? '' : undefined,
    value: props.searchQuery,
  });
  const [rawValue, setValue] = useAutoControlled({
    defaultValue: props.defaultValue,
    initialValue: [],
    value: props.value,
  });
  const value = normalizeValue(multiple, rawValue);

  const [a11ySelectionStatus, setA11ySelectionStatus] = React.useState('');
  const [focused, setFocused] = React.useState(false);
  const [isFromKeyboard, setIsFromKeyboard] = React.useState(false);
  const [itemIsFromKeyboard, setItemIsFromKeyboard] = React.useState(false);
  const [startingString, setStartingString] = React.useState<string | undefined>(search ? undefined : '');

  const { filteredItems, filteredItemStrings } = getFilteredValues({
    itemToString,
    itemToValue,
    items,
    multiple,
    search,
    searchQuery,
    value,
  });

  const { classes, styles: resolvedStyles } = useStyles<DropdownStylesProps>(Dropdown.displayName, {
    className: dropdownClassName,
    mapPropsToStyles: () => ({
      disabled,
      error,
      fluid,
      focused,
      isEmptyClearIndicator: isEmpty(clearIndicator),
      hasToggleIndicator: !!toggleIndicator,
      inline,
      inverted,
      isFromKeyboard,
      multiple,
      open,
      position: positioningProps?.position ?? position,
      search: !!search,
      hasItemsSelected: value.length > 0,
    }),
    mapPropsToInlineStyles: () => ({
      className,
      design,
      styles,
      variables,
    }),
    rtl: context.rtl,
  });

  const clearA11ySelectionMessage = React.useMemo(
    () =>
      _.debounce(() => {
        setA11ySelectionStatus('');
      }, a11yStatusCleanupTime),
    [],
  );
  const clearStartingString = React.useMemo(
    () =>
      _.debounce(() => {
        setStartingString('');
      }, charKeyPressedCleanupTime),
    [],
  );

  const handleChange = (e: React.SyntheticEvent) => {
    // Dropdown component doesn't present any `input` component in markup, however all of our
    // components should handle events transparently.
    _.invoke(props, 'onChange', e, { ...props, value });
  };

  const handleOnBlur = (e: React.SyntheticEvent) => {
    // Dropdown component doesn't present any `input` component in markup, however all of our
    // components should handle events transparently.
    if (e.target !== buttonRef.current) {
      _.invoke(props, 'onBlur', e, props);
    }
  };

  const renderTriggerButton = (getToggleButtonProps: (options?: GetToggleButtonPropsOptions) => any): JSX.Element => {
    const content = getSelectedItemAsString(value[0]);
    const triggerButtonId = triggerButton['id'] || defaultTriggerButtonId;

    const triggerButtonProps = getToggleButtonProps({
      disabled,
      onFocus: handleTriggerButtonOrListFocus,
      onBlur: handleTriggerButtonBlur,
      onKeyDown: e => {