Svelte REPLs
Don't forget your saved Svelte REPLs. There maybe helpful things in there.
Export function to Svelte file
<script>
import capitalize from '../helpers/string'
console.log(capitalize('hey'))
</script>
export function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
Snippet for small saved notification
{#if newTabCreation}
{#if tabJustSaved}
Saved!
{/if}
{/if}
Iterate over Object.entries
{#each Object.entries(categoryDefinitions) as [name, categoricalDefinitions], i}
<DefineCategory name={name} {categoricalDefinitions} />
{/each}
Bind to iterable being iterated over while in loop
{#each categoryDefinitions as category, i}
<DefineCategory bind:category={categoryDefinitions[i]} storageKey={''}
<div class="text-xs font-extrabold text-red-400 hover:text-red-500 cursor-pointer top-2 relative" slot="delete" on:click={() => deleteCategory(i)}>
X
</div>
</DefineCategory>
{/each}
What is happening here is basically you shouldn't bind category to category (ie: bind:category={category})
That doesn't work. However if you bind to the index of the looped object, it does work.
This also applies for objects but using the key instead of an index.
Always make your changes directly to the variable that is defined outside of the loop.
Append something to the body of an element
Wrap the element in the <Portal> code as shown below
Portal code
<Portal>
<div>This is appended to the body</div>
</Portal>
<script>
// src/components/Portal.svelte
import { onMount, onDestroy } from "svelte";
let ref;
let portal;
onMount(async () => {
portal = document.createElement("div");
portal.className = "portal";
document.body.appendChild(portal);
portal.appendChild(ref);
});
onDestroy(() => {
document.body.removeChild(portal);
});
</script>
<style>
.portal-clone {
display: none;
}
</style>
<div class="portal-clone">
<div bind:this={ref}>
<slot />
</div>
</div>
Positioning something absolutely while also having a transition
Transitions require that the element be not even created yet and so you cannot bind to them.
This is a hacky workaround that says basically make the element but make it invisible and absolute
(if absolute is desired in the end product) in order to get the exact width of the element.
Here is the relevant (not full) code:
<script>
const POSITIONS = {
'top-left': `left: 50px; top: 50px;`,
'top-center': (translateX, translateY) => `left: calc(50% - ${translateX}px); top: 50px;`,
}
function setPosition(pos, open) {
let [xOffset, yOffset] = handleForOffset();
let modalWidth;
let modalHeight;
let translateX;
let translateY;
try {
modalWidth = modal.offsetWidth;
modalHeight = modal.offsetHeight;
translateX = modalWidth / 2;
translateY = modalHeight / 2;
} catch {
translateX = 0;
translateY = 0;
}
style = POSITIONS[pos](translateX, translateY)
}
</script>
{#if example}
<button on:click={() => open = true}>Open Modal</button>
<svelte:self bind:open={open}>
<div class="px-4 py-2 bg-slate-800">
This is an example modal
</div>
</svelte:self>
{:else}
{#if open}
<Portal>
<div bind:this={modal}
in:fly=
out:fly=
class="modal absolute z-50 shadow-8"
style="{style}">
<slot />
</div>
</Portal>
{:else}
<div bind:this={modal} class="absolute invisible"><slot /></div>
{/if}
<DocumentBackdrop bind:visible={open} />
{/if}
Generating Example for component
This is a small example of how to pass necessary variables to the "non-example" component from the "example" component.
<script>
import BaseModal from "../../modals/BaseModal.svelte";
export let example = false;
export let open = false;
export let position = 'middle-center'
</script>
{#if example}
<button on:click={() => open = true}>Open Modal</button>
<svelte:self bind:open={open} position={position}>
<div slot="title">Delete Category</div>
<div slot="description">Are you sure you want to delete this category?</div>
</svelte:self>
{:else}
<BaseModal bind:open={open} position={position} >
hey
</BaseModal>
{/if}
Call parent function from child
In this example the following assumptions are made:
The "parent component" is the component that is inherited from, NOT a component that "houses" the child
The "child component" basically inherits from the parent component and makes assumptions about certain variables
For example the BaseModal would be the parent, and the Delete modal (which inherits from BaseModal) would be the child.
Ok so I think I found a solution to this.
Bind the child component to a variable, then we can call any function that is exported by the parent
Example:
Chart bind:this={chartRef}
Then in the script tag we can say this:
chartRef.exportedFunction();
In the parent component we have to export said function in regular script tag:
export function exportedFunction() => { doStuff(); }
This is not tested but I think it makes sense
Animations stopping new page from rendering immediately
Use the local tag to make transitions only occur when the element itself is added or deleted.
By default it includes any parent that is added or deleted.
in:fly|local=
out:fly|local=
transition:fly|local
Dynamic Named Slots
Dynamic named slots are not supported. Right now I have no good solution, unfortunately.
Get filename of current file
console.log($$props.$$scope.ctx[3].name);