Closed BigBoulard closed 10 months ago
I'm not familiar with SvelteKit, but emoji-picker-element
is a bog-standard custom element. So you should be able to just import it the way you would import it in any other framework.
The main difference is that emoji-picker-element
uses Svelte under the hood, so you're free to do import 'emoji-picker-element/svelte.js'
to save some bytes. But it's a very minor performance optimization.
The other consideration is that this project doesn't support SSR, and you probably wouldn't want to SSR it anyway since it makes more sense to lazy-load it from a user interaction, client-side.
I hope that helps! Let me know if anything is unclear from the documentation. :bow:
Hi @nolanlawson thank you for your response. I just realized that my question was misleading, sorry. In fact, I'm using sveltekit but I don't need SSR, so my question is not really specific to sveltekit but svelte.
I just tried to install using the npm module cause I don't want to load the library at the application startup using the script tag (and all dependencies are actually managed as npm modules) but it failed I don't know why (I'm not a frontend dev):
pnpm run dev emoji-picker-element
In component.svelte
...
<script>
import 'emoji-picker-element';
...
</script>
<emoji-picker />
requestAnimationFrame is not defined
ReferenceError: requestAnimationFrame is not defined
at file:///Users/me/dev/project/node_modules/.pnpm/emoji-picker-element@1.18.4/node_modules/emoji-picker-element/picker.js:676:13
at ModuleJob.run (node:internal/modules/esm/module_job:192:25)
at async DefaultModuleLoader.import (node:internal/modules/esm/loader:228:24)
at async nodeImport (file:///Users/me/dev/project/node_modules/.pnpm/vite@4.5.0_terser@5.22.0/node_modules/vite/dist/node/chunks/dep-bb8a8339.js:56097:17)
at async ssrImport (file:///Users/me/dev/project/node_modules/.pnpm/vite@4.5.0_terser
Yep, that's because it only works in client-side rendering, not server-side rendering. I don't know what the mechanism in SvelteKit is to force something to render only client-side, but that's what you would need to do. requestAnimationFrame is only available in the browser, not in Node.js.
Hi,
about prerendering: https://kit.svelte.dev/docs/page-options#prerender about SSR: https://kit.svelte.dev/docs/page-options#ssr
I disabled prerendering by adding this file /routes/+layout.js
with the code below
export const prerender = false;
export const ssr = false;
From there, It would have been great if I could be able to import like this but there's probably some adaptation to do in the npm package.
import { Picker } from 'emoji-picker-element';
// or this if there was a default export: import Picker from 'emoji-picker-element';
// or something like: import { Picker } from 'emoji-picker-element/svelte';
let picker = new Picker.default({
locale: 'en'
});
picker.addEventListener('emoji-click', onPickerClick);
emojiPanel.appendChild(picker);
So, in the end, here is what's working. Pretty ugly but it works
I think it would be beneficial if you could adapt this a little bit this snippet and add it as an example to your README.md
.
import { onMount } from 'svelte';
let Picker = null; // picker lib
let picker = null; // picker instance
onMount(async () => {
Picker = await import('emoji-picker-element/svelte');
picker = new Picker.default({
locale: 'en'
});
picker.addEventListener('emoji-click', onPickerClick);
emojiPanel.appendChild(picker);
});
function onPickerClick(e) {
console.log(e.detail);
}
</script>
<div class="emoji-panel" class:hidden={!showEmojiPanel} bind:this={emojiPanel} />
<div class="input-wrapper">
<input
type="text"
class="input-field"
name="message"
autocomplete="off"
/>
<button class="emoji-button" on:click={() => (showEmojiPanel = !showEmojiPanel)}>😄</button>
<button class="send-button" on:click={send}>Send</button>
</div>
<style>
.emoji-panel {
position: absolute;
bottom: 50px;
right: 80px;
}
.input-wrapper{
display: flex;
align-items: center;
padding: 10px;
}
.input-field {
flex-grow: 1;
border: none;
outline: none;
padding: 5px;
text-align: right;
width: 100%;
}
.emoji-button {
background-color: transparent;
border: none;
cursor: pointer;
font-size: 20px;
margin-left: 10px;
}
.send-button {
background-color: blue;
padding: 10px 20px;
cursor: pointer;
}
</style>
Thanks for the explanation. This is the key point I think:
onMount(async () => {
Picker = await import('emoji-picker-element/svelte');
// ...
})
onMount
only runs in the browser when using Svelte. So this avoids the SSR issue.
I would add something to the README, but I don't necessarily want to put something SvelteKit-specific in there. The advice will vary from container to container (Next, Remix, SolidStart, Vue+Vite, etc.).
BTW here is a simpler solution (IMO):
<emoji-picker></emoji-picker>
<script>
import { onMount } from 'svelte'
onMount(() => import('emoji-picker-element/svelte'))
</script>
The <emoji-picker>
tag is rendered server-side, but it's only upgraded to a custom element in onMount
when the component is imported. I tested it in a minimal SvelteKit app, and it works:
BTW here is a simpler solution (IMO):
<emoji-picker></emoji-picker> <script> import { onMount } from 'svelte' onMount(() => import('emoji-picker-element/svelte')) </script>
The
<emoji-picker>
tag is rendered server-side, but it's only upgraded to a custom element inonMount
when the component is imported. I tested it in a minimal SvelteKit app, and it works:
To complete the answer, you can listen to events as you do on the JSX part of the code like below:
<emoji-picker on:emoji-click={doSomething} />
This was really helpful. I wish the instructions were printed in the README, because I had to spend about 30 minutes searching around for it. I'm not very skilled as a frontend dev so it was nice to find this explanation in the issue tracker.
Thanks for the feedback. Added a note to the README ^
Hi guys,
What's the best way to install your project with a SvelteKit app?
Best.