react-icons/fa#FaRegQuestionCircle TypeScript Examples

The following examples show how to use react-icons/fa#FaRegQuestionCircle. 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: Section.tsx    From slice-machine with Apache License 2.0 6 votes vote down vote up
Section: React.FC<{
  children: React.ReactNode;
  heading: React.ReactNode;
}> = ({ children, heading }) => (
  <Flex sx={{ padding: "16px 20px" }}>
    <Flex
      sx={{
        padding: 3,
        backgroundColor: (t) => t.colors?.gray,
        borderRadius: 8,
        flexDirection: "column",
      }}
    >
      <Flex sx={{ alignItems: "center", mb: 3 }}>
        <Flex sx={{ mr: 2 }}>
          <FaRegQuestionCircle size={20} color="grey05" />
        </Flex>
        <Text sx={{ fontSize: 2, fontWeight: 500 }}>{heading}</Text>
      </Flex>
      <Text sx={{ color: (t) => t.colors?.textClear }}>{children}</Text>
    </Flex>
  </Flex>
)
Example #2
Source File: RepositoryWarningModal.tsx    From hub with Apache License 2.0 5 votes vote down vote up
RepositoryWarningModal = () => {
  const [openStatus, setOpenStatus] = useState<boolean>(false);

  return (
    <>
      <button
        className={`d-inline-block ps-0 pe-1 py-0 btn btn-link btn-sm fs-6 text-dark ${styles.trackingWarningBtn}`}
        onClick={() => setOpenStatus(true)}
        aria-label="Open repository warning modal"
      >
        <small>
          <FaRegQuestionCircle className={`position-relative ${styles.icon}`} />
        </small>
      </button>
      {openStatus && (
        <Modal className="d-inline-block" noFooter onClose={() => setOpenStatus(false)} open={openStatus}>
          <div className="mw-100 text-start text-dark">
            <div className="d-flex flex-row justify-content-between mb-4">
              <div className={`h3 d-flex flex-row align-items-baseline ${styles.title}`}>Warning info</div>

              <div>
                <button
                  type="button"
                  className={`btn-close p-3 ${styles.closeModalBtn}`}
                  onClick={() => {
                    setOpenStatus(false);
                  }}
                  aria-label="Close"
                ></button>
              </div>
            </div>

            <div className="fs-6">
              <p>
                This warning sign indicates that the tracking operation that took place at the processed time displayed
                failed. You can see more details about why it failed by opening the tracking errors log modal.
              </p>
              <p>
                Please note that <span className="fw-bold">this warning will remain visible</span> until the next time
                the repository is processed successfully. Repositories are checked for updates every{' '}
                <span className="fst-italic">30 minutes approximately</span>, but they are only
                <span className="fst-italic mx-1">processed</span> if they have{' '}
                <span className="fw-bold">changed since the last time they were processed</span>.
              </p>
              <p>
                Depending on the nature of the error, an action on your side may be required or not. In the case of
                isolated network errors, you can ignore the warning and it'll be cleaned up automatically on the next
                successful tracking operation.
              </p>
            </div>
          </div>
        </Modal>
      )}
    </>
  );
}
Example #3
Source File: SearchBar.tsx    From hub with Apache License 2.0 4 votes vote down vote up
SearchBar = (props: Props) => {
  const history = useHistory();
  const dropdownRef = useRef(null);
  const [value, setValue] = useState(props.tsQueryWeb || '');
  const inputEl = useRef<HTMLInputElement>(null);
  const [packages, setPackages] = useState<Package[] | null>(null);
  const [totalPackagesNumber, setTotalPackagesNumber] = useState<number | null>(null);
  const [visibleDropdown, setVisibleDropdown] = useState<boolean>(false);
  const point = useBreakpointDetect();
  const [highlightedItem, setHighlightedItem] = useState<number | null>(null);
  const [dropdownTimeout, setDropdownTimeout] = useState<NodeJS.Timeout | null>(null);

  useOutsideClick([dropdownRef], visibleDropdown, () => {
    cleanSearch();
  });

  const onChange = (e: ChangeEvent<HTMLInputElement>): void => {
    setValue(e.target.value);
  };

  const cleanSearchBox = (): void => {
    setValue('');
    forceFocus();
  };

  const forceFocus = (): void => {
    if (!isNull(inputEl) && !isNull(inputEl.current)) {
      inputEl.current.focus();
    }
  };

  const forceBlur = (): void => {
    if (!isNull(inputEl) && !isNull(inputEl.current)) {
      inputEl.current.blur();
    }
  };

  const goToSearch = () => {
    cleanTimeout();
    forceBlur();
    cleanSearch();

    history.push({
      pathname: '/packages/search',
      search: prepareQueryString({
        pageNumber: 1,
        tsQueryWeb: value || undefined,
      }),
    });
  };

  const cleanTimeout = () => {
    if (!isNull(dropdownTimeout)) {
      clearTimeout(dropdownTimeout);
      setDropdownTimeout(null);
    }
  };

  const cleanSearch = () => {
    setPackages(null);
    setTotalPackagesNumber(null);
    setVisibleDropdown(false);
    setHighlightedItem(null);
  };

  const onKeyDown = (e: KeyboardEvent<HTMLInputElement>): void => {
    switch (e.key) {
      case 'Escape':
        cleanSearch();
        return;
      case 'ArrowDown':
        updateHighlightedItem('down');
        return;
      case 'ArrowUp':
        updateHighlightedItem('up');
        return;
      case 'Enter':
        e.preventDefault();
        if (!isNull(packages) && !isNull(highlightedItem)) {
          if (highlightedItem === packages.length) {
            goToSearch();
          } else {
            const selectedPackage = packages[highlightedItem];
            if (selectedPackage) {
              goToPackage(selectedPackage);
            }
          }
        } else {
          goToSearch();
        }
        return;
      default:
        return;
    }
  };

  const updateHighlightedItem = (arrow: 'up' | 'down') => {
    if (!isNull(packages) && visibleDropdown) {
      if (!isNull(highlightedItem)) {
        let newIndex: number = arrow === 'up' ? highlightedItem - 1 : highlightedItem + 1;
        if (newIndex > packages.length) {
          newIndex = 0;
        }
        if (newIndex < 0) {
          newIndex = packages.length;
        }
        setHighlightedItem(newIndex);
      } else {
        if (packages && packages.length > 0) {
          const newIndex = arrow === 'up' ? packages.length : 0; // We don't subtract 1 because See all results (x) has to be count
          setHighlightedItem(newIndex);
        }
      }
    }
  };

  const goToPackage = (selectedPackage: Package) => {
    forceBlur();
    setValue('');
    cleanSearch();
    history.push({
      pathname: buildPackageURL(selectedPackage.normalizedName, selectedPackage.repository, selectedPackage.version!),
    });
  };

  useEffect(() => {
    setValue(props.tsQueryWeb || '');
  }, [props.tsQueryWeb]);

  async function searchPackages() {
    try {
      const searchResults = await API.searchPackages(
        {
          tsQueryWeb: value,
          filters: {},
          limit: 5,
          offset: 0,
        },
        false
      );
      const total = parseInt(searchResults.paginationTotalCount);
      if (total > 0) {
        const isInputFocused = inputEl.current === document.activeElement;
        // We have to be sure that input has focus to display results
        if (isInputFocused) {
          setPackages(searchResults.packages);
          setTotalPackagesNumber(total);
          setVisibleDropdown(true);
        } else {
          cleanSearch();
        }
      } else {
        cleanSearch();
      }
    } catch (err: any) {
      cleanSearch();
    }
  }

  useEffect(() => {
    // Don't display search options for mobile devices
    if (point !== 'xs') {
      const isInputFocused = inputEl.current === document.activeElement;
      if (value.length >= MIN_CHARACTERS_SEARCH && isInputFocused) {
        cleanTimeout();
        setDropdownTimeout(
          setTimeout(() => {
            setHighlightedItem(null);
            searchPackages();
          }, SEARCH_DELAY)
        );
      } else {
        cleanSearch();
      }
    }

    return () => {
      if (!isNull(dropdownTimeout)) {
        clearTimeout(dropdownTimeout);
      }
    };
  }, [value]); /* eslint-disable-line react-hooks/exhaustive-deps */

  return (
    <>
      <div className={`position-relative ${props.formClassName}`}>
        <div
          className={`d-flex align-items-center overflow-hidden searchBar lh-base bg-white ${styles.searchBar} ${
            styles[props.size]
          }`}
          role="combobox"
          aria-haspopup="listbox"
          aria-owns="search-list"
          aria-expanded={visibleDropdown && !isNull(packages)}
          aria-controls="search-list"
        >
          <div
            data-testid="searchBarIcon"
            className={`d-flex align-items-center ${styles.iconWrapper}`}
            onClick={forceFocus}
          >
            <FiSearch />
          </div>

          <input
            ref={inputEl}
            className={`flex-grow-1 ps-2 ps-md-0 border-0 shadow-none bg-transparent ${styles.input}`}
            type="text"
            autoComplete="off"
            autoCorrect="off"
            autoCapitalize="none"
            spellCheck="false"
            placeholder="Search packages"
            aria-label="Search packages"
            value={value}
            onChange={onChange}
            onKeyDown={onKeyDown}
            disabled={props.isSearching}
          />

          <div className="d-none" tabIndex={0}>
            <div aria-live="polite">{!isNull(packages) ? `${packages.length} results found` : ''}</div>
          </div>

          {props.isSearching && (
            <div
              className={classnames('position-absolute text-secondary', styles.loading, {
                [styles.bigLoading]: props.size === 'big',
              })}
            >
              <span data-testid="searchBarSpinning" className="spinner-border spinner-border-sm" />
            </div>
          )}

          <button
            type="button"
            className={classnames('btn-close lh-lg ps-2 pe-3', styles.inputClean, {
              invisible: value === '' || props.isSearching,
            })}
            onClick={cleanSearchBox}
            aria-label="Close"
          ></button>

          <div
            className={classnames('position-absolute text-dark', styles.tipIcon, {
              [styles.bigTipIcon]: props.size === 'big',
            })}
          >
            <button
              onClick={() => props.setOpenTips(true)}
              className={classnames('btn btn-link p-2 text-light', {
                'btn-lg': props.size === 'big',
              })}
              aria-label="Open search tips modal"
            >
              <FaRegQuestionCircle />
            </button>
          </div>
        </div>

        {visibleDropdown && !isNull(packages) && (
          <div
            ref={dropdownRef}
            className={`dropdown-menu dropdown-menu-left p-0 shadow-sm w-100 show noFocus ${styles.dropdown}`}
            role="listbox"
            id="search-list"
            aria-activedescendant={highlightedItem ? `sl-opt${highlightedItem}` : ''}
            tabIndex={0}
            aria-roledescription="Packages list"
          >
            <HoverableItem onLeave={() => setHighlightedItem(null)}>
              <>
                {packages.map((pkg: Package, index: number) => {
                  return (
                    <HoverableItem
                      key={`pkg_${pkg.packageId}`}
                      onHover={() => setHighlightedItem(index)}
                      onLeave={() => setHighlightedItem(null)}
                    >
                      <button
                        type="button"
                        className={classnames(
                          'btn btn-link w-100 border-bottom rounded-0 d-flex flex-row align-items-stretch text-decoration-none text-dark p-3',
                          { [styles.activeDropdownItem]: index === highlightedItem }
                        )}
                        onClick={() => {
                          goToPackage(pkg);
                        }}
                        aria-label={`Open package ${pkg.displayName || pkg.name} detail`}
                        role="option"
                        aria-selected={index === highlightedItem}
                        id={`sl-opt${index}`}
                      >
                        <div
                          className={`d-none d-md-flex align-items-center justify-content-center overflow-hidden rounded-circle p-1 border border-2 bg-white position-relative ${styles.imageWrapper} imageWrapper`}
                        >
                          <Image
                            imageId={pkg.logoImageId}
                            alt={`Logo ${pkg.displayName || pkg.name}`}
                            className={styles.image}
                            kind={pkg.repository.kind}
                          />
                        </div>

                        <div className={`ms-0 ms-md-3 flex-grow-1 ${styles.truncateWrapper}`}>
                          <div className="d-flex flex-row align-items-center">
                            <div className={`text-truncate fw-bold ${styles.title}`}>{pkg.displayName || pkg.name}</div>

                            <div
                              className={`align-self-start d-flex align-items-center text-uppercase ms-auto ps-2 ${styles.midText}`}
                            >
                              <StarBadge className="me-1" starsNumber={pkg.stars} />
                              <RepositoryIconLabel kind={pkg.repository.kind} iconClassName={styles.kindIcon} />
                            </div>
                          </div>

                          <div className="d-flex flex-row align-items-center mt-2">
                            <div className={`text-truncate ${styles.smallText}`}>
                              <small className="text-muted text-uppercase">
                                {pkg.repository.userAlias ? 'User' : 'Org'}:
                              </small>
                              <span className="ms-1 me-2">
                                {pkg.repository.userAlias ||
                                  pkg.repository.organizationDisplayName ||
                                  pkg.repository.organizationName}
                              </span>

                              <small className="text-muted text-uppercase">Repo:</small>
                              <span className="text-truncate ms-1">{pkg.repository.name}</span>
                            </div>

                            <div className="ms-auto d-flex flex-nowrap ps-2">
                              <OfficialBadge
                                official={isPackageOfficial(pkg)}
                                className="d-inline"
                                type="package"
                                withoutTooltip
                              />
                            </div>
                          </div>
                        </div>
                      </button>
                    </HoverableItem>
                  );
                })}

                <HoverableItem
                  onHover={() => setHighlightedItem(packages.length)}
                  onLeave={() => setHighlightedItem(null)}
                >
                  <button
                    type="button"
                    className={classnames('btn btn-link w-100 text-dark p-2', styles.dropdownItem, {
                      [styles.activeDropdownItem]: packages.length === highlightedItem,
                    })}
                    onClick={goToSearch}
                    aria-label="See all results"
                    role="option"
                    aria-selected={packages.length === highlightedItem}
                    id={`sl-opt${packages.length}`}
                  >
                    See all results ({totalPackagesNumber})
                  </button>
                </HoverableItem>
              </>
            </HoverableItem>
          </div>
        )}
      </div>
    </>
  );
}