Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use mixins and decorators for scroll restoration and tippy cleanup #2415

Merged
merged 6 commits into from
Apr 11, 2024

Conversation

matc-pub
Copy link
Collaborator

Description

Mixins prevent repetitions across multiple components.

Without decorators the use of a mixin would roughly look like this:

class Home_ { /* ... */ }
export const Home = mixin(Home_);

With decorators:

@mixin
export class Home { /* ... */ }

The class decorator functions (the mixins) in this PR are compatible with
"legacy" and "2023-11" proposal-decorators versions. "legacy" transpiles to
slightly smaller javascript. (Switching between versions requires changes in
tsconfig and babelrc.)

Typescript requires two arguments for non-legacy class decorator functions. I
had to add { "argsIgnorePattern": "^_" } to no-unused-vars.

Commits

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".

Dependency already exists
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).
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".
Comment on lines +38 to +50
queueMicrotask(() => {
requested = false;
if (shownInstances.size) {
// Avoid randomly closing tooltips.
return;
}
// delegate from tippy.js creates tippy instances when needed, but only
// destroys them when the delegate instance is destroyed.
const current = instance?.reference ?? null;
destroyTippy();
setupTippy({ current });
});
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there is an edge case triggering the tippy memory leak warning. Positioning the mouse over a content action dropdown button, refreshing the page and then clicking without moving the mouse.

Copy link
Member

@dessalines dessalines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this and it seems to work well. Not really a huge fan of these OO hacks, but it does simplify both a lot.

Copy link
Member

@SleeplessOne1917 SleeplessOne1917 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't even know mixins were a thing. I'll have to look into using them for modals as well.

@SleeplessOne1917 SleeplessOne1917 enabled auto-merge (squash) April 11, 2024 17:16
@SleeplessOne1917 SleeplessOne1917 merged commit e48590b into LemmyNet:main Apr 11, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants