How to Properly Configure Vite to Compile data-src Attributes for Lazy Loading Images?

I am working on a project using Vite and trying to implement lazy loading for images. I have the following HTML structure for my images:

html

<img
  class="lazy"
  src="./src/images/lazy/note.webp"
  data-src="./src/images/note.webp"
  alt="Image of a book"
  class="bookImage"
/>

after build the html looks like this

 <img
   class="lazy"
   src="/assets/note-BK5rAaOe.webp"
   data-src="./src/images/note.webp"
   alt="Image of a book"
   class="bookImage"
 />

Problem:
The issue I am facing is that during the Vite build, the data-src attributes for my images are not being processed. As a result, lazy loading does not work as expected as the location is wrong

To achieve lazy loading, I’m using the following JavaScript:

document.addEventListener('DOMContentLoaded', function () {
  const lazyImages = document.querySelectorAll('.lazy');

  const lazyLoad = (entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src;
        img.classList.add('loaded'); // Add loaded class for the animation
        observer.unobserve(img); // Stop observing the image once it's loaded
      }
    });
  };

  const observer = new IntersectionObserver(lazyLoad, {
    root: null,
    rootMargin: '0px',
    threshold: 0.1,
  });

  lazyImages.forEach(img => observer.observe(img));
});

Additionally, here is my vite.config.js file:

import { defineConfig } from 'vite';

export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        // Use the modern API
        api: 'modern-compiler', // or "modern"
      },
    },
  },
});

How can I configure Vite to compile the data-src attributes properly?
Do I need to manually add images to achieve lazy loading, or is there a way to automate this process?
I also tried building the same setup using Parcel, but I encountered the same issue with the data-src attributes not being compiled.
Any guidance or suggestions on how to resolve this issue would be greatly appreciated!

compileSdkVersion is not specified during configuration of project ‘expo-camera’

When building my expo react-native app I get the build error:

  • Where:
    Script ‘/DELIBERATELY_HIDDEN/node_modules/expo-modules-autolinking/scripts/android/autolinking_implementation.gradle’ line: 377

  • What went wrong:
    A problem occurred evaluating project ‘:expo’.

A problem occurred configuring project ‘:expo-camera’.
Failed to notify project evaluation listener.
> com.android.builder.errors.EvalIssueException: compileSdkVersion is not specified. Please add it to build.gradle
> Could not get unknown property ‘release’ for SoftwareComponent container of type org.gradle.api.internal.component.DefaultSoftwareComponentContainer.

I’ve tried every answer in every related post but it hasn’t helped.

I’ve looked at my android project level, android app level and expo-camera node_modules level build.gradle file’s, but they all specify a compileSdkVersion!

I don’t want to change anything in node_modules as it will be wiped every time I have to reinstall them.

It used to build just fine using expo-camera version 14.1.3, react 18.2.0, react native 0.73.6 & expo 50.0.0 and I haven’t changed those versions.

Incidentally, I also get the following in my problems tab in VS Code, but similar errors have happened with other modules, before, without causing build errors:

Missing Gradle project configuration folder: .settings

Here are my build.gradle file’s:

Project level:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    ext {
        buildToolsVersion = findProperty('android.buildToolsVersion') ?: '34.0.0'
        minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '23')
        compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '34')
        targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '34')
        kotlinVersion = findProperty('android.kotlinVersion') ?: '1.8.10'

        ndkVersion = "25.1.8937393"
    }
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath('com.android.tools.build:gradle')
        classpath('com.facebook.react:react-native-gradle-plugin')
    }
}

apply plugin: "com.facebook.react.rootproject"

allprojects {
    repositories {
        maven {
            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
            url(new File(['node', '--print', "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), '../android'))
        }
        maven {
            // Android JSC is installed from npm
            url(new File(['node', '--print', "require.resolve('jsc-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), '../dist'))
        }

        google()
        mavenCentral()
        maven { url 'https://www.jitpack.io' }
        maven {
            // expo-camera bundles a custom com.google.android:cameraview
            url "$rootDir/../node_modules/expo-camera/android/maven"
        }
    }
}

App level:

apply plugin: 'com.android.application'
apply plugin: "com.facebook.react"

def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()

/**
 * This is the configuration block to customize your React Native Android app.
 * By default you don't need to apply any configuration, just uncomment the lines you need.
 */
react {
    entryFile = file(["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android", "absolute"].execute(null, rootDir).text.trim())
    reactNativeDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
    hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc"
    codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()

    // Use Expo CLI to bundle the app, this ensures the Metro config
    // works correctly with Expo projects.
    cliFile = new File(["node", "--print", "require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })"].execute(null, rootDir).text.trim())
    bundleCommand = "export:embed"

    /* Folders */
    //   The root of your project, i.e. where "package.json" lives. Default is '..'
    // root = file("../")
    //   The folder where the react-native NPM package is. Default is ../node_modules/react-native
    // reactNativeDir = file("../node_modules/react-native")
    //   The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen
    // codegenDir = file("../node_modules/@react-native/codegen")

    /* Variants */
    //   The list of variants to that are debuggable. For those we're going to
    /* Bundling */
    //   A list containing the node command and its flags. Default is just 'node'.
    // nodeExecutableAndArgs = ["node"]

    //
    //   The path to the CLI configuration file. Default is empty.
    // bundleConfig = file(../rn-cli.config.js)
    // hermesFlags = ["-O", "-output-source-map"]
}

/**
 * Set this to true to Run Proguard on Release builds to minify the Java bytecode.
 */
def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean()

/**
 * The preferred build flavor of JavaScriptCore (JSC)
 *
 * For example, to use the international variant, you can use:
 * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
 *
 * The international variant includes ICU i18n library and necessary data
 * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
 * give correct results when using with locales other than en-US. Note that
 * this variant is about 6MiB larger per architecture than default.
 */
def jscFlavor = 'org.webkit:android-jsc:+'

apply plugin: "org.jetbrains.kotlin.android"

android {
    ndkVersion rootProject.ext.ndkVersion

    buildToolsVersion rootProject.ext.buildToolsVersion
    compileSdk rootProject.ext.compileSdkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    namespace 'co.uk.tycho.provisioner'
    defaultConfig {
        applicationId 'co.uk.tycho.provisioner'
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 14
        versionName "1.0.0"

        buildConfigField("boolean", "REACT_NATIVE_UNSTABLE_USE_RUNTIME_SCHEDULER_ALWAYS", (findProperty("reactNative.unstable_useRuntimeSchedulerAlways") ?: true).toString())

        missingDimensionStrategy 'react-native-camera', 'general'
    }
    signingConfigs {
        debug {
            storeFile file('debug.keystore')
            storePassword 'android'
            keyAlias 'provisionerDebugKey'
            keyPassword 'android'
        }
    }
    buildTypes {
        debug {
            signingConfig signingConfigs.debug
        }
        release {
            // Caution! In production, you need to generate your own keystore file.
            // see https://reactnative.dev/docs/signed-apk-android.
            signingConfig signingConfigs.debug
            shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }
    packagingOptions {
        jniLibs {
            useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false)
        }
    }
    // flavorDimensions 'react-native-camera'
    // productFlavors {
    //     general {
    //         dimension 'react-native-camera'
    //     }
    //     mlkit {
    //         dimension 'react-native-camera'
    //     }
    // }
}

// Apply static values from `gradle.properties` to the `android.packagingOptions`
// Accepts values in comma delimited lists, example:
// android.packagingOptions.pickFirsts=/LICENSE,**/picasa.ini
["pickFirsts", "excludes", "merges", "doNotStrip"].each { prop ->
    // Split option: 'foo,bar' -> ['foo', 'bar']
    def options = (findProperty("android.packagingOptions.$prop") ?: "").split(",");
    // Trim all elements in place.
    for (i in 0..<options.size()) options[i] = options[i].trim();
    // `[] - ""` is essentially `[""].filter(Boolean)` removing all empty strings.
    options -= ""

    if (options.length > 0) {
        println "android.packagingOptions.$prop += $options ($options.length)"
        // Ex: android.packagingOptions.pickFirsts += '**/SCCS/**'
        options.each {
            android.packagingOptions[prop] += it
        }
    }
}

dependencies {
    // The version of react-native is set by the React Native Gradle Plugin
    implementation("com.facebook.react:react-android")

    def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
    def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
    def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true";

    if (isGifEnabled) {
        // For animated gif support
        implementation("com.facebook.fresco:animated-gif:${reactAndroidLibs.versions.fresco.get()}")
    }

    if (isWebpEnabled) {
        // For webp support
        implementation("com.facebook.fresco:webpsupport:${reactAndroidLibs.versions.fresco.get()}")
        if (isWebpAnimatedEnabled) {
            // Animated webp support
            implementation("com.facebook.fresco:animated-webp:${reactAndroidLibs.versions.fresco.get()}")
        }
    }

    implementation("com.facebook.react:flipper-integration")

    if (hermesEnabled.toBoolean()) {
        implementation("com.facebook.react:hermes-android")
    } else {
        implementation jscFlavor
    }
}

apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), "../native_modules.gradle");
applyNativeModulesAppBuildGradle(project)

expo-camera node_modules level:

apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'maven-publish'

group = 'host.exp.exponent'
version = '14.1.3'

def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
if (expoModulesCorePlugin.exists()) {
  apply from: expoModulesCorePlugin
  applyKotlinExpoModulesCorePlugin()
  // Remove this check, but keep the contents after SDK49 support is dropped
  if (safeExtGet("expoProvidesDefaultConfig", false)) {
    useExpoPublishing()
    useCoreDependencies()
  }
}

buildscript {
  // Simple helper that allows the root project to override versions declared by this library.
  ext.safeExtGet = { prop, fallback ->
    rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
  }

  // Ensures backward compatibility
  ext.getKotlinVersion = {
    if (ext.has("kotlinVersion")) {
      ext.kotlinVersion()
    } else {
      ext.safeExtGet("kotlinVersion", "1.8.10")
    }
  }

  repositories {
    mavenCentral()
  }

  dependencies {
    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getKotlinVersion()}")
  }
}

// Remove this if and it's contents, when support for SDK49 is dropped
if (!safeExtGet("expoProvidesDefaultConfig", false)) {
  afterEvaluate {
    publishing {
      publications {
        release(MavenPublication) {
          from components.release
        }
      }
      repositories {
        maven {
          url = mavenLocal().url
        }
      }
    }
  }
}

android {
  // Remove this if and it's contents, when support for SDK49 is dropped
  if (!safeExtGet("expoProvidesDefaultConfig", false)) {
    compileSdkVersion safeExtGet("compileSdkVersion", 34)

    defaultConfig {
      minSdkVersion safeExtGet("minSdkVersion", 23)
      targetSdkVersion safeExtGet("targetSdkVersion", 34)
    }

    publishing {
      singleVariant("release") {
        withSourcesJar()
      }
    }

    lintOptions {
      abortOnError false
    }
  }

  def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
  if (agpVersion.tokenize('.')[0].toInteger() < 8) {
    compileOptions {
      sourceCompatibility JavaVersion.VERSION_11
      targetCompatibility JavaVersion.VERSION_11
    }

    kotlinOptions {
      jvmTarget = JavaVersion.VERSION_11.majorVersion
    }
  }

  namespace "expo.modules.camera"
  defaultConfig {
    versionCode 32
    versionName "14.1.3"
  }
}

repositories {
  mavenCentral()
  maven {
    url "$projectDir/maven"
  }
}

dependencies {
  // Remove this if and it's contents, when support for SDK49 is dropped
  if (!safeExtGet("expoProvidesDefaultConfig", false)) {
    implementation project(':expo-modules-core')
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
  }
  def camerax_version = "1.4.0-alpha02"

  api "androidx.exifinterface:exifinterface:1.3.6"
  api 'com.google.android:cameraview:1.0.0'

  implementation "androidx.camera:camera-core:${camerax_version}"
  implementation "androidx.camera:camera-camera2:${camerax_version}"
  implementation "androidx.camera:camera-lifecycle:${camerax_version}"
  implementation "androidx.camera:camera-video:${camerax_version}"

  implementation "androidx.camera:camera-view:${camerax_version}"
  implementation "androidx.camera:camera-extensions:${camerax_version}"
  implementation "com.google.mlkit:barcode-scanning:17.2.0"
  implementation 'androidx.camera:camera-mlkit-vision:1.4.0-alpha02'

  api 'com.google.android:cameraview:1.0.0'
}

How to Correcting Off-by-One Error in a Loop?

You are given a method that is supposed to print numbers from 1 to N. However, there is an off-by-one error that causes the loop to skip the last number. Identify and correct the error.

public class PrintNumbers {
    public static void printNumbers(int N) {
        for (int i = 1; i < N; i++) { // Incorrect loop condition
            System.out.print(i + " ");
        }
    }

    public static void main(String[] args) {
        printNumbers(5); // Expected Output: 1 2 3 4 5
                         // Actual Output: 1 2 3 4
    }
}
public static void main(String[] args) {
        printNumbers(5); // Expected Output: 1 2 3 4 5
                         // Actual Output: 1 2 3 4
    }
}

TypeError (is not iterable) when adding SVG to FabricJS canvas

I have a fabricjs canvas, and I’m trying to add an SVG to it. But whatever I do, I get problems. It keeps saying:
“Uncaught (in promise) TypeError: t is not iterable”.

let svg = `<svg viewBox="-8 -8 136 136">
<path stroke="#000000" stroke-width="8" d="m0 51.82677l0 0c0 -28.623135 23.203636 -51.82677 51.82677 -51.82677l0 0c13.745312 0 26.927654 5.4603047 36.64706 15.17971c9.719406 9.719404 15.17971 22.901749 15.17971 36.64706l0 0c0 28.623135 -23.203636 51.82677 -51.82677 51.82677l0 0c-28.623135 0 -51.82677 -23.203636 -51.82677 -51.82677zm25.913385 0l0 0c0 14.311565 11.60182 25.913387 25.913385 25.913387c14.311565 0 25.913387 -11.601822 25.913387 -25.913387c0 -14.311565 -11.601822 -25.913385 -25.913387 -25.913385l0 0c-14.311565 0 -25.913385 11.60182 -25.913385 25.913385z" fill="none"></path>
</svg>`;

let canvas = new fabric.Canvas("canvas");
let path = fabric.loadSVGFromString(svg, function(objects, options) {
    let obj = fabric.util.groupSVGElements(objects, options);
    
    obj.set({
        left: canvas.width / 2 - obj.width / 2,
        top: canvas.height / 2 - obj.height / 2
    });
    canvas.add(obj).renderAll();
});

Hopefully someone can help me out

How do I wait for action complete on introjs onbeforechange

In my intro tour, I have a section where I need to expand a div with a slider before I can run intro on the internal elements. I use onbeforechange to expand the div, but it is a jquery animation. The problem is that the top coordinate of the div is off screen when I get to this step of my tour. I want to wait until the animation is complete before drawing the next introjs box. Is there a way to do this? Here is my code…

       }).onbeforechange(function(targetElement) {
            // Check if you want to trigger a click on the current step
            if (this._currentStep === 3 || this._currentStep === 4 ||this._currentStep === 5 ||this._currentStep === 6 ||this._currentStep === 7) {
                if ($('.btn-arrow').text() == 'Click for ↓ Details') {
                    const elementToClick = document.querySelector(".btn-arrow");
                    if (elementToClick) {
                        elementToClick.click();
                    }
                }   
            }

The conditional is a test for whether the div is expanded yet. It is saying “if not, then expand before change.” but introjs does not wait for the expand to complete since it is asynchronous. I guess what I need is a ‘pause’ introjs, then a ‘restart’ that I can trigger on complete of my animation?

Thanks for any hints.

JavaScript Fullscreen: fullscreenEnabled is always false and fullscreenElement is not the element requested on

There is a [Lit] WebComponent that I call requestFullscreen() on (this.requestFullscreen()). It’s a toggle, so when the same action is clicked again I check for if (document.fullscreenElement === this), since this is the element that requested fullscreen.

However, document.fullscreenElement is actually the next highest ancestor WebComponent, not even any of the native HTML ancestors between these two WebComponents. So I decided to use document.fullscreenEnabled, just to see if it was and toggle fullscreen off. Turns out, document.fullscreenEnabled is always false.

For now my workaround, because document.fullscreenElement is either that ancestor or null, I am just checking if (!!document.fullscreenElement). This is kinda kludgy, IMO, but works.

Why is document.fullscreenEnabled always false and document.fullscreenElement not this when I called this.requestFullscreen() to invoke fullscreen?

trace cookie creation in browser devtools

I’m trying to understand a website’s login process

After I login, it creates a cookie but I can’t find out which code is creating this cookie

I used firefox devTools and I can see that after posting data to login page the next request contains that specific cookie but none of the previous request’s responses have any header to create that cookie

I searched for document.cookie in every js file, and set breakpoint on every line but none of them triggered for that cookie creation

I injected this code in console before login, but still no luck

origDescriptor = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie');
Object.defineProperty(document, 'cookie', {
  get() {
    return origDescriptor.get.call(this);
  },
  set(value) {
    debugger;
    return origDescriptor.set.call(this, value);
  },
  enumerable: true,
  configurable: true
});

The website is written with angular I guess (ng-version=”17.0.8″)

Is there any other way to create cookies? I’m a web developer myself and I’ve always thought that it’s only possible to create cookie through js and http response headers

P.S: I was googling around and saw some posts about firebug and the ability to create breakpoint on cookie creation but it seems it’s replaced by firefox dev edition and this one doesn’t have that ability

Unexpected behaviour with JavaScript’s “onanimationend” – follow-up

This is a follow-up to this question along with its accepted answer.

This time there is one more list level and the list style item is also highlighted.

Please have a look at this code snippet:

const highlight = (element) => {
  element.classList.remove('highlight');
  setTimeout(() => {
    element.classList.add('highlight');
  }, 0);
  element.onanimationend = e => {
    e.stopPropagation();
    element.classList.remove('highlight');
  }
}
document.querySelector('body').addEventListener('click', event => {
  if (event.target.hash) {
    const element = document.querySelector(event.target.hash);
    highlight(element);
  }
});
@keyframes highlight {
  from {
    background: red;
  }
  to {
    background: transparent;
  }
}

ol {
  counter-reset: enumeration;
  list-style: none;
}

ol > li {
  position: relative;
}

ol > li::before {
  position: absolute;
  margin-left: -2em;
  width: 1em;
  counter-increment: enumeration;
  content: counter(enumeration) '.';
}

ol > li > ol {
  counter-reset: alphabet;
  list-style: none;
}

ol > li > ol > li {
  position: relative;
}

ol > li > ol > li::before {
  position: absolute;
  margin-left: -2em;
  width: 1em;
  counter-increment: alphabet;
  content: counter(alphabet, lower-alpha) ')';
}

div.highlight,
ol > li.highlight,
ol > li.highlight::before,
ol > li:has(.highlight)::before {
  animation: highlight 5s;
}
<ul>
  <li>
    <a href="#foo">Foo</a>
    <div>
      <ul>
        <li>
          <a href="#foo-1">Foo 1</a>
          <ul>
            <li><a href="#foo-1-1">Foo 1.1</a></li>
            <li><a href="#foo-1-2">Foo 1.2</a></li>
            <li><a href="#foo-1-3">Foo 1.3</a></li>
          </ul>
        </li>
        <li><a href="#foo-2">Foo 2</a></li>
        <li><a href="#foo-3">Foo 3</a></li>
      </ul>
    </div>
  </li>
  <li><a href="#bar">Bar</a></li>
  <li><a href="#baz">Baz</a></li>
</ul>

<hr>

<div id="foo">
  <h2>Foo</h2>
  <ol>
    <li id="foo-1">
      Foo 1
      <ol>
        <li id="foo-1-1">Foo 1.1</li>
        <li id="foo-1-2">Foo 1.2</li>
        <li id="foo-1-3">Foo 1.3</li>
      </ol>
    </li>
    <li id="foo-2"> Foo 2</li>
    <li id="foo-3"> Foo 3</li>
  </ol>
</div>

<div id="bar">
  <h2>Bar</h2>
</div>

<div id="baz">
  <h2>Baz</h2>
</div>

Then please run the code snippet (preferably on full page) and try:

Click on “Foo 1.1” (or “Foo 1.2” or “Foo 1.3”), wait 3 seconds and then click on “Foo”. As you can see, the background color animation of “Foo” ends at the same time as the background color animation of “Foo 1.1” (or “Foo 1.2” or “Foo 1.3”). One could also say that the CSS class “highlight” is removed from “Foo” too early.

Furthermore, if you initially click on “Foo 1.1” (or “Foo 1.2” or “Foo 1.3”), the list style item of “Foo” is highlighted as expected (and intended). But if you click on “Foo 1.1” (or “Foo 1.2” or “Foo 1.3”) again within 5 seconds, the list style item of “Foo” is not highlighted again. Only after waiting 5 seconds at least and then clicking on “Foo 1.1” (or “Foo 1.2” or “Foo 1.3”) again, the list style item of “Foo” is highlighted again.

This strange behaviour may be due to the pseudo-element ::before. So it is about ol > li:has(.highlight)::before. stopPropagation() doesn’t seem to affect pseudo-elements because they are not part of the actual DOM.

Any idea how to fix this?

Can’t figure out how to configure Chakra-UI

I have this to templates main.jsx and app.jsx

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import { Provider } from "@chakra-ui/react";

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <Provider>
      <App />
    </Provider>
  </React.StrictMode>
);

and app.jsx

import { Button } from "@chakra-ui/react";

function App() {
  return (
    <>
      <Button>Hello!</Button>
    </>
  );
}

export default App;

I’m trying to configure and use Chakra-UI but that button won’t be added there with everything that I tried
I also tried this in main.js

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import ChakraProvider from "@chakra-ui/react";

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <ChakraProvider>
      <App />
    </ChakraProvider>
  </React.StrictMode>
);

The error for the first type of main.jsx is

The requested module '/node_modules/.vite/deps/@chakra-ui_react.js?v=88ddfe76' does not provide an export named 'Provider' (at main.jsx:4:10)

And for the second type

 The requested module '/node_modules/.vite/deps/@chakra-ui_react.js?v=88ddfe76' does not provide an export named 'default' (at main.jsx:4:8)

Please help me with some ideas…

Javascript array with data inside but ’empty header’ [duplicate]

I’m new to JS. I created the 1st array with loop and push, from cloud database. Then I manually declared the 2nd array with the same data. But in firefox console, when you console.log() them, it is like this:

enter image description here

As it shows, the 1st one has an ’empty header’ and length is empty too.

The difference I have found so far is that when you run:

console.log(JSON.stringify(array1));
console.log(JSON.stringify(array2));

The output is gonna be:
console outputs

My question is: How to transform (or fix) the 1st array to make it exactly same as the 2nd array?

——————————–
Updated the code to fetch data from Firebase.

        // Function to fetch locations from Firebase
        const loclist = [];
        async function getLocs() {
            const dbRef = await db.ref('chatbot')

            await dbRef.once('value', (snapshot) => {
                snapshot.forEach((childSnapshot) => {
                    const childData = childSnapshot.val();
                    if (childData && childData.user_loc) { // Check if loc exists
                        loclist.push(childData.user_loc); // Add loc to the list
                    }
                });

                // Display in the HTML
                const userlocElement = document.getElementById("loclist_html");
                loclist.forEach(loc => {
                    const li = document.createElement("li");
                    li.textContent = loc; // Set loc as the text content of the list item
                    userlocElement.appendChild(li); // Append list item to the list
                });
            });
        };

        getLocs();

How to get pixel position in non-geographical Leaflet map?

I have a problem, getting pixel coordinates in Leaflet. Any help would be greatly appreciated!

What I want to achieve:

I want to display an image using leaflet (no tiles – just a image, non-geographical map) and the user should have the option to click on the image, set a marker and I need the pixel position of that marker. For testing purposes, I’ve created a JSFiddle, that uses this image.

Displaying the image and setting the marker is not a problem. There are plenty of tutorials out there for that.

But getting that pixel position is – at least for me – somehow impossible. I’ve read every post / article / … about the different methods provided by Leaflet, but still no success.

What I achieved so far:

In an image editing program I can see, that the top of this tower on the image has roughly these pixel coordinates: x=1350, y=625.

Image showing the pixel position of the top of the tower

So when the user clicks on the top of the tower, I get the LatLng of this point and I can set the marker. When the user does not change the zoom level, my code is actually working. Clicking on the top of the tower, I get pixel coordinates, that are correct (see the blue marker on the image, showing where i clicked, and the pixels calculated displayed on the console):

Image showing the correct calculated position, if the user didn’t zoom

My problem

But when the user starts zooming, the calculated pixel coordinates are definitely wrong:

Image showing the wrong calculated position, after the user zoomed

My code

I’ve created this JSFiddle to share my code: https://jsfiddle.net/q36f1ytu/73/

The code that handles the click event is basically this (see my JSFiddle for the whole code):

map.on("click", function (e) {
  const marker = new L.Marker(e.latlng).addTo(map)

    // Here I want to get the pixel coordinate of the image
  var imagePixelCoords = map.project(e.latlng, map.getZoom())
  console.log("imagePixelCoords: " + imagePixelCoords)
})

I am quite lost, how to calculate the pixel coordinates correctly, when the user zooms.

Thank you very much in advance!

Best regards

How to achieve smooth frame rate independent animations

I have the following animation that I would like to make smooth and frame rate independent:

const duration = 25;
const friction = 0.68;
const target = 400;

let velocity = 0;
let location = 0;

function update() {
  const displacement = target - location;

  velocity += displacement / duration;
  velocity *= friction;
  location += velocity;

  element.style.transform = `translate3d(${location}px, 0px, 0px)`;
}

This is what I want to achieve:

  1. The animation duration should be the same regardless of the device refresh rate whether it’s 30Hz, 60Hz or 120Hz or higher. Small insignificant fluctuations in milliseconds are acceptable.
  2. The animation should be smooth on all devices with 60Hz refresh rate or higher.
  3. The animation behavior should remain the same while achieving point 1-2 above.

How do I go about solving this?


What I’ve tried

I’ve tried implementing the by many devs praised technique in the Fix Your Timestep! article, which decouples the update process and rendering. This is supposed to make the animation smooth regardless of the device refresh rate:

function runAnimation() {
  const squareElement = document.getElementById('square');
  const timeStep = 1000 / 60;
  const duration = 25;
  const friction = 0.68;
  const target = 400;
  const settleThreshold = 0.001;

  let location = 0;
  let previousLocation = 0;
  let velocity = 0;
  let lastTimeStamp = 0;
  let lag = 0;
  let animationFrame = 0;

  function animate(timeStamp) {
    if (!animationFrame) return;
    if (!lastTimeStamp) lastTimeStamp = timeStamp;

    const elapsed = timeStamp - lastTimeStamp;
    lastTimeStamp = timeStamp;
    lag += elapsed;

    while (lag >= timeStep) {
      update();
      lag -= timeStep;
    }

    const lagOffset = lag / timeStep;
    render(lagOffset);

    if (animationFrame) {
      animationFrame = requestAnimationFrame(animate);
    }
  }

  function update() {
    const displacement = target - location;
    previousLocation = location;

    velocity += displacement / duration;
    velocity *= friction;
    location += velocity;
  }

  function render(lagOffset) {
    const interpolatedLocation =
      location * lagOffset + previousLocation * (1 - lagOffset);

    squareElement.style.transform = `translate3d(${interpolatedLocation}px, 0px, 0px)`;

    if (Math.abs(target - location) < settleThreshold) {
      cancelAnimationFrame(animationFrame);
    }
  }

  animationFrame = requestAnimationFrame(animate);
}

runAnimation();
body {
  background-color: black;
}

#square {
  background-color: cyan;
  width: 100px;
  height: 100px;
}
<div id="square"></div>

…However, devs claim that the animation runs smoothly on devices with 60Hz refresh rate but that the animation is stuttering/is choppy on devices with 120Hz refresh rates and up. So I tried to plot the animation curve on different refresh rates to see if there’s something obvious that I’m doing wrong, but judging from the charts, it seems like the animation should be smooth regardless of refresh rate?

function plotCharts() {
  function randomIntFromInterval(min, max) {
    return Math.floor(Math.random() * (max - min + 1) + min);
  }

  function simulate(hz, color) {
    const chartData = [];

    const targetLocation = 400;
    const settleThreshold = 0.001;

    const duration = 25;
    const friction = 0.68;
    const fixedFrameRate = 1000 / 60;
    const deltaTime = 1000 / hz;

    let location = 0;
    let previousLocation = location;
    let interpolatedLocation = location;

    let velocity = 0;
    let timeElapsed = 0;
    let lastTimeStamp = 0;
    let lag = 0;

    function update() {
      const displacement = targetLocation - location;
      previousLocation = location;

      velocity += displacement / duration;
      velocity *= friction;
      location += velocity;
    }

    function shouldSettle() {
      const displacement = targetLocation - location;
      return Math.abs(displacement) < settleThreshold;
    }

    while (!shouldSettle()) {
      const timeStamp = performance.now();

      if (!lastTimeStamp) {
        lastTimeStamp = timeStamp;
        update();
      }

      /* 
      Number between -1 to 1 including numbers with 3 decimal points
      The deltaTimeFluctuation variable simulates the fluctuations of deltaTime that real devices have. For example, if the device has a refresh rate of 60Hz, the time between frames will almost never be exactly 16,666666666666667 (1000 / 60).
      */
      const deltaTimeFluctuation =
        randomIntFromInterval(-1000, 1000) / 1000;
      const elapsed = deltaTime + deltaTimeFluctuation;

      lastTimeStamp = timeStamp;
      lag += elapsed;

      while (lag >= fixedFrameRate) {
        update();
        lag -= fixedFrameRate;
      }

      const lagOffset = lag / fixedFrameRate;

      interpolatedLocation =
        location * lagOffset + previousLocation * (1 - lagOffset);

      timeElapsed += elapsed;

      chartData.push({
        time: parseFloat((timeElapsed / 1000).toFixed(2)),
        position: interpolatedLocation,
      });
    }

    const timeData = chartData.map((point) => point.time);
    const positionData = chartData.map((point) => point.position);

    const canvas = document.createElement("canvas");
    canvas.width = 600;
    canvas.height = 400;
    const ctx = canvas.getContext("2d");
    document.body.appendChild(canvas);

    const chart = new Chart(ctx, {
      type: "line",
      data: {
        labels: timeData,
        datasets: [{
          label: `${hz}Hz (with Interpolation)`,
          data: positionData,
          borderColor: color,
          fill: false,
        }, ],
      },
      options: {
        scales: {
          x: { title: { display: true, text: "Time (seconds)" } },
          y: { title: { display: true, text: "Position (px)" } },
        },
      },
    });
  }

  const simulations = [{
      hz: 30,
      color: "yellow"
    },
    {
      hz: 60,
      color: "blue"
    },
    {
      hz: 120,
      color: "red"
    },
    {
      hz: 240,
      color: "cyan"
    },
    {
      hz: 360,
      color: "purple"
    },
  ];

  simulations.forEach((simulation) => {
    simulate(simulation.hz, simulation.color);
  });
}

plotCharts()
body {
  background-color: black;
}
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

I’m probably doing something wrong so any help is appreciated! Please note that alternative approaches to the fixed time step with render interpolation are welcome, as long as the animation behaves the same.

Can React props be used in CSS?

I have a display: grid;, set to the body of my react-app.
I have a component that uses a part of the grid that I want to repeat itself two more times side by side.
How do I used props for the CSS property, grid-area: , so I can change the position of other two within the grid, slightly modifying the reusable component?

I tried using props the usual way but this only affects the html and am confused on how to change a css property for a reusable component.

Here is the code:

function App() {

  return (
    <>
      <Nav />
      <Sidebar />
      <Main />
      <Content h1="Content1"/>
      
      <Footer/>
    </>
  )
}

export default App
import './Content.css'

function Content(props) {
    return (
        <div className="content">
            <h1>{props.h1}</h1>
            <p>
                Lorem, ipsum dolor sit amet consectetur adipisicing elit. 
                Nemo laborum sapiente placeat dolorem a quae!
            </p>
        </div>
    );
}
export default Content
.content {
    grid-area: content1;
}
.content h1 {
    padding: 1rem;
    background: orange;
    color: white;
    font-weight: 700;
    border-radius: 0.25rem 0.25rem 0 0;
}
.content p {
    padding: 1rem;
    line-height: 1.6;
}

The layout is working as expected,
I just want to change the CSS property grid-area: to a newer position.
Do you know the syntax for modifying a specific CSS property when styling with react props?

Microphone Access and Audio Recording Not Working in Telegram Mini App Web View

I’m developing a Telegram Mini App that requires microphone access to record audio and transcribe it. I’ve been trying to use the MediaRecorder API for this functionality. However, the recorded audio is either empty or not functioning as expected when the app runs in the Telegram Mini App web view (in-app browser)

Here’s the basic setup I’m using to request microphone access and record audio with MediaRecorder:

const AudioRecorderComponent = () => {
  const [isRecording, setIsRecording] = useState(false);
  const [audioBlob, setAudioBlob] = useState(null);

  const startRecording = async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      const mediaRecorder = new MediaRecorder(stream);
      const chunks = [];

      mediaRecorder.ondataavailable = (event) => {
        chunks.push(event.data);
      };

      mediaRecorder.onstop = () => {
        const audio = new Blob(chunks, { type: 'audio/wav' });
        setAudioBlob(audio);
        stream.getTracks().forEach(track => track.stop());
      };

      mediaRecorder.start();
      setIsRecording(true);

      // Stop recording after 5 seconds as a test
      setTimeout(() => {
        mediaRecorder.stop();
        setIsRecording(false);
      }, 5000);
    } catch (error) {
      console.error("Microphone access error:", error);
    }
  };

  return (
    <div>
      <button onClick={startRecording} disabled={isRecording}>
        {isRecording ? 'Recording...' : 'Start Recording'}
      </button>
      {audioBlob && <audio controls src={URL.createObjectURL(audioBlob)} />}
    </div>
  );
};

export default AudioRecorderComponent;

Questions

Does Telegram Mini App support microphone access via MediaRecorder? I couldn’t find documentation specifically addressing this for Telegram Mini Apps.
Are there any workarounds or alternative approaches to reliably access the microphone in Telegram’s web view?
Has anyone successfully implemented audio recording in a Telegram Mini App, and if so, what approach did you use?

What I’ve Tried
Testing in Different Environments: The code works perfectly in a regular browser (both mobile and desktop), but not in the Telegram Mini App web view.
Checking Permissions: I verified that microphone permissions are being requested and granted. The MediaRecorder API seems to initialize without errors, but the recorded Blob always has the same size, and there’s no audible playback.
Console Logs for Debugging:
Added logs in the ondataavailable event to check chunk sizes – each chunk has a size of 0 in the Telegram web view.
Verified that navigator.mediaDevices and MediaRecorder are supported in the environment, as indicated by the lack of initialization errors.

Resetting auth During Unit Testing

I am trying to run unit tests for a few portions of my Firebase web app, but I am running into issues with authentication. I have the mock authentication working (triggering onAuthStateChanged as expected). The problem I am having is that it seems the Firebase SDK is holding onto the auth object I pass in first, which makes sense other than I can’t seem to sign out or reset the auth object in between tests.

My onAuthStateChanged observer:

onAuthStateChanged(auth, async (user) => {
    console.log('onAuthStateChanged', auth, user);

    if (!user || (user && !user.currentUser.emailVerified)) {
        window.location.href = 'index.html';
    } else {
        await showInputs();
    }
});

My first test is:

const mockAuth = { currentUser: { uid: true, emailVerified: true } };

getAuth.mockReturnValue(mockAuth);
        
require('./register.js');

await onAuthStateChanged.mock.calls[0][1](mockAuth);

As expected, console.log prints

onAuthStateChanged
auth: { currentUser: { uid: true, emailVerified: true } }
user: { currentUser: { uid: true, emailVerified: true } }

But, on the next test mockAuth is set to

const mockAuth = { currentUser: { uid: true, emailVerified: false } };
                                                            ^^^^^

and console.log prints:

onAuthStateChanged
auth: { currentUser: { uid: true, emailVerified: true } }
user: { currentUser: { uid: true, emailVerified: false } }

Clearly, the SDK is holding onto the auth state, (again, this makes sense given I haven’t logged out), but I have tried getAuth.mockReset(), signOut(getAuth()), getAuth.mockReturnValue(null), and a few others to no avail.

It isn’t so much that I need to sign out, as much as I need to alter the auth object for other tests. These tests are merely checking authentication and are working as expected (they are simply easy examples to illustrate my problem).

I need to be able to add/update the auth.currentUser.email field for later tests. Since the SDK is hanging on to the auth object I initially provide (ignoring getAuth.mockReturnValue(mockAuth) on subsequent calls), I cannot test my code fully.

For this particular test, in my beforeEach call, I have:

getAuth.mockReset();

mockAuth = { currentUser: { uid: true, emailVerified: true, email: "[email protected]" } };

getAuth.mockReturnValue(mockAuth);

But, when executed, auth.currentUser.email is undefined.

The problem function:

onValue(child(firebaseRef, `items`), items => {
    document.getElementById('itemList').innerHTML = '';

    // fill item list
    if (auth.currentUser) {
        items.forEach(i => {
            if (i.child('seller').val() === auth.currentUser.email && !i.hasChild('inactive')) {
                addItemToList(i);
            }
        });
    }
});

auth.currentUser.email is always undefined because when it is set in my first authentication test, I do not need nor provide an email property, but that is the auth object used for the entirety of the test run. If I change the mockAuth object and re-run the test, auth will have the new values (so maybe it doesn’t have anything to do with ‘signing out’??).