react-icons/io#IoIosClose TypeScript Examples

The following examples show how to use react-icons/io#IoIosClose. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: InputTypeahead.tsx    From hub with Apache License 2.0 4 votes vote down vote up
InputTypeahead = forwardRef((props: Props, ref: Ref<RefInputTypeaheadField>) => {
  const inputEl = useRef<HTMLInputElement>(null);
  const itemsWrapper = useRef<HTMLDivElement | null>(null);
  const [inputValue, setInputValue] = useState('');
  const [highlightedText, setHighlightedText] = useState<RegExp | null>(null);
  const [highlightedItem, setHighlightedItem] = useState<number | null>(null);

  useImperativeHandle(ref, () => ({
    reset: () => {
      setInputValue('');
    },
    getValue(): string {
      return inputValue;
    },
    updateValue(newValue: string): void {
      setInputValue(newValue);
    },
  }));

  const getVisibleItems = useCallback((): Option[] | null => {
    let filteredItems: Option[] = [];
    let elements: any[] | null = null;

    if (!isNull(highlightedItem)) {
      setHighlightedItem(null);
    }

    if (isUndefined(props.displayItemsInValueLength) || inputValue.length >= props.displayItemsInValueLength) {
      filteredItems = props.options.filter((opt: Option) => opt.name.toLowerCase().includes(inputValue.toLowerCase()));
      elements = orderBy(
        filteredItems,
        [
          (item: Option) =>
            props.selected.hasOwnProperty(item.filterKey) && props.selected[item.filterKey].includes(item.id.toString())
              ? -1
              : 1,
          'total',
        ],
        ['asc', 'desc']
      );
      // Scroll top when new visible items are displayed
      if (itemsWrapper && itemsWrapper.current) {
        itemsWrapper.current.scroll(0, 0);
      }
    }

    return elements;
  }, [highlightedItem, props.displayItemsInValueLength, props.options, props.selected, inputValue]);

  const getSelectedItems = useCallback((): Option[] => {
    let selectedItems: Option[] = [];
    Object.keys(props.selected).forEach((fKey: string) => {
      props.selected[fKey].forEach((item: string) => {
        const selected = props.options.find((opt: Option) => opt.id.toString() === item && opt.filterKey === fKey);
        if (!isUndefined(selected)) {
          selectedItems.push(selected);
        }
      });
    });
    return orderBy(selectedItems, 'total', 'desc');
  }, [props.options, props.selected]);

  const getOptionName = (name: string): JSX.Element => {
    if (!isNull(highlightedText)) {
      const stringParts: string[] = compact(name.split(highlightedText));
      if (stringParts.length === 1) {
        return (
          <span
            className={classnames({
              'fw-bold highlighted': name.toLowerCase() === inputValue.toLowerCase(),
            })}
          >
            {name}
          </span>
        );
      }

      return (
        <>
          {stringParts.map((str: string, index: number) => (
            <span
              key={`${name}_${index}`}
              className={classnames({
                'fw-bold highlighted': str.toLowerCase() === inputValue.toLowerCase(),
              })}
            >
              {str}
            </span>
          ))}
        </>
      );
    } else {
      return <>{name}</>;
    }
  };

  const [visibleItems, setVisibleItems] = useState<Option[] | null>(null);
  const [selectedItems, setSelectedItems] = useState<Option[]>(getSelectedItems());

  useEffect(() => {
    setVisibleItems(getVisibleItems());
  }, [inputValue, props.options]); /* eslint-disable-line react-hooks/exhaustive-deps */

  useEffect(() => {
    setSelectedItems(getSelectedItems());
  }, [getSelectedItems, props.selected]);

  const onChange = (e: ChangeEvent<HTMLInputElement>) => {
    e.stopPropagation();
    e.preventDefault();

    setHighlightedItem(null);
    setInputValue(e.target.value);

    const escapedValue = escapeRegExp(e.target.value.toLowerCase());
    setHighlightedText(e.target.value !== '' ? new RegExp(`(${escapedValue})`, 'gi') : null);
  };

  const onSelect = (filterKey: string, id: string, isSelected: boolean) => {
    setHighlightedItem(null);
    props.onChange(filterKey, id, !isSelected);
    if (props.onChangeSelection) {
      props.onChangeSelection();
    }
  };

  const onKeyDown = (e: KeyboardEvent<HTMLInputElement>): void => {
    switch (e.key) {
      case 'ArrowDown':
        updateHighlightedItem('down');
        return;
      case 'ArrowUp':
        updateHighlightedItem('up');
        return;
      case 'Enter':
        if (!isNull(highlightedItem) && visibleItems) {
          const item = visibleItems[highlightedItem];
          const isSelected =
            props.selected.hasOwnProperty(item.filterKey) &&
            props.selected[item.filterKey].includes(item.id.toString());
          onSelect(item.filterKey, item.id.toString(), isSelected);
        }
        return;
      default:
        return;
    }
  };

  const scrollDropdown = (index: number) => {
    if (itemsWrapper && itemsWrapper.current) {
      const itemsOnScreen = Math.floor(itemsWrapper.current.clientHeight / ITEM_HEIGHT);
      if (index + 1 > itemsOnScreen) {
        itemsWrapper.current.scroll(0, (index + 1 - itemsOnScreen) * ITEM_HEIGHT);
      } else {
        itemsWrapper.current.scroll(0, 0);
      }
    }
  };

  const updateHighlightedItem = (arrow: 'up' | 'down') => {
    if (!isNull(highlightedItem)) {
      let newIndex: number = arrow === 'up' ? highlightedItem - 1 : highlightedItem + 1;
      if (newIndex > visibleItems!.length - 1) {
        newIndex = 0;
      }
      if (newIndex < 0) {
        newIndex = visibleItems!.length - 1;
      }
      scrollDropdown(newIndex);
      setHighlightedItem(newIndex);
    } else {
      if (visibleItems && visibleItems.length > 0) {
        const newIndex = arrow === 'up' ? visibleItems.length - 1 : 0;
        scrollDropdown(newIndex);
        setHighlightedItem(newIndex);
      }
    }
  };

  if (props.options.length === 0) return null;

  return (
    <>
      <div className={`mb-3 input-group-sm ${styles.inputWrapper} ${props.inputWrapperClassName}`}>
        <input
          ref={inputEl}
          type="text"
          placeholder={props.placeholder || `Search ${props.label}`}
          className={classnames(
            'flex-grow-1 form-control',
            styles.input,
            { 'ps-3 pe-4': props.searchIcon },
            { 'px-3': isUndefined(props.searchIcon) || !props.searchIcon }
          )}
          name={`inputTypeahead_${props.label}`}
          value={inputValue}
          onChange={onChange}
          onKeyDown={onKeyDown}
          spellCheck="false"
          autoFocus={!isUndefined(props.autofocus) && props.autofocus}
        />

        {props.searchIcon && <FaSearch className={`text-muted position-absolute ${styles.searchIcon}`} />}

        {!isUndefined(props.additionalInfo) && <div className="alert p-0 mt-3">{props.additionalInfo}</div>}
      </div>

      {selectedItems.length > 0 && props.visibleClear && (
        <div className="py-1 border-bottom">
          <button
            className="btn btn-sm w-100"
            onClick={() => {
              if (props.onClear) {
                props.onClear();
              }
            }}
            aria-label="Clear all"
          >
            <div className="d-flex flex-row align-items-center text-muted">
              <IoIosClose />
              <small className="ms-2">Clear all</small>
            </div>
          </button>
        </div>
      )}

      {visibleItems && (
        <>
          {visibleItems.length === 0 ? (
            <div className={`p-3 text-center ${props.listClassName}`}>
              <small className="text-muted">Sorry, no matches found</small>
            </div>
          ) : (
            <div className={`${styles.itemsList} ${props.listClassName}`} ref={itemsWrapper}>
              {visibleItems.map((opt: Option, index: number) => {
                const isSelected =
                  props.selected.hasOwnProperty(opt.filterKey) &&
                  props.selected[opt.filterKey].includes(opt.id.toString());
                const name = getOptionName(opt.name);

                return (
                  <button
                    key={`opt_${opt.filterKey}_${opt.id}`}
                    data-testid="typeaheadDropdownBtn"
                    className={classnames(
                      'dropdown-item',
                      styles.option,
                      props.optClassName,
                      {
                        [styles.selected]: isSelected,
                      },
                      {
                        [styles.highlighted]: index === highlightedItem,
                      }
                    )}
                    onClick={() => {
                      onSelect(opt.filterKey, opt.id.toString(), isSelected);
                      if (props.onChangeSelection) {
                        props.onChangeSelection();
                      }
                    }}
                    aria-label={`${isSelected ? 'Unselect' : 'Select'} option`}
                  >
                    <div className="d-flex flex-row align-items-center position-relative">
                      {isSelected && (
                        <div className={`position-absolute ${styles.checkMark}`}>
                          <IoIosCheckmark />
                        </div>
                      )}
                      <InputTypeaheadOptionItem opt={opt} name={name} iconClassName={styles.icon} />

                      {isSelected && (
                        <div className={`position-absolute ${styles.close}`}>
                          <IoIosClose />
                        </div>
                      )}
                    </div>
                  </button>
                );
              })}
            </div>
          )}
        </>
      )}
    </>
  );
})
Example #2
Source File: WidgetsGroupModal.tsx    From hub with Apache License 2.0 4 votes vote down vote up
WidgetsGroupModal = (props: Props) => {
  const widthInput = useRef<RefInputField>(null);
  const whiteLabel = isWhiteLabel();
  const [theme, setTheme] = useState<string>(DEFAULT_THEME);
  const [header, setHeader] = useState<boolean>(false);
  const [stars, setStars] = useState<boolean>(true);
  const [loading, setLoading] = useState<boolean>(true);
  const [color, setColor] = useState<string>(DEFAULT_COLOR);
  const [fixedWidth, setFixedWidth] = useState<string | undefined>();
  const [groupWrapperWidthOpt, setGroupWrapperWidthOpt] = useState<string>(DEFAULT_WRAPPER_OPTION);
  const [isValidCode, setIsValidCode] = useState<boolean>(true);

  const onFixedWidthChange = (e: ChangeEvent<HTMLInputElement>) => {
    setFixedWidth(e.target.value);
    widthInput.current!.checkIsValid().then((res: boolean) => {
      setIsValidCode(res);
    });
  };

  const buildWidgetsGroupCode = (): string => {
    const code = `<div class="artifacthub-widget-group" data-url="${
      window.location.href
    }" data-theme="${theme}" data-header="${!header ? 'false' : 'true'}" data-stars="${
      !stars ? 'false' : 'true'
    }" data-color="${color}" data-responsive="${groupWrapperWidthOpt === 'responsive'}" ${
      fixedWidth ? `data-width="${fixedWidth}"` : ''
    } data-loading="${loading ? 'true' : 'false'}"></div><script async src="${
      window.location.origin
    }/artifacthub-widget.js"></script>`;

    return code;
  };

  const [widgetCode, setWidgetCode] = useState<string>(buildWidgetsGroupCode());

  const resetValues = () => {
    setTheme(DEFAULT_THEME);
    setHeader(false);
    setLoading(true);
    setFixedWidth(undefined);
    setColor(DEFAULT_COLOR);
    setGroupWrapperWidthOpt(DEFAULT_WRAPPER_OPTION);
    setWidgetCode(buildWidgetsGroupCode());
  };

  const onCloseModal = () => {
    props.setOpenStatus(false);
    resetValues();
  };

  const handleColorChange = (color: any) => {
    setColor(color.hex);
  };

  useEffect(() => {
    setWidgetCode(buildWidgetsGroupCode());
    /* eslint-disable react-hooks/exhaustive-deps */
  }, [
    theme,
    header,
    stars,
    fixedWidth,
    groupWrapperWidthOpt,
    color,
    loading,
    props.visibleWidget,
  ]); /* eslint-enable react-hooks/exhaustive-deps */

  return (
    <>
      {props.visibleWidget && (
        <Modal
          modalDialogClassName="fs-6"
          header={<div className={`h3 m-2 flex-grow-1 ${styles.title}`}>Widgets group</div>}
          onClose={onCloseModal}
          open={props.visibleWidget}
        >
          <div className="w-100 position-relative">
            <label className={`form-label fw-bold ${styles.label}`} htmlFor="theme">
              Theme
            </label>
            <div className="d-flex flex-row mb-3">
              {THEMES.map((themeOpt: RadioProps) => {
                return (
                  <div className="form-check me-4" key={`radio_theme_${themeOpt.name}`}>
                    <input
                      className="form-check-input"
                      type="radio"
                      name="theme"
                      id={themeOpt.name}
                      value={themeOpt.name}
                      checked={theme === themeOpt.name}
                      onChange={() => {
                        setTheme(themeOpt.name);
                      }}
                      required
                    />
                    <label className="form-label text-capitalize form-check-label" htmlFor={themeOpt.name}>
                      <div className="d-flex flex-row align-items-center">
                        {themeOpt.icon}
                        <span className="ms-1">{themeOpt.name}</span>
                      </div>
                    </label>
                  </div>
                );
              })}
            </div>

            {!whiteLabel && (
              <div className="mt-4 mb-3">
                <div className="form-check form-switch ps-0">
                  <label htmlFor="header" className={`form-check-label fw-bold ${styles.label}`}>
                    Header
                  </label>
                  <input
                    id="header"
                    type="checkbox"
                    className="form-check-input position-absolute ms-2"
                    value="true"
                    role="switch"
                    onChange={() => setHeader(!header)}
                    checked={header}
                  />
                </div>

                <div className="form-text text-muted mt-2">Display Artifact Hub header at the top of the widget.</div>
              </div>
            )}

            <div className="mt-4 mb-3">
              <div className="form-check form-switch ps-0">
                <label htmlFor="stars" className={`form-check-label fw-bold ${styles.label}`}>
                  Stars
                </label>
                <input
                  id="stars"
                  type="checkbox"
                  className="form-check-input position-absolute ms-2"
                  value="true"
                  role="switch"
                  onChange={() => setStars(!stars)}
                  checked={stars}
                />
              </div>

              <div className="form-text text-muted mt-2">Display number of stars given to the package.</div>
            </div>

            <div className="d-flex flex-row">
              <div>
                <label className={`form-label fw-bold ${styles.label}`} htmlFor="groupWrapperWidthOpt">
                  Container width
                </label>
                <div className="d-flex flex-row">
                  {WRAPPER_OPTIONS.map((wrapperOpt: RadioProps) => {
                    return (
                      <div className="form-check me-4" key={`radio_wrapperOpt_${wrapperOpt.name}`}>
                        <input
                          className="form-check-input"
                          type="radio"
                          name="groupWrapperWidthOpt"
                          id={wrapperOpt.name}
                          value={wrapperOpt.name}
                          checked={groupWrapperWidthOpt === wrapperOpt.name}
                          onChange={() => {
                            if (wrapperOpt.name === 'fixed') {
                              setFixedWidth((WIDGET_WIDTH * 2).toString());
                            } else {
                              setIsValidCode(true);
                              setFixedWidth(undefined);
                            }
                            setGroupWrapperWidthOpt(wrapperOpt.name);
                          }}
                          required
                        />
                        <label className="text-capitalize form-check-label" htmlFor={wrapperOpt.name}>
                          <div className="d-flex flex-row align-items-center">
                            {wrapperOpt.icon}
                            <span className="ms-1">{wrapperOpt.name}</span>
                          </div>
                        </label>
                      </div>
                    );
                  })}
                </div>
              </div>
              <div className={`position-relative ${styles.inputWrapper}`}>
                {groupWrapperWidthOpt === 'fixed' && (
                  <div className="position-absolute d-flex flex-row">
                    <InputField
                      ref={widthInput}
                      type="number"
                      name="fixedWidth"
                      min={380}
                      className="mb-0"
                      inputClassName={styles.input}
                      invalidText={{
                        default: 'This field is required',
                        rangeUnderflow: 'The min value is 380',
                      }}
                      onChange={onFixedWidthChange}
                      value={fixedWidth}
                      validateOnBlur
                      required
                    />
                    <div className="mt-1 text-muted ms-2">px</div>
                  </div>
                )}
              </div>
            </div>
            <div className="mt-4 mb-3">
              <div className="form-check form-switch ps-0">
                <label htmlFor="loading" className={`form-check-label fw-bold ${styles.label}`}>
                  Loading spinner
                </label>
                <input
                  id="loading"
                  type="checkbox"
                  role="switch"
                  className="form-check-input position-absolute ms-2"
                  value="true"
                  onChange={() => setLoading(!loading)}
                  checked={loading}
                />
              </div>

              <div className="form-text text-muted mt-2">Display loading spinner while waiting for search results.</div>
            </div>

            <div className="mt-4 mb-3">
              <div className="d-flex flex-row align-items-center">
                <label htmlFor="color" className={`form-label fw-bold mb-0 ${styles.label}`}>
                  Color
                </label>
                <div className={`btn btn-sm btn-light border p-1 ms-2 ${styles.colorInputWrapper}`}>
                  <div
                    className={styles.colorInput}
                    style={{
                      backgroundColor: color,
                    }}
                  />
                </div>
                {color !== DEFAULT_COLOR && (
                  <button
                    className="btn btn-sm btn-link text-muted py-0"
                    onClick={() => setColor(DEFAULT_COLOR)}
                    aria-label="Reset to default"
                  >
                    <IoIosClose />
                    <small>Reset to default</small>
                  </button>
                )}
              </div>
              <div className="form-text text-muted mt-3 mb-2">
                Color used for widgets border, header and loading spinner.
              </div>
              <div className={`pb-2 ${styles.colorPickerWrapper}`}>
                <SketchPicker
                  color={color}
                  presetColors={PRESET_COLORS}
                  onChangeComplete={handleColorChange}
                  disableAlpha
                />
              </div>
            </div>

            <div className="mt-3 mb-2">
              <label className={`form-label fw-bold ${styles.label}`}>Code</label>

              <div data-testid="block-content" className={`flex-grow-1 me-3 user-select-none ${styles.blockWrapper}`}>
                <SyntaxHighlighter
                  language="text"
                  style={docco}
                  customStyle={{
                    backgroundColor: 'var(--color-1-10)',
                  }}
                >
                  {widgetCode}
                </SyntaxHighlighter>
              </div>

              <ButtonCopyToClipboard
                text={widgetCode}
                tooltipClassName={`bs-tooltip-end ${styles.copyBtnTooltip}`}
                arrowClassName={styles.copyBtnArrow}
                visibleBtnText
                contentBtn="Copy code to clipboard"
                className="btn-outline-secondary px-2 py-1 text-uppercase"
                disabled={!isValidCode}
                label="Copy code to clipboard"
              />
            </div>
          </div>
        </Modal>
      )}
    </>
  );
}