From 27c3127699bbac6fb2b83b26c4137680ea23c9ad Mon Sep 17 00:00:00 2001 From: Corbin Crutchley Date: Fri, 23 Jun 2023 21:01:42 -0700 Subject: [PATCH] chore: get things to stop throwing errors --- astro.config.ts | 3 +- package-lock.json | 119 ++++++++++++------ package.json | 7 +- .../pagination/pagination-popover.tsx | 37 ++++++ src/components/pagination/pagination.tsx | 119 ++++++++++-------- 5 files changed, 194 insertions(+), 91 deletions(-) create mode 100644 src/components/pagination/pagination-popover.tsx diff --git a/astro.config.ts b/astro.config.ts index 3806e172..ebcd6277 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -28,7 +28,7 @@ export default defineConfig({ site: siteUrl, integrations: [ image(), - preact(), + preact({ compat: true }), mdx(), sitemap({ changefreq: ChangeFreq.DAILY, @@ -46,6 +46,7 @@ export default defineConfig({ vite: { ssr: { external: ["svgo"], + noExternal: ["@floating-ui/react", "@floating-ui/react-dom"], }, plugins: [svgr()], }, diff --git a/package-lock.json b/package-lock.json index cb079d91..e4137f67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.3.0-alpha.1", "license": "MPL-2.0", "dependencies": { + "@floating-ui/react": "^0.24.3", "medium-zoom": "^1.0.8", "preact": "^10.15.1" }, @@ -25,7 +26,6 @@ "@testing-library/preact": "^3.2.3", "@types/jest": "^29.4.0", "@types/node": "^18.13.0", - "@types/react": "^18.0.33", "@types/uuid": "^9.0.2", "@typescript-eslint/eslint-plugin": "^5.60.0", "@typescript-eslint/parser": "^5.60.0", @@ -60,7 +60,6 @@ "prettier-plugin-astro": "^0.10.0", "probe-image-size": "^7.2.3", "puppeteer-core": "^10.4.0", - "react": "^18.2.0", "rehype-raw": "^6.1.1", "rehype-retext": "^3.0.2", "rehype-slug-custom-id": "^1.1.0", @@ -1226,6 +1225,45 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.3.1.tgz", + "integrity": "sha512-Bu+AMaXNjrpjh41znzHqaz3r2Nr8hHuHZT6V2LBKMhyMl0FgKA62PNYbqnfgmzOhoWZj70Zecisbo4H1rotP5g==" + }, + "node_modules/@floating-ui/dom": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.4.2.tgz", + "integrity": "sha512-VKmvHVatWnewmGGy+7Mdy4cTJX71Pli6v/Wjb5RQBuq5wjUYx+Ef+kRThi8qggZqDgD8CogCpqhRoVp3+yQk+g==", + "dependencies": { + "@floating-ui/core": "^1.3.1" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.24.3", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.24.3.tgz", + "integrity": "sha512-wWC9duiog4HmbgKSKObDRuXqMjZR/6m75MIG+slm5CVWbridAjK9STcnCsGYmdpK78H/GmzYj4ADVP8paZVLYQ==", + "dependencies": { + "@floating-ui/react-dom": "^2.0.1", + "aria-hidden": "^1.1.3", + "tabbable": "^6.0.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.1.tgz", + "integrity": "sha512-rZtAmSht4Lry6gdhAJDrCp/6rKN7++JnL1/Anbr/DdeyYXQPxvg/ivrbYvJulbRf4vL8b212suwMM2lxbv+RQA==", + "dependencies": { + "@floating-ui/dom": "^1.3.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -3478,23 +3516,6 @@ "dev": true, "peer": true }, - "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true - }, - "node_modules/@types/react": { - "version": "18.0.33", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.33.tgz", - "integrity": "sha512-sHxzVxeanvQyQ1lr8NSHaj0kDzcNiGpILEVt69g9S31/7PfMvNCKLKcsHw4lYKjs3cGNJjXSP4mYzX43QlnjNA==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, "node_modules/@types/resolve": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", @@ -3516,12 +3537,6 @@ "@types/node": "*" } }, - "node_modules/@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", - "dev": true - }, "node_modules/@types/semver": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", @@ -4303,6 +4318,17 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/aria-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.3.tgz", + "integrity": "sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/aria-query": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", @@ -6323,12 +6349,6 @@ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "dev": true }, - "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true - }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -13044,8 +13064,7 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "3.14.1", @@ -13867,7 +13886,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, + "peer": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -17077,7 +17096,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dev": true, + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -17085,6 +17104,19 @@ "node": ">=0.10.0" } }, + "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==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -18460,6 +18492,15 @@ "node": ">=v12.22.7" } }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, "node_modules/section-matter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", @@ -19602,6 +19643,11 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/tabbable": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.1.2.tgz", + "integrity": "sha512-qCN98uP7i9z0fIS4amQ5zbGBOq+OSigYeGvPy7NDk8Y9yncqDZ9pRPgfsc2PJIVM9RrJj7GIfuRgmjoUU9zTHQ==" + }, "node_modules/tar": { "version": "6.1.11", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", @@ -20076,8 +20122,7 @@ "node_modules/tslib": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", - "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", - "dev": true + "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==" }, "node_modules/tsutils": { "version": "3.21.0", diff --git a/package.json b/package.json index 8a1048aa..3f9822c0 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,6 @@ "@testing-library/preact": "^3.2.3", "@types/jest": "^29.4.0", "@types/node": "^18.13.0", - "@types/react": "^18.0.33", "@types/uuid": "^9.0.2", "@typescript-eslint/eslint-plugin": "^5.60.0", "@typescript-eslint/parser": "^5.60.0", @@ -85,7 +84,6 @@ "prettier": "^2.8.8", "prettier-plugin-astro": "^0.10.0", "puppeteer-core": "^10.4.0", - "react": "^18.2.0", "rehype-raw": "^6.1.1", "rehype-retext": "^3.0.2", "rehype-slug-custom-id": "^1.1.0", @@ -114,7 +112,12 @@ "*.{js,ts,astro,jsx}": "prettier --write" }, "dependencies": { + "@floating-ui/react": "^0.24.3", "medium-zoom": "^1.0.8", "preact": "^10.15.1" + }, + "overrides": { + "react": "npm:@preact/compat@latest", + "react-dom": "npm:@preact/compat@latest" } } diff --git a/src/components/pagination/pagination-popover.tsx b/src/components/pagination/pagination-popover.tsx new file mode 100644 index 00000000..9c2ca4a1 --- /dev/null +++ b/src/components/pagination/pagination-popover.tsx @@ -0,0 +1,37 @@ +import { useClick, useFloating, useInteractions } from "@floating-ui/react"; +import { useState } from "preact/hooks"; +import { Fragment } from "preact"; +import { createPortal } from "preact/compat"; + +export function PaginationPopover() { + const [isOpen, setIsOpen] = useState(false); + + const { refs, floatingStyles, context } = useFloating({ + open: isOpen, + onOpenChange: setIsOpen, + }); + + const click = useClick(context); + + const { getReferenceProps, getFloatingProps } = useInteractions([click]); + + const portal = createPortal( +
+ Floating element +
, + document.querySelector("body") + ); + + return ( + +
+ Reference element +
+ {isOpen && portal} +
+ ); +} diff --git a/src/components/pagination/pagination.tsx b/src/components/pagination/pagination.tsx index 925d4512..8ec28f41 100644 --- a/src/components/pagination/pagination.tsx +++ b/src/components/pagination/pagination.tsx @@ -4,6 +4,8 @@ import { Button } from "components/base"; import forward from "src/icons/forward.svg?raw"; import back from "src/icons/back.svg?raw"; import more from "src/icons/more-horizontal.svg?raw"; +import { PaginationPopover } from "components/pagination/pagination-popover"; +import { useEffect, useState } from "preact/hooks"; const PAGE_BUTTON_COUNT = 6; @@ -15,11 +17,13 @@ interface PaginationProps { getPageHref?: (pageNum: number) => string; } -function PaginationButton(props: { pageNum: number, selected: boolean, href: string }) { +function PaginationButton(props: { + pageNum: number; + selected: boolean; + href: string; +}) { return ( -
  • +
  • - ) + ); } function PaginationMenu(props: Pick) { return ( -
  • +
  • - ) + ); +} + +/** + * This prevents the pagination menu from rendering on SSR, which throws errors + */ +function PaginationMenuWrapper( + props: Pick +) { + const [shouldRender, setShouldRender] = useState(false); + + useEffect(() => { + setShouldRender(true); + }); + + if (!shouldRender) return null; + + return ; } export const Pagination = ({ @@ -55,8 +74,7 @@ export const Pagination = ({ getPageHref = (pageNum: number) => `${rootURL}${pageNum}`, }: PaginationProps) => { // if there's only one page, don't render anything - if (page.currentPage === 1 && page.lastPage < 2) - return <>; + if (page.currentPage === 1 && page.lastPage < 2) return <>; const isPreviousEnabled = page.currentPage > 1; const isNextEnabled = page.currentPage < page.lastPage; @@ -66,63 +84,62 @@ export const Pagination = ({ // if the current page is close to the end, dots should be before so that the end is continuous const isDotsFirst = page.lastPage - page.currentPage < PAGE_BUTTON_COUNT; - const firstPageNum = Math.max(2, Math.min(page.lastPage - PAGE_BUTTON_COUNT, page.currentPage - 1)); + const firstPageNum = Math.max( + 2, + Math.min(page.lastPage - PAGE_BUTTON_COUNT, page.currentPage - 1) + ); const pages = [ // first page is always displayed 1, isDotsFirst && "...", - ...Array(PAGE_BUTTON_COUNT).fill(0).map((_, i) => i + firstPageNum), + ...Array(PAGE_BUTTON_COUNT) + .fill(0) + .map((_, i) => i + firstPageNum), !isDotsFirst && "...", // last page is always displayed page.lastPage, ].filter( // ensure that displayed pages are within the desired range - i => (i === "..." && isDotsEnabled) || (+i > 0 && +i <= page.lastPage) + (i) => (i === "..." && isDotsEnabled) || (+i > 0 && +i <= page.lastPage) ); - return <> -
    - +
    + + ); };