Skip to content

Instantly share code, notes, and snippets.

@naif-sameer
Forked from peltho/svelte.md
Created November 25, 2021 06:55
Show Gist options
  • Save naif-sameer/bf6175a91b9869ef51676d24f256e97b to your computer and use it in GitHub Desktop.
Save naif-sameer/bf6175a91b9869ef51676d24f256e97b to your computer and use it in GitHub Desktop.

Revisions

  1. @peltho peltho revised this gist Apr 19, 2020. 1 changed file with 43 additions and 4 deletions.
    47 changes: 43 additions & 4 deletions svelte.md
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,41 @@

    [Doc examples](https://svelte.dev/examples)

    ### Table of Contents
    1. [Structure](#structure)
    2. [Imports](#imports)
    3. [Variables](#variables)
    4. [Reactivity](#reactivity)
    1. [Variables](#variables)
    2. [Statements](#statements)
    3. [Updating objects](#updating-objects)
    5. [Props](#props)
    6. [Logic](#logic)
    1. [Conditions](#conditions)
    2. [Loops](#loops)
    3. [Promises](#promises)
    7. [Events](#events)
    1. [Event dispatcher](#event-dispatcher)
    2. [Event forwarding](#event-forwarding)
    8. [Bindings](#bindings)
    9. [Lifecycle](#lifecycle)
    10. [Store](#store)
    1. [Usage](#usage)
    2. [Readable store](#readable-store)
    3. [Writable store](#writable-store)
    4. [Derived store](#derived-store)
    5. [Custom store](#custom-store)
    11. [Motion](#motion)
    1. [Tweened](#tweened)
    2. [Spring](#spring)
    12. [Transitions](#transitions)
    13. [Dynamic classes](#dynamic-classes)
    14. [Slots](#slots)
    15. [Contexts](#contexts)
    16. [Debugging](#debugging)
    17. [Integrations](#integrations)
    1. [GraphQL integration](#graphql-integration)

    Your components are inside `.svelte` files.

    ### Structure
    @@ -360,7 +395,8 @@ You can use auto-subscription to get rid of `subscribe` and `onDestroy` methods:

    > **Warning**: The store value must be imported or declared at the top-level scope of a component !
    #### Readable store (read-only store)
    #### Readable store
    It's a read-only store.

    ```svelte
    <script>
    @@ -390,7 +426,8 @@ You then have to define a `set` callback which is called when the store gets its
    ```
    It can be altered with `set` and `update`. It can also be `bind` to a tag.

    #### Derived store (from another store)
    #### Derived store
    ...from another store.
    ```svelte
    <script>
    import { derived } from 'svelte/store';
    @@ -464,7 +501,8 @@ It's usable like an ordinary store:
    <button on:click="{() => progress.set(0)}">0%</button>
    ```

    #### Spring (works better with frequently changing value)
    #### Spring
    ...works better with frequently changing value.

    ```svelte
    <script>
    @@ -579,7 +617,8 @@ Almost the same as **stores** but **less reactive**.
    Instead of using `debugger;` use `{@debug variable}`

    ## Integrations
    ### GraphQL integration (with Apollo)
    ### GraphQL integration
    ...with Apollo

    You'll have to import some plugins:

  2. @peltho peltho revised this gist Apr 19, 2020. 1 changed file with 10 additions and 0 deletions.
    10 changes: 10 additions & 0 deletions svelte.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,7 @@
    ## Svelte cheatsheet

    [Doc examples](https://svelte.dev/examples)

    Your components are inside `.svelte` files.

    ### Structure
    @@ -567,6 +569,14 @@ You can pass props to slots:
    ```
    The `let:` directive goes on the element with the slot attribute.

    ### Contexts

    Almost the same as **stores** but **less reactive**.
    [Documentation](https://svelte.dev/docs#setContext)

    ### Debugging

    Instead of using `debugger;` use `{@debug variable}`

    ## Integrations
    ### GraphQL integration (with Apollo)
  3. @peltho peltho revised this gist Apr 18, 2020. 1 changed file with 92 additions and 91 deletions.
    183 changes: 92 additions & 91 deletions svelte.md
    Original file line number Diff line number Diff line change
    @@ -66,14 +66,14 @@ Notice the usage of *`* (backquotes).
    Because Svelte's reactivity is **triggered** by **assignments** following code won't do anything when called:
    ```javascript
    function addNumber() {
    numbers.push(numbers.length + 1);
    numbers.push(numbers.length + 1);
    }
    ```
    Unless you add it this assignment:
    ```javascript
    function addNumber() {
    numbers.push(numbers.length + 1);
    numbers = numbers;
    numbers.push(numbers.length + 1);
    numbers = numbers;
    }
    ```

    @@ -102,14 +102,14 @@ When passing multiple **props** typically as an object of properties, you can **

    ```svelte
    <script>
    import Info from './Info.svelte';
    const pkg = {
    name: 'svelte',
    version: 3,
    speed: 'blazing',
    website: 'https://svelte.dev'
    };
    import Info from './Info.svelte';
    const pkg = {
    name: 'svelte',
    version: 3,
    speed: 'blazing',
    website: 'https://svelte.dev'
    };
    </script>
    <Info name={pkg.name} version={pkg.version} speed={pkg.speed} website={pkg.website}/>
    @@ -125,15 +125,15 @@ Assuming we have `export`ed `name`, `version`, and so on in the `Info` component
    To conditionally render some markup, we wrap it in an if block:
    ```svelte
    {#if user.loggedIn}
    <button on:click={toggle}>
    Log out
    </button>
    <button on:click={toggle}>
    Log out
    </button>
    {/if}
    {#if !user.loggedIn}
    <button on:click={toggle}>
    Log in
    </button>
    <button on:click={toggle}>
    Log in
    </button>
    {/if}
    ```

    @@ -147,9 +147,9 @@ Expressed this way:

    ```svelte
    {#each cats as cat, i}
    <li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
    {i}: {cat.name}
    </a></li>
    <li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
    {i}: {cat.name}
    </a></li>
    {/each}
    ```
    > **Tip**: You can also de-structure as: `{#each cats as { id, name }}` and then use `{name}` instead of `{cat.name}`
    @@ -159,9 +159,9 @@ Thus, be sure to **identify** the right object when updating its value(s):

    ```svelte
    {#each cats as cat, i (cat)} // Notice the (cat)
    <li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
    {i}: {cat.name}
    </a></li>
    <li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
    {i}: {cat.name}
    </a></li>
    {/each}
    ```

    @@ -185,15 +185,15 @@ You can bind functions / events to your tags:

    ```svelte
    <script>
    let count = 0;
    let count = 0;
    function handleClick() {
    count += 1;
    }
    function handleClick() {
    count += 1;
    }
    </script>
    <button on:click={handleClick}>
    Clicked {count} {count === 1 ? 'time' : 'times'}
    Clicked {count} {count === 1 ? 'time' : 'times'}
    </button>
    ```

    @@ -210,24 +210,24 @@ It must be called when component is first instantiated.
    <script>
    import { createEventDispatcher } from 'svelte';
    const dispatch = createEventDispatcher();
    const dispatch = createEventDispatcher();
    function sayHello() {
    dispatch('message', {
    text: 'Hello!'
    });
    }
    function sayHello() {
    dispatch('message', {
    text: 'Hello!'
    });
    }
    </script>
    ```
    On the other side:

    ```svelte
    <script>
    import Inner from './Inner.svelte';
    import Inner from './Inner.svelte';
    function handleMessage(event) {
    alert(event.detail.text);
    }
    function handleMessage(event) {
    alert(event.detail.text);
    }
    </script>
    <Inner on:message={handleMessage}/> // on:eventname
    @@ -239,7 +239,7 @@ You can handle events from any other component by calling them with their own ev
    ```svelte
    // Outer.svelte
    <script>
    import Inner from './Inner.svelte';
    import Inner from './Inner.svelte';
    </script>
    <Inner on:message/>
    @@ -259,7 +259,7 @@ Data flow is *top down*, that means a **parent** component can **set props on a

    ```svelte
    <script>
    let name = 'world';
    let name = 'world';
    </script>
    <input bind:value={name}> // name and value are tied together, they are bind
    @@ -271,19 +271,19 @@ You can also use a **group** of bindings:
    ```svelte
    <script>
    let flavourList = [
    'Cookies and cream',
    'Mint choc chip',
    'Raspberry ripple'
    'Cookies and cream',
    'Mint choc chip',
    'Raspberry ripple'
    ];
    </script>
    <h2>Flavours</h2>
    {#each flavourList as flavour}
    <label>
    <input type=checkbox bind:group={flavourList} value={flavour}>
    {flavour}
    </label>
    <label>
    <input type=checkbox bind:group={flavourList} value={flavour}>
    {flavour}
    </label>
    {/each}
    ```

    @@ -295,14 +295,14 @@ Is ruled by a bunch of functions:

    ```svelte
    <script>
    import { onMount } from 'svelte';
    import { onMount } from 'svelte';
    let photos = [];
    let photos = [];
    onMount(async () => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/photos?_limit=20`);
    photos = await res.json();
    });
    onMount(async () => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/photos?_limit=20`);
    photos = await res.json();
    });
    </script>
    ```

    @@ -317,8 +317,8 @@ A store is simply an object with a **subscribe** method that allows interested p
    <script>
    let countValue;
    const unsubscribe = count.subscribe(value => {
    count_value = value;
    });
    count_value = value;
    });
    onDestroy(unsubscribe);
    </script>
    @@ -327,16 +327,16 @@ A store is simply an object with a **subscribe** method that allows interested p
    Then, you can **update** the stored value:
    ```svelte
    <script>
    function increment() {
    count.update(n => n + 1)
    }
    function increment() {
    count.update(n => n + 1)
    }
    </script>
    ```
    Or set a value:
    ```svelte
    <script>
    function reset() {
    count.set(0);
    count.set(0);
    }
    </script>
    ```
    @@ -394,7 +394,7 @@ It can be altered with `set` and `update`. It can also be `bind` to a tag.
    import { derived } from 'svelte/store';
    const delayed = derived(time, ($a, set) => {
    setTimeout(() => set($a), 1000);
    setTimeout(() => set($a), 1000);
    }, 'one moment...');
    // or (read-only derived):
    @@ -413,22 +413,22 @@ First argument is the original store. **Second** one is **facultative** and adde

    import { writable } from 'svelte/store';
    function createCount() {
    const { subscribe, set, update } = writable(0);

    return {
    subscribe,
    increment: () => update(n => n + 1),
    decrement: () => update(n => n - 1),
    reset: () => set(0)
    };
    const { subscribe, set, update } = writable(0);

    return {
    subscribe,
    increment: () => update(n => n + 1),
    decrement: () => update(n => n - 1),
    reset: () => set(0)
    };
    }
    export const count = createCount();
    ```

    In the component:
    ```svelte
    <script>
    import { count } from './store.js';
    import { count } from './store.js';
    </script>
    <h1>The count is {$count}</h1>
    @@ -488,7 +488,8 @@ There're a lot:
    To affect a `class` to a tag dynamically when condition are met:
    ```javascript
    <button
    class:active="{current === 'foo'}">
    class:active="{current === 'foo'}"
    >
    Text
    </button>

    @@ -506,23 +507,23 @@ Here we affect the class `.active` when condition is true.
    Slots give you the opportunity to shape a component inside another one.
    ```svelte
    <script>
    import Box from './Box.svelte';
    import Box from './Box.svelte';
    </script>
    <Box>
    <h2>Hello!</h2>
    <p>This is a box. It can contain anything.</p>
    <h2>Hello!</h2>
    <p>This is a box. It can contain anything.</p>
    </Box>
    // Box.svelte
    <div class="box">
    <slot>A default value here</slot>
    <slot>A default value here</slot>
    </div>
    ```
    Slots can be named:
    ```svelte
    <script>
    import ContactCard from './ContactCard.svelte';
    import ContactCard from './ContactCard.svelte';
    </script>
    <ContactCard>
    @@ -531,35 +532,35 @@ Slots can be named:
    // ContactCard.svelte
    <article class="contact-card">
    <h2>
    <slot name="name">
    <span class="missing">Unknown name</span> // Will display T. Pellegatta because it has been defined
    </slot>
    </h2>
    <h2>
    <slot name="name">
    <span class="missing">Unknown name</span> // Will display T. Pellegatta because it has been defined
    </slot>
    </h2>
    <div class="address">
    <slot name="address">
    <span class="missing">Unknown address</span>
    </slot>
    </div>
    <slot name="address">
    <span class="missing">Unknown address</span>
    </slot>
    </div>
    </article>
    ```

    You can pass props to slots:
    ```svelte
    <!-- App.svelte -->
    <FancyList {items}>
    <div slot="item" let:item={item}>{item.text}</div>
    <p slot="footer">Copyright (c) 2019 Svelte Industries</p>
    <div slot="item" let:item={item}>{item.text}</div>
    <p slot="footer">Copyright (c) 2019 Svelte Industries</p>
    </FancyList>
    <!-- FancyList.svelte -->
    <ul>
    {#each items as item}
    <li class="fancy">
    <slot name="item" item={item}></slot>
    </li>
    {/each}
    {#each items as item}
    <li class="fancy">
    <slot name="item" item={item}></slot>
    </li>
    {/each}
    </ul>
    <slot name="footer"></slot>
  4. @peltho peltho revised this gist Apr 18, 2020. 1 changed file with 95 additions and 95 deletions.
    190 changes: 95 additions & 95 deletions svelte.md
    Original file line number Diff line number Diff line change
    @@ -66,14 +66,14 @@ Notice the usage of *`* (backquotes).
    Because Svelte's reactivity is **triggered** by **assignments** following code won't do anything when called:
    ```javascript
    function addNumber() {
    numbers.push(numbers.length + 1);
    numbers.push(numbers.length + 1);
    }
    ```
    Unless you add it this assignment:
    ```javascript
    function addNumber() {
    numbers.push(numbers.length + 1);
    numbers = numbers;
    numbers.push(numbers.length + 1);
    numbers = numbers;
    }
    ```

    @@ -102,14 +102,14 @@ When passing multiple **props** typically as an object of properties, you can **

    ```svelte
    <script>
    import Info from './Info.svelte';
    const pkg = {
    name: 'svelte',
    version: 3,
    speed: 'blazing',
    website: 'https://svelte.dev'
    };
    import Info from './Info.svelte';
    const pkg = {
    name: 'svelte',
    version: 3,
    speed: 'blazing',
    website: 'https://svelte.dev'
    };
    </script>
    <Info name={pkg.name} version={pkg.version} speed={pkg.speed} website={pkg.website}/>
    @@ -125,15 +125,15 @@ Assuming we have `export`ed `name`, `version`, and so on in the `Info` component
    To conditionally render some markup, we wrap it in an if block:
    ```svelte
    {#if user.loggedIn}
    <button on:click={toggle}>
    Log out
    </button>
    <button on:click={toggle}>
    Log out
    </button>
    {/if}
    {#if !user.loggedIn}
    <button on:click={toggle}>
    Log in
    </button>
    <button on:click={toggle}>
    Log in
    </button>
    {/if}
    ```

    @@ -147,9 +147,9 @@ Expressed this way:

    ```svelte
    {#each cats as cat, i}
    <li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
    {i}: {cat.name}
    </a></li>
    <li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
    {i}: {cat.name}
    </a></li>
    {/each}
    ```
    > **Tip**: You can also de-structure as: `{#each cats as { id, name }}` and then use `{name}` instead of `{cat.name}`
    @@ -159,9 +159,9 @@ Thus, be sure to **identify** the right object when updating its value(s):

    ```svelte
    {#each cats as cat, i (cat)} // Notice the (cat)
    <li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
    {i}: {cat.name}
    </a></li>
    <li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
    {i}: {cat.name}
    </a></li>
    {/each}
    ```

    @@ -185,15 +185,15 @@ You can bind functions / events to your tags:

    ```svelte
    <script>
    let count = 0;
    let count = 0;
    function handleClick() {
    count += 1;
    }
    function handleClick() {
    count += 1;
    }
    </script>
    <button on:click={handleClick}>
    Clicked {count} {count === 1 ? 'time' : 'times'}
    Clicked {count} {count === 1 ? 'time' : 'times'}
    </button>
    ```

    @@ -210,24 +210,24 @@ It must be called when component is first instantiated.
    <script>
    import { createEventDispatcher } from 'svelte';
    const dispatch = createEventDispatcher();
    const dispatch = createEventDispatcher();
    function sayHello() {
    dispatch('message', {
    text: 'Hello!'
    });
    }
    function sayHello() {
    dispatch('message', {
    text: 'Hello!'
    });
    }
    </script>
    ```
    On the other side:

    ```svelte
    <script>
    import Inner from './Inner.svelte';
    import Inner from './Inner.svelte';
    function handleMessage(event) {
    alert(event.detail.text);
    }
    function handleMessage(event) {
    alert(event.detail.text);
    }
    </script>
    <Inner on:message={handleMessage}/> // on:eventname
    @@ -239,7 +239,7 @@ You can handle events from any other component by calling them with their own ev
    ```svelte
    // Outer.svelte
    <script>
    import Inner from './Inner.svelte';
    import Inner from './Inner.svelte';
    </script>
    <Inner on:message/>
    @@ -259,7 +259,7 @@ Data flow is *top down*, that means a **parent** component can **set props on a

    ```svelte
    <script>
    let name = 'world';
    let name = 'world';
    </script>
    <input bind:value={name}> // name and value are tied together, they are bind
    @@ -271,19 +271,19 @@ You can also use a **group** of bindings:
    ```svelte
    <script>
    let flavourList = [
    'Cookies and cream',
    'Mint choc chip',
    'Raspberry ripple'
    'Cookies and cream',
    'Mint choc chip',
    'Raspberry ripple'
    ];
    </script>
    <h2>Flavours</h2>
    {#each flavourList as flavour}
    <label>
    <input type=checkbox bind:group={flavourList} value={flavour}>
    {flavour}
    </label>
    <label>
    <input type=checkbox bind:group={flavourList} value={flavour}>
    {flavour}
    </label>
    {/each}
    ```

    @@ -295,14 +295,14 @@ Is ruled by a bunch of functions:

    ```svelte
    <script>
    import { onMount } from 'svelte';
    import { onMount } from 'svelte';
    let photos = [];
    let photos = [];
    onMount(async () => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/photos?_limit=20`);
    photos = await res.json();
    });
    onMount(async () => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/photos?_limit=20`);
    photos = await res.json();
    });
    </script>
    ```

    @@ -317,8 +317,8 @@ A store is simply an object with a **subscribe** method that allows interested p
    <script>
    let countValue;
    const unsubscribe = count.subscribe(value => {
    count_value = value;
    });
    count_value = value;
    });
    onDestroy(unsubscribe);
    </script>
    @@ -327,16 +327,16 @@ A store is simply an object with a **subscribe** method that allows interested p
    Then, you can **update** the stored value:
    ```svelte
    <script>
    function increment() {
    count.update(n => n + 1)
    }
    function increment() {
    count.update(n => n + 1)
    }
    </script>
    ```
    Or set a value:
    ```svelte
    <script>
    function reset() {
    count.set(0);
    count.set(0);
    }
    </script>
    ```
    @@ -394,7 +394,7 @@ It can be altered with `set` and `update`. It can also be `bind` to a tag.
    import { derived } from 'svelte/store';
    const delayed = derived(time, ($a, set) => {
    setTimeout(() => set($a), 1000);
    setTimeout(() => set($a), 1000);
    }, 'one moment...');
    // or (read-only derived):
    @@ -413,22 +413,22 @@ First argument is the original store. **Second** one is **facultative** and adde

    import { writable } from 'svelte/store';
    function createCount() {
    const { subscribe, set, update } = writable(0);

    return {
    subscribe,
    increment: () => update(n => n + 1),
    decrement: () => update(n => n - 1),
    reset: () => set(0)
    };
    const { subscribe, set, update } = writable(0);

    return {
    subscribe,
    increment: () => update(n => n + 1),
    decrement: () => update(n => n - 1),
    reset: () => set(0)
    };
    }
    export const count = createCount();
    ```

    In the component:
    ```svelte
    <script>
    import { count } from './store.js';
    import { count } from './store.js';
    </script>
    <h1>The count is {$count}</h1>
    @@ -452,8 +452,8 @@ It's usable like an ordinary store:
    import { cubicOut } from 'svelte/easing';
    const progress = tweened(0, {
    duration: 400,
    easing: cubicOut
    duration: 400,
    easing: cubicOut
    });
    </script>
    @@ -469,8 +469,8 @@ It's usable like an ordinary store:
    import { spring } from 'svelte/motion';
    let coords = spring({ x: 50, y: 50 }, {
    stiffness: 0.1,
    damping: 0.25
    stiffness: 0.1,
    damping: 0.25
    });
    let size = spring(10);
    </script>
    @@ -488,7 +488,7 @@ There're a lot:
    To affect a `class` to a tag dynamically when condition are met:
    ```javascript
    <button
    class:active="{current === 'foo'}">
    class:active="{current === 'foo'}">
    Text
    </button>

    @@ -506,23 +506,23 @@ Here we affect the class `.active` when condition is true.
    Slots give you the opportunity to shape a component inside another one.
    ```svelte
    <script>
    import Box from './Box.svelte';
    import Box from './Box.svelte';
    </script>
    <Box>
    <h2>Hello!</h2>
    <p>This is a box. It can contain anything.</p>
    <h2>Hello!</h2>
    <p>This is a box. It can contain anything.</p>
    </Box>
    // Box.svelte
    <div class="box">
    <slot>A default value here</slot>
    <slot>A default value here</slot>
    </div>
    ```
    Slots can be named:
    ```svelte
    <script>
    import ContactCard from './ContactCard.svelte';
    import ContactCard from './ContactCard.svelte';
    </script>
    <ContactCard>
    @@ -531,35 +531,35 @@ Slots can be named:
    // ContactCard.svelte
    <article class="contact-card">
    <h2>
    <slot name="name">
    <span class="missing">Unknown name</span> // Will display T. Pellegatta because it has been defined
    </slot>
    </h2>
    <h2>
    <slot name="name">
    <span class="missing">Unknown name</span> // Will display T. Pellegatta because it has been defined
    </slot>
    </h2>
    <div class="address">
    <slot name="address">
    <span class="missing">Unknown address</span>
    </slot>
    </div>
    <slot name="address">
    <span class="missing">Unknown address</span>
    </slot>
    </div>
    </article>
    ```

    You can pass props to slots:
    ```svelte
    <!-- App.svelte -->
    <FancyList {items}>
    <div slot="item" let:item={item}>{item.text}</div>
    <p slot="footer">Copyright (c) 2019 Svelte Industries</p>
    <div slot="item" let:item={item}>{item.text}</div>
    <p slot="footer">Copyright (c) 2019 Svelte Industries</p>
    </FancyList>
    <!-- FancyList.svelte -->
    <ul>
    {#each items as item}
    <li class="fancy">
    <slot name="item" item={item}></slot>
    </li>
    {/each}
    {#each items as item}
    <li class="fancy">
    <slot name="item" item={item}></slot>
    </li>
    {/each}
    </ul>
    <slot name="footer"></slot>
  5. @peltho peltho revised this gist Apr 18, 2020. No changes.
  6. @peltho peltho revised this gist Apr 18, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion svelte.md
    Original file line number Diff line number Diff line change
    @@ -613,7 +613,7 @@ In another one (or the same) use it to fetch/push data:
    {:then result}
    <p>Total todos: {result.data.getTodos.length}</p>
    <ul>
    {each esult.data.getTodos as todo}
    {each result.data.getTodos as todo}
    <li>{todo.text}</li>
    {/each}
    </ul>
  7. @peltho peltho created this gist Apr 18, 2020.
    623 changes: 623 additions & 0 deletions svelte.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,623 @@
    ## Svelte cheatsheet

    Your components are inside `.svelte` files.

    ### Structure

    Your component use few tags to be operating:
    - `<script>`
    - `<style>`

    `<script>` will describe how to animate the component.
    `<style>` how to render it


    ### Imports
    You can include a component inside another one by importing it:
    ```svelte
    <script>
    import Nested from './Nested.svelte'
    </script>
    <Nested/>
    ```

    ### Variables

    You can define variables in your `<script>` tag and then use it with brackets:
    ```svelte
    <script>
    let foo = "bar"
    </script>
    <p class={bar}>Some text</p>
    ```

    > **Tip**: It also works inside double-quotes: `<p class="primary-{bar}">Some text</p>`
    Moreover, when var = attribute, (`src={src}`) you can use it this way: `{src}`.

    ### Reactivity

    **Reactivity is triggered by assignments**
    What does it mean? Every change will be triggered after an assignment has been done.

    More on that later.

    ##### Variables
    Sometimes a variable is result from a computation, you'll have to use a *reactive declaration*:
    ```javascript
    let count = 0
    $: doubled = count * 2
    ```

    ##### Statements
    We're not limited to variable declaration, we can also use reactive statements:
    ```javascript
    $: console.log(`the count is ${count}`);
    ```
    Here `console.log` is called whenever `count` value changes.
    Notice the usage of *`* (backquotes).

    > **Tip**: You can group more statements by using `$: { ... }`.
    ##### Updating objects

    Because Svelte's reactivity is **triggered** by **assignments** following code won't do anything when called:
    ```javascript
    function addNumber() {
    numbers.push(numbers.length + 1);
    }
    ```
    Unless you add it this assignment:
    ```javascript
    function addNumber() {
    numbers.push(numbers.length + 1);
    numbers = numbers;
    }
    ```

    ### Props

    There's an easy way to pass props to a child component. Just `export` it !
    ```svelte
    // Nested.svelte
    <script>
    export let answer = 42
    </script>
    <p>The answer is {answer}</p>
    // App.svelte
    <script>
    import Nested from './Nested.svelte'
    </script>
    <Nested/> // Will display: The answer is 42
    ```

    > **Tip**: You can also use `<Nested answer={42}/>` to set a default value to a prop that hasn't been initialized into it's own component.

    When passing multiple **props** typically as an object of properties, you can **spread** them to a component instead of specifying each one with `...`:

    ```svelte
    <script>
    import Info from './Info.svelte';
    const pkg = {
    name: 'svelte',
    version: 3,
    speed: 'blazing',
    website: 'https://svelte.dev'
    };
    </script>
    <Info name={pkg.name} version={pkg.version} speed={pkg.speed} website={pkg.website}/>
    <Info {...pkg}/>
    ```

    Assuming we have `export`ed `name`, `version`, and so on in the `Info` component.

    ### Logic

    #### Conditions

    To conditionally render some markup, we wrap it in an if block:
    ```svelte
    {#if user.loggedIn}
    <button on:click={toggle}>
    Log out
    </button>
    {/if}
    {#if !user.loggedIn}
    <button on:click={toggle}>
    Log in
    </button>
    {/if}
    ```

    You can also make use of :
    - `{:else}`
    - `{:else if .. }`

    #### Loops

    Expressed this way:

    ```svelte
    {#each cats as cat, i}
    <li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
    {i}: {cat.name}
    </a></li>
    {/each}
    ```
    > **Tip**: You can also de-structure as: `{#each cats as { id, name }}` and then use `{name}` instead of `{cat.name}`
    When a value isn't **exported** but is computed by a **prop**, you can go into problems when updating values since it's a *copy* and not a *reference*.
    Thus, be sure to **identify** the right object when updating its value(s):

    ```svelte
    {#each cats as cat, i (cat)} // Notice the (cat)
    <li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
    {i}: {cat.name}
    </a></li>
    {/each}
    ```

    #### Promises
    You can deal with **promises** and display at each of the promise lifecycle:

    ```svelte
    {#await promise}
    <p>Loading...</p>
    {:then result}
    <p>It returns {result}</p>
    {:catch error}
    <p>An error occurred: {error.message}</p>
    {/await}
    ```

    > **Tip**: You can also skip loading step by using: `{#await promise then result}`
    ### Events
    You can bind functions / events to your tags:

    ```svelte
    <script>
    let count = 0;
    function handleClick() {
    count += 1;
    }
    </script>
    <button on:click={handleClick}>
    Clicked {count} {count === 1 ? 'time' : 'times'}
    </button>
    ```

    You can use all javascript event (click, mousemove, ...).
    You can also *modify* event by *piping* **modifiers** to it:
    `<button on:click|once={handleClick}>`
    You can *chain* them by adding pipes.

    #### Event dispatcher

    You can create an event dispatcher inside a component.
    It must be called when component is first instantiated.
    ```svelte
    <script>
    import { createEventDispatcher } from 'svelte';
    const dispatch = createEventDispatcher();
    function sayHello() {
    dispatch('message', {
    text: 'Hello!'
    });
    }
    </script>
    ```
    On the other side:

    ```svelte
    <script>
    import Inner from './Inner.svelte';
    function handleMessage(event) {
    alert(event.detail.text);
    }
    </script>
    <Inner on:message={handleMessage}/> // on:eventname
    ```

    #### Event forwarding

    You can handle events from any other component by calling them with their own event:
    ```svelte
    // Outer.svelte
    <script>
    import Inner from './Inner.svelte';
    </script>
    <Inner on:message/>
    ```
    Here we can intercept event `message` from `Inner`.
    Then, **when called**, we can define how the component **reacts**:

    ```svelte
    <Outer on:message={handleMessage}/>
    ```

    ### Bindings

    Data flow is *top down*, that means a **parent** component can **set props on a child** component but **not the other way** around.

    **Bindings** can break that rule:

    ```svelte
    <script>
    let name = 'world';
    </script>
    <input bind:value={name}> // name and value are tied together, they are bind
    <h1>Hello {name}!</h1>
    ```

    You can also use a **group** of bindings:
    ```svelte
    <script>
    let flavourList = [
    'Cookies and cream',
    'Mint choc chip',
    'Raspberry ripple'
    ];
    </script>
    <h2>Flavours</h2>
    {#each flavourList as flavour}
    <label>
    <input type=checkbox bind:group={flavourList} value={flavour}>
    {flavour}
    </label>
    {/each}
    ```

    ### Lifecycle

    Is ruled by a bunch of functions:

    - `onMount`

    ```svelte
    <script>
    import { onMount } from 'svelte';
    let photos = [];
    onMount(async () => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/photos?_limit=20`);
    photos = await res.json();
    });
    </script>
    ```

    - `onDestroy`
    - `beforeUpdate`
    - `afterUpdate`

    ### Store

    A store is simply an object with a **subscribe** method that allows interested parties to be **notified** whenever the **store value** changes:
    ```svelte
    <script>
    let countValue;
    const unsubscribe = count.subscribe(value => {
    count_value = value;
    });
    onDestroy(unsubscribe);
    </script>
    <h1>The count is {count_value}</h1>
    ```
    Then, you can **update** the stored value:
    ```svelte
    <script>
    function increment() {
    count.update(n => n + 1)
    }
    </script>
    ```
    Or set a value:
    ```svelte
    <script>
    function reset() {
    count.set(0);
    }
    </script>
    ```

    > **Best practice**: Auto-subscription
    #### Usage

    You can use auto-subscription to get rid of `subscribe` and `onDestroy` methods:

    ```svelte
    <script>
    import { storeValue } from './AnotherComponent'
    // ...other imports come after
    </script>
    <h1>The count is {$storeValue}</h1>
    ```

    > **Warning**: The store value must be imported or declared at the top-level scope of a component !
    #### Readable store (read-only store)

    ```svelte
    <script>
    export const time = readable(new Date(), function start(set) {
    // Implementation
    set()
    return function stop() {
    // Implementation
    }
    })
    </script>
    ```
    The **first argument** can be null, it represents an **initial value**.
    You then have to define a `set` callback which is called when the store gets its **first subscriber** and a `stop` callback when the last subscriber unsubscribes.

    #### Writable store
    ```svelte
    <script>
    import { writable } from 'svelte/store';
    const count = writable(0, () => {
    console.log('got a subscriber');
    return () => console.log('no more subscribers');
    });
    </script>
    ```
    It can be altered with `set` and `update`. It can also be `bind` to a tag.

    #### Derived store (from another store)
    ```svelte
    <script>
    import { derived } from 'svelte/store';
    const delayed = derived(time, ($a, set) => {
    setTimeout(() => set($a), 1000);
    }, 'one moment...');
    // or (read-only derived):
    const elapsed = derived(time, $time =>
    Math.round(($time - start) / 1000)
    );
    </script>
    ```
    First argument is the original store. **Second** one is **facultative** and added if you want to **write** on the store.

    #### Custom store
    ```javascript
    // store.js

    import { writable } from 'svelte/store';
    function createCount() {
    const { subscribe, set, update } = writable(0);

    return {
    subscribe,
    increment: () => update(n => n + 1),
    decrement: () => update(n => n - 1),
    reset: () => set(0)
    };
    }
    export const count = createCount();
    ```

    In the component:
    ```svelte
    <script>
    import { count } from './store.js';
    </script>
    <h1>The count is {$count}</h1>
    <button on:click={count.increment}>+</button>
    <button on:click={count.decrement}>-</button>
    <button on:click={count.reset}>reset</button>
    ```

    ### Motion

    Stores are cool but you can make them even smoother by adding animation when transposed to UI.

    #### Tweened

    It's usable like an ordinary store:

    ```svelte
    <script>
    import { tweened } from 'svelte/motion';
    import { cubicOut } from 'svelte/easing';
    const progress = tweened(0, {
    duration: 400,
    easing: cubicOut
    });
    </script>
    <progress value={$progress}></progress>
    <button on:click="{() => progress.set(0)}">0%</button>
    ```

    #### Spring (works better with frequently changing value)

    ```svelte
    <script>
    import { spring } from 'svelte/motion';
    let coords = spring({ x: 50, y: 50 }, {
    stiffness: 0.1,
    damping: 0.25
    });
    let size = spring(10);
    </script>
    ```

    ### Transitions

    There're a lot:
    - Fade in/out: `transition:fade` (ie: `<p transition:fade>Some text</p>`)
    - Fly (disappear in a given direction): `transition:fly`
    - ...

    ### Dynamic classes

    To affect a `class` to a tag dynamically when condition are met:
    ```javascript
    <button
    class:active="{current === 'foo'}">
    Text
    </button>

    <style>
    .active {
    background-color: #ff3e00;
    color: white;
    }
    </style>
    ```
    Here we affect the class `.active` when condition is true.

    ### Slots

    Slots give you the opportunity to shape a component inside another one.
    ```svelte
    <script>
    import Box from './Box.svelte';
    </script>
    <Box>
    <h2>Hello!</h2>
    <p>This is a box. It can contain anything.</p>
    </Box>
    // Box.svelte
    <div class="box">
    <slot>A default value here</slot>
    </div>
    ```
    Slots can be named:
    ```svelte
    <script>
    import ContactCard from './ContactCard.svelte';
    </script>
    <ContactCard>
    <span slot="name">T. Pellegatta</span>
    </ContactCard>
    // ContactCard.svelte
    <article class="contact-card">
    <h2>
    <slot name="name">
    <span class="missing">Unknown name</span> // Will display T. Pellegatta because it has been defined
    </slot>
    </h2>
    <div class="address">
    <slot name="address">
    <span class="missing">Unknown address</span>
    </slot>
    </div>
    </article>
    ```

    You can pass props to slots:
    ```svelte
    <!-- App.svelte -->
    <FancyList {items}>
    <div slot="item" let:item={item}>{item.text}</div>
    <p slot="footer">Copyright (c) 2019 Svelte Industries</p>
    </FancyList>
    <!-- FancyList.svelte -->
    <ul>
    {#each items as item}
    <li class="fancy">
    <slot name="item" item={item}></slot>
    </li>
    {/each}
    </ul>
    <slot name="footer"></slot>
    ```
    The `let:` directive goes on the element with the slot attribute.


    ## Integrations
    ### GraphQL integration (with Apollo)

    You'll have to import some plugins:

    - `apollo-boost`
    - `graphql`
    - `svelte-apollo`

    Then, in the main component instantiate a client:
    ```svelte
    <script>
    import ApolloClient from 'apollo-boost'
    import { setClient } from 'svelte-apollo'
    const client = new ApolloClient({
    uri: 'http://site/graphqlApi/endpoint'
    })
    setClient(client)
    </script>
    ```

    In another one (or the same) use it to fetch/push data:
    ```svelte
    <script>
    import { getClient, query } from 'svelte-apollo'
    import { gql } from 'apollo-boost'
    const GET_TODOS = gql`
    {
    getTodos {
    id
    text
    }
    }
    `
    const client = getClient()
    const todos = query(client, { query: GET_TODOS })
    </script>
    {#await $todos}
    Loading...
    {:then result}
    <p>Total todos: {result.data.getTodos.length}</p>
    <ul>
    {each esult.data.getTodos as todo}
    <li>{todo.text}</li>
    {/each}
    </ul>
    {:catch error}
    <p>{error.message}</p>
    {/await}
    ```