Optional class property for object

I want to be able to define objects as:

/**@type{CheckData}**/
object1 = {check:true}
/**@type{CheckData}**/
object2 = {check:false, data: 'Why?'} 

While I can use this @typedef with success:

/**
 * @typedef {Object} CheckData
 * @property {boolean} check
 * @property {*=} data
 */

I have the following class:

/**
 * @class CheckData
 * @property {boolean} check - Indicates if the operation was successful.
 * @property {*=} [data] - Optional data associated with the status.
 */
export class CheckData {
    /**
     * Creates an instance of CheckData.
     * @param {boolean} check - Whether the operation is considered successful.
     * @param {*=} [data] - Optional data. 
     */
    constructor(check, data) {
        this.check = check;
        if (data !== undefined) { 
            this.data = data;
        }
    }
}

This class type works fine for object2 = {check:false, data: 'Why?'}, but it fails for object1 = {check:true}, despite data being a optional property:

Property 'data' is missing in type '{ check: true; }' but required in type 'CheckData'

Yet if I use @typedef, it works fine.

How can I define data to be an optional property in CheckData class?

html2canvas and jsPDF not rendering lightning combobox values in LWR app

We have a web app running in LWR using LWC and Node.js as backend.

We want to implement a “export as PDF” functionality for every of our pages. After some time of research I decided to use a combination of html2canvas + jsPDF to do this and it works perfect! Except for some base lightning-combobox components we use for some selectors.

The combobox itself is exported correctly (the container and icon with correct colors) but the text inside the combobox is not displayed (the values / placeholders). This is very important because those values are information we want in the PDF so I need this resolved.

The code for the export:

async function exportToPDF(content, filename = 'export.pdf', canvasOptions, pdfOptions) {

    const canvas = await html2canvas(content, canvasOptions || {
        scale: 2,  // improves quality
        useCORS: true  // enable if you load images from other domains
    });

    const imgData = canvas.toDataURL('image/png');
    const pdf = new jsPDF(pdfOptions || {
        orientation: 'portrait',
        unit: 'px',
        format: [canvas.width, canvas.height]
    });

    pdf.addImage(imgData, 'PNG', 0, 0, canvas.width, canvas.height);
    pdf.save(filename);
}

Screenshot of one of our pages:
page

Screenshot of resulting PDF

pdf

Is there something I can do here? I understand this maybe has something to do with Shadow DOM protecting the component inside.. Is there a workaround?

How can i keep this div visible until it moves to its end position but scroll past it after it has moved to its end position?

I am able to make this div move right when scrolling but i want its position to be fixed while scrolling before it has reached its end position. The problem I am having is that when I scroll further after the movingDiv has reached its end position, the position continues to remain fixed.

const container = document.querySelector(".container");
const movingDiv = document.querySelector(".moving-div");
let scrollPosition = 0;
let endPosition = 0;

window.addEventListener("scroll", () => {
  let scrollPosition = window.scrollY;

  movingDiv.style.transform = scrollPosition <= endPosition ?
    `translateX(${scrollPosition}px)` :
    `translate(300px)`;

  // Stop movement when movingDiv reaches maxPosition

  if (movingDiv.offsetLeft >= movingDiv.maxPosition) {
    movingDiv.style.position = "absolute";
  } else {
    movingDiv.style.position = "fixed";
  }
});
.container {
  height: 200vh;
}

.moving-div {
  height: 100px;
  width: 100px;
  background-color: black;
  left: 0;
  transition: 0.3s right ease;
}
<div class="container">
  <div class="moving-div"></div>
</div>

Goole maps api polyline label

my project

my project
I want to add

I want to add

I want to show the routes, distances and times between two regions on Google API. I combined the two examples and made it the current one, but when I click on the routes, I cannot show the distance, time or the route it is.

var directionDisplay;
var directionsRenderers = [];
var directionsService = new google.maps.DirectionsService();
var map;

function drawMap(midpoint) {
    var mid = midpoint.split(",");
    var start = new google.maps.LatLng(mid[0], mid[1]);
    var myOptions = {
        zoom: 7,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        center: start,
        mapTypeControl: false
    };
    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
}

function getRendererOptions(main_route) {
    var _colour;
    var _strokeWeight;
    var _strokeOpacity;
    var _suppressMarkers;
    var _label;
    if (main_route) {
        _colour = '#00458E';
        _strokeWeight = 4;
        _strokeOpacity = 1.0;
        _suppressMarkers = false;
    } else {
        _colour = '#ED1C24';
        _strokeWeight = 4;
        _strokeOpacity = 0.4;
        _suppressMarkers = false;
    }

    var polylineOptions = {
        strokeColor: _colour,
        strokeWeight: _strokeWeight,
        strokeOpacity: _strokeOpacity
        
    };

    var rendererOptions = {
        draggable: false,
        suppressMarkers: _suppressMarkers,
        polylineOptions: polylineOptions
    };

    return rendererOptions;
}

function renderDirections(result, rendererOptions, routeToDisplay) {
    var _colour;
    var _strokeWeight;
    var _strokeOpacity;
    var _suppressMarkers;

    if (routeToDisplay === 0) {
        _colour = '#00458E';
        _strokeWeight = 6;
        _strokeOpacity = 1.0;
        _suppressMarkers = false;
    } else {
        _colour = '#ED1C24';
        _strokeWeight = 4;
        _strokeOpacity = 0.4;
        _suppressMarkers = false;
    }

    // create new renderer object
    var directionsRenderer = new google.maps.DirectionsRenderer({
        draggable: false,
        suppressMarkers: _suppressMarkers,
        polylineOptions: {
            strokeColor: _colour,
            strokeWeight: _strokeWeight,
            strokeOpacity: _strokeOpacity
            
        }
    });
    directionsRenderer.setMap(map);
    directionsRenderer.setDirections(result);
    directionsRenderer.setRouteIndex(routeToDisplay);
    directionsRenderers.push(directionsRenderer);

}

function requestDirections(start, end, routeToDisplay, main_route) {
    for (var i = 0; i < directionsRenderers.length; i++) {
        directionsRenderers[i].setMap(null);
    }
    directionsRenderers = [];

    var request = {
        origin: start,
        destination: end,
        travelMode: google.maps.DirectionsTravelMode.DRIVING,
        provideRouteAlternatives: main_route
    };

    directionsService.route(request, function (result, status) {

             
        var rendererOptions;
        if (status == google.maps.DirectionsStatus.OK) {
            if (main_route) {
                rendererOptions = getRendererOptions(true);
                for (var i = 0; i < result.routes.length; i++) {
                    renderDirections(result, rendererOptions, i);
                }
            } else {
                rendererOptions = getRendererOptions(false);
                renderDirections(result, rendererOptions, routeToDisplay);
            }   
                document.getElementById('msg').innerHTML = "";
                for (var i = 0; i < result.routes.length; i++) {
                    var directionsData = result.routes[i].legs[0]; // Get data about the mapped route
                    if (!directionsData) {
                      window.alert('Yol tarifi isteği başarısız oldu');
                      return;
                    }
                    else {
                      if(i==0){ color = '#00458E';} else{ color = '#ED1C24';}
                      document.getElementById('msg').innerHTML += " <font color='" + color + "'> Mesafe " + directionsData.distance.text + " (" + directionsData.duration.text + ").</font/></br>";
                    }
                }
        }   
    
    });
}




// users route
requestDirections('(Letchworth)', '(Crawley)', 0, true);
drawMap("türkiye");
    html, body, #map_canvas {
    height: 90%;
    width: 100%;
    margin: 0px;
    padding: 0px
}
<!DOCTYPE html>
<html>

<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>JSFiddle uLu7w814</title>

  <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyA5dMMFQXt4os3Ndk0gMu8sGOHqGYv4_VU&libraries=geometry,places&ext=.js"></script>
</head>
<body>
  <label>Start</label>&nbsp;
<input id="start" size="50" value="Letchworth" />
<br />
<label>End</label>&nbsp;&nbsp;
<input id="end" size="50" value="Crawley" />
<input type="button" value="post directions" id="btn" onclick="requestDirections(document.getElementById('start').value, document.getElementById('end').value,0,true);" />
<div id="msg"></div>
<div id="map_canvas"></div>

</body>
</html>

I want to add information to polylines as in the 2nd image.

Input field’s old and new value are shown after changing the value with js [closed]

I have a weird situation where I change the value of a hidden input field from “2” to “3”.

Actual screen shot after change with js

At the first sight the new value “3” seems to be accepted and assigned to the attribute value.

But when I open the details information and scroll down to the attribute value, there is still the old value “2” standing.

enter image description here

When I select for the value (document.getElementById("rowid").value) then I get the old value “2”. Why is this so?

Vanilla JS Scroll Virtualization Causes Element Shuffling and Slow Performance Despite Throttling/requestAnimationFrame

I’m implementing a custom scroll virtualization for a testimonials section in Vanilla JS. When clicking “show more testimonials,” I add 10 more elements and collect all of them using querySelectorAll, then handle scroll events to remove items outside the viewport and replace them with empty div (we could see it despite using BUFFER if scroll too fast). However, this causes severe scroll lag and element shuffling.
gif file about mixing https://jmp.sh/s/o4xIAyjHp2QQ28gWG7K5
gif file about red empty div https://jmp.sh/s/PZl3lQUIp9u6TXlBJXjI

export function virtualize() {
const scroll = document.querySelector(".testimonial-container");
  const container = scroll.querySelector(".phantom-container");
  const ITEM_HEIGHT = 150;

  let allTestimonials = Array.from(container.querySelectorAll(".testimonial"));

  scroll.removeEventListener("scroll", virtualizeScroll);
  scroll.addEventListener("scroll", virtualizeScroll);

  let topEmptyDiv = scroll.querySelector(".empty-div--top");
  if (!topEmptyDiv) {
    topEmptyDiv = document.createElement("div");
    topEmptyDiv.classList.add("empty-div--top");
    topEmptyDiv.style.height = 0 + "px";
    topEmptyDiv.style.backgroundColor = "red";
    topEmptyDiv.style.width = "100%";
    topEmptyDiv.style.flexShrink = "0";

    scroll.prepend(topEmptyDiv);
  }

  

  let deletedTop = [];
  const BUFFER = 10;
  let rafId = null;
  function virtualizeScroll() {
    if (rafId) {
      cancelAnimationFrame(rafId);
    }
    let isAboveTop = 1;
    rafId = requestAnimationFrame(() => {
      toggleTopElements();
    });

    function toggleTopElements() {
      if (allTestimonials.length) {
        isAboveTop = ITEM_HEIGHT * BUFFER + allTestimonials[0].offsetTop < scroll.scrollTop;

        if (isAboveTop) {
          let element = allTestimonials.shift();

          deletedTop.unshift(element);
          element.remove();
          topEmptyDiv.style.height = `${parseInt(getComputedStyle(topEmptyDiv).height) + ITEM_HEIGHT}px`;
        }
      }
      let isBelowTop = scroll.scrollTop < topEmptyDiv.offsetHeight + ITEM_HEIGHT * BUFFER;
      if (isBelowTop && deletedTop.length) {
        let element = deletedTop.shift();

        allTestimonials.unshift(element);

        container.prepend(element);
        topEmptyDiv.style.height = `${parseInt(getComputedStyle(topEmptyDiv).height) - element.offsetHeight}px`;
      }
    }

“Why is real-time key press detection does not work in Windows PHP CLI without hitting the ‘ENTER’ key?” [duplicate]

I am trying to capture real-time keypresses in Windows CLI using PHP, but Windows buffers input, forcing me to press Enter before any key detection occurs. In Linux/macOS, I can use stty -icanon to disable input buffering, but Windows does not support this.
I have tried setting stream_set_blocking(STDIN, false) but still requires ENTER.
Capturing the keypress without ENTER works via FFI where C functions like _getch(), _kbhit() which is present in msvcrt.dll are being used.
Is there any pure PHP solution to handle real-time key detection in Windows without using FFI, PowerShell, or Node.js or has anyone tried solving this problem?

sample code does not work

<?php
    $stdin = fopen('php://stdin', 'rb+');
    stream_set_blocking($stdin, 0);
    while(1)
    {
        $keypress = fgets($stdin);
        if($keypress)
        {
            echo 'Key pressed: ' . $keypress . PHP_EOL;
        }
    }

still waits for ENTER before detecting input in Windows CLI. Any pure PHP alternative?`

PHP chrome-php/chrome timed out

I’m using Symfony’s chrome-php/chrome library to measure page load performance. Some pages of the same site load, and some do not, with an error Operation timed out after 30s. Increased the timeout to a minute and up to two, but it doesn’t help. I don’t understand what the problem is, I hope for help from people who care) Function code:

    public function checkPageMetrics(string $url, string $deviceType = 'desktop'): array
{
    if (!in_array($deviceType, ['desktop', 'mobile'])) {
        throw new InvalidArgumentException('Device type must be either "desktop" or "mobile"');
    }

    $browserFactory = new BrowserFactory('/usr/bin/google-chrome');

    $browser = $browserFactory->createBrowser([
        'headless' => true,
        'noSandbox' => true,
        'windowSize' => $deviceType === 'mobile' ? [375, 812] : [1920, 1080],
        'userAgent' => $deviceType === 'mobile'
            ? 'Mozilla/5.0 (Linux; Android 10; Pixel 3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Mobile Safari/537.36'
            : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
    ]);

    try {
        $page = $browser->createPage();

        $page->addPreScript('Object.defineProperty(navigator, "webdriver", { get: () => false });');

        $page->addPreScript('
            window.performanceMetrics = {
                ttfb: 0,
                domInteractive: 0,
                loadEventEnd: 0
            };

            new PerformanceObserver((list) => {
                const entries = list.getEntries();
                if (entries.length > 0) {
                    window.performanceMetrics.ttfb = entries[0].responseStart;
                }
            }).observe({type: "navigation", buffered: true});
            
            document.addEventListener("readystatechange", () => {
                if (document.readyState === "interactive") {
                    window.performanceMetrics.domInteractive = performance.now();
                }
            });
            
            window.addEventListener("load", () => {
                window.performanceMetrics.loadEventEnd = performance.now();
            });
        ');

        $navigation = $page->navigate($url);
        $navigation->waitForNavigation(Page::LOAD, 30000);

        $metrics = $page->evaluate('window.performanceMetrics')->getReturnValue();

        return [
            'device_type' => $deviceType,
            'first_byte_ms' => round($metrics['ttfb']),
            'interactive_ms' => round($metrics['domInteractive']),
            'complete_load_ms' => round($metrics['loadEventEnd']),
            'error' => null
        ];
    } catch (Exception $e) {
        return [
            'device_type' => $deviceType,
            'first_byte_ms' => null,
            'interactive_ms' => null,
            'complete_load_ms' => null,
            'error' => $e->getMessage()
        ];
    } catch (OperationTimedOut $e) {
        return [
            'device_type' => $deviceType,
            'first_byte_ms' => null,
            'interactive_ms' => null,
            'complete_load_ms' => null,
            'error' => $e->getMessage()
        ];
    } catch (NavigationExpired $e) {
        return [
            'device_type' => $deviceType,
            'first_byte_ms' => null,
            'interactive_ms' => null,
            'complete_load_ms' => null,
            'error' => $e->getMessage()
        ];
    }
}

empty array or square bracket in my laravel filament application

i wonder has anyone of you encounter this issue before ? i used laravel filament and the server technology – nginx. i have tried many method to get this fixed , however the square bracket still exists. i tried

php artisan route:clear
php artisan optimize:clear
php artisan config:clear
php artisan view:clear
php artisan cache:clear

filament screenshot

How to resolve a “414: Request-URI Too Long” on SiteGround shared hosting of WordPress running Nginx? There is no direct access to Nginx configs

I am managing a WordPress site that is hosted on SiteGround and is being run behind Nginx which is returning “414: Request-URI Too Long” on some long post submits.

I have seen various solutions — like this one here on Stack Overflow as well as this one — that explain that config changes have to be made to core Nginx configs like this:

fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;

client_max_body_size 24M;
client_body_buffer_size 128k;

client_header_buffer_size 5120k;
large_client_header_buffers 16 5120k;

But shared hosting on SiteGround does not provide direct access to Nginx configs to make a change like that.

Is there any other way I can overcome “414: Request-URI Too Long” while running WordPress on Nginx but without mucking with core Nginx configs? Perhaps in the wp-config.php? If so, how?

Linux, DirectAdmin and Rouncube password save [closed]

I need to configure my email server in such way that my employees should change their password the first time they log-in. I have configured that everything , except for that password plugin that does not want to work. I have the following the config of password plugin.

 $config['password_driver'] = 'expect'; 
 $config['password_expect_params'] = '%o %u %P';
 $config['password_expect_command'] = '/var/www/html/roundcube/passwdupdater.sh';

The problem is that I get this in roundcube log file:

 [29-May-2025 17:37:40 America/New_York] PHP Warning:  popen() has been disabled for security reasons in /var/www/html/roundcubemail-1.6.9/plugins/password/drivers/expect.php on line 53 
[29-May-2025 17:37:40 America/New_York] PHP Warning:  fwrite() expects parameter 1 to be resource, null given in /var/www/html/roundcubemail-1.6.9/plugins/password/drivers/expect.php on line 54 
[29-May-2025 17:37:40 America/New_York] PHP Warning:  fwrite() expects parameter 1 to be resource, null given in /var/www/html/roundcubemail-1.6.9/plugins/password/drivers/expect.php on line 55 [29-May-2025 17:37:40 America/New_York] PHP Warning:  fwrite() expects parameter 1 to be resource, null given in /var/www/html/roundcubemail-1.6.9/plugins/password/drivers/expect.php on line 56
 [29-May-2025 17:37:40 America/New_York] PHP Warning:  pclose() expects parameter 1 to be resource, null given in /var/www/html/roundcubemail-1.6.9/plugins/password/drivers/expect.php on line 58

I tried to enable popen in /usr/local/… /disabled_php_functions

It did not help.

Any solutions?

local HTML slideshow display images when opened directly without a server

I’m building a local HTML slideshow for a wedding. It runs offline — I want to be able to double-click index.html and have it work without setting up a server.

The slideshow uses a SmugMug iframe and overlays a random image (from images/overlay/) every 30 minutes for 60 seconds. The overlay image doesn’t show — the screen just goes black during that time.

There are no JavaScript errors in the console, and I’ve double-checked my folder structure and image paths.

Folder structure

Wedding Show/
├── index.html
└── images/
    └── overlay/
        ├── welcome1.jpg
        ├── welcome2.jpg
        └── welcome3.jpg

Code

    <!-- File: index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>Wedding Slideshow</title>
  <style>
    html, body {
      margin: 0; padding: 0; height: 100%; overflow: hidden; background: black;
    }
    #slideshowContainer {
      width: 100vw; height: 100vh; position: relative; background: black;
    }
    #onlineGallery {
      width: 100%; height: 100%; border: none;
      position: absolute; top: 0; left: 0; z-index: 1;
    }
    #googleDriveSlideshow {
      width: 100%; height: 100%;
      position: absolute; top: 0; left: 0; z-index: 2;
      display: none;
      background-size: contain;
      background-position: center;
      background-repeat: no-repeat;
      background-color: black;
    }
    #googleDriveIndicator {
      position: absolute; top: 20px; left: 20px; z-index: 4;
      background-color: rgba(255,255,255,0.8);
      color: #333; padding: 10px 15px;
      font-family: Arial, sans-serif; font-weight: bold;
      border-radius: 5px; display: none;
    }
  </style>
</head>
<body>
  <div id="slideshowContainer">
    <iframe id="onlineGallery"></iframe>
    <div id="googleDriveSlideshow"></div>
    <div id="googleDriveIndicator">Displaying Special Photo</div>
  </div>

  <script>
    const config = {
      baseSlideShowUrl: "https://gallery.captureeverymemory.com/frame/slideshow?key=bRFrVp&speed=10&transition=fade&autoStart=1&captions=0&navigation=0&playButton=0&randomize=0&transitionSpeed=2",
      localOverlayImages: ['welcome1.jpg', 'welcome2.jpg', 'welcome3.jpg'],
      localOverlayPath: 'images/overlay/',
      localPhotoDisplayTime: 60000,
      localPhotoSelectionInterval: 1800000,
    };

    const state = {
      shownLocalPhotos: new Set(),
      isOverlayVisible: false,
    };

    function getRandomLocalPhoto() {
      const unused = config.localOverlayImages.filter(img => !state.shownLocalPhotos.has(img));
      if (unused.length === 0) state.shownLocalPhotos.clear();
      const list = unused.length ? unused : config.localOverlayImages;
      const img = list[Math.floor(Math.random() * list.length)];
      state.shownLocalPhotos.add(img);
      return img;
    }

    function displayLocalOverlayPhoto() {
      const overlay = document.getElementById('googleDriveSlideshow');
      const gallery = document.getElementById('onlineGallery');
      const indicator = document.getElementById('googleDriveIndicator');
      const img = getRandomLocalPhoto();

      overlay.style.backgroundImage = `url('${config.localOverlayPath}${img}')`;
      overlay.style.display = 'block';
      gallery.style.visibility = 'hidden';
      indicator.style.display = 'block';
      state.isOverlayVisible = true;

      setTimeout(() => {
        overlay.style.display = 'none';
        gallery.style.visibility = 'visible';
        indicator.style.display = 'none';
        state.isOverlayVisible = false;
      }, config.localPhotoDisplayTime);
    }

    function scheduleLocalOverlayDisplay() {
      setInterval(() => {
        if (!state.isOverlayVisible) displayLocalOverlayPhoto();
      }, config.localPhotoSelectionInterval);
      setTimeout(displayLocalOverlayPhoto, 10000); // initial display after 10 sec
    }

    function refreshSlideshow() {
      const frame = document.getElementById('onlineGallery');
      frame.src = config.baseSlideShowUrl + "&refresh=" + new Date().getTime();
    }

    function initialize() {
      refreshSlideshow();
      scheduleLocalOverlayDisplay();
    }

    window.onload = initialize;
  </script>
</body>
</html>

When I open index.html by double-clicking (file:// path), the slideshow works fine but the overlay image doesn’t show up — just a black screen.

Is there a way to get background-image: url(‘images/overlay/filename.jpg’) to work when running HTML from file://, or do I have to switch to or use a local server?

Any workaround to make this slideshow fully portable without needing localhost?

How to open mobile app from browser in ios

In one of my projects, when a user tries to access the site from a mobile device, I want to redirect them to the existing mobile application. If the app is not installed, I want to open the App Store or Play Store so the user can install it. If the app is already installed, it should open and the user should be able to continue from there.

When I run the following code, it successfully opens the app on Android if it’s installed. However, on iOS, it doesn’t open the app and I get the error: “Safari cannot open the page because the address is invalid.”

const el = document.createElement('a');
el.href = "myApplication://";
el.click();

The app IDs are the same for both iOS and Android.

What to pass instead of ‘this’ in react function components

I have a task to rewrite class component to function one in React. Here’s the method that bothers me

    openDictionary = async () => {
        const {
            special,
            sysColumnName,
            label,
            listLabel,
            sysColumnId,
            columnId,
        } = this.model;
        const {
            match,
            location,
            listValue,
        } = this.props;
        const width = window.screen.width * .7;
        const height = window.screen.height * .7;
        const top = 0;
        const left = 0;
        window.editReferenceField = this; // This line!
        ...
    };

So, the line I marked as ‘This line!’ sets to a global window object’s field editReferenceField a class instance, which is a component itself. Logging it into the console gives me a real instance with all its methods etc.
The project I work on is quite big, and there’re several places I could find where the window.editReferenceField is used to access the component’s methods (and there’re also many places which I couldn’t find, I’m positive with that, because the app is very dynamic and allows user to add logic via scripts).

So, the question is, is there a way to do something similar in the function components? Unfortunately, I can’t know for sure which methods/fields will be accessed, so I can’t just assign this editReferenceField to an object with chosen methods, I need to pass the whole thing.
I’ll appreciate any help, thanks!

How to get React-Router Route object properties?

From docs: https://reactrouter.com/6.30.1/route/route

Type declaration
interface RouteObject {
  path?: string;
  index?: boolean;
  children?: RouteObject[];
  caseSensitive?: boolean;
  id?: string;
  loader?: LoaderFunction;
  action?: ActionFunction;
  element?: React.ReactNode | null;
  hydrateFallbackElement?: React.ReactNode | null;
  errorElement?: React.ReactNode | null;
  Component?: React.ComponentType | null;
  HydrateFallback?: React.ComponentType | null;
  ErrorBoundary?: React.ComponentType | null;
  handle?: RouteObject["handle"];
  shouldRevalidate?: ShouldRevalidateFunction;
  lazy?: LazyRouteFunction<RouteObject>;
}

How to get id property? I tried using hooks useLocation and
useParams but none showed this property.

UPD: I need to know if the user can edit the data on the page. Along with the user information, accesses to the pages come, for example: [“Page1.FullAccess”,”Pag2.Read”,]

I created:

const Page1Component = lazy(() =>
    import('./page1.ui').then((module) => ({ default: module.Page1 })),
);

const page1Route: RouteObject = {
    id: 'Page1',
path: '/lalala',
    element: createElement(enhance(Page1Component)),
};

AND

const browserRouter = createBrowserRouter(
    [
        {
            errorElement: <BubbleError />,
            children: [
                {
                    element: createElement(enhance(GenericLayout)),
                    children: [
                        page1Route,
                          ...
                    ],
                },
              .....

In the hook that I insert on the page

const useIsCan = () => {
    const location = useLocation();
    const params = useParams();

    const { data, isLoading } = useQuery(getCurrentUserPropsQuery());



const isCanEdit =
    data && data.roles.includes(`${The page ID should be here}.FullAccess`)