mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 09:30:31 +03:00
Merge pull request #791 from acelaya-forks/feature/fix-ref-types
Improved types on element ref objects and their usage
This commit is contained in:
commit
aac2832eb7
7 changed files with 26 additions and 31 deletions
|
@ -1,4 +1,4 @@
|
|||
import { FC, useEffect, useRef, useState } from 'react';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { UncontrolledTooltip } from 'reactstrap';
|
||||
import { ExternalLink } from 'react-external-link';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
@ -8,8 +8,8 @@ import {
|
|||
faCircleNotch as loadingStatusIcon,
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import { MediaMatcher } from '../../utils/types';
|
||||
import { mutableRefToElementRef } from '../../utils/helpers/components';
|
||||
import { DomainStatus } from '../data';
|
||||
import { useElementRef } from '../../utils/helpers/hooks';
|
||||
|
||||
interface DomainStatusIconProps {
|
||||
status: DomainStatus;
|
||||
|
@ -17,7 +17,7 @@ interface DomainStatusIconProps {
|
|||
}
|
||||
|
||||
export const DomainStatusIcon: FC<DomainStatusIconProps> = ({ status, matchMedia = window.matchMedia }) => {
|
||||
const ref = useRef<HTMLSpanElement>();
|
||||
const ref = useElementRef<HTMLSpanElement>();
|
||||
const matchesMobile = () => matchMedia('(max-width: 991px)').matches;
|
||||
const [isMobile, setIsMobile] = useState<boolean>(matchesMobile());
|
||||
|
||||
|
@ -35,13 +35,13 @@ export const DomainStatusIcon: FC<DomainStatusIconProps> = ({ status, matchMedia
|
|||
|
||||
return (
|
||||
<>
|
||||
<span ref={mutableRefToElementRef(ref)}>
|
||||
<span ref={ref}>
|
||||
{status === 'valid'
|
||||
? <FontAwesomeIcon fixedWidth icon={checkIcon} className="text-muted" />
|
||||
: <FontAwesomeIcon fixedWidth icon={invalidIcon} className="text-danger" />}
|
||||
</span>
|
||||
<UncontrolledTooltip
|
||||
target={(() => ref.current) as any}
|
||||
target={ref}
|
||||
placement={isMobile ? 'top-start' : 'left'}
|
||||
autohide={status === 'valid'}
|
||||
>
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import { useRef, ChangeEvent, useState, useEffect, FC, PropsWithChildren } from 'react';
|
||||
import { ChangeEvent, useState, useEffect, FC, PropsWithChildren } from 'react';
|
||||
import { Button, UncontrolledTooltip } from 'reactstrap';
|
||||
import { complement, pipe } from 'ramda';
|
||||
import { faFileUpload as importIcon } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { useToggle } from '../../utils/helpers/hooks';
|
||||
import { mutableRefToElementRef } from '../../utils/helpers/components';
|
||||
import { useElementRef, useToggle } from '../../utils/helpers/hooks';
|
||||
import { ServersImporter } from '../services/ServersImporter';
|
||||
import { ServerData, ServersMap } from '../data';
|
||||
import { DuplicatedServersModal } from './DuplicatedServersModal';
|
||||
|
@ -34,7 +33,7 @@ export const ImportServersBtn = ({ importServersFromFile }: ServersImporter): FC
|
|||
tooltipPlacement = 'bottom',
|
||||
className = '',
|
||||
}) => {
|
||||
const ref = useRef<HTMLInputElement>();
|
||||
const ref = useElementRef<HTMLInputElement>();
|
||||
const [serversToCreate, setServersToCreate] = useState<ServerData[] | undefined>();
|
||||
const [duplicatedServers, setDuplicatedServers] = useState<ServerData[]>([]);
|
||||
const [isModalOpen,, showModal, hideModal] = useToggle();
|
||||
|
@ -79,7 +78,7 @@ export const ImportServersBtn = ({ importServersFromFile }: ServersImporter): FC
|
|||
type="file"
|
||||
accept="text/csv"
|
||||
className="import-servers-btn__csv-select"
|
||||
ref={mutableRefToElementRef(ref)}
|
||||
ref={ref}
|
||||
onChange={onFile}
|
||||
/>
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { FC, ReactNode, useRef } from 'react';
|
||||
import { FC, ReactNode } from 'react';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { IconDefinition } from '@fortawesome/fontawesome-common-types';
|
||||
import { faLinkSlash, faCalendarXmark, faCheck } from '@fortawesome/free-solid-svg-icons';
|
||||
import { UncontrolledTooltip } from 'reactstrap';
|
||||
import { isBefore } from 'date-fns';
|
||||
import { mutableRefToElementRef } from '../../utils/helpers/components';
|
||||
import { ShortUrl } from '../data';
|
||||
import { formatHumanFriendly, now, parseISO } from '../../utils/helpers/date';
|
||||
import { useElementRef } from '../../utils/helpers/hooks';
|
||||
|
||||
interface ShortUrlStatusProps {
|
||||
shortUrl: ShortUrl;
|
||||
|
@ -70,15 +70,15 @@ const resolveShortUrlStatus = (shortUrl: ShortUrl): StatusResult => {
|
|||
};
|
||||
|
||||
export const ShortUrlStatus: FC<ShortUrlStatusProps> = ({ shortUrl }) => {
|
||||
const tooltipRef = useRef<HTMLElement | undefined>();
|
||||
const tooltipRef = useElementRef<HTMLElement>();
|
||||
const { icon, className, description } = resolveShortUrlStatus(shortUrl);
|
||||
|
||||
return (
|
||||
<>
|
||||
<span style={{ cursor: !description ? undefined : 'help' }} ref={mutableRefToElementRef(tooltipRef)}>
|
||||
<span style={{ cursor: !description ? undefined : 'help' }} ref={tooltipRef}>
|
||||
<FontAwesomeIcon icon={icon} className={className} />
|
||||
</span>
|
||||
<UncontrolledTooltip target={(() => tooltipRef.current) as any} placement="bottom">
|
||||
<UncontrolledTooltip target={tooltipRef} placement="bottom">
|
||||
{description}
|
||||
</UncontrolledTooltip>
|
||||
</>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { useRef } from 'react';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons';
|
||||
import { UncontrolledTooltip } from 'reactstrap';
|
||||
|
@ -7,8 +6,8 @@ import { prettify } from '../../utils/helpers/numbers';
|
|||
import { ShortUrl } from '../data';
|
||||
import { SelectedServer } from '../../servers/data';
|
||||
import { ShortUrlDetailLink } from './ShortUrlDetailLink';
|
||||
import { mutableRefToElementRef } from '../../utils/helpers/components';
|
||||
import { formatHumanFriendly, parseISO } from '../../utils/helpers/date';
|
||||
import { useElementRef } from '../../utils/helpers/hooks';
|
||||
import './ShortUrlVisitsCount.scss';
|
||||
|
||||
interface ShortUrlVisitsCountProps {
|
||||
|
@ -37,20 +36,20 @@ export const ShortUrlVisitsCount = (
|
|||
return visitsLink;
|
||||
}
|
||||
|
||||
const tooltipRef = useRef<HTMLElement | undefined>();
|
||||
const tooltipRef = useElementRef<HTMLElement>();
|
||||
|
||||
return (
|
||||
<>
|
||||
<span className="indivisible">
|
||||
{visitsLink}
|
||||
<small className="short-urls-visits-count__max-visits-control" ref={mutableRefToElementRef(tooltipRef)}>
|
||||
<small className="short-urls-visits-count__max-visits-control" ref={tooltipRef}>
|
||||
{maxVisits && <> / {prettify(maxVisits)}</>}
|
||||
<sup className="ms-1">
|
||||
<FontAwesomeIcon icon={infoIcon} />
|
||||
</sup>
|
||||
</small>
|
||||
</span>
|
||||
<UncontrolledTooltip target={(() => tooltipRef.current) as any} placement="bottom">
|
||||
<UncontrolledTooltip target={tooltipRef} placement="bottom">
|
||||
<ul className="list-unstyled mb-0">
|
||||
{maxVisits && (
|
||||
<li className="short-url-visits-count__tooltip-list-item">
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { FC, PropsWithChildren, useRef } from 'react';
|
||||
import { FC, PropsWithChildren } from 'react';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons';
|
||||
import { UncontrolledTooltip } from 'reactstrap';
|
||||
import { Placement } from '@popperjs/core';
|
||||
import { mutableRefToElementRef } from './helpers/components';
|
||||
import { useElementRef } from './helpers/hooks';
|
||||
|
||||
export type InfoTooltipProps = PropsWithChildren<{
|
||||
className?: string;
|
||||
|
@ -11,14 +11,14 @@ export type InfoTooltipProps = PropsWithChildren<{
|
|||
}>;
|
||||
|
||||
export const InfoTooltip: FC<InfoTooltipProps> = ({ className = '', placement, children }) => {
|
||||
const ref = useRef<HTMLSpanElement | undefined>();
|
||||
const ref = useElementRef<HTMLSpanElement>();
|
||||
|
||||
return (
|
||||
<>
|
||||
<span className={className} ref={mutableRefToElementRef(ref)}>
|
||||
<span className={className} ref={ref}>
|
||||
<FontAwesomeIcon icon={infoIcon} />
|
||||
</span>
|
||||
<UncontrolledTooltip target={(() => ref.current) as any} placement={placement}>{children}</UncontrolledTooltip>
|
||||
<UncontrolledTooltip target={ref} placement={placement}>{children}</UncontrolledTooltip>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
import { MutableRefObject, Ref } from 'react';
|
||||
|
||||
export const mutableRefToElementRef = <T>(ref: MutableRefObject<T | undefined>): Ref<T> => (el) => {
|
||||
ref.current = el ?? undefined; // eslint-disable-line no-param-reassign
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
import { useState, useRef, EffectCallback, DependencyList, useEffect } from 'react';
|
||||
import { DependencyList, EffectCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useSwipeable as useReactSwipeable } from 'react-swipeable';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
@ -91,3 +91,5 @@ export const useDomId = (): string => {
|
|||
const { current: id } = useRef(`dom-${uuid()}`);
|
||||
return id;
|
||||
};
|
||||
|
||||
export const useElementRef = <T>() => useRef<T | null>(null);
|
||||
|
|
Loading…
Reference in a new issue