How to trigger command pallette in monaco editor with custom keyboard shortcut

Hi I’m creating a JS/TS editor online learnjs.app but I would like to give user is when user presses cmd/ctrl + p depend upon os then it should show/open command pallette. But I couldn’t find any solution as of now.

I’ve tried some solutions as per some blogs or chatGPT suggestion but not working like below:

const action = monacoRef.current.editor.getAction(
    "editor.action.showCommands"
);

if (action) {
    action.run();
}

Trying above code on keyboard listenr on cmd + p. But that doesn’t seems to be working. Any suggestions

Are built-in static methods bound? [duplicate]

According to the specification, are built-in Javascript static methods, like Array.from, Object.assign, console.log, etc meant to be bound or do they need to be invoked via the constructor/object?

Consider the following:

const assign = Object.assign;
const o1 = assign({}, {x: 1}); // OK in Chrome & Firefox
const o2 = assign.call(Object, {}, {x: 1}); // saefest, but is it necessary?

Assigning one of these static functions to a variable and invoking without the original context seems fine in the modern browsers I tested, but I often see the use of the more verbose approach of setting this to the original context via Function.prototype.call or Function.prototype.apply.

Is this necessary in practice? I can’t find anything on the specification that says whether the above mentioned method and similar ones are “context-free” so to speak, i.e. can be safely called from an aliased variable without setting thisArg.

Oauth2 flow / State validation with redirect endpoint on the frontend side

I have a question regarding oauth2 flow. I am using python/fastapi and I have implemented oauth2 flow, where the redirect endpoint is on the front end side because the backend isn’t accessible from the outside. The flow looks like this

  1. FE send login request to BE
  2. BE, generates state in request.session and redirects request to Identity Provider
  3. IDP validates input and redirect request to the given redirect url
  4. FE receives auth code and state and sends authorize request on the BE
  5. BE validates state AND HERE IS THE PROBLEM, he receives new session, BANG, can’t validate received input.
  6. Access token validation ….

The FE is using react js and simply receives code and state from IDP and forwards it. What would be the issue? Should frontend process the request in such a manner that it wouldn’t lose the session or maybe request.session isn’t a good choice (oauth2 lib implementation do the same).

I was testing it locally, so session resetting on different domain shouldn’t be the case. It was working without redirect endpoint, when redirect url was on the BE.

Dynamic Scaling of ApexCharts Scatter Plot with Large Dataset

I am using ApexCharts to render a scatter plot with a large dataset (around 300+ points) where each point has an x and y value. Here’s an example of my data: (client requirement)

**opr_planned_arr1** = [
   {x: 3, y: 22},
  {x: 3, y: 27},
  {x: 3, y: 33},
   ...
]

**opr_Executed_arr1**= [
  {x: 6, y: 93},
  {x: 6, y: 94},
  {x: 8, y: 104},
  {x: 10, y: 113}
]

 **opr_Reviewed_arr1** = []
 

const xValues = allData.map(point => point.x);
const yValues = allData.map(point => point.y);

const xMin = Math.min(...xValues);
const xMax = Math.max(...xValues);
const yMin = Math.min(...yValues);
const yMax = Math.max(...yValues);

const tickAmountX = xMax - xMin;
const tickAmountY = yMax - yMin;

// Adjust height
const chartHeight = Math.min(Math.max(140, tickAmountY * 10), 1000);

const chartOptions = {
  series: [
    {
      name: "Planned",
      data: opr_Planned_arr1,
      color: '#FE2836'
    },
    {
      name: "Execution In Progress",
      data: opr_Executed_arr1,
      color: '#feb019',
    },
    {
      name: "Completed",
      data: opr_Reviewed_arr1,
      color: '#00e396',
    },
  ],
  chart: {
    type: 'scatter',
    zoom: { enabled: false },
    toolbar: { show: false },
    height: chartHeight ,
  },
  markers: {
    size: 6,
  },
  xaxis: {
    type: 'numeric',
    tickAmount: 23,
    min: 0,
    max: 23,
  },
  yaxis: {
    tickAmount: tickAmountX ,
    min: 0,
    max: xMax,
  },
  stroke: { width: 1 },
};
  • How can I ensure that all points are properly aligned with their respective x and y values?
  • Is there a better way to dynamically calculate and set the tickAmount, min, max, and chart height for large datasets in ApexCharts?

Any insights, suggestions, or examples would be greatly appreciated!

  1. I used ApexCharts to render a scatter plot with dynamic axis configurations. I calculated the min, max, and tickAmount for both x and y axes based on my dataset. Additionally, I adjusted the chart height dynamically to fit the data and enabled zoom for better navigation.

  2. I expected all data points to align correctly on the chart, with no overlaps or misalignments. I also aimed for the chart to scale dynamically based on the dataset’s range and size, ensuring that the scatter points were clear and visually distinguishable.

3.Some points are not aligned correctly with their respective axes, especially when the dataset is large or has sparse x-values. The chart does not always scale as expected, and some points seem skipped or misrepresented.

I need to replicate he journey slider similar to DuckDuckGo website

I need help replicating the journey slider feature on the DuckDuckGo website (https://start.duckduckgo.com/about). The slider on their page effectively showcases a series of steps or stages in a visually engaging way, and I would like to implement something similar on my website. Can you guide me through the process of creating this interactive journey slider? I’m looking for how to structure it, any recommended tools or libraries to use, and how to make it responsive for various screen sizes.

Here is my dummy code which i made –

Timeline Example

    body {
        margin: 0;
        font-family: Arial, sans-serif;
        background-color: white;
    }
    .story-section {
        text-align: center;
        padding: 50px 20px;
    }
    .story-section h2 {
        font-size: 2.5rem;
        margin-bottom: 10px;
        color: #654321;
    }
    .story-section p {
        font-size: 1.2rem;
        color: #996515;
    }
    .timeline-container {
        position: relative;
        margin: 50px auto;
        width: 90%;
        max-width: 800px;
    }
    .timeline {
        display: flex;
        justify-content: space-between;
        align-items: center;
        position: relative;
    }
    .timeline::before {
        content: '';
        position: absolute;
        top: 50%;
        left: 0;
        width: 100%;
        height: 4px;
        background-color: burlywood;
        transform: translateY(-50%);
        z-index: 1;
    }
    .timeline-circle {
        width: 20px;
        height: 20px;
        background-color: burlywood;
        border-radius: 50%;
        z-index: 2;
        position: relative;
        cursor: pointer;
        transition: background-color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
    }
    .timeline-circle:hover {
        background-color: #654321;
        transform: scale(1.3);
        box-shadow: 0 0 15px #654321;
    }
    .timeline-circle.active {
        background-color: #654321;
    }
    .timeline-labels {
        display: flex;
        justify-content: space-between;
        margin-top: 10px;
        font-size: 0.9rem;
    }
    .timeline-labels span {
        color: brown;
    }
    .arrow {
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        background-color: #ebd4b7;
        border: none;
        width: 40px;
        height: 40px;
        color: #654321;
        font-size: 1.2rem;
        border-radius: 50%;
        cursor: pointer;
    }
    .arrow.left {
        left: -50px;
    }
    .arrow.right {
        right: -50px;
    }
    .arrow:hover {
        background-color: burlywood;
    }
    .details-container {
        margin-top: 30px;
        text-align: center;
        color: #654321;
    }
    .details-container h3 {
        font-size: 1.8rem;
        margin-bottom: 10px;
    }
    .details-container p {
        font-size: 1rem;
        color: #996515;
    }
    .image-div img {
        height: 220px;
        width: 220px;
        display: none;
    }
    .image-div img.active {
        display: inline-block;
    }
    @media (max-width: 600px) {
        .timeline-container {
            position: relative;
            margin: 20px auto;
            padding: 0 20px;
        }
        .arrow {
            width: 30px;
            height: 30px;
            font-size: 1rem;
        }
        .arrow.left {
            left: 5px;
        }
        .arrow.right {
            right: 5px;
        }
        .timeline {
            justify-content: space-around;
        }
        .timeline-labels {
            font-size: 0.8rem;
        }
    }




<h2>Lorem Ipsum Dolor</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin vitae eros id augue pharetra malesuada.</p>

    
        <img src="https://via.placeholder.com/220" alt="image">
        <img src="https://via.placeholder.com/220" alt="image">
        <img src="https://via.placeholder.com/220" alt="image">
        <img src="https://via.placeholder.com/220" alt="image">
        <img src="https://via.placeholder.com/220" alt="image">
        <img src="https://via.placeholder.com/220" alt="image">
    
    <h3>2008: Lorem Ipsum</h3>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam blandit arcu nec nisl varius scelerisque.</p>


    &#8249;
    
        <div class="timeline-circle active" data-year="2008"
             data-title="2008: Lorem Ipsum"
             data-description="Lorem ipsum dolor sit amet, consectetur adipiscing elit.">
        <div class="timeline-circle" data-year="2010"
             data-title="2010: Dolor Sit"
             data-description="Dolor sit amet, consectetur adipiscing elit.">
        <div class="timeline-circle" data-year="2015"
             data-title="2015: Amet Consectetur"
             data-description="Amet consectetur adipiscing elit, sed do eiusmod tempor.">
        <div class="timeline-circle" data-year="2018"
             data-title="2018: Adipiscing Elit"
             data-description="Adipiscing elit, sed do eiusmod tempor incididunt ut labore.">
        <div class="timeline-circle" data-year="2020"
             data-title="2020: Eiusmod Tempor"
             data-description="Eiusmod tempor incididunt ut labore et dolore magna aliqua.">
        <div class="timeline-circle" data-year="2023"
             data-title="2023: Incididunt Labore"
             data-description="Incididunt labore et dolore magna aliqua, ut enim ad minim veniam.">
    
    
        2008
        2010
        2015
        2018
        2020
        2023
    
    &#8250;



function scrollTimeline(direction) {
    const circles = document.querySelectorAll('.timeline-circle');
    const activeIndex = Array.from(circles).findIndex(circle => circle.classList.contains('active'));

    if (direction === -1 && activeIndex > 0) {
        setActiveNode(circles[activeIndex - 1]);
    } else if (direction === 1 && activeIndex < circles.length - 1) {
        setActiveNode(circles[activeIndex + 1]);
    }
}

function setActiveNode(node) {
    document.querySelectorAll('.timeline-circle').forEach(circle => circle.classList.remove('active'));
    node.classList.add('active');

    document.getElementById('timeline-title').innerText = node.getAttribute('data-title');
    document.getElementById('timeline-description').innerText = node.getAttribute('data-description');

    document.querySelectorAll('.image-div img').forEach(img => {
        img.classList.toggle('active', img.classList.contains(`image-${node.getAttribute('data-year')}`));
    });
}

document.querySelectorAll('.timeline-circle').forEach(circle =>
    circle.addEventListener('click', () => setActiveNode(circle))
);

Shopify app What is the minimum description required to place a draft order on the app?

It seems that it is dangerous to use access tokens on the front end.

In the back end, the app automatically generates access tokens.

I have prepared a template app, but where do I set it?

I tried it as shown below. I also set the scope. I also set the app. I wrote the access token in env.

Frontend

       const response = await fetch('/admin/api/2023-10/draft_orders.json', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'X-Shopify-Access-Token': 'shpat_',
          },
          body: JSON.stringify(orderData),

Change the endpoint to:
Frontend

        const response = await fetch('/create-draft-order', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify(orderData),
                });

Backend
app/routes/create-draft-order.tsx

  const response = await axios.post('https://{shop}.myshopify.com/admin/api/2023-10/draft_orders.json', orderData, {
        headers: {
            'Content-Type': 'application/json',
            'X-Shopify-Access-Token': process.env.SHOPIFY_ACCESS_TOKEN,
        },
    });

I thought this would handle the endpoints, am I forgetting something?

How to validate and handle edge cases in a coast fire calculator?

I’m building a web application to calculate the Coast FIRE (Financial Independence, Retire Early) number. The calculator estimates the future value of current savings using compound interest, assuming no additional contributions.

The formula I’m using is:
Future Value = Present Value × (1 + Rate of Return) ^ Years

I’ve implemented the following JavaScript function for this calculation:

function calculateFutureValue(presentValue, rateOfReturn, years) {
    return presentValue * Math.pow(1 + rateOfReturn, years);
}

// Example usage
const presentValue = 50000; // $50,000
const rateOfReturn = 0.07;  // 7%
const years = 30;           // 30 years

const futureValue = calculateFutureValue(presentValue, rateOfReturn, years);
console.log(futureValue);   // Expected output: ~380612.54

The code works correctly for basic inputs, but I want to handle edge cases to make it more robust. For example:

  1. Invalid inputs: What’s the best way to validate that presentValue, rateOfReturn, and years are non-negative numbers?
  2. Edge cases: How should I handle scenarios where one or more inputs are missing, null, or undefined?

I gather user input using basic HTML form fields, as shown below:

<form id="fire-calculator">
    <label for="presentValue">Present Value ($):</label>
    <input type="number" id="presentValue" min="0" required>

    <label for="rateOfReturn">Rate of Return (%):</label>
    <input type="number" id="rateOfReturn" min="0" step="0.01" required>

    <label for="years">Years:</label>
    <input type="number" id="years" min="0" required>

    <button type="submit">Calculate</button>
</form>

Here’s the JavaScript I’ve written to gather the form inputs and call the calculation function:

document.getElementById("fire-calculator").addEventListener("submit", function (event) {
    event.preventDefault();

    const presentValue = parseFloat(document.getElementById("presentValue").value);
    const rateOfReturn = parseFloat(document.getElementById("rateOfReturn").value) / 100;
    const years = parseInt(document.getElementById("years").value, 10);

    try {
        if (isNaN(presentValue) || isNaN(rateOfReturn) || isNaN(years)) {
            throw new Error("All inputs must be valid numbers.");
        }

        if (presentValue < 0 || rateOfReturn < 0 || years < 0) {
            throw new Error("Inputs must be non-negative.");
        }

        const futureValue = calculateFutureValue(presentValue, rateOfReturn, years);
        alert(`Future Value: $${futureValue.toFixed(2)}`);
    } catch (error) {
        alert(error.message);
    }
});

Specific Problem:

How can I improve the input validation and error handling to make it more robust and user-friendly? For example:

Is there a better way to handle validation at both the form and function levels?
Are there any best practices for handling missing or invalid data in calculations like this?
I would appreciate any feedback on improving the robustness of the calculator while keeping the code maintainable and user-friendly.

How to Validate and Handle Edge Cases in a Coast FIRE Calculator Using JavaScript

I’m building a web application to calculate the Coast FIRE (Financial Independence, Retire Early) number. The calculator estimates the future value of current savings using compound interest, assuming no additional contributions.

The formula I’m using is:
Future Value = Present Value × (1 + Rate of Return) ^ Years

I’ve implemented the following JavaScript function for this calculation:

function calculateFutureValue(presentValue, rateOfReturn, years) {
    return presentValue * Math.pow(1 + rateOfReturn, years);
}

// Example usage
const presentValue = 50000; // $50,000
const rateOfReturn = 0.07;  // 7%
const years = 30;           // 30 years

const futureValue = calculateFutureValue(presentValue, rateOfReturn, years);
console.log(futureValue);   // Expected output: ~380612.54

The code works correctly for basic inputs, but I want to handle edge cases to make it more robust. For example:

  1. Invalid inputs: What’s the best way to validate that presentValue, rateOfReturn, and years are non-negative numbers?
  2. Edge cases: How should I handle scenarios where one or more inputs are missing, null, or undefined?

I gather user input using basic HTML form fields, as shown below:

<form id="fire-calculator">
    <label for="presentValue">Present Value ($):</label>
    <input type="number" id="presentValue" min="0" required>

    <label for="rateOfReturn">Rate of Return (%):</label>
    <input type="number" id="rateOfReturn" min="0" step="0.01" required>

    <label for="years">Years:</label>
    <input type="number" id="years" min="0" required>

    <button type="submit">Calculate</button>
</form>

Here’s the JavaScript I’ve written to gather the form inputs and call the calculation function:

document.getElementById("fire-calculator").addEventListener("submit", function (event) {
    event.preventDefault();

    const presentValue = parseFloat(document.getElementById("presentValue").value);
    const rateOfReturn = parseFloat(document.getElementById("rateOfReturn").value) / 100;
    const years = parseInt(document.getElementById("years").value, 10);

    try {
        if (isNaN(presentValue) || isNaN(rateOfReturn) || isNaN(years)) {
            throw new Error("All inputs must be valid numbers.");
        }

        if (presentValue < 0 || rateOfReturn < 0 || years < 0) {
            throw new Error("Inputs must be non-negative.");
        }

        const futureValue = calculateFutureValue(presentValue, rateOfReturn, years);
        alert(`Future Value: $${futureValue.toFixed(2)}`);
    } catch (error) {
        alert(error.message);
    }
});

Specific Problem:

How can I improve the input validation and error handling to make it more robust and user-friendly? For example:

Is there a better way to handle validation at both the form and function levels?
Are there any best practices for handling missing or invalid data in calculations like this?
I would appreciate any feedback on improving the robustness of the calculator while keeping the code maintainable and user-friendly.

Dynamically add columns in React DataSheet Grid

I’m using React DataSheet Grid and I want to know if it’s possible to add columns dynamically. I tried using the code below, but for some reason, it’s not working.

import React, { useState } from "react";
import {
  DataSheetGrid,
  textColumn,
  checkboxColumn,
  keyColumn,
} from "react-datasheet-grid";
import "react-datasheet-grid/dist/style.css";

const App = () => {
  const [data, setData] = useState([
    { active: true, firstName: "Elon", lastName: "Musk" },
  ]);

  const [columns, setColumns] = useState([
    { ...keyColumn("active", checkboxColumn), title: "Active" },
    { ...keyColumn("firstName", textColumn), title: "First Name" },
    { ...keyColumn("lastName", textColumn), title: "Last Name" },
  ]);

  const addColumn = () => {
    const newColumnKey = `column${columns.length + 1}`;
    const newColumn = {
      ...keyColumn(newColumnKey, textColumn),
      title: `Column ${columns.length + 1}`,
    };

    setColumns([...columns, newColumn]);

    setData((prevData) =>
      prevData.map((row) => ({
        ...row,
        [newColumnKey]: "", 
      }))
    );

  };

  return (
    <div>
      <button onClick={addColumn} style={{ marginBottom: "10px" }}>
        Add Column
      </button>
      <DataSheetGrid value={data} onChange={setData} columns={columns} />
    </div>
  );
};

export default App;

I expect the new column to be added to the grid when I call addColumn().

React native Stripe Ressource setupintent inexistante : ‘seti_*****************************’

i have this error when i try add a card with tripe on my react native application.

err : {
    "code": "Failed", 
    "declineCode": null, 
    "localizedMessage": "Une erreur inattendue est survenue. Réessayez dans quelques secondes.", 
    "message": "Ressource setupintent inexistante : 'seti_*****************'", 
    "stripeErrorCode": "resource_missing", 
    "type": "invalid_request_error"
}

My code in when this error is catch

const handleSubmit = React.useCallback(() => {
    setLoading(true);
    console.log("--- dataSetup")
    console.log(dataSetup?.createSetupIntent?.setupIntentClientSecret)
    if (dataSetup && dataSetup.createSetupIntent) {
      confirmSetupIntent(
        dataSetup?.createSetupIntent?.setupIntentClientSecret,
        { paymentMethodType: 'Card' },
      )
        .then(async e => {
          if (e.error) {
            console.error('err :', e.error);
            Alert.alert(
              t('error'),
              `${t('toast.toast2Warning')}: ${e.error.message}`,
            );
          } else {
            if (e.setupIntent?.status === 'Succeeded') {
              await client.refetchQueries({
                include: [USER_CARDS],
              });
            }
          }
          BSRef?.current?.close();
          setOpen?.(false);
          setLoading(false);
        })
        .catch(err => {
          setLoading(false);

          console.error('err :', err);
        });
    }
  }, [confirmSetupIntent, dataSetup, setOpen, BSRef]);

Have you ever encountered this error ? My code has not changed between v2 (it works) and v3 (no works) maybe a problem with the configuration of my stripe ?

Why is my boostrap button stretching down when clicked on?

i have a bootstrap login page component that i am using for a react project. however, i noticed that whenever i click on the login button, for some reason it stretches all the way down and i asm not sure why it is doing so every time it is clicked. here so the component i got from the botstrap website:

`import React from ‘react’;
import {
MDBContainer,
MDBInput,
MDBCheckbox,
MDBBtn,
MDBIcon
}
from ‘mdb-react-ui-kit’;

function App() {
return (

  <MDBInput wrapperClass='mb-4' label='Email address' id='form1' type='email'/>
  <MDBInput wrapperClass='mb-4' label='Password' id='form2' type='password'/>

  <div className="d-flex justify-content-between mx-3 mb-4">
    <MDBCheckbox name='flexCheck' value='' id='flexCheckDefault' label='Remember me' />
    <a href="!#">Forgot password?</a>
  </div>

  <MDBBtn className="mb-4">Sign in</MDBBtn>

  <div className="text-center">
    <p>Not a member? <a href="#!">Register</a></p>
    <p>or sign up with:</p>

    <div className='d-flex justify-content-between mx-auto' style={{width: '40%'}}>
      <MDBBtn tag='a' color='none' className='m-1' style={{ color: '#1266f1' }}>
        <MDBIcon fab icon='facebook-f' size="sm"/>
      </MDBBtn>

      <MDBBtn tag='a' color='none' className='m-1' style={{ color: '#1266f1' }}>
        <MDBIcon fab icon='twitter' size="sm"/>
      </MDBBtn>

      <MDBBtn tag='a' color='none' className='m-1' style={{ color: '#1266f1' }}>
        <MDBIcon fab icon='google' size="sm"/>
      </MDBBtn>

      <MDBBtn tag='a' color='none' className='m-1' style={{ color: '#1266f1' }}>
        <MDBIcon fab icon='github' size="sm"/>
      </MDBBtn>

    </div>
  </div>

</MDBContainer>

);
}

export default App;`

I tried looking at the code and seeing where clikcing the button is causing it to stetch but cannot seem to find this. If i could get some help i would appreciate it.

Why are template strings in 11ty not rendering values from JSON content files?

I’m using 11ty to build a simple static site and have structured my project into templates and content directories. The template strings in my Nunjuck .njk templates are not rendering values from their corresponding JSON content files — they remain empty.

Here’s my project structure:

project-root/
├── templates/
│   ├── index.njk
│   ├── about.njk
├── content/
│   ├── index.json
│   ├── about.json
├── dist/
├── .eleventy.js
└── package.json

Content and corresponding template:

index.json

{
  "title": "My Website",
  "heading": "Welcome to my website"
}

index.njk

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{{ title }}</title>
</head>
<body>
  <h1>{{ heading }}</h1>
  <p>...</p>
</body>
</html>

11ty config:

.eleventy.js

module.exports = function(eleventyConfig) {
  return {
    dir: {
      input: "templates",
      data: "content",
      output: "dist"
    }
  };
};

Problem

After running the build with npx @11ty/eleventy, the dist/index.html output contains empty template strings where {{ title }} and {{ heading }} should be rendered. The final HTML looks like this:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title></title>
</head>
<body>
  <h1></h1>
  <p>...</p>
</body>
</html>

Question

Why is 11ty failing to render the content from the JSON files into my templates? How can I properly configure my project to resolve this issue?

Svelte5 and Bootstrap5

I have recently been getting into Svelte and really like it. It’s my first framework with the binding stuff, and I have been enjoying just working on some personal projects with it.

However, I am having a hell of a time getting bootstrap5 working. Now, I am able to import both the style sheets and the javascript from the CDN. I was also able to load the js locally as well within the app.html.

However, I now want to be able to open a modal without a button being pressed (I actually don’t really want this for my project, but I suspect it will come up again eventually so I’ve been trying to get this to work. It DOES work with “data-target” tags and everything. I am trying to reference bootstrap.Modal from the page.svelte.

So I have the following issues when I try to do this:

  1. Trying to import the library within the +page.svelte at the top of the script with a ‘import bootstrap from “$lib/bs5/bootstrap.bundle.min.js”‘ causes an error with the message “document is not defined”. I am assuming this is because the js file is trying to reference document, and that would need to be done with the svelte onmount. But I dont seem to be able to find a way to import within an onmount.

  2. Removing the import statement and just loading the js locally does let me reference “bootstrap.Modal” which is what I need, but VS Code/typescript does not allow me to use intellisense, and constantly claims there is an error since it has no reference to bootstrap.Modal. Admittedly this works, but I was assuming/hoping there is something I am missing that would make this part work. To be clear – this does work functionally, but no intellisense and the file always reporting an error.

I saw “sveltestrap”, but that seems a bit over the top to me… I just want to be able to use the same things I see in the official bootstrap documentation, and sveltestrap seems to have a lot of differences.

Has anyone had experience with this before? Would love to be able to get that error cleared up.

Layout Shifts in React during Ordered Animations (Typing and Fade-in Effects)

I’m experiencing layout shifts in my React application, particularly when animating components in order. The issue arises when I try to animate Heading with a typing animation and then animate the body text with a fade-in effect. While the animations work fine individually, when used together, I notice that the content “jerks” and resizes during the animations, even though I’ve attempted to fix the layout with min-height.
Here is the scenario:

Heading uses a typing animation where the text appears one character at a time.
Body text uses a fade-in animation.

When both of these components are animated in sequence, there is a noticeable layout shift, and the content seems to resize and move around as the animations proceed.
What I’ve tried:

Adding min-height to prevent content from resizing, but this hasn’t fully solved the issue.
The problem does not occur when the animations are run without order (i.e., both components are animated simultaneously).

What I want to achieve:

I want to animate the content in order (first the heading, then the body text) without causing layout shifts or resizing.
I would like to understand if there’s a better way to manage the animation order or any other workaround to avoid these shifts.
import React, { useState } from "react";
import { motion } from "framer-motion";
import Heading from "../Heading/Heading";
import BodyText from "../BodyText/BodyText";
import AnimatedBackground from "../../utilities/AnimatedBackground/AnimatedBackground";
import Marquee from "../Marquee/Marquee";
import { theme } from "../../theme";

const slideContent = {
  title: "Innovative Solutions Through",
  subtitle: "Custom Software Development",
  description:
    "Empowering businesses with tailored, cutting-edge tech solutions that transform ideas into impactful realities.",
};

const Hero = () => {
  const [animationStep, setAnimationStep] = useState(0);

  const handleTitleComplete = () => setAnimationStep(1);
  const handleSubtitleComplete = () => setAnimationStep(2);
  const handleDescriptionComplete = () => setAnimationStep(3);

  return (
    <AnimatedBackground
      className={`hero-section relative flex flex-col justify-between w-full min-h-screen`}
    >
      <div
        className={` ${theme.layoutPages.paddingHorizontal}  w-full grid grid-cols-12 items-center text-center py-6 relative z-10 flex-grow`}
      >
        <div className="col-span-12">
          <motion.div
         
          >
            {/* Title Animation */}
            <div className="min-h-[60px]">
              <Heading
                text={slideContent.title}
                isAnimate={animationStep === 0}
                onAnimationComplete={handleTitleComplete}
                size="text-50px"
              />
            </div>

            {/* Subtitle Animation */}
            <div className="min-h-[80px]">
              {animationStep >= 1 && (
                <Heading
                  text={slideContent.subtitle}
                  color="text-neon"
                  size="text-60px"
                  centered={true}
                  isAnimate={animationStep === 1}
                  onAnimationComplete={handleSubtitleComplete}
                />
              )}
            </div>

            {/* Description Animation */}
            <div className="min-h-[80px]">
              {animationStep >= 2 && (
                <BodyText
                  text={slideContent.description}
                  centered={true}
                  className="md:px-40"
                  isAnimate={animationStep === 2}
                  onAnimationComplete={handleDescriptionComplete}
                />
              )}
            </div>
          </motion.div>
        </div>
      </div>

      {/* Marquee Component */}
      <Marquee />
    </AnimatedBackground>
  );
};

export default Hero;

import React from 'react';
import PropTypes from 'prop-types';
import { motion } from 'framer-motion';
import useTypingAnimation from '../../utilities/Animations/useTypingAnimation.js';

const Heading = ({
  text,
  spanText = '',
  spanColor = 'text-neon',
  color = 'text-white',
  size = 'text-50px',
  centered = true,
  fontFamily = 'font-monument',
  fontWeight = 'font-normal',
  isAnimate = true,
  order = 0,
  speedMultiplier = 0.7,
  onAnimationComplete,
  className = '',
  breakSpan = false,
}) => {
  const parts = spanText ? text.split(spanText) : [text];
  const { controls, ref, characterVariants } = useTypingAnimation({
    text,
    isAnimate,
    order,
    speedMultiplier,
  });

  // Split text into words while preserving spaces
  const splitIntoWords = (string) => {
    return string.split(/(s+)/).filter(word => word.length > 0);
  };

  // Split words into characters for animation
  const splitWordIntoChars = (word) => {
    return word.split('').map((char) => (char === ' ' ? 'u00A0' : char));
  };

  const totalLength = text.length;
  let charCount = 0;

  // Render without animations if isAnimate is false
  if (!isAnimate) {
    return (
      <h1
        className={`${centered ? 'text-center' : ''} ${color} ${size} ${fontFamily} ${fontWeight} ${className}`}
        style={{
          wordBreak: 'normal',
          overflowWrap: 'break-word',
          whiteSpace: 'pre-wrap'
        }}
      >
        {parts[0]}
        {spanText && (
          <>
            {!parts[0].endsWith(' ') && ' '}
            <span className={`${spanColor} ${breakSpan ? 'block' : 'inline'}`}>
              {spanText}
            </span>
            {!parts[1]?.startsWith(' ') && ' '}
          </>
        )}
        {parts[1]}
      </h1>
    );
  }

  // Render with animations if isAnimate is true
  return (
    <h1
      ref={ref}
      className={`${centered ? 'text-center' : ''} ${color} ${size} ${fontFamily} ${fontWeight} ${className}`}
      style={{
        wordBreak: 'normal',
        overflowWrap: 'break-word',
        whiteSpace: 'pre-wrap'
      }}
    >
      {/* First part */}
      {splitIntoWords(parts[0]).map((word, wordIndex, wordArray) => (
        <span
          key={`word-1-${wordIndex}`}
          style={{ display: 'inline-block' }}
        >
          {splitWordIntoChars(word).map((char, charIndex) => {
            const currentCharIndex = charCount++;
            return (
              <motion.span
                key={`char-1-${wordIndex}-${charIndex}`}
                custom={currentCharIndex}
                initial="hidden"
                animate={controls}
                variants={characterVariants}
                style={{ display: 'inline-block' }}
                onAnimationComplete={
                  currentCharIndex === totalLength - 1 && onAnimationComplete
                    ? onAnimationComplete
                    : undefined
                }
              >
                {char}
              </motion.span>
            );
          })}
        </span>
      ))}

      {/* Span text */}
      {spanText && (
        <>
          {!parts[0].endsWith(' ') && (
            <span style={{ display: 'inline-block' }}>{'u00A0'}</span>
          )}
          <span 
            className={`${spanColor} ${breakSpan ? 'block' : 'inline-block'}`}
          >
            {splitIntoWords(spanText).map((word, wordIndex) => (
              <span
                key={`word-span-${wordIndex}`}
                style={{ display: 'inline-block' }}
              >
                {splitWordIntoChars(word).map((char, charIndex) => {
                  const currentCharIndex = charCount++;
                  return (
                    <motion.span
                      key={`char-span-${wordIndex}-${charIndex}`}
                      custom={currentCharIndex}
                      initial="hidden"
                      animate={controls}
                      variants={characterVariants}
                      style={{ display: 'inline-block' }}
                      onAnimationComplete={
                        currentCharIndex === totalLength - 1 && onAnimationComplete
                          ? onAnimationComplete
                          : undefined
                      }
                    >
                      {char}
                    </motion.span>
                  );
                })}
              </span>
            ))}
          </span>
          {!parts[1]?.startsWith(' ') && (
            <span style={{ display: 'inline-block' }}>{'u00A0'}</span>
          )}
        </>
      )}

      {/* Second part */}
      {parts[1] && splitIntoWords(parts[1]).map((word, wordIndex) => (
        <span
          key={`word-2-${wordIndex}`}
          style={{ display: 'inline-block' }}
        >
          {splitWordIntoChars(word).map((char, charIndex) => {
            const currentCharIndex = charCount++;
            return (
              <motion.span
                key={`char-2-${wordIndex}-${charIndex}`}
                custom={currentCharIndex}
                initial="hidden"
                animate={controls}
                variants={characterVariants}
                style={{ display: 'inline-block' }}
                onAnimationComplete={
                  currentCharIndex === totalLength - 1 && onAnimationComplete
                    ? onAnimationComplete
                    : undefined
                }
              >
                {char}
              </motion.span>
            );
          })}
        </span>
      ))}
    </h1>
  );
};

Heading.propTypes = {
  text: PropTypes.string.isRequired,
  spanText: PropTypes.string,
  spanColor: PropTypes.string,
  color: PropTypes.string,
  size: PropTypes.string,
  centered: PropTypes.bool,
  fontFamily: PropTypes.string,
  fontWeight: PropTypes.string,
  isAnimate: PropTypes.bool,
  order: PropTypes.number,
  onAnimationComplete: PropTypes.func,
  className: PropTypes.string,
  breakSpan: PropTypes.bool,
};

export default Heading;
import React from 'react';
import PropTypes from 'prop-types';
import { motion } from 'framer-motion';
import useFadeInAnimation from '../../utilities/Animations/useFadeInAnimation';

const BodyText = ({
  text,
  color = 'text-white',
  size = 'text-35px',
  lineHeight = 'leading-normal',
  fontFamily = 'font-mulish',
  fontWeight = 'font-extralight',
  centered = true,
  isAnimate = true,
  delay = 0,
  onAnimationComplete = null,
  className = '',
}) => {
  // Initialize animation hooks
  const { controls, ref, fadeInVariants } = useFadeInAnimation({ isAnimate, delay });

  // Render without animation if `isAnimate` is false
  if (!isAnimate) {
    return (
      <p
        className={`${centered ? 'text-center' : ''} ${color} ${size} ${lineHeight} ${fontFamily} ${fontWeight} ${className}`}
      >
        {text}
      </p>
    );
  }

  // Render with animation
  return (
    <motion.p
      ref={ref}
      initial="hidden"
      animate={controls}
      variants={fadeInVariants}
      onAnimationComplete={onAnimationComplete}
      style={{ position: 'relative' }} // Ensure position relative to avoid layout shift
      layout={true} // Prevent layout changes
      className={`${centered ? 'text-center' : ''} break-words ${color} ${size} ${lineHeight} ${fontFamily} ${fontWeight} ${className}`}
    >
      {text}
    </motion.p>
  );
};

BodyText.propTypes = {
  text: PropTypes.string.isRequired,
  color: PropTypes.string,
  size: PropTypes.string,
  lineHeight: PropTypes.string,
  fontFamily: PropTypes.string,
  fontWeight: PropTypes.string,
  centered: PropTypes.bool,
  isAnimate: PropTypes.bool,
  delay: PropTypes.number,
  onAnimationComplete: PropTypes.func,
  className: PropTypes.string,
};

export default BodyText;

import { useAnimation } from 'framer-motion';
import { useInView } from 'react-intersection-observer';
import { useEffect } from 'react';

const useTypingAnimation = ({ text, isAnimate, speedMultiplier = 0.8 }) => {
  const controls = useAnimation();
  const [ref, inView] = useInView({
    triggerOnce: true,
    threshold: 0.5,
  });

  const characterDelay = 0.06 * speedMultiplier;

  useEffect(() => {
    if (inView && isAnimate) {
      controls.start('visible');
    }
  }, [inView, isAnimate, controls]);

  const characterVariants = {
    hidden: {
      opacity: 0,
    },
    visible: i => ({
      opacity: 1,
      transition: {
        delay: i * characterDelay,
        duration: 0.05 * speedMultiplier,
      },
    }),
  };

  return { controls, ref, characterVariants };
};

export default useTypingAnimation;

import { useAnimation } from 'framer-motion';
import { useInView } from 'react-intersection-observer';
import { useEffect } from 'react';

const useFadeInAnimation = ({ isAnimate = true, delay = 0.3, duration = 1, threshold = 0.5 }) => {
  const controls = useAnimation();
  const [ref, inView] = useInView({
    triggerOnce: true, // Only animate once when in view
    threshold, // Controls when the animation is triggered (default 50% visibility)
  });

  useEffect(() => {
    if (inView && isAnimate) {
      controls.start('visible');
    }
  }, [inView, isAnimate, controls]);

  const fadeInVariants = {
    hidden: { opacity: 0 },
    visible: {
      opacity: 1,
      transition: { delay, duration,       ease: 'easeInOut',
      },
    },
  };

  return { controls, ref, fadeInVariants };
};

export default useFadeInAnimation;