Useful Custom Svelte Stores

Published: July 12, 2022 Updated: July 18, 2022

Useful Custom Svelte Stores

Table of Contents

History

This store tracks this history of its value and provides undo and redo functions. Demo REPL

Credit for this code goes to /u/Graineon and /u/Mustard_kat on Reddit.

import { writable } from "svelte/store";

export function history<T>(initial: T) {
  const current = writable(initial);
  const history = [initial];
  let index = 0;

  const refresh = () => current.set(history[index]);

  const set = (newState: T) => {
    history.splice(index + 1, history.length - index, newState);
    index++;
    refresh();
  };

  return {
    set,
    subscribe: current.subscribe,
    undo: () => {
      index = Math.max(0, index - 1);
      refresh();
    },
    redo: () => {
      index = Math.min(history.length - 1, index + 1);
      refresh();
    }
  };
}

WebSockets

This is a read-only store I wrote to track the state of a WebSocket connection. It is a very basic example.

import { writable } from "svelte/store";

export default function createSocket<T>(initial?: T) {
  const { subscribe, set } = writable(initial || null);

  let websocket: WebSocket;

  return {
    subscribe,
    connect(url: string) {
      if (websocket) {
        websocket.close();
      }

      websocket = new WebSocket(url);

      websocket.onopen = () => {
        console.log("Websocket connected!");
      };

      websocket.onerror = error => {
        console.log("Websocket error:", error);
      };

      websocket.onmessage = event => {
        const data = JSON.parse(event.data);
        set(data);
      };
    },
    send(data: T) {
      if (websocket.readyState !== websocket.OPEN) throw new Error("No websocket connection");
      websocket.send(JSON.stringify(data));
    }
  };
}

Then in your Svelte component:

<script lang="ts">
  import { onMount } from 'svelte';
  import createSocket from "$lib/stores/websocket"
  import { WEBSOCKET_URL } from "$lib/env"

  const store = createSocket();

  onMount(() => {
    store.connect(WEBSOCKET_URL)
  });

  $: console.log($store)
</script>

Toasts

This is another store I had written to manage toast messages.

import { writable } from "svelte/store";

export type ToastType = "success" | "error" | "warning" | "info";

export interface Toast {
  id: number;
  type: ToastType;
  message: string;
}

export const toasts = (() => {
  const { update, set, subscribe } = writable<Toast[]>([]);
  const remove = (id: number) => update(t => t.filter(t => t.id !== id));
  const reset = () => set([]);
  const add = (type: ToastType, message: string, timer = 5000) =>
    update(t => {
      const toast: Toast = {
        id: Math.random(),
        type,
        message
      };
      if (timer)
        setTimeout(() => {
          remove(toast.id || 0);
        }, timer);
      return [...t, toast];
    });

  return {
    subscribe,
    add,
    remove,
    reset
  };
})();