reduce ResizeObserver number
All checks were successful
/ depoly (push) Successful in 1m28s

This commit is contained in:
thislight 2025-03-15 14:46:43 +08:00
parent 8f7d28d525
commit c41a8e31d1
7 changed files with 165 additions and 6 deletions

BIN
bun.lockb

Binary file not shown.

View file

@ -52,6 +52,7 @@
"@solid-primitives/map": "^0.4.13", "@solid-primitives/map": "^0.4.13",
"@solid-primitives/page-visibility": "^2.0.17", "@solid-primitives/page-visibility": "^2.0.17",
"@solid-primitives/resize-observer": "^2.0.26", "@solid-primitives/resize-observer": "^2.0.26",
"@solid-primitives/static-store": "^0.1.0",
"@solidjs/router": "^0.15.2", "@solidjs/router": "^0.15.2",
"@suid/icons-material": "^0.8.1", "@suid/icons-material": "^0.8.1",
"@suid/material": "^0.18.0", "@suid/material": "^0.18.0",

View file

@ -33,6 +33,7 @@ import { Service } from "./serviceworker/services.js";
import { makeEventListener } from "@solid-primitives/event-listener"; import { makeEventListener } from "@solid-primitives/event-listener";
import { ServiceWorkerProvider } from "./platform/host.js"; import { ServiceWorkerProvider } from "./platform/host.js";
import StackedRouter from "./platform/StackedRouter.js"; import StackedRouter from "./platform/StackedRouter.js";
import {ResizeObserverBoundary} from "~platform/resize-observer.jsx";
const AccountSignIn = lazy(() => import("./accounts/SignIn.js")); const AccountSignIn = lazy(() => import("./accounts/SignIn.js"));
const AccountMastodonOAuth2Callback = lazy( const AccountMastodonOAuth2Callback = lazy(
@ -157,6 +158,7 @@ const App: Component = () => {
}} }}
> >
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<ResizeObserverBoundary>
<AppLocaleProvider <AppLocaleProvider
value={{ value={{
language: lang, language: lang,
@ -176,6 +178,7 @@ const App: Component = () => {
</ServiceWorkerProvider> </ServiceWorkerProvider>
</ClientProvider> </ClientProvider>
</AppLocaleProvider> </AppLocaleProvider>
</ResizeObserverBoundary>
</ThemeProvider> </ThemeProvider>
</ErrorBoundary> </ErrorBoundary>
); );

View file

@ -1,4 +1,4 @@
import { createElementSize } from "@solid-primitives/resize-observer"; import { createElementSize } from "~platform/resize-observer";
import { import {
JSX, JSX,
Show, Show,

View file

@ -10,7 +10,7 @@ import {
} from "solid-js"; } from "solid-js";
import { Dynamic, type DynamicProps } from "solid-js/web"; import { Dynamic, type DynamicProps } from "solid-js/web";
import MasonryLayout from "masonry-layout"; import MasonryLayout from "masonry-layout";
import { createElementSize } from "@solid-primitives/resize-observer"; import { createElementSize } from "~platform/resize-observer";
import "./Masonry.css"; import "./Masonry.css";
type MasonryContainer = type MasonryContainer =

View file

@ -0,0 +1,158 @@
import {
createContext,
createEffect,
onCleanup,
sharedConfig,
useContext,
type JSX,
} from "solid-js";
import { isDev, isServer } from "solid-js/web";
import { createStaticStore } from "@solid-primitives/static-store";
export type ObserveCallback<E extends Element> = (
entry: ResizeObserverEntry & { readonly target: E },
) => void;
export type ObserveElement = <E extends Element = Element>(
element: E,
callback: ObserveCallback<E>,
) => () => void;
const ResizeObserverContext = /* @__PURE__ */ createContext<ObserveElement>();
export function useResizeObserver() {
const observe = useContext(ResizeObserverContext);
if (isDev && !observe) {
throw new TypeError(
"ObserverElement is not found, this function must be called in <ResizeOberserBoundary />",
);
}
return observe!;
}
function ResizeObserverBoundaryClient(props: { children: JSX.Element }) {
const map = new Map<
Element,
ObserveCallback<Element> | ObserveCallback<Element>[]
>();
const observer = new ResizeObserver((entries) => {
for (const entry of entries) {
const callback = map.get(entry.target);
if (!callback) return;
if (Array.isArray(callback)) {
for (const f of callback) {
f(entry);
}
} else {
callback(entry);
}
}
});
onCleanup(() => {
observer.disconnect();
});
const observe: ObserveElement = (
element: Element,
callback: ObserveCallback<any>,
) => {
const callbacks = map.get(element);
if (!callbacks) {
map.set(element, callback);
observer.observe(element);
} else if (Array.isArray(callbacks)) {
callbacks.push(callback);
} else {
map.set(element, [callbacks, callback]);
}
return () => {
const callbacks = map.get(element);
if (callbacks === null) {
observer.unobserve(element);
} else if (Array.isArray(callbacks)) {
const idx = callbacks.indexOf(callback);
if (idx !== -1) {
callbacks.splice(idx, 1);
}
if (callbacks.length === 0) {
observer.unobserve(element);
map.delete(element);
}
} else {
observer.unobserve(element);
map.delete(element);
}
};
};
return (
<ResizeObserverContext.Provider value={observe}>
{props.children}
</ResizeObserverContext.Provider>
);
}
function ResizeObserverBoundaryServer(props: { children: JSX.Element }) {
return (
<ResizeObserverContext.Provider
value={(() => {}) as unknown as ObserveElement}
>
{props.children}
</ResizeObserverContext.Provider>
);
}
export const ResizeObserverBoundary = isServer
? ResizeObserverBoundaryServer
: ResizeObserverBoundaryClient;
const ELEMENT_SIZE_FALLBACK = { width: null, height: null };
function getElementSize(target: Element) {
if (isServer || !target) {
return { ...ELEMENT_SIZE_FALLBACK };
}
const { width, height } = target.getBoundingClientRect();
return { width, height };
}
export type NullableSize = {width: number | null, height: number | null}
export function createElementSize(
target: Element | (() => Element | undefined | null | false),
): Readonly<NullableSize> {
if (isServer) {
return ELEMENT_SIZE_FALLBACK;
}
const isFn = typeof target === "function";
const [size, setSize] = createStaticStore(
sharedConfig.context || isFn
? ELEMENT_SIZE_FALLBACK
: getElementSize(target),
);
const callback: ObserveCallback<Element> = (entry) => {
setSize(getElementSize(entry.target));
};
const observe = useResizeObserver();
if (isFn) {
createEffect(() => {
const el = target();
if (el) {
setSize(getElementSize(el));
const unobserve = observe(el, callback);
onCleanup(unobserve);
}
});
} else {
const unobserve = observe(target, callback);
onCleanup(unobserve);
}
return size;
}
export { useWindowSize } from "@solid-primitives/resize-observer";

View file

@ -12,10 +12,7 @@ import {
} from "solid-js"; } from "solid-js";
import MediaViewer from "../MediaViewer"; import MediaViewer from "../MediaViewer";
import { render } from "solid-js/web"; import { render } from "solid-js/web";
import { import { createElementSize, useWindowSize } from "~platform/resize-observer";
createElementSize,
useWindowSize,
} from "@solid-primitives/resize-observer";
import { useStore } from "@nanostores/solid"; import { useStore } from "@nanostores/solid";
import { $settings } from "../../settings/stores"; import { $settings } from "../../settings/stores";
import { averageColorHex } from "~platform/blurhash"; import { averageColorHex } from "~platform/blurhash";