react-use#useKeyPressEvent TypeScript Examples

The following examples show how to use react-use#useKeyPressEvent. 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: Modals.tsx    From flood with GNU General Public License v3.0 6 votes vote down vote up
Modals: FC = observer(() => {
  const {id} = UIStore.activeModal || {};

  useKeyPressEvent('Escape', () => UIStore.setActiveModal(null));

  let modal;
  if (id != null) {
    modal = (
      <CSSTransition key={id} classNames="modal__animation" timeout={{enter: 500, exit: 500}}>
        <div className="modal">
          <div
            className="modal__overlay"
            role="none"
            onClick={() => {
              UIStore.setActiveModal(null);
            }}
          />
          {createModal(id)}
        </div>
      </CSSTransition>
    );
  }

  return <TransitionGroup>{modal}</TransitionGroup>;
})
Example #2
Source File: ContextMenuMountPoint.tsx    From flood with GNU General Public License v3.0 4 votes vote down vote up
ContextMenuMountPoint: FC<ContextMenuMountPointProps> = observer(({id}: ContextMenuMountPointProps) => {
  const isOpen = UIStore.activeContextMenu?.id === id;
  const items = UIStore.activeContextMenu?.items ?? [];
  const triggerCoordinates = UIStore.activeContextMenu?.clickPosition ?? {
    x: 0,
    y: 0,
  };

  const {i18n} = useLingui();

  useKeyPressEvent('Escape', () => UIStore.dismissContextMenu(id));

  return (
    <ContextMenu
      triggerCoordinates={triggerCoordinates}
      onOverlayClick={() => {
        UIStore.dismissContextMenu(id);
      }}
      onOverlayRightClick={(e) => {
        e.preventDefault();
      }}
      isIn={isOpen}
    >
      {items.map((item, index) => {
        let menuItemContent;
        let menuItemClasses;

        switch (item.type) {
          case 'action':
            menuItemClasses = classnames('menu__item', {
              'is-selectable': item.clickHandler,
            });
            menuItemContent = (
              <span>
                <span
                  className={classnames('menu__item__label--primary', {
                    'has-action': item.labelAction,
                  })}
                >
                  <span className="menu__item__label">{i18n._(item.label)}</span>
                  {item.labelAction ? (
                    <span className="menu__item__label__action">
                      <item.labelAction />
                    </span>
                  ) : undefined}
                </span>
                {item.labelSecondary ? (
                  <span className="menu__item__label--secondary">
                    <item.labelSecondary />
                  </span>
                ) : undefined}
              </span>
            );
            break;
          case 'separator':
          default:
            menuItemClasses = classnames('menu__item', {
              'menu__item--separator': item.type === 'separator',
            });
            break;
        }

        return (
          <li className={menuItemClasses} key={item.type === 'action' ? item.action : `sep-${index}`}>
            <button
              type="button"
              disabled={item.type !== 'action' || !item.clickHandler}
              onClick={(event) => {
                if (item.type !== 'separator') {
                  if (item.dismissMenu === false) {
                    event.nativeEvent.stopImmediatePropagation();
                  }

                  if (item.clickHandler) {
                    item.clickHandler(event);
                  }

                  if (item.dismissMenu !== false) {
                    UIStore.dismissContextMenu(id);
                  }
                }

                return false;
              }}
              onContextMenu={(event) => {
                event.preventDefault();
              }}
            >
              {menuItemContent}
            </button>
          </li>
        );
      })}
    </ContextMenu>
  );
})
Example #3
Source File: Dropdown.tsx    From flood with GNU General Public License v3.0 4 votes vote down vote up
Dropdown = observer(
  <T extends string = string>({
    baseClassName,
    dropdownWrapperClass,
    dropdownButtonClass,
    dropdownClickRef,
    direction,
    header,
    matchButtonWidth,
    menuItems,
    noWrap,
    trigger,
    width,
    isFocusHandled,
    handleItemSelect,
    onOpen,
  }: DropdownProps<T>) => {
    const id = useRef<string>(uniqueId('dropdown_'));
    const isOpen = UIStore.activeDropdownMenu === id.current;
    const dropdownWrapperClassName = classnames(dropdownWrapperClass, `${baseClassName}--direction-${direction}`, {
      [`${baseClassName}--match-button-width`]: matchButtonWidth,
      [`${baseClassName}--width-${width}`]: width != null,
      [`${baseClassName}--no-wrap`]: noWrap,
      'is-expanded': isOpen,
    });

    const closeDropdown = useCallback(() => {
      window.removeEventListener('click', closeDropdown);

      UIStore.setActiveDropdownMenu(null);
    }, []);

    useKeyPressEvent('Escape', () => closeDropdown());

    const openDropdown = useCallback(() => {
      window.addEventListener('click', closeDropdown);

      if (onOpen) {
        onOpen();
      }

      UIStore.setActiveDropdownMenu(id.current);
    }, [closeDropdown, onOpen]);

    const handleDropdownClick = (event?: SyntheticEvent): void => {
      event?.stopPropagation();

      if (isOpen) {
        closeDropdown();
      } else {
        openDropdown();
      }
    };

    if (dropdownClickRef) {
      // eslint-disable-next-line no-param-reassign
      dropdownClickRef.current = handleDropdownClick;
    }

    let contentElement: ReactNode;
    if (isOpen) {
      const headerElement = (
        <div className="dropdown__header" key="dropdown-header">
          <DropdownButton
            className={dropdownButtonClass}
            label={header}
            isFocusHandled={isFocusHandled ?? false}
            onClick={handleDropdownClick}
          />
        </div>
      );

      const listElement = (
        <ul className="dropdown__items" key="dropdown-items">
          {menuItems.map((items, index) => (
            // eslint-disable-next-line react/no-array-index-key
            <div className="dropdown__list" key={index}>
              {items.map((item, itemIndex) => {
                const classes = classnames('dropdown__item menu__item', item.className, {
                  'is-selectable': item.selectable !== false,
                  'is-selected': item.selected,
                });

                return (
                  // eslint-disable-next-line react/no-array-index-key
                  <li className={classes} key={itemIndex}>
                    <button
                      type="button"
                      disabled={item.selectable === false}
                      onClick={
                        item.selectable === false
                          ? undefined
                          : () => {
                              closeDropdown();
                              handleItemSelect(item);
                            }
                      }
                    >
                      {item.displayName}
                    </button>
                  </li>
                );
              })}
            </div>
          ))}
        </ul>
      );

      contentElement = (
        <CSSTransition classNames="menu" timeout={{enter: 250, exit: 250}}>
          <div className="dropdown__content menu">
            {direction === 'up' ? [listElement, headerElement] : [headerElement, listElement]}
          </div>
        </CSSTransition>
      );
    }

    return (
      <div className={dropdownWrapperClassName}>
        <DropdownButton
          className={dropdownButtonClass}
          label={trigger ?? header}
          isFocusHandled={isFocusHandled ?? false}
          onClick={handleDropdownClick}
        />
        <TransitionGroup>{contentElement}</TransitionGroup>
      </div>
    );
  },
)
Example #4
Source File: TagSelect.tsx    From flood with GNU General Public License v3.0 4 votes vote down vote up
TagSelect: FC<TagSelectProps> = ({defaultValue, placeholder, id, label, onTagSelected}: TagSelectProps) => {
  const [isOpen, setIsOpen] = useState<boolean>(false);
  const [selectedTags, setSelectedTags] = useState<Array<string>>(defaultValue ?? []);
  const formRowRef = useRef<HTMLDivElement>(null);
  const menuRef = useRef<HTMLDivElement>(null);
  const textboxRef = useRef<HTMLInputElement>(null);

  const classes = classnames('select form__element', {
    'select--is-open': isOpen,
  });

  useKeyPressEvent('Escape', (e) => {
    e.preventDefault();
    setIsOpen(false);
  });

  useEffect(() => {
    const handleDocumentClick = (e: Event) => {
      if (!formRowRef.current?.contains(e.target as unknown as Node)) {
        setIsOpen(false);
      }
    };

    document.addEventListener('click', handleDocumentClick);

    return () => {
      document.removeEventListener('click', handleDocumentClick);
    };
  }, []);

  useEffect(() => {
    if (textboxRef.current != null) {
      textboxRef.current.value = selectedTags.join();
    }
    if (onTagSelected) {
      onTagSelected(selectedTags);
    }
  }, [selectedTags, onTagSelected]);

  return (
    <FormRowItem ref={formRowRef}>
      <div className={classes}>
        <Textbox
          autoComplete={isOpen ? 'off' : undefined}
          id={id || 'tags'}
          addonPlacement="after"
          defaultValue={defaultValue}
          label={label}
          onChange={() => {
            if (textboxRef.current != null) {
              let selectedTagsArray = textboxRef.current.value
                .split(',')
                .map((tag) => tag.trim())
                .filter((tag) => tag.length > 0);

              if (textboxRef.current.value.trimEnd().endsWith(',')) {
                // Ensures that the trailing ',' does not get removed automatically.
                selectedTagsArray.push('');

                // Deduplicate
                selectedTagsArray = [...new Set(selectedTagsArray)];
              }

              setSelectedTags(selectedTagsArray);
            }
          }}
          placeholder={placeholder}
          ref={textboxRef}
        >
          <FormElementAddon
            onClick={() => {
              setIsOpen(!isOpen);
            }}
            className="select__indicator"
          >
            <Chevron />
          </FormElementAddon>
          <Portal>
            <ContextMenu
              isIn={isOpen}
              onClick={(event) => {
                if (SettingStore.floodSettings.UITagSelectorMode !== 'single') {
                  event.nativeEvent.stopImmediatePropagation();
                }
              }}
              overlayProps={{isInteractive: false}}
              ref={menuRef}
              triggerRef={textboxRef}
            >
              {[
                ...new Set([
                  'untagged',
                  ...sort(Object.keys(TorrentFilterStore.taxonomy.tagCounts)).asc(),
                  ...selectedTags,
                ]),
              ].reduce((accumulator: Array<ReactElement>, tag) => {
                if (tag === '') {
                  return accumulator;
                }

                accumulator.push(
                  <SelectItem
                    id={tag}
                    key={tag}
                    isSelected={selectedTags.includes(tag)}
                    onClick={() => {
                      if (tag === 'untagged') {
                        setSelectedTags([]);
                      } else if (selectedTags.includes(tag)) {
                        setSelectedTags(selectedTags.filter((key) => key !== tag && key !== ''));
                      } else {
                        setSelectedTags([...selectedTags.filter((key) => key !== ''), tag]);
                      }
                    }}
                  >
                    {tag === 'untagged' ? <Trans id="filter.untagged" /> : tag}
                  </SelectItem>,
                );
                return accumulator;
              }, [])}
            </ContextMenu>
          </Portal>
        </Textbox>
      </div>
    </FormRowItem>
  );
}