From e48590b9d6c37403c7ef64d3587d082d645b68cd Mon Sep 17 00:00:00 2001 From: matc-pub <161147791+matc-pub@users.noreply.github.com> Date: Thu, 11 Apr 2024 19:18:07 +0200 Subject: [PATCH] Use mixins and decorators for scroll restoration and tippy cleanup (#2415) * Enable @babel/plugin-proposal-decorators Dependency already exists * Use tippy.js delegate addon, cleanup tippy instances from a mixin. The delegate addon creates tippy instances from mouse and touch events with a matching `event.target`. This is initially significantly cheaper than creating all instances at once. The addon keeps all created tippy instances alive until it is destroyed itself. `tippyMixin` destroys the addon instance after every render, as long as all instances are hidden. This drops some tippy instances that may have to be recreated later (e.g when the mouse moves over the trigger again), but is otherwise fairly cheap (creates one tippy instance). * Restore scroll positions when resource loading settles. The history module generates a random string (`location.key`) for every browser history entry. The names for saved positions include this key. The position is saved before a route component unmounts or before the `location.key` changes. The `scrollMixin` tires to restore the scroll position after every change of `location.key`. It only does so after the first render for which the route components `loadingSettled()` returns true. Things like `scrollToComments` should only scroll when `history.action` is not "POP". * Drop individual scrollTo calls * Scroll to comments without reloading post --------- Co-authored-by: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com> --- .babelrc | 7 +- .eslintrc.json | 4 + src/client/index.tsx | 2 + src/shared/components/app/app.tsx | 12 +- src/shared/components/app/navbar.tsx | 2 + .../components/comment/comment-node.tsx | 5 +- .../components/comment/comment-report.tsx | 2 + .../common/content-actions/action-button.tsx | 2 + .../content-action-dropdown.tsx | 2 + src/shared/components/common/emoji-picker.tsx | 2 + .../components/common/markdown-textarea.tsx | 12 +- src/shared/components/common/moment-time.tsx | 2 + .../components/common/password-input.tsx | 2 + src/shared/components/common/user-badges.tsx | 4 +- src/shared/components/common/vote-buttons.tsx | 13 +- .../components/community/communities.tsx | 9 +- .../components/community/community-form.tsx | 2 + src/shared/components/community/community.tsx | 28 ++-- .../components/community/create-community.tsx | 8 +- src/shared/components/community/sidebar.tsx | 2 + src/shared/components/home/admin-settings.tsx | 8 +- src/shared/components/home/emojis-form.tsx | 2 + src/shared/components/home/home.tsx | 33 ++-- src/shared/components/home/instances.tsx | 7 + src/shared/components/home/login-reset.tsx | 8 +- src/shared/components/home/login.tsx | 2 + src/shared/components/home/setup.tsx | 8 +- src/shared/components/home/signup.tsx | 17 +- src/shared/components/home/site-sidebar.tsx | 2 + src/shared/components/home/tagline-form.tsx | 2 + src/shared/components/mixins/scroll-mixin.ts | 145 ++++++++++++++++++ src/shared/components/mixins/tippy-mixin.ts | 25 +++ src/shared/components/modlog.tsx | 7 + src/shared/components/person/cake-day.tsx | 2 + src/shared/components/person/inbox.tsx | 16 +- .../components/person/password-change.tsx | 8 +- .../components/person/person-details.tsx | 5 - src/shared/components/person/profile.tsx | 15 +- .../person/registration-applications.tsx | 10 +- src/shared/components/person/reports.tsx | 12 +- src/shared/components/person/settings.tsx | 12 +- src/shared/components/person/verify-email.tsx | 8 +- src/shared/components/post/create-post.tsx | 2 + src/shared/components/post/post-form.tsx | 2 - src/shared/components/post/post-listing.tsx | 7 +- src/shared/components/post/post-report.tsx | 2 + src/shared/components/post/post.tsx | 41 ++--- .../create-private-message.tsx | 7 + .../private_message/private-message-form.tsx | 5 - .../private-message-report.tsx | 2 + .../private_message/private-message.tsx | 2 + src/shared/components/remote-fetch.tsx | 8 +- src/shared/components/search.tsx | 18 ++- src/shared/tippy.ts | 64 ++++++-- src/shared/utils/browser/index.ts | 8 +- src/shared/utils/browser/next-user-action.ts | 46 ++++++ .../utils/browser/restore-scroll-position.ts | 6 - .../utils/browser/save-scroll-position.ts | 6 - src/shared/utils/browser/snap-to-top.ts | 3 + src/shared/utils/helpers/index.ts | 2 + src/shared/utils/helpers/resources-settled.ts | 5 + tsconfig.json | 2 +- 62 files changed, 571 insertions(+), 143 deletions(-) create mode 100644 src/shared/components/mixins/scroll-mixin.ts create mode 100644 src/shared/components/mixins/tippy-mixin.ts create mode 100644 src/shared/utils/browser/next-user-action.ts delete mode 100644 src/shared/utils/browser/restore-scroll-position.ts delete mode 100644 src/shared/utils/browser/save-scroll-position.ts create mode 100644 src/shared/utils/browser/snap-to-top.ts create mode 100644 src/shared/utils/helpers/resources-settled.ts diff --git a/.babelrc b/.babelrc index fbfb0025..0b2c6939 100644 --- a/.babelrc +++ b/.babelrc @@ -13,7 +13,12 @@ ["@babel/typescript", { "isTSX": true, "allExtensions": true }] ], "plugins": [ - "@babel/plugin-transform-runtime", + ["@babel/plugin-proposal-decorators", { "version": "legacy" }], + [ + "@babel/plugin-transform-runtime", + // version defaults to 7.0.0 for which non-legacy decorators produce duplicate code + { "version": "^7.24.3" } + ], ["babel-plugin-inferno", { "imports": true }], ["@babel/plugin-transform-class-properties", { "loose": true }] ] diff --git a/.eslintrc.json b/.eslintrc.json index 4d0e7562..651ba006 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -21,6 +21,10 @@ "@typescript-eslint/explicit-module-boundary-types": 0, "@typescript-eslint/no-empty-function": 0, "@typescript-eslint/no-non-null-assertion": 0, + "@typescript-eslint/no-unused-vars": [ + "error", + { "argsIgnorePattern": "^_" } + ], "arrow-body-style": 0, "curly": 0, "eol-last": 0, diff --git a/src/client/index.tsx b/src/client/index.tsx index f2518e8f..db0a9ef7 100644 --- a/src/client/index.tsx +++ b/src/client/index.tsx @@ -16,6 +16,8 @@ async function startClient() { verifyDynamicImports(true).then(x => console.log(x)); }; + window.history.scrollRestoration = "manual"; + initializeSite(window.isoData.site_res); lazyHighlightjs.enableLazyLoading(); diff --git a/src/shared/components/app/app.tsx b/src/shared/components/app/app.tsx index 30f445f7..1538b045 100644 --- a/src/shared/components/app/app.tsx +++ b/src/shared/components/app/app.tsx @@ -13,15 +13,25 @@ import { Navbar } from "./navbar"; import "./styles.scss"; import { Theme } from "./theme"; import AnonymousGuard from "../common/anonymous-guard"; +import { destroyTippy, setupTippy } from "../../tippy"; export class App extends Component { private isoData: IsoDataOptionalSite = setIsoData(this.context); private readonly mainContentRef: RefObject; + private readonly rootRef = createRef(); constructor(props: any, context: any) { super(props, context); this.mainContentRef = createRef(); } + componentDidMount(): void { + setupTippy(this.rootRef); + } + + componentWillUnmount(): void { + destroyTippy(); + } + handleJumpToContent(event) { event.preventDefault(); this.mainContentRef.current?.focus(); @@ -34,7 +44,7 @@ export class App extends Component { return ( <> -
+