I retrieve HTML text from a database and I am performing some animation to display the content. In order to keep layout clean I want to get the height and width of the element and empty it before starting my animation. But the onMount call does give me dimensions like it is empty.
I get the correct dimensions if the text is static but not dynamic. Is there anything I can do to avoid this ?
//+page.svelte
<script>
import { page } from '$app/state';
</script>
<div class="catch-phrase">
<TypewriterEffect>
<div>
{ page.data.personalMessage}
</div>
</TypewriterEffect>
</div>
<style>
.catch-phrase {
display: flex;
align-items: center;
margin: 0 10vw;
max-width: 1200px;
height: 90dvh;
}
</style>
//Typewriter.svelte
<script>
onMount(() => {
fullNode = container.cloneNode(true);
container.style.height = container.offsetHeight + 'px';
container.style.width = container.offsetWidth + 'px';
container.innerHTML = '';
isReady = true;
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
console.log('launch !!');
typewriter();
observer.disconnect();
}
});
},
{
root: null, // viewport
threshold: 1 // percentage of element visible
}
);
observer.observe(container);
});
const typewriter = async () => {
var fullHtmlText = '';
for (var i = 0; i < fullNode.childNodes.length; i++) {
if (fullNode.childNodes[i].nodeType === 1) {
fullHtmlText = fullNode.childNodes[i].textContent;
splittedText = splitHtmlText(fullHtmlText, chunkSize);
container.appendChild(fullNode.childNodes[i]);
container.childNodes[i].textContent = '';
await type(container.childNodes[i], fullHtmlText, 0);
}
}
function type(node, fullHtmlText, currentIndex) {
return new Promise((resolve) => {
if (node.textContent.length >= fullHtmlText.length) {
resolve();
clearTimeout(timeout);
callback();
return;
}
node.innerHTML = splittedText.slice(0, currentIndex).join('');
var timeout = setTimeout(() => type(node, fullHtmlText, currentIndex + 1), 10);
});
}
return {
destroy() {
clearTimeout(timeout);
}
};
};
}
</script>
<div bind:this={container}>{@render children?.()}</div>
Here is a screenshot of the conatainer height :
Thanks for your help.
Apparently the problem comes from the page.data and seems to be a bug (posted here and here.
Using data.personalMessage
message instead of page.data.personalMessage
is both a workaround and a better practice.
//+page.svelte
<script>
const { data } = $props();
</script>
<TypewriterEffect>
{@html data.personalMessage}
</TypewriterEffect>
Thanks to @brunnerh for the solution.