forked from MapComplete/MapComplete
		
	ToSvelte will now bind directly to svelte in the case that a SvelteUIElement is passed. This helps with cleaning up MapLibre maps, which should help with #2024
This commit is contained in:
		
							parent
							
								
									7038fcc6f6
								
							
						
					
					
						commit
						7d678d95c7
					
				
					 4 changed files with 54 additions and 18 deletions
				
			
		| 
						 | 
					@ -11,7 +11,7 @@ export default class SvelteUIElement<
 | 
				
			||||||
    Events extends Record<string, any> = any,
 | 
					    Events extends Record<string, any> = any,
 | 
				
			||||||
    Slots extends Record<string, any> = any
 | 
					    Slots extends Record<string, any> = any
 | 
				
			||||||
> extends BaseUIElement {
 | 
					> extends BaseUIElement {
 | 
				
			||||||
    private readonly _svelteComponent: {
 | 
					    public readonly _svelteComponent: {
 | 
				
			||||||
        new (args: {
 | 
					        new (args: {
 | 
				
			||||||
            target: HTMLElement
 | 
					            target: HTMLElement
 | 
				
			||||||
            props: Props
 | 
					            props: Props
 | 
				
			||||||
| 
						 | 
					@ -19,10 +19,11 @@ export default class SvelteUIElement<
 | 
				
			||||||
            slots?: Slots
 | 
					            slots?: Slots
 | 
				
			||||||
        }): SvelteComponentTyped<Props, Events, Slots>
 | 
					        }): SvelteComponentTyped<Props, Events, Slots>
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    private readonly _props: Props
 | 
					    public readonly _props: Props
 | 
				
			||||||
    private readonly _events: Events
 | 
					    public readonly _events: Events
 | 
				
			||||||
    private readonly _slots: Slots
 | 
					    public readonly _slots: Slots
 | 
				
			||||||
    private tag: "div" | "span" = "div"
 | 
					    private tag: "div" | "span" = "div"
 | 
				
			||||||
 | 
					    public readonly isSvelte = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(svelteElement, props?: Props, events?: Events, slots?: Slots) {
 | 
					    constructor(svelteElement, props?: Props, events?: Events, slots?: Slots) {
 | 
				
			||||||
        super()
 | 
					        super()
 | 
				
			||||||
| 
						 | 
					@ -47,4 +48,18 @@ export default class SvelteUIElement<
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        return el
 | 
					        return el
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public getClass(){
 | 
				
			||||||
 | 
					        if(this.clss.size === 0){
 | 
				
			||||||
 | 
					            return undefined
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return this.clss
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public getStyle(){
 | 
				
			||||||
 | 
					        if(this.style === ""){
 | 
				
			||||||
 | 
					            return undefined
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return this.style
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,24 @@
 | 
				
			||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
  import BaseUIElement from "../BaseUIElement.js"
 | 
					  import BaseUIElement from "../BaseUIElement.js"
 | 
				
			||||||
  import { onDestroy, onMount } from "svelte"
 | 
					  import { onDestroy, onMount } from "svelte"
 | 
				
			||||||
 | 
					  import SvelteUIElement from "./SvelteUIElement"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export let construct: BaseUIElement | (() => BaseUIElement)
 | 
					  export let construct: BaseUIElement | (() => BaseUIElement)
 | 
				
			||||||
  let elem: HTMLElement
 | 
					  let elem: HTMLElement
 | 
				
			||||||
  let html: HTMLElement
 | 
					  let html: HTMLElement
 | 
				
			||||||
 | 
					  let isSvelte = false
 | 
				
			||||||
 | 
					  let uiElement : BaseUIElement | SvelteUIElement | undefined
 | 
				
			||||||
 | 
					  let svelteElem: SvelteUIElement
 | 
				
			||||||
  onMount(() => {
 | 
					  onMount(() => {
 | 
				
			||||||
    const uiElem = typeof construct === "function" ? construct() : construct
 | 
					    uiElement = typeof construct === "function" ? construct() : construct
 | 
				
			||||||
    html = uiElem?.ConstructElement()
 | 
					
 | 
				
			||||||
 | 
					    if (uiElement?.["isSvelte"]) {
 | 
				
			||||||
 | 
					      isSvelte = true
 | 
				
			||||||
 | 
					      svelteElem = <SvelteUIElement> uiElement
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    html = uiElement?.ConstructElement()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (html !== undefined) {
 | 
					    if (html !== undefined) {
 | 
				
			||||||
      elem?.replaceWith(html)
 | 
					      elem?.replaceWith(html)
 | 
				
			||||||
| 
						 | 
					@ -16,7 +27,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  onDestroy(() => {
 | 
					  onDestroy(() => {
 | 
				
			||||||
    html?.remove()
 | 
					    html?.remove()
 | 
				
			||||||
 | 
					    uiElement?.Destroy()
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<span bind:this={elem} />
 | 
					{#if isSvelte}
 | 
				
			||||||
 | 
					  <svelte:component this={svelteElem?._svelteComponent} {...svelteElem._props} class={svelteElem.getClass()} style={svelteElem.getStyle()}/>
 | 
				
			||||||
 | 
					{:else}
 | 
				
			||||||
 | 
					  <span bind:this={elem} />
 | 
				
			||||||
 | 
					{/if}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,7 +63,7 @@ export default abstract class BaseUIElement {
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Adds all the relevant classes, space separated
 | 
					     * Adds all the relevant classes, space separated
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public SetClass(clss: string) {
 | 
					    public SetClass(clss: string): this {
 | 
				
			||||||
        if (clss == undefined) {
 | 
					        if (clss == undefined) {
 | 
				
			||||||
            return this
 | 
					            return this
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -101,7 +101,7 @@ export default abstract class BaseUIElement {
 | 
				
			||||||
        return this.clss.has(clss)
 | 
					        return this.clss.has(clss)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public SetStyle(style: string): BaseUIElement {
 | 
					    public SetStyle(style: string): this {
 | 
				
			||||||
        this.style = style
 | 
					        this.style = style
 | 
				
			||||||
        if (this._constructedHtmlElement !== undefined) {
 | 
					        if (this._constructedHtmlElement !== undefined) {
 | 
				
			||||||
            this._constructedHtmlElement.style.cssText = style
 | 
					            this._constructedHtmlElement.style.cssText = style
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,13 +50,13 @@
 | 
				
			||||||
      center: { lng: lon, lat },
 | 
					      center: { lng: lon, lat },
 | 
				
			||||||
      maxZoom: 24,
 | 
					      maxZoom: 24,
 | 
				
			||||||
      interactive: true,
 | 
					      interactive: true,
 | 
				
			||||||
      attributionControl: false,
 | 
					      attributionControl: false
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    _map = new maplibre.Map(options)
 | 
					    _map = new maplibre.Map(options)
 | 
				
			||||||
    window.requestAnimationFrame(() => {
 | 
					    window.requestAnimationFrame(() => {
 | 
				
			||||||
      _map.resize()
 | 
					      _map.resize()
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    _map.on("load", function () {
 | 
					    _map.on("load", function() {
 | 
				
			||||||
      _map.resize()
 | 
					      _map.resize()
 | 
				
			||||||
      const canvas = _map.getCanvas()
 | 
					      const canvas = _map.getCanvas()
 | 
				
			||||||
      if (interactive) {
 | 
					      if (interactive) {
 | 
				
			||||||
| 
						 | 
					@ -71,13 +71,18 @@
 | 
				
			||||||
    map.set(_map)
 | 
					    map.set(_map)
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
  onDestroy(async () => {
 | 
					  onDestroy(async () => {
 | 
				
			||||||
    await Utils.waitFor(250)
 | 
					    await Utils.waitFor(100)
 | 
				
			||||||
    try {
 | 
					    requestAnimationFrame(
 | 
				
			||||||
      if (_map) _map.remove()
 | 
					      () => {
 | 
				
			||||||
      map = null
 | 
					        try {
 | 
				
			||||||
    } catch (e) {
 | 
					          _map?.remove()
 | 
				
			||||||
      console.error("Could not destroy map")
 | 
					          console.log("Removed map")
 | 
				
			||||||
    }
 | 
					          map = null
 | 
				
			||||||
 | 
					        } catch (e) {
 | 
				
			||||||
 | 
					          console.error("Could not destroy map")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue