react#ClipboardEvent TypeScript Examples

The following examples show how to use react#ClipboardEvent. 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: index.ts    From anchor-web-app with Apache License 2.0 4 votes vote down vote up
export function useRestrictedNumberInput({
  type = 'decimal',
  maxDecimalPoints,
  maxIntegerPoinsts,
  onChange: _onChange,
}: RestrictedNumberInputParams): RestrictedInputReturn {
  const { onKeyPress: restrictCharacters } = useRestrictedInput(
    type === 'integer' ? '0-9' : '0-9.',
  );

  const isInvalid = useCallback(
    (nextValue: string): boolean => {
      return (
        Number.isNaN(+nextValue) ||
        (typeof maxIntegerPoinsts === 'number' &&
          new RegExp(`^[0-9]{${maxIntegerPoinsts + 1},}`).test(nextValue)) ||
        (type === 'decimal' &&
          typeof maxDecimalPoints === 'number' &&
          new RegExp(`\\.[0-9]{${maxDecimalPoints + 1},}$`).test(nextValue))
      );
    },
    [maxDecimalPoints, maxIntegerPoinsts, type],
  );

  const onKeyPress = useCallback(
    (event: KeyboardEvent<HTMLInputElement>) => {
      restrictCharacters(event);

      if (event.isDefaultPrevented()) {
        return;
      }

      const { value, selectionStart, selectionEnd } =
        event.target as HTMLInputElement;

      if (
        typeof selectionStart !== 'number' ||
        typeof selectionEnd !== 'number'
      ) {
        event.preventDefault();
        event.stopPropagation();
        return;
      }

      const char = event.key;

      const nextValue =
        value.substring(0, selectionStart) +
        char +
        value.substring(selectionEnd);

      if (isInvalid(nextValue)) {
        event.preventDefault();
        event.stopPropagation();
      }
    },
    [restrictCharacters, isInvalid],
  );

  const onPaste = useCallback(
    (event: ClipboardEvent<HTMLInputElement>) => {
      const pastedText = event.clipboardData?.getData('text');

      if (!/^[0-9.]+$/.test(pastedText)) {
        event.preventDefault();
        event.stopPropagation();
      }

      const { value, selectionStart, selectionEnd } =
        event.target as HTMLInputElement;

      if (
        typeof selectionStart !== 'number' ||
        typeof selectionEnd !== 'number'
      ) {
        event.preventDefault();
        event.stopPropagation();
        return;
      }

      const nextValue =
        value.substring(0, selectionStart) +
        pastedText +
        value.substring(selectionEnd);

      if (isInvalid(nextValue)) {
        event.preventDefault();
        event.stopPropagation();
      }
    },
    [isInvalid],
  );

  const onChange = useCallback(
    (event: ChangeEvent<HTMLInputElement>) => {
      if (_onChange) {
        const hasNonNumeralCharacters = /[^0-9.]/g;

        if (hasNonNumeralCharacters.test(event.target.value)) {
          event.target.value = event.target.value.replace(/[^0-9.]/g, '');
        }

        _onChange(event);
      }
    },
    [_onChange],
  );

  return { onKeyPress, onPaste, onChange };
}
Example #2
Source File: CommentBox.tsx    From apps with GNU Affero General Public License v3.0 4 votes vote down vote up
function CommentBox({
  authorImage,
  authorName,
  publishDate,
  contentHtml,
  editContent,
  editId,
  input,
  errorMessage,
  sendingComment,
  onInput,
  onKeyDown,
  sendComment,
  parentSelector,
  post,
}: CommentBoxProps): ReactElement {
  const onTextareaInput = (content: string) =>
    onInput(cleanupEmptySpaces(content));
  const { user } = useContext(AuthContext);
  const commentRef = useRef<HTMLDivElement>(null);
  const {
    onMentionClick,
    onMentionKeypress,
    offset,
    mentions,
    mentionQuery,
    selected,
    onInitializeMention,
    onInputClick,
  } = useUserMention({
    postId: post.id,
    commentRef,
    onInput: onTextareaInput,
  });

  useEffect(() => {
    commentRef.current?.focus();
    if (commentRef.current && editContent) {
      commentRef.current.innerText = editContent;
    }
  }, []);

  const onPaste = (event: ClipboardEvent): void => {
    event.preventDefault();
    const text = event.clipboardData.getData('text/plain');
    if (document.queryCommandSupported('insertText')) {
      document.execCommand('insertText', false, text);
    } else {
      document.execCommand('paste', false, text);
    }
  };

  const handleKeydown = (e: KeyboardEvent<HTMLDivElement>) => {
    const defaultCallback = () => onMentionKeypress(e);
    onKeyDown(e, defaultCallback);
  };

  return (
    <>
      <div className="overflow-auto" style={{ maxHeight: '31rem' }}>
        <article
          className={classNames(
            'flex flex-col items-stretch',
            commentBoxClassNames,
          )}
        >
          <header className="flex items-center mb-2">
            <RoundedImage
              src={authorImage}
              alt={`${authorName}'s profile`}
              className="bg-theme-bg-secondary"
              loading="lazy"
            />
            <div className="flex flex-col ml-2">
              <div className="truncate typo-callout">{authorName}</div>
              <time
                dateTime={publishDate.toString()}
                className="text-theme-label-tertiary typo-callout"
              >
                {commentDateFormat(publishDate)}
              </time>
            </div>
          </header>
          <Markdown content={contentHtml} />
        </article>
        <div className="flex items-center px-2 h-11">
          <div className="ml-3 w-px h-full bg-theme-divider-tertiary" />
          <div className="ml-6 text-theme-label-secondary typo-caption1">
            Reply to{' '}
            <strong className="font-bold text-theme-label-primary">
              {authorName}
            </strong>
          </div>
        </div>
        <div className="flex relative flex-1 pl-2">
          <ProfilePicture user={user} size="small" nativeLazyLoading />
          <div
            className={classNames(
              'ml-3 pr-2 flex-1 text-theme-label-primary bg-transparent whitespace-pre-line border-none caret-theme-label-link break-words typo-subhead resize-none',
              styles.textarea,
            )}
            ref={commentRef}
            contentEditable
            role="textbox"
            aria-multiline
            aria-placeholder="Write your comment..."
            onInput={(e) => onTextareaInput(e.currentTarget.innerText)}
            onKeyDown={handleKeydown}
            onClick={onInputClick}
            onPaste={onPaste}
            tabIndex={0}
            aria-label="New comment box"
          />
        </div>
        <RecommendedMentionTooltip
          elementRef={commentRef}
          offset={offset}
          mentions={mentions}
          selected={selected}
          query={mentionQuery}
          appendTo={parentSelector}
          onMentionClick={onMentionClick}
        />
        <div
          className="my-2 mx-3 text-theme-status-error typo-caption1"
          style={{ minHeight: '1rem' }}
        >
          {errorMessage && <span role="alert">{errorMessage}</span>}
        </div>
      </div>
      <footer className="flex items-center pt-3">
        <Button
          className="mx-1 btn-tertiary"
          buttonSize="small"
          icon={<AtIcon />}
          onClick={onInitializeMention}
        />
        <div className="ml-2 w-px h-6 border border-opacity-24 border-theme-divider-tertiary" />
        <ClickableText
          tag="a"
          href="https://www.markdownguide.org/cheat-sheet/"
          className="ml-4 typo-caption1"
          defaultTypo={false}
          target="_blank"
        >
          Markdown supported
        </ClickableText>
        <Button
          disabled={!input?.trim().length || input === editContent}
          loading={sendingComment}
          onClick={sendComment}
          className="ml-auto btn-primary-avocado"
        >
          {editId ? 'Update' : 'Comment'}
        </Button>
      </footer>
    </>
  );
}