Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@beyonk/svelte-mapbox

Package Overview
Dependencies
Maintainers
8
Versions
61
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@beyonk/svelte-mapbox - npm Package Compare versions

Comparing version
11.0.0
to
12.0.0
eslint.config.js
+55
import { load } from '../asset-loader.js'
import { bindEvents } from '../event-bindings.js'
export default function geocoderAttachment (options) {
return (element) => {
let geocoderInstance
let unbind = () => {}
const resources = [
{ type: 'script', value: `//api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/${options.version}/mapbox-gl-geocoder.min.js`, id: 'byk-gc-js' }
]
const customStylesheetUrl = options.customStylesheetUrl
if (customStylesheetUrl) {
resources.push({ type: 'link', value: customStylesheetUrl, id: 'byk-gcsu-css' })
} else {
resources.push({ type: 'link', value: `//api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/${options.version}/mapbox-gl-geocoder.css`, id: 'byk-gc-css' })
}
load(resources, () => {
geocoderInstance = new window.MapboxGeocoder(options)
geocoderInstance.addTo(`#${element.id}`)
if (options.value) {
geocoderInstance.setInput(options.value)
}
unbind = bindEvents(geocoderInstance, handlers, false, element)
})
return () => {
unbind()
geocoderInstance && geocoderInstance.remove && geocoderInstance.remove()
}
}
}
const handlers = {
results: (el, ev) => {
return [ 'results', ev ]
},
result: (el, ev) => {
return [ 'result', ev ]
},
loading: (el, ev) => {
return [ 'loading', ev ]
},
error: (el, ev) => {
return [ 'error', ev ]
},
clear: (el, ev) => {
return [ 'clear', ev ]
},
load: el => {
return [ 'ready', { geocoder: el } ]
}
}
import { load } from '../asset-loader.js'
import { bindEvents } from '../event-bindings.js'
export default function mapAttachment (options = {}) {
return (element) => {
console.log('attach', element, options)
let map
function init (options) {
window.mapboxgl.accessToken = options.accessToken
const el = new window.mapboxgl.Map(options)
return bindEvents(el, handlers, window.mapboxgl, element)
}
const resources = [
{ type: 'script', attr: 'src', value: `//api.mapbox.com/mapbox-gl-js/${options.version}/mapbox-gl.js`, id: 'byk-gl-js' },
{ type: 'link', attr: 'href', value: `//api.mapbox.com/mapbox-gl-js/${options.version}/mapbox-gl.css`, id: 'byk-gl-css' }
]
const customStylesheetUrl = options.customStylesheetUrl
if (customStylesheetUrl) {
resources.push({ type: 'link', attr: 'href', value: customStylesheetUrl, id: 'byk-mcsu-css' })
}
let unbind = () => {}
load(resources, () => {
unbind = init({ ...options, container: element })
})
return {
destroy () {
unbind()
map && map.remove && map.remove()
}
}
}
}
const handlers = {
dragend: el => {
return [ 'dragend', { center: el.getCenter() } ]
},
drag: el => {
return [ 'drag', { center: el.getCenter() } ]
},
moveend: el => {
return [ 'recentre', { center: el.getCenter() } ]
},
click: (el, { lngLat }) => {
return [ 'click', { lng: lngLat.lng, lat: lngLat.lat } ]
},
zoomstart: el => {
return [ 'zoomstart', { zoom: el.getZoom() } ]
},
zoom: el => {
return [ 'zoom', { zoom: el.getZoom() } ]
},
zoomend: el => {
return [ 'zoomend', { zoom: el.getZoom() } ]
},
load: (el, ev, mapbox) => {
return [ 'ready', { map: el, mapbox } ]
}
}
export class EventQueue {
queue = []
started = false
map = null
send (command, params = []) {
if (!command) { return }
this.queue.push([ command, params ])
this.#process()
}
start (map) {
this.started = true
this.map = map
}
#process () {
if (!this.started) { return }
while (this.queue.length) {
const [ command, params ] = this.queue.shift()
this.map[command].apply(this.map, params)
}
}
stop () {
if (!this.started) { return }
this.queue = []
this.map = null
this.started = false
}
}
+1
-9

@@ -5,13 +5,5 @@ name: publish

push:
branches:
- '*'
tags:
- 'v*'
pull_request:
branches:
- '*'
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
jobs:

@@ -28,3 +20,3 @@ publish-npm:

corepack enable
pnpm config set '//registry.npmjs.org/:_authToken' "${NODE_AUTH_TOKEN}"
pnpm config set '//registry.npmjs.org/:_authToken' "${{secrets.NPM_TOKEN}}"
pnpm i

@@ -31,0 +23,0 @@

{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"$lib": ["src/lib"],
"$lib/*": ["src/lib/*"]
}
},
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"]
}
{
"name": "@beyonk/svelte-mapbox",
"version": "11.0.0",
"version": "12.0.0",
"devDependencies": {

@@ -8,10 +8,10 @@ "@beyonk/eslint-config": "^8.0.2",

"@eslint/js": "^9.14.0",
"@sveltejs/kit": "^2.8.0",
"@sveltejs/vite-plugin-svelte": "^4.0.0",
"@sveltejs/kit": "^2.55.0",
"@sveltejs/vite-plugin-svelte": "^7.0.0",
"eslint": "^9.14.0",
"eslint-plugin-svelte": "^2.46.0",
"svelte": "^5.1.14",
"svelte": "^5.55.0",
"svelte2tsx": "^0.7.23",
"typescript": "^5.6.3",
"vite": "^5.4.11"
"vite": "^8.0.2"
},

@@ -26,3 +26,2 @@ "peerDependencies": {

"type": "module",
"packageManager": "pnpm@8.15.7",
"scripts": {

@@ -29,0 +28,0 @@ "dev": "vite dev --port 3030",

@@ -1,30 +0,19 @@

<div
id={fieldId}
use:action={optionsWithDefaults}
on:ready={init}
on:results
on:result
on:loading
on:error
on:clear
on:load
></div>
<script>
import { createEventDispatcher } from 'svelte'
import action from './geocoder-action.js'
import geocoderAttachment from './geocoder-attachment.js'
export let accessToken
export let options = {}
export let version = 'v5.0.3'
export let types = [ 'country', 'region', 'postcode', 'district', 'place', 'locality', 'neighborhood', 'address' ]
export let placeholder = 'Search'
export let value = null
export let customStylesheetUrl = false
export let geocoder
let {
accessToken,
options = {},
version = 'v5.1.0',
types = [ 'country', 'region', 'postcode', 'district', 'place', 'locality', 'neighborhood', 'address' ],
placeholder = 'Search',
value = null,
customStylesheetUrl = false,
geocoder = $bindable(),
...rest
} = $props()
const dispatch = createEventDispatcher()
const fieldId = 'bsm-' + Math.random().toString(36).substring(6)
const optionsWithDefaults = Object.assign({
const optionsWithDefaults = $derived.by(() => Object.assign({
version,

@@ -36,10 +25,17 @@ accessToken,

value
}, options)
}, options))
function init ({ detail }) {
geocoder = detail.geocoder
dispatch('ready')
function init (e) {
geocoder = e.detail.geocoder
onready?.()
}
</script>
<div
id={fieldId}
{@attach geocoderAttachment(optionsWithDefaults)}
onready={init}
{...rest}
></div>
<style>

@@ -49,2 +45,2 @@ div {

}
</style>
</style>

@@ -1,56 +0,38 @@

<div
bind:this={dispatcher}
on:error
on:geolocate
on:outofmaxbounds
on:trackuserlocationend
on:trackuserlocationstart
/>
<script>
import { getContext, onMount } from 'svelte'
import { contextKey } from '../../mapbox.js'
import { bindEvents } from '../../event-bindings.js'
import { getContext, onMount, untrack } from 'svelte'
import { contextKey } from '../../mapbox.js'
import { bindEvents } from '../../event-bindings.js'
const { getMap, getMapbox } = getContext(contextKey)
const map = getMap()
const mapbox = getMapbox()
const { getMap, getMapbox } = getContext(contextKey)
const map = getMap()
const mapbox = getMapbox()
export let position = 'top-left'
export let options = {}
let { position = 'top-left', options = {}, ...rest } = $props()
let dispatcher
let dispatcher = $state()
const handlers = {
error: (el, ev) => {
return [ 'error', ev ]
},
geolocate: (el, ev) => {
return [ 'geolocate', ev ]
},
outofmaxbounds: (el, ev) => {
return [ 'outofmaxbounds', ev ]
},
trackuserlocationend: (el, ev) => {
return [ 'trackuserlocationend', ev ]
},
trackuserlocationstart: (el, ev) => {
return [ 'trackuserlocationstart', ev ]
}
}
const handlers = {
error: (el, ev) => [ 'error', ev ],
geolocate: (el, ev) => [ 'geolocate', ev ],
outofmaxbounds: (el, ev) => [ 'outofmaxbounds', ev ],
trackuserlocationend: (el, ev) => [ 'trackuserlocationend', ev ],
trackuserlocationstart: (el, ev) => [ 'trackuserlocationstart', ev ]
}
const geolocate = new mapbox.GeolocateControl(options)
map.addControl(geolocate, position)
const geolocate = new mapbox.GeolocateControl(untrack(() => options))
map.addControl(geolocate, untrack(() => position))
onMount(() => {
return bindEvents(geolocate, handlers, mapbox, dispatcher)
})
onMount(() => {
return bindEvents(geolocate, handlers, mapbox, dispatcher)
})
export function trigger () {
geolocate.trigger()
}
export function trigger () {
geolocate.trigger()
}
</script>
<div bind:this={dispatcher} {...rest}></div>
<style>
div { display: none; }
div { display: none; }
</style>
<script>
import { getContext } from 'svelte'
import { contextKey } from '../../mapbox.js'
import { getContext, untrack } from 'svelte'
import { contextKey } from '../../mapbox.js'
const { getMap, getMapbox } = getContext(contextKey)
const map = getMap()
const mapbox = getMapbox()
const { getMap, getMapbox } = getContext(contextKey)
const map = getMap()
const mapbox = getMapbox()
export let position = 'top-right'
export let options = {}
let { position = 'top-right', options = {} } = $props()
const nav = new mapbox.NavigationControl(options)
map.addControl(nav, position)
</script>
const nav = new mapbox.NavigationControl(untrack(() => options))
map.addControl(nav, untrack(() => position))
</script>
<script>
import { getContext } from 'svelte'
import { contextKey } from '../../mapbox.js'
import { getContext, untrack } from 'svelte'
import { contextKey } from '../../mapbox.js'
const { getMap, getMapbox } = getContext(contextKey)
const map = getMap()
const mapbox = getMapbox()
const { getMap, getMapbox } = getContext(contextKey)
const map = getMap()
const mapbox = getMapbox()
export let position = 'bottom-right'
export let options = {}
let { position = 'bottom-right', options = {} } = $props()
const optionsWithDefaults = Object.assign({
maxWidth: 80,
unit: 'metric'
}, options)
const optionsWithDefaults = untrack(() => Object.assign({
maxWidth: 80,
unit: 'metric'
}, options))
const scale = new mapbox.ScaleControl(optionsWithDefaults)
map.addControl(scale, position)
</script>
const scale = new mapbox.ScaleControl(optionsWithDefaults)
map.addControl(scale, untrack(() => position))
</script>

@@ -1,58 +0,28 @@

<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
<div
use:action={optionsWithDefaults}
on:ready={init}
on:recentre
on:dragend
on:click
on:zoomstart
on:zoom
on:zoomend
on:drag
on:keydown
on:keyup
role="application"
>
{#if map}
<slot></slot>
{/if}
</div>
<style>
div {
width: 100%;
height: 100%;
}
</style>
<script>
import { setContext, onDestroy, createEventDispatcher } from 'svelte'
import { setContext, untrack } from 'svelte'
import { contextKey } from '../mapbox.js'
import action from './map-action.js'
import { EventQueue } from '../queue.js'
import mapAttachment from './map-attachment.js'
import { EventQueue } from '../queue.svelte.js'
export let map = null
export let version = 'v3.7.0'
export let center = [ 0, 0 ]
export let zoom = 9
export let zoomRate = 1
export let wheelZoomRate = 1
export let options = {}
export let accessToken
export let customStylesheetUrl = false
export let style = 'mapbox://styles/mapbox/streets-v11'
let {
map = $bindable(null),
version = 'v3.20.0',
center = [ 0, 0 ],
zoom = $bindable(9),
zoomRate = 1,
wheelZoomRate = 1,
options = {},
accessToken,
customStylesheetUrl = false,
style = 'mapbox://styles/mapbox/streets-v11',
children,
onready,
...rest
} = $props()
const dispatch = createEventDispatcher()
let mapbox = $state()
setContext(contextKey, {
getMap: () => map,
getMapbox: () => mapbox
})
let container
let mapbox
const optionsWithDefaults = Object.assign({
const optionsWithDefaults = {
accessToken,
container,
style,

@@ -65,19 +35,35 @@ center,

customStylesheetUrl,
map
}, options)
map,
...options
}
setContext(contextKey, {
getMap: () => map,
getMapbox: () => mapbox
})
const queue = new EventQueue()
function init ({ detail }) {
map = detail.map
mapbox = detail.mapbox
function init (e) {
map = e.detail.map
mapbox = e.detail.mapbox
queue.start(map)
dispatch('ready')
onready?.()
map.on('zoomend', (e) => {
zoom = map.getZoom()
})
}
onDestroy(() => {
queue.stop()
map = undefined
$effect(() => {
return () => {
queue.stop()
map = undefined
}
})
$effect(() => {
zoom && setZoom(zoom)
})
export function fitBounds (bbox, data = {}) {

@@ -114,4 +100,20 @@ queue.send('fitBounds', [ bbox, data ])

}
</script>
$: zoom && setZoom(zoom)
</script>
<div
{@attach mapAttachment(optionsWithDefaults)}
onready={init}
{...rest}
role="presentation"
>
{#if map}
{@render children?.()}
{/if}
</div>
<style>
div {
width: 100%;
height: 100%;
}
</style>

@@ -13,2 +13,21 @@ <script>

let {
lat,
lng,
label = 'Marker',
popupClassName = 'beyonk-mapbox-popup',
markerOffset = [ 0, 0 ],
popupOffset = 10,
color = randomColour(),
popup = true,
popupOptions = {},
markerOptions = {},
children,
popupContent
} = $props()
let marker = $state()
let element = $state()
let elementPopup = $state()
function move (lng, lat) {

@@ -18,28 +37,13 @@ marker.setLngLat({ lng, lat })

export let lat
export let lng
export let label = 'Marker'
export let popupClassName = 'beyonk-mapbox-popup'
export let markerOffset = [ 0, 0 ]
export let popupOffset = 10
export let color = randomColour()
export let popup = true
export let popupOptions = {}
export let markerOptions = {}
$effect(() => {
if (marker) move(lng, lat)
})
let marker
let element
let elementPopup
$: marker && move(lng, lat)
onMount(() => {
const namedParams = Object.assign(
{
offset: markerOffset
},
{ offset: markerOffset },
element.hasChildNodes() ? { element } : { color }
)
marker = new mapbox.Marker(Object.assign(namedParams, markerOptions))
if (popup) {

@@ -53,3 +57,2 @@ const namedPopupParams = { offset: popupOffset, className: popupClassName }

}
marker.setPopup(popupEl)

@@ -73,7 +76,7 @@ }

<div bind:this={element}>
<slot></slot>
{@render children?.()}
</div>
<div class='popup' bind:this={elementPopup}>
<slot name="popup"></slot>
{@render popupContent?.()}
</div>

@@ -0,1 +1,49 @@

<script>
import { PUBLIC_MAPBOX_TOKEN } from '$env/static/public'
import { Map, Geocoder, Marker, controls } from '$lib/components.js'
import Earthquakes from './_Earthquakes.svelte'
const { GeolocateControl, NavigationControl } = controls
let place = $state(null)
let page = $state('about')
let center = $state({ lat: 53.3358627, lng: -2.8572362 })
let marker = $derived(center)
let zoom = $state(11.15)
let mapComponent = $state()
function navigate (next) {
page = next
}
function placeChanged (e) {
const { result } = e.detail
mapComponent.setCenter(result.center, 14)
place = result
}
function randomLng () {
return 77 + (Math.random() - 0.5) * 30
}
function randomLat () {
return 13 + (Math.random() - 0.5) * 30
}
function flyToRandomPlace () {
mapComponent.flyTo({
center: [ randomLng(), randomLat() ],
essential: true
})
}
function recentre (e) {
center = e.detail.center
}
function drag (e) {
marker = e.detail.center
}
</script>
<header>

@@ -45,8 +93,8 @@ <div class="container">

<div class="menu-box">
<h4>Navigation</h4>
<h4>Navigation</h4>
<nav>
<ul>
<li><a href="#geocoder" on:click={() => { navigate('geocoder') } } class:current={page === 'geocoder'}>Geocoder</a></li>
<li><a href="#map" on:click={() => { navigate('map') }} class:current={page === 'map'}>Map</a></li>
</ul>
<li><a href="#geocoder" onclick={() => navigate('geocoder')} class:current={page === 'geocoder'}>Geocoder</a></li>
<li><a href="#map" onclick={() => navigate('map')} class:current={page === 'map'}>Map</a></li>
</ul>
</nav>

@@ -57,24 +105,17 @@ </div>

<div class="action-buttons">
<button id="fly-to" on:click={flyToRandomPlace}
>Fly to random location</button
>
<button
id="change-zoom"
on:click={() => (zoom = Math.floor(Math.random() * 10))}
>Change Zoom Level</button
>
</div>
<button id="fly-to" onclick={flyToRandomPlace}>Fly to random location</button>
<button id="change-zoom" onclick={() => (zoom = Math.floor(Math.random() * 10))}>Change Zoom Level</button>
</div>
<div class="section-txt" id="geocoder">
<form>
<Geocoder value="(Near London)" accessToken={PUBLIC_MAPBOX_TOKEN} on:result={placeChanged} on:clear={() => mapComponent.setCenter({ lng: 0, lat: 0 })} />
{#if place}
<dl>
<dt>Name:</dt>
<dd>{place.label}</dd>
<dt>Geolocation:</dt>
<dd>lat: {place.geometry.lat}, lng: {place.geometry.lng}</dd>
</dl>
{/if}
<Geocoder value="(Near London)" accessToken={PUBLIC_MAPBOX_TOKEN} onresult={placeChanged} onclear={() => mapComponent.setCenter({ lng: 0, lat: 0 })} />
{#if place}
<dl>
<dt>Name:</dt>
<dd>{place.place_name}</dd>
<dt>Geolocation:</dt>
<dd>lat: {place.geometry.coordinates[1]}, lng: {place.geometry.coordinates[0]}</dd>
</dl>
{/if}
</form>

@@ -87,4 +128,4 @@ </div>

accessToken={PUBLIC_MAPBOX_TOKEN}
on:recentre={recentre}
on:drag={drag}
onrecentre={recentre}
ondrag={drag}
{center}

@@ -95,3 +136,3 @@ bind:zoom

<NavigationControl />
<GeolocateControl on:geolocate={e => console.log('geolocated', e.detail)} />
<GeolocateControl ongeolocate={e => console.log('geolocated', e.detail)} />
<Marker lat={marker.lat} lng={marker.lng} />

@@ -164,53 +205,2 @@ </Map>

}
</style>
<script>
import { PUBLIC_MAPBOX_TOKEN } from '$env/static/public'
import { Map, Geocoder, Marker, controls } from '$lib/components.js'
import Earthquakes from './_Earthquakes.svelte'
const { GeolocateControl, NavigationControl } = controls
const place = null
let page = 'about'
let center = { lat: 53.3358627, lng: -2.8572362 }
let marker = center
let zoom = 11.15
let mapComponent
function navigate (next) {
page = next
}
function placeChanged (e) {
const { result } = e.detail
mapComponent.setCenter(result.center, 14)
}
function randomLng () {
return 77 + (Math.random() - 0.5) * 30
}
function randomLat () {
return 13 + (Math.random() - 0.5) * 30
}
function flyToRandomPlace () {
mapComponent.flyTo({
center: [
randomLng(),
randomLat()
],
essential: true
})
}
function recentre ({ detail }) {
center = detail.center
}
function drag ({ detail }) {
marker = detail.center
}
</script>
/** @type {import('@sveltejs/kit').Config} */
const config = {}
const config = {
vitePlugin: {
inspector: true
}
}
export default config

Sorry, the diff of this file is not supported yet

import { load } from '../asset-loader.js'
import { bindEvents } from '../event-bindings.js'
export default function action (node, options = {}) {
let map
const resources = [
{ type: 'script', value: `//api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/${options.version}/mapbox-gl-geocoder.min.js`, id: 'byk-gc-js' }
]
const customStylesheetUrl = options.customStylesheetUrl
if (customStylesheetUrl) {
resources.push({ type: 'link', value: customStylesheetUrl, id: 'byk-gcsu-css' })
} else {
resources.push({ type: 'link', value: `//api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/${options.version}/mapbox-gl-geocoder.css`, id: 'byk-gc-css' })
}
let unbind = () => {}
load(resources, () => {
unbind = init(options, node)
})
return {
destroy () {
unbind()
map && map.remove && map.remove()
}
}
}
function init (options, node) {
const geocoder = new window.MapboxGeocoder(options)
geocoder.addTo(`#${node.id}`)
if (options.value) {
geocoder.setInput(options.value)
}
return bindEvents(geocoder, handlers, false, node)
}
const handlers = {
results: (el, ev) => {
return [ 'results', ev ]
},
result: (el, ev) => {
return [ 'result', ev ]
},
loading: (el, ev) => {
return [ 'loading', ev ]
},
error: (el, ev) => {
return [ 'error', ev ]
},
clear: (el, ev) => {
return [ 'clear', ev ]
},
load: el => {
return [ 'ready', { geocoder: el } ]
}
}
import { load } from '../asset-loader.js'
import { bindEvents } from '../event-bindings.js'
export default function action (node, options = {}) {
let map
const resources = [
{ type: 'script', attr: 'src', value: `//api.mapbox.com/mapbox-gl-js/${options.version}/mapbox-gl.js`, id: 'byk-gl-js' },
{ type: 'link', attr: 'href', value: `//api.mapbox.com/mapbox-gl-js/${options.version}/mapbox-gl.css`, id: 'byk-gl-css' }
]
const customStylesheetUrl = options.customStylesheetUrl
if (customStylesheetUrl) {
resources.push({ type: 'link', attr: 'href', value: customStylesheetUrl, id: 'byk-mcsu-css' })
}
let unbind = () => {}
load(resources, () => {
unbind = init({ ...options, container: node }, node)
})
return {
destroy () {
unbind()
map && map.remove && map.remove()
}
}
}
function init (options, node) {
window.mapboxgl.accessToken = options.accessToken
const el = new window.mapboxgl.Map(options)
return bindEvents(el, handlers, window.mapboxgl, node)
}
const handlers = {
dragend: el => {
return [ 'dragend', { center: el.getCenter() } ]
},
drag: el => {
return [ 'drag', { center: el.getCenter() } ]
},
moveend: el => {
return [ 'recentre', { center: el.getCenter() } ]
},
click: (el, { lngLat }) => {
return [ 'click', { lng: lngLat.lng, lat: lngLat.lat } ]
},
zoomstart: el => {
return [ 'zoomstart', { zoom: el.getZoom() } ]
},
zoom: el => {
return [ 'zoom', { zoom: el.getZoom() } ]
},
zoomend: el => {
return [ 'zoomend', { zoom: el.getZoom() } ]
},
load: (el, ev, mapbox) => {
return [ 'ready', { map: el, mapbox } ]
}
}
import { writable } from 'svelte/store'
export class EventQueue {
constructor () {
this.queue = writable([])
this.unsubscribe = null
this.started = false
}
send (command, params = []) {
if (!command) { return }
this.queue.update(q => ([ ...q, [ command, params ] ]))
}
start (map) {
this.unsubscribe = this.queue.subscribe(queue => {
while (queue.length) {
const [ command, params ] = queue.shift()
map[command].apply(map, params)
}
})
this.started = true
}
stop () {
if (!this.started) { return }
this.unsubscribe()
this.queue = writable([])
this.started = false
}
}