1
0
Fork 0
firefox/browser/extensions/newtab/content-src/lib/utils.jsx
Daniel Baumann 5e9a113729
Adding upstream version 140.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-25 09:37:52 +02:00

112 lines
3.9 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import { useEffect, useRef } from "react";
/**
* A custom react hook that sets up an IntersectionObserver to observe a single
* or list of elements and triggers a callback when the element comes into the viewport
* Note: The refs used should be an array type
* @function useIntersectionObserver
* @param {function} callback - The function to call when an element comes into the viewport
* @param {Object} options - Options object passed to Intersection Observer:
* https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver#options
* @param {Boolean} [isSingle = false] Boolean if the elements are an array or single element
*
* @returns {React.MutableRefObject} a ref containing an array of elements or single element
*
*
*
*/
function useIntersectionObserver(callback, threshold = 0.3) {
const elementsRef = useRef([]);
useEffect(() => {
const observer = new IntersectionObserver(
entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
callback(entry.target);
observer.unobserve(entry.target);
}
});
},
{ threshold }
);
elementsRef.current.forEach(el => {
if (el) {
observer.observe(el);
}
});
// Cleanup function to disconnect observer on unmount
return () => observer.disconnect();
}, [callback, threshold]);
return elementsRef;
}
/**
* Determines the active card size ("small", "medium", or "large") based on the screen width
* and class names applied to the card element at the time of an event (example: click)
*
* @param {number} screenWidth - The current window width (in pixels).
* @param {string | string[]} classNames - A string or array of class names applied to the sections card.
* @param {boolean[]} sectionsEnabled - If sections is not enabled, all cards are `medium-card`
* @param {number} flightId - Error ege case: This function should not be called on spocs, which have flightId
* @returns {"small-card" | "medium-card" | "large-card" | null} The active card type, or null if none is matched.
*/
function getActiveCardSize(screenWidth, classNames, sectionsEnabled, flightId) {
// Only applies to sponsored content
if (flightId) {
return "spoc";
}
// Default layout only supports `medium-card`
if (!sectionsEnabled) {
// Missing arguments
return "medium-card";
}
// Return null if no values are available
if (!screenWidth || !classNames) {
// Missing arguments
return null;
}
const classList = classNames.split(" ");
// Each breakpoint corresponds to a minimum screen width and its associated column class
const breakpoints = [
{ min: 1374, column: "col-4" }, // $break-point-sections-variant
{ min: 1122, column: "col-3" }, // $break-point-widest
{ min: 724, column: "col-2" }, // $break-point-layout-variant
{ min: 0, column: "col-1" }, // (default layout)
];
const cardTypes = ["small", "medium", "large"];
// Determine which column is active based on the current screen width
const currColumnCount = breakpoints.find(bp => screenWidth >= bp.min).column;
// Match the card type for that column count
for (let type of cardTypes) {
const className = `${currColumnCount}-${type}`;
if (classList.includes(className)) {
// Special case: below $break-point-medium (610px), report `col-1-small` as medium
if (
screenWidth < 610 &&
currColumnCount === "col-1" &&
type === "small"
) {
return "medium-card";
}
// Will be either "small-card", "medium-card", or "large-card"
return `${type}-card`;
}
}
return null;
}
export { useIntersectionObserver, getActiveCardSize };