From 9b40f4dafdb08a2c208271100eec184f396daad0 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Thu, 2 Jan 2025 17:09:14 +0100 Subject: [PATCH] Add support for React 19 --- CHANGELOG.md | 2 +- package-lock.json | 136 +++++++++--------- package.json | 14 +- src/ShlinkWebComponent.tsx | 2 +- src/domains/helpers/DomainStatusIcon.tsx | 4 +- src/overview/helpers/HighlightCard.tsx | 6 +- src/short-urls/helpers/ShortUrlStatus.tsx | 4 +- .../helpers/ShortUrlVisitsCount.tsx | 3 +- src/utils/components/InfoTooltip.tsx | 6 +- 9 files changed, 90 insertions(+), 87 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed0d6294..009ff118 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] ### Added -* *Nothing* +* Add support for React 19 ### Changed * *Nothing* diff --git a/package-lock.json b/package-lock.json index 0999d06b..34db0787 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,14 +61,14 @@ "@fortawesome/free-brands-svg-icons": "^6.4.2", "@fortawesome/free-regular-svg-icons": "^6.4.2", "@fortawesome/free-solid-svg-icons": "^6.4.2", - "@fortawesome/react-fontawesome": "^0.2.0", - "@reduxjs/toolkit": "^2.0.1", - "@shlinkio/shlink-frontend-kit": "^0.7.0", + "@fortawesome/react-fontawesome": "^0.2.2", + "@reduxjs/toolkit": "^2.5.0", + "@shlinkio/shlink-frontend-kit": "^0.7.1", "@shlinkio/shlink-js-sdk": "^1.3.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-redux": "^9.0.1", - "react-router": "^7.0.2", + "react": "^18.3 || ^19.0", + "react-dom": "^18.3 || ^19.0", + "react-redux": "^9.2.0", + "react-router": "^7.1.1", "reactstrap": "^9.2.0" }, "peerDependenciesMeta": { @@ -1090,9 +1090,10 @@ } }, "node_modules/@fortawesome/react-fontawesome": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", - "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz", + "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==", + "license": "MIT", "peer": true, "dependencies": { "prop-types": "^15.8.1" @@ -1759,18 +1760,19 @@ } }, "node_modules/@reduxjs/toolkit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.0.1.tgz", - "integrity": "sha512-fxIjrR9934cmS8YXIGd9e7s1XRsEU++aFc9DVNMFMRTM5Vtsg2DCRMj21eslGtDt43IUf9bJL3h5bwUlZleibA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.5.0.tgz", + "integrity": "sha512-awNe2oTodsZ6LmRqmkFhtb/KH03hUhxOamEQy411m3Njj3BbFvoBovxo4Q1cBWnV1ErprVj9MlF0UPXkng0eyg==", + "license": "MIT", "peer": true, "dependencies": { "immer": "^10.0.3", - "redux": "^5.0.0", + "redux": "^5.0.1", "redux-thunk": "^3.1.0", - "reselect": "^5.0.1" + "reselect": "^5.1.0" }, "peerDependencies": { - "react": "^16.9.0 || ^17.0.0 || ^18", + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "peerDependenciesMeta": { @@ -2169,9 +2171,9 @@ } }, "node_modules/@shlinkio/shlink-frontend-kit": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@shlinkio/shlink-frontend-kit/-/shlink-frontend-kit-0.7.0.tgz", - "integrity": "sha512-FJyO71B+RCqoqEUT/KrySgJYhaA/33ddTm4UtQYw129TLrpXOSDAg7JCKNTHzL4yTwh17gXeOG7mi0YAiL6qng==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@shlinkio/shlink-frontend-kit/-/shlink-frontend-kit-0.7.1.tgz", + "integrity": "sha512-aP29rrvAS1ZZgAsvogQGVAu5D+j2KoQtx043s4hmI3GN2cSPk6lggyAOi4nlRCDqiAR64dCV+edCmLKVxQRN+A==", "license": "MIT", "peer": true, "dependencies": { @@ -2180,9 +2182,9 @@ "peerDependencies": { "@fortawesome/fontawesome-free": "^6.4.2", "@fortawesome/free-solid-svg-icons": "^6.4.2", - "@fortawesome/react-fontawesome": "^0.2.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "@fortawesome/react-fontawesome": "^0.2.2", + "react": "^18.3 || ^19.0", + "react-dom": "^18.3 || ^19.0", "react-router": "^7.0.2", "reactstrap": "^9.2.0" } @@ -2544,7 +2546,7 @@ "version": "19.0.2", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.2.tgz", "integrity": "sha512-c1s+7TKFaDRRxr1TxccIX2u7sfCnc3RxkVyBIUA2lCpyqCF+QoAwQ/CBg7bsMdVwP120HEH143VQezKtef5nCg==", - "devOptional": true, + "dev": true, "peerDependencies": { "@types/react": "^19.0.0" } @@ -2556,9 +2558,10 @@ "dev": true }, "node_modules/@types/use-sync-external-store": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==", + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT", "peer": true }, "node_modules/@typescript-eslint/eslint-plugin": { @@ -7582,9 +7585,10 @@ } }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", "peer": true, "dependencies": { "loose-envify": "^1.1.0" @@ -7594,16 +7598,17 @@ } }, "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", "peer": true, "dependencies": { "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.3.1" } }, "node_modules/react-external-link": { @@ -7657,35 +7662,24 @@ } }, "node_modules/react-redux": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.0.1.tgz", - "integrity": "sha512-d+S89OqyChnY2J0O8wv8boRgnGo0tjvxkMLV78wx7h2ZyJvyeOQcBg4yrm7IxY36gxc63iOCfjjQAyhohKWJbA==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "license": "MIT", "peer": true, "dependencies": { - "@types/use-sync-external-store": "^0.0.3", - "use-sync-external-store": "^1.0.0" + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" }, "peerDependencies": { - "@types/react": "^18.2.41", - "@types/react-dom": "^18.2.17", - "react": "^18.0", - "react-dom": "^18.0", - "react-native": ">=0.71", + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", "redux": "^5.0.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true }, - "@types/react-dom": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - }, "redux": { "optional": true } @@ -7701,9 +7695,9 @@ } }, "node_modules/react-router": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.0.2.tgz", - "integrity": "sha512-m5AcPfTRUcjwmhBzOJGEl6Y7+Crqyju0+TgTQxoS4SO+BkWbhOrcfZNq6wSWdl2BBbJbsAoBUb8ZacOFT+/JlA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.1.tgz", + "integrity": "sha512-39sXJkftkKWRZ2oJtHhCxmoCrBCULr/HAH4IT5DHlgu/Q0FCPV0S4Lx+abjDTx/74xoZzNYDYbOZWlJjruyuDQ==", "license": "MIT", "peer": true, "dependencies": { @@ -7888,9 +7882,10 @@ } }, "node_modules/redux": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.0.tgz", - "integrity": "sha512-blLIYmYetpZMET6Q6uCY7Jtl/Im5OBldy+vNPauA8vvsdqyt66oep4EUpAMWNHauTC6xa9JuRPhRB72rY82QGA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT", "peer": true }, "node_modules/redux-thunk": { @@ -7957,9 +7952,10 @@ } }, "node_modules/reselect": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.0.1.tgz", - "integrity": "sha512-D72j2ubjgHpvuCiORWkOUxndHJrxDaSolheiz5CO+roz8ka97/4msh2E8F5qay4GawR5vzBt5MkbDHT+Rdy/Wg==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", + "license": "MIT", "peer": true }, "node_modules/resize-observer-polyfill": { @@ -8161,9 +8157,10 @@ } }, "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", "peer": true, "dependencies": { "loose-envify": "^1.1.0" @@ -10020,12 +10017,13 @@ } }, "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", + "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", + "license": "MIT", "peer": true, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/util-deprecate": { diff --git a/package.json b/package.json index f07b3d3b..a600ba35 100644 --- a/package.json +++ b/package.json @@ -44,14 +44,14 @@ "@fortawesome/free-brands-svg-icons": "^6.4.2", "@fortawesome/free-regular-svg-icons": "^6.4.2", "@fortawesome/free-solid-svg-icons": "^6.4.2", - "@fortawesome/react-fontawesome": "^0.2.0", - "@reduxjs/toolkit": "^2.0.1", - "@shlinkio/shlink-frontend-kit": "^0.7.0", + "@fortawesome/react-fontawesome": "^0.2.2", + "@reduxjs/toolkit": "^2.5.0", + "@shlinkio/shlink-frontend-kit": "^0.7.1", "@shlinkio/shlink-js-sdk": "^1.3.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-redux": "^9.0.1", - "react-router": "^7.0.2", + "react": "^18.3 || ^19.0", + "react-dom": "^18.3 || ^19.0", + "react-redux": "^9.2.0", + "react-router": "^7.1.1", "reactstrap": "^9.2.0" }, "peerDependenciesMeta": { diff --git a/src/ShlinkWebComponent.tsx b/src/ShlinkWebComponent.tsx index fdb74b37..d38f41dc 100644 --- a/src/ShlinkWebComponent.tsx +++ b/src/ShlinkWebComponent.tsx @@ -32,7 +32,7 @@ export const createShlinkWebComponent = ( { serverVersion, apiClient, settings, routesPrefix = '', createNotFound, tagColorsStorage }, ) => { const features = useFeatures(serverVersion); - const mainContent = useRef(); + const mainContent = useRef(undefined); const [theStore, setStore] = useState(); const inRouterContext = useInRouterContext(); diff --git a/src/domains/helpers/DomainStatusIcon.tsx b/src/domains/helpers/DomainStatusIcon.tsx index bd564bd6..b8871e4f 100644 --- a/src/domains/helpers/DomainStatusIcon.tsx +++ b/src/domains/helpers/DomainStatusIcon.tsx @@ -5,7 +5,7 @@ import { } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { useElementRef } from '@shlinkio/shlink-frontend-kit'; -import type { FC } from 'react'; +import type { FC, RefObject } from 'react'; import { ExternalLink } from 'react-external-link'; import { UncontrolledTooltip } from 'reactstrap'; import { useMaxResolution } from '../../utils/helpers/hooks'; @@ -33,7 +33,7 @@ export const DomainStatusIcon: FC = ({ status, matchMedia : } } placement={isMobile ? 'right' : 'left'} autohide={status === 'valid'} > diff --git a/src/overview/helpers/HighlightCard.tsx b/src/overview/helpers/HighlightCard.tsx index 5ade3e17..35ef4760 100644 --- a/src/overview/helpers/HighlightCard.tsx +++ b/src/overview/helpers/HighlightCard.tsx @@ -1,7 +1,7 @@ import { faArrowAltCircleRight as linkIcon } from '@fortawesome/free-regular-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { useElementRef } from '@shlinkio/shlink-frontend-kit'; -import type { FC, PropsWithChildren, ReactNode } from 'react'; +import type { FC, PropsWithChildren, ReactNode, RefObject } from 'react'; import { Link } from 'react-router'; import { Card, CardText, CardTitle, UncontrolledTooltip } from 'reactstrap'; import './HighlightCard.scss'; @@ -22,7 +22,9 @@ export const HighlightCard: FC = ({ children, title, link, t {title} {children} - {tooltip && {tooltip}} + {tooltip && ( + } placement="bottom">{tooltip} + )} ); }; diff --git a/src/short-urls/helpers/ShortUrlStatus.tsx b/src/short-urls/helpers/ShortUrlStatus.tsx index 8a93f998..17b895af 100644 --- a/src/short-urls/helpers/ShortUrlStatus.tsx +++ b/src/short-urls/helpers/ShortUrlStatus.tsx @@ -3,7 +3,7 @@ import { faCalendarXmark, faCheck, faLinkSlash } from '@fortawesome/free-solid-s import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { useElementRef } from '@shlinkio/shlink-frontend-kit'; import { isBefore } from 'date-fns'; -import type { FC, ReactNode } from 'react'; +import type { FC, ReactNode, RefObject } from 'react'; import { UncontrolledTooltip } from 'reactstrap'; import type { ShlinkShortUrl } from '../../api-contract'; import { formatHumanFriendly, now, parseISO } from '../../utils/dates/helpers/date'; @@ -78,7 +78,7 @@ export const ShortUrlStatus: FC = ({ shortUrl }) => { - + } placement="bottom"> {description} diff --git a/src/short-urls/helpers/ShortUrlVisitsCount.tsx b/src/short-urls/helpers/ShortUrlVisitsCount.tsx index 1d21737e..877801ca 100644 --- a/src/short-urls/helpers/ShortUrlVisitsCount.tsx +++ b/src/short-urls/helpers/ShortUrlVisitsCount.tsx @@ -2,6 +2,7 @@ import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { useElementRef } from '@shlinkio/shlink-frontend-kit'; import { clsx } from 'clsx'; +import type { RefObject } from 'react'; import { UncontrolledTooltip } from 'reactstrap'; import type { ShlinkShortUrl } from '../../api-contract'; import { formatHumanFriendly, parseISO } from '../../utils/dates/helpers/date'; @@ -45,7 +46,7 @@ export const ShortUrlVisitsCount = ( - + } placement="bottom">
    {maxVisits && (
  • diff --git a/src/utils/components/InfoTooltip.tsx b/src/utils/components/InfoTooltip.tsx index 1b5a9e8a..0470338b 100644 --- a/src/utils/components/InfoTooltip.tsx +++ b/src/utils/components/InfoTooltip.tsx @@ -2,7 +2,7 @@ import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import type { Placement } from '@popperjs/core'; import { useElementRef } from '@shlinkio/shlink-frontend-kit'; -import type { FC, PropsWithChildren } from 'react'; +import type { FC, PropsWithChildren, RefObject } from 'react'; import { UncontrolledTooltip } from 'reactstrap'; export type InfoTooltipProps = PropsWithChildren<{ @@ -18,7 +18,9 @@ export const InfoTooltip: FC = ({ className = '', placement, c - {children} + } placement={placement}> + {children} + ); };