Infinite CSS/JS image carousel using swipe left/swipe right and large number of images

I want to create a static image gallery with a carousel that can be used with swipe left/swipe right gestures.

Currently I have a scrollable view that uses the scroll-snap features of CSS. It works like intended, but has an optical issue.

As the number of images can get fairly large, I have an ugly scroll effect when directly jumping to a certain image by clicking on a thumbnail. AFAIK there is no other way than using scroll()/scrollTo()/etc. to set the viewport of the carousel to a certain position.

While thinking about a workaround, I had the idea to create 3 scrollable <div> elements and combine them to an infinite scroller. They will have a fixed size to avoid the ugly scroll effect, and to not have a huge horizontal view with a large number of images. The hidden <div> elements will be preloaded with the next/previous images in the background and are shown when the user reaches the end of the currently visible <div>.

What do you think about this? Does this sound sensible? I’m not an expert regarding CSS/JS, just learning and trying to create things I want to have.

How to download a file in JavaScript without using anchor tag download attr? [duplicate]

I need to download a file to the user without using the <a download></a> hack, but am unable to find an alternative method. Basically, with this method, it just downloads the file without the “Save as” file prompt showing up. I want the “Save as” file dialog to show up so that the user can rename the file or pick which folder it should be in.

Without asking the user to change their settings, how can this be done? I’ve seen this done in many web apps, so I know it’s possible, but many web searches and Stack Overflow searches return nothing useful.

Node.js fetch to BoardGameGeek API always returns 403 Forbidden despite using API token [closed]

I’m trying to fetch board game information from the BoardGameGeek XML API using Node.js. I have a valid API token, but every request returns a 403 Forbidden response.

Here’s my current setup:

async function getInfoFromBGG(gameId) {

  const url = `https://rpggeek.com/xmlapi2/thing?id=${gameId}`

  let result
  const controller = new AbortController()
  const timeoutId = setTimeout(() => controller.abort(), 5000)

  try {
    const response = await fetch(url, {
      headers: {
        "Authorization": "Bearer i put my token here",
        "User-Agent": "BoardgameAlbum/1.0 ([email protected])",
        "Accept": "application/xml"
      }
    });

    clearTimeout(timeoutId)

    if (!response.ok) {
      console.log(response)
      console.log(`HTTP Error: ${response.status} ${response.statusText}`)
      return { error: "Failed to fetch from BGG" }
    }

    const xml = await response.text()
    const parser = new DOMParser()
    result = parser.parseFromString(xml, "text/xml")

    const item = result.querySelector("item")
    if (!item) {
      return { error: "Game not found" }
    }

    return {
      id: item.getAttribute("id"),
      name: item.querySelector("name[type='primary']")?.getAttribute("value"),
      yearPublished: item.querySelector("yearpublished")?.getAttribute("value"),
    }

  } catch (error) {
    clearTimeout(timeoutId)
    console.error("Fetch error:", error)
    if (error.name === "AbortError") {
      return { error: "Request timed out" }
    }
    return { error: "Internal server error: " + error.message }
  }
}

the same code will work without any problem in browser, but i have to remove the token if i want the code to be executed perfectly. i have tried different approaches but noting helped. the code wont run in server.

I’m trying to fetch game data from the BoardGameGeek API. I’ve tried several approaches, both from the frontend and Node.js backend:

Using fetch from the frontend with Authorization: Bearer and User-Agent headers.

Adding Accept: application/xml and other headers recommended by BGG.

Using node-fetch in Node.js with the same headers.

Using the bgg-xml-api-client package in Node.js.

Verified that the API token is valid and not expired.

Despite this, I always get either:

CORS errors when calling from the frontend, or

403 Forbidden when calling from Node.js, even with correct headers.

I expected to be able to fetch game data from BGG API from my server without these errors.

Has anyone successfully fetched data from BGG API recently? Are there special requirements for browser requests or server requests with their token?

JS Slow http request [closed]

i have a website that is selling some products online, and everyday there are updates, i try to be the first that is getting those products, and i created a bot in js runned by tampermonkey to make this automation and get all first, it worked well till a moment, site started to run slow for me ( and maybe for all rest users also) and when i was trying to buy the products when the update was launched, other users(or maybe one specific user) is buying all what i need before me, i tried to change the script , so that it will not click the ui elements, but trough http requests and stuff, still the server response are way too slow to get in front and buy all the things, is there any solution to make this happen and be the first ? thank you for the attention

i tried ui auto clicker script, and http requests

Arabic text gets corrupted to “E1-(‘ (‘D9’DE” when creating PDF annotations with @iwater/annotpdf library

I’m using the @iwater/annotpdf library to create PDF annotations in an Angular application. When I try to create free text annotations with Arabic text, the text gets corrupted to unreadable characters.

Expected Result:
Arabic text should display as: مرحبا بالعالم (Hello World in Arabic)

Actual Result:
Arabic text displays as: E1-(‘ (‘D9’DE

// In my free-text-annotation.service.ts
 createFreeTextAnnotation(annotation: any): any {
  return this.annotationFactoryService.annotationFactory!.createFreeTextAnnotation({
  page: pageNumber - 1,
  rect: annotation.rect,
  contents: "مرحبا بالعالم", // Arabic text
  author: annotation.author || 'User',
  color: annotation.color || '#FF0000',
  fontSize: annotation.fontSize || 12
  });
}

What I’ve tried:

  1. Setting textAlign: ‘right’ and direction: ‘rtl’ for RTL support
  2. Using UTF-8 encoding/decoding
  3. Adding Arabic font families like “Noto Sans Arabic”
  4. Base64 encoding the text before passing to the library

Environment:

  • Angular 17

  • @iwater/annotpdf library

  • English text works fine, only Arabic text gets corrupted

Question:

How can I properly handle Arabic text in PDF annotations using the @iwater/annotpdf library? Is there a specific encoding or configuration needed for Unicode/Arabic characters?

React image drag function not working – function not detecting the mousedown on image

I am trying to build an image zoom / drag application but it is not working. I have a ‘mousedown’ event handler attached to the image I want to drag but it is not being detected. The mousedown is detected when I attached the document to the event handler but not the image, I’m struggling to understand why.

  document?.removeEventListener("mousedown", handleMouseDown);

If anyone has any suggestions I would be interested to hear them…
Thank you.

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import { useState, useEffect } from "react";
import { useRef } from "react";
import img1 from "./img1.jpg";
import img2 from "./img2.jpg";


function App() {
  const images = {
    1: img1,
    2: img2
  };

  return (
    <div>
      <ImageZoomInOut img1={img1} images={images} />
    </div>
  );
}
////////////////////////////////////////////

function ImageZoomInOut({ images }) {
  //state for img scale
  const [scale, setScale] = useState(1);
  //state for img position
  const [position, setPosition] = useState({ x: 0, y: 0 });

  //reference to the img element
  const imageRef = useRef(null);

  //zoom in function
  function handleZoomIn() {
    return setScale((scale) => scale + 0.05);
  }
  //zoom out function
  function handleZoomOut() {
    return setScale((scale) => scale - 0.05);
  }

  //image drag and zoom/////////////////////////////

  useEffect(() => {
    const image = imageRef.current;
    let isDragging = false;
    let prevPosition = { x: 0, y: 0 };

    //mouse down event handler for starting img drag

    const handleMouseDown = (e) => {
      isDragging = true;
      prevPosition = { x: e.ClientX, y: e.clientY };
    };

    //mouse move event handler for dragging img

    const handleMouseMove = (e) => {
      if (!isDragging) return;

      const deltaX = e.clientX - prevPosition.x;
      const deltaY = e.clientY - prevPosition.y;
      prevPosition = { x: e.clientX, y: e.clientY };
      setPosition((position) => ({
        x: position.x + deltaX,
        y: position.y + deltaY,
      }));
    };

    //mouse up event handler for ending img drag

    const handleMouseUp = () => {
      isDragging = false;
    };

    const image1 = document.getElementById("2");

    //add event listeners
    image1.addEventListener("mousedown", handleMouseDown);
    image1.addEventListener("mousemove", handleMouseMove);
    image1.addEventListener("mouseup", handleMouseUp);

    //remove event listners on component unmount
    return () => {
      image?.removeEventListener("mousedown", handleMouseDown);
      image?.removeEventListener("mousemove", handleMouseMove);
      image?.removeEventListener("mouseup", handleMouseUp);
    };
  }, [imageRef, scale]);

  //////////
  return (
    <div style={{ position: "relative", overflow: "hidden" }}>
      <div className="btns">
        <button className="btn1" onClick={handleZoomIn}>
          +
        </button>
        <button className="btn2" onClick={handleZoomOut}>
          -
        </button>
      </div>
      {/* image element */}
      <img
        ref={imageRef}
        id="2"
        src={images[2]}
        alt=""
        style={{
          width: "900px",
          height: "auto",
          cursor: "move",
          transform: `scale(${scale}) translate(${position.x}px, ${position.y}px)`,
        }}
        draggable={false}
        onClick={() => console.log("hi")}
      />
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

How to keep the React DateRange calendar from react-date-range focused on the end month after selecting the final date?

I’m using the DateRange component from the react-date-range library.
When I select a start date and then an end date, the calendar automatically jumps back to show the month of the start date, even if the end date is in a different month.

I would like the calendar to stay focused on the month of the end date after selection — for example, if I select October 28 as the start and December 3 as the end, I want the calendar to remain showing December, not go back to October.

Here’s a simplified version of my current code:

<DateRange
      locale={customPtBR}
      editableDateInputs={true}
      onChange={(item) => {
        setState([item.selection]);
      }}
      preventSnapRefocus="disabled"
      moveRangeOnFirstSelection={false}
      months={1}
      ranges={state}
      className="border-radius"
      minDate={new Date()}
    />

I noticed there’s a prop called onRangeFocusChange, I tried using it but the behavior doesn’t change. I also used preventSnapRefocus=”disabled” and nothing changes too.

How can I make the DateRange component stay on the end date’s month after I select the final date, instead of automatically going back to the start date’s month?

Having An Issue to know if user has paid the amount for product on order summary and payment page in ecommerce [closed]

currently i am making this website using react js + tailwind + node js + express js + mysql workbench

i am currently creating ecommerce and everything is set in whole website from adding product to cart and login and proceed the user the payment page and also we have given the option to user to enter its email and select address which user added from its user dashboard or profile seciton and also is able to pay qr code using any upi platform

and before payment the product data which user wants to order and all address and email all information is being stored in Database for tempory as order_status = pending but i want that how can make sure user has paid and once user has done payment then we will make order_status of that purticular product change to “confirmed”

this is my current recent_order databse table in which the product details would be stored

Table: recent_order
Columns:
id int AI PK
order_id varchar(100)
payment_method enum(‘COD’,’CARD’,’UPI’,’NET_BANKING’,’PAYPAL’)
payment_id varchar(150)
name varchar(150)
phone_number varchar(20)
email_id varchar(150)
address_id int
total_amount decimal(10,2)
order_status enum(‘PENDING’,’CONFIRMED’,’SHIPPED’,’DELIVERED’,’CANCELLED’,’RETURNED’)
order_placed_date datetime
order_arrived_date datetime
product_id json
created_at timestamp
updated_at timestamp
deleted_at tinyint(1)

now how can archive that without using any payment gateway ?

i am expecting that once payment is done by the user then it would check in databse if payment is done in every five seconds using setTimeout and once payment is done then it would update order_status and clear the interval of every five second check

Perl Multilanguage PDF generation [closed]

In perl any module available for multilanguage pdf generation ? if yes then please guide me for this ?

please give me some tips to how to generate multilanguage pdf genaration.
and guide me for this how to create modal in perl

i am trying but any single language show in pdf other language is hide and show box in this palce

How can I calculate the number of years between a date and today [closed]

there is a lot of questions about this situation but the best i’ve found is these 2 similar questions.

I’ve been using jQuery for a short time and I didn’t find the way to achieve what i need from my side even with these example:

1.
Calculate the number years between a historic date and today

2.
How can I calculate the number of years between two dates?

I want a div where i can display automatically each year the number of years between a specific date and today. I think jquery could be the simpliest way to achieve that ?

At this time i’m working on this part of code i’ve found who displayed the actual date in a div automatically, i don’t know how to edit it.

here is a snippet:

$(document).ready(function() {
  $(".wl-creation-date").append(new Date().getFullYear());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<span class='wl-creation-date'>+</span>

Here is my jsfiddle: https://jsfiddle.net/kodjoe/nLm8r6dy/4/

How can I calculate the number of years between a date and today in jquery

*Update my question, since i can’t use microsoft datediff-function:

there is a lot of questions about this situation but the best i’ve found is these 2 similar questions. But i didn’t find the way to achieve what i need:

1.
Calculate the number years between a historic date and today

2.
How can I calculate the number of years between two dates?

I want to create a jquery function who gives me the number between a date and today in my div ? Because at this time i can only show the actual date in my div.

here is a snippet:

$(document).ready(function() {
  $(".wl-creation-date").append(new Date().getFullYear());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<span class='wl-creation-date'>+</span>

Here is my jsfiddle: https://jsfiddle.net/kodjoe/nLm8r6dy/4/

Hardhat3: How to deploy smartcontract in script on localhost?

I’m playing with a simple project of issuing ERC20 token. Following the example in hardhat3 doc, I successifully deployed the contract on localhost with CLI as below:

  • run local blockchain npx hardhat node
  • deploy the smart contract npx hardhat ignition deploy --network localhost ignition/modules/LeoCoin.js

then interact with the smart contract in file under scripts also fine.

But got trouble when trying deploy that contract in script on loaclhost

  1. Code for ../Ignition/modules/LeoCoin.js
import { buildModule } from '@nomicfoundation/hardhat-ignition/modules';

export default buildModule('LeoCoin', (m) => {
  const LeoCoin = m.contract('LeoCoin', ['LeoCoin', 'LC', 100000]);

  return { LeoCoin };
});
  1. Code for the script I want to run
import LeoCoinModule from '../ignition/modules/LeoCoin.js';
import hre from 'hardhat';

async function main() {
  const connection = await hre.network.connect();
  const { LeoCoin } = await connection.ignition.deploy(LeoCoinModule);
  let res = await LeoCoin.getAddress();
  console.log(`LeoCoin deployed to: ${res}`);
  const accounts = await connection.ethers.getSigners();
  res = await LeoCoin.balanceOf(accounts[0].address);
  console.log(res);
}

main().catch(console.error);

And I run it with npx hardhat run scripts/script.js --network localhost

I received below result:

LeoCoin deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
Error: could not decode result data (value="0x", info={ "method": "balanceOf", "signature": "balanceOf(address)" }, code=BAD_DATA, version=6.15.0)
    at makeError (E:CodeOptionnode_modulesetherssrc.tsutilserrors.ts:698:21)
    at assert (E:CodeOptionnode_modulesetherssrc.tsutilserrors.ts:719:25)
    at Interface.decodeFunctionResult (E:CodeOptionnode_modulesetherssrc.tsabiinterface.ts:916:9)
    at staticCallResult (E:CodeOptionnode_modulesetherssrc.tscontractcontract.ts:346:35)
    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
    at async staticCall (E:CodeOptionnode_modulesetherssrc.tscontractcontract.ts:303:24)
    at async Proxy.balanceOf (E:CodeOptionnode_modulesetherssrc.tscontractcontract.ts:351:41)
    at async main (file:///E:/Code/Option/scripts/Option.js:16:9) {
  code: 'BAD_DATA',
  value: '0x',
  info: { method: 'balanceOf', signature: 'balanceOf(address)' },
  shortMessage: 'could not decode result data'
}

And I don’t see the node terminal return any message regarding deployment.

Does it mean the contract is not deployed on localhost? if yes, how to?

How to better smooth the fading edges of an arc

I am creating a frame plugin. The arc seems to be drawn okay as shown here:
enter image description here

But if you look carefully, you will notice the wild edges compared to this idle frame:
enter image description here

So, how can I smooth the edges to match the second image, given this code piece:

function drawFancyArcFrame(mainCtx, opts) {
        const {
          cx, cy, radius, width, startDeg, sweepDeg,
          color1, color2, capStyle = 'feather',
          capLengthPx = 24, pixelSize = 4
        } = opts;

        if (sweepDeg <= 0 || width <= 0) return;

        const startRad = (startDeg * Math.PI) / 180;
        const endRad   = ((startDeg + sweepDeg) * Math.PI) / 180;

        const W = mainCtx.canvas.width;
        const H = mainCtx.canvas.height;

        const off = document.createElement('canvas');
        off.width = W; off.height = H;
        const ctx = off.getContext('2d');

        const grad = ctx.createLinearGradient(0, 0, W, H);
        grad.addColorStop(0, color1);
        grad.addColorStop(1, color2);

        // draw base arc with flat ends so we can sculpt
        ctx.save();
        ctx.strokeStyle = grad;
        ctx.lineWidth = width;
        ctx.lineCap = 'butt';
        ctx.globalAlpha = 0.85;
        ctx.beginPath();
        ctx.arc(cx, cy, radius, startRad, endRad, false);
        ctx.stroke();
        ctx.restore();

        // endpoints + tangents
        const sx = cx + radius * Math.cos(startRad);
        const sy = cy + radius * Math.sin(startRad);
        const ex = cx + radius * Math.cos(endRad);
        const ey = cy + radius * Math.sin(endRad);
        const tStart = startRad + Math.PI / 2;
        const tEnd   = endRad   + Math.PI / 2;

        // erasers (destination-out)
        const eraseFeather = (x, y, ang) => {
          ctx.save();
          ctx.translate(x, y);
          ctx.rotate(ang);
          ctx.globalCompositeOperation = 'destination-out';
          const g = ctx.createLinearGradient(0, 0, capLengthPx, 0);
          g.addColorStop(0, 'rgba(0,0,0,1)');
          g.addColorStop(1, 'rgba(0,0,0,0)');
          ctx.fillStyle = g;
          ctx.fillRect(0, -width/2, capLengthPx, width);
          ctx.restore();
        };

        const eraseChop = (x, y, ang) => {
          ctx.save();
          ctx.translate(x, y);
          ctx.rotate(ang);
          ctx.globalCompositeOperation = 'destination-out';
          ctx.beginPath();
          ctx.moveTo(0, -width/2);
          ctx.lineTo(capLengthPx, 0);
          ctx.lineTo(0, width/2);
          ctx.closePath();
          ctx.fillStyle = 'rgba(0,0,0,1)';
          ctx.fill();
          ctx.restore();
        };

        const erasePixel = (x, y, ang) => {
          ctx.save();
          ctx.translate(x, y);
          ctx.rotate(ang);
          ctx.globalCompositeOperation = 'destination-out';
          const cols = Math.ceil(capLengthPx / pixelSize);
          const rows = Math.ceil(width / pixelSize);
          const y0 = -width / 2;
          for (let c = 0; c < cols; c++) {
            const frac = 1 - (c / cols);
            const activeRows = Math.max(1, Math.floor(rows * frac));
            const x0 = c * pixelSize;
            for (let r = 0; r < activeRows; r++) {
              if (Math.random() < 0.85) {
                const yCell = y0 + r * pixelSize;
                ctx.fillStyle = 'rgba(0,0,0,1)';
                ctx.fillRect(x0, yCell, pixelSize, pixelSize);
              }
            }
          }
          ctx.restore();
        };

        switch (capStyle) {
          case 'feather':
            eraseFeather(sx, sy, tStart);
            eraseFeather(ex, ey, tEnd + Math.PI);
            break;
          case 'chop':
            eraseChop(sx, sy, tStart);
            eraseChop(ex, ey, tEnd + Math.PI);
            break;
          case 'pixel':
            erasePixel(sx, sy, tStart);
            erasePixel(ex, ey, tEnd + Math.PI);
            break;
        }

        mainCtx.drawImage(off, 0, 0);
      }

I want to remove the straight-edge seams to match the second image’s smooth fading.
enter image description here

How to better smooth out the edges of this drawn arc

I am creating this frame plugin. The arc seems to be drawn okay as shown here:
enter image description here

But if you look carefully, you will notice the wild edges compared to this idle frame:
enter image description here

So, how can I smooth the edges to match the second image, given this code piece:

function drawFancyArcFrame(mainCtx, opts) {
        const {
          cx, cy, radius, width, startDeg, sweepDeg,
          color1, color2, capStyle = 'feather',
          capLengthPx = 24, pixelSize = 4
        } = opts;

        if (sweepDeg <= 0 || width <= 0) return;

        const startRad = (startDeg * Math.PI) / 180;
        const endRad   = ((startDeg + sweepDeg) * Math.PI) / 180;

        const W = mainCtx.canvas.width;
        const H = mainCtx.canvas.height;

        const off = document.createElement('canvas');
        off.width = W; off.height = H;
        const ctx = off.getContext('2d');

        const grad = ctx.createLinearGradient(0, 0, W, H);
        grad.addColorStop(0, color1);
        grad.addColorStop(1, color2);

        // draw base arc with flat ends so we can sculpt
        ctx.save();
        ctx.strokeStyle = grad;
        ctx.lineWidth = width;
        ctx.lineCap = 'butt';
        ctx.globalAlpha = 0.85;
        ctx.beginPath();
        ctx.arc(cx, cy, radius, startRad, endRad, false);
        ctx.stroke();
        ctx.restore();

        // endpoints + tangents
        const sx = cx + radius * Math.cos(startRad);
        const sy = cy + radius * Math.sin(startRad);
        const ex = cx + radius * Math.cos(endRad);
        const ey = cy + radius * Math.sin(endRad);
        const tStart = startRad + Math.PI / 2;
        const tEnd   = endRad   + Math.PI / 2;

        // erasers (destination-out)
        const eraseFeather = (x, y, ang) => {
          ctx.save();
          ctx.translate(x, y);
          ctx.rotate(ang);
          ctx.globalCompositeOperation = 'destination-out';
          const g = ctx.createLinearGradient(0, 0, capLengthPx, 0);
          g.addColorStop(0, 'rgba(0,0,0,1)');
          g.addColorStop(1, 'rgba(0,0,0,0)');
          ctx.fillStyle = g;
          ctx.fillRect(0, -width/2, capLengthPx, width);
          ctx.restore();
        };

        const eraseChop = (x, y, ang) => {
          ctx.save();
          ctx.translate(x, y);
          ctx.rotate(ang);
          ctx.globalCompositeOperation = 'destination-out';
          ctx.beginPath();
          ctx.moveTo(0, -width/2);
          ctx.lineTo(capLengthPx, 0);
          ctx.lineTo(0, width/2);
          ctx.closePath();
          ctx.fillStyle = 'rgba(0,0,0,1)';
          ctx.fill();
          ctx.restore();
        };

        const erasePixel = (x, y, ang) => {
          ctx.save();
          ctx.translate(x, y);
          ctx.rotate(ang);
          ctx.globalCompositeOperation = 'destination-out';
          const cols = Math.ceil(capLengthPx / pixelSize);
          const rows = Math.ceil(width / pixelSize);
          const y0 = -width / 2;
          for (let c = 0; c < cols; c++) {
            const frac = 1 - (c / cols);
            const activeRows = Math.max(1, Math.floor(rows * frac));
            const x0 = c * pixelSize;
            for (let r = 0; r < activeRows; r++) {
              if (Math.random() < 0.85) {
                const yCell = y0 + r * pixelSize;
                ctx.fillStyle = 'rgba(0,0,0,1)';
                ctx.fillRect(x0, yCell, pixelSize, pixelSize);
              }
            }
          }
          ctx.restore();
        };

        switch (capStyle) {
          case 'feather':
            eraseFeather(sx, sy, tStart);
            eraseFeather(ex, ey, tEnd + Math.PI);
            break;
          case 'chop':
            eraseChop(sx, sy, tStart);
            eraseChop(ex, ey, tEnd + Math.PI);
            break;
          case 'pixel':
            erasePixel(sx, sy, tStart);
            erasePixel(ex, ey, tEnd + Math.PI);
            break;
        }

        mainCtx.drawImage(off, 0, 0);
      }

I want to remove the straight-edge seams to match the second image’s smooth fading.
enter image description here

React safe way to render children [duplicate]

I have multiple banner components that each render a <BannerAlert /> based on API data.
Each banner handles its own visibility logic — if the API response is false, it returns null; if true, it renders the banner.

Example of one banner:

import { Alert } from "@/ui";
import { useHook } from "@/utils";

export const OneChild = () => {
  const { data, isLoading } = useHook();
  if (isLoading || !data?.balances?.hasOneChild) return null;

  return (
    <Alert
      type="error"
      title="OneChild"
      message="OneChild is active."
    />
  );
};

On the dashboard, I want to display only the first banner that is not null (in order of priority).
I created a wrapper called RenderChildren that wraps all banners:

<RenderChildren>
  <OneChild />
  <SecondChild />
  <ThirdChild />
  <FourthChild />
</RenderChildren>

And here’s my first attempt:

export const RenderChildren = ({ children }: { children: React.ReactNode }) => {
  const childrenArray = React.Children.toArray(children);

  const validChildren = childrenArray.filter((child) => {
    if (!React.isValidElement(child)) return false;
    if (typeof child.type === 'function') {
      try {
        const rendered = (child.type as (props: unknown) => React.ReactNode)(child.props);
        return rendered !== null && rendered !== undefined;
      } catch {
        return false;
      }
    }
    return true;
  });

  const firstChild = validChildren[0];
  return firstChild || null;
};

This works, but it calls each component function manually (child.type(child.props)), which breaks React’s rules of hooks and is not safe.

What I’ve tried / What I know:

I understand that manually calling a component breaks React’s render cycle.

I’ve looked into React.Children.map() and cloneElement, but those don’t help detect what each child returns.

My supervisor asked me to find a more performant and React-safe approach — possibly similar to patterns used by packages like react-if or react-conditionally.

What’s a React-safe and performant pattern to render only the first non-null child among several conditional components?
Is there an established pattern or compositional approach (without manually invoking children) that achieves this?