Skip to content

Instantly share code, notes, and snippets.

@Neophen
Last active March 30, 2024 09:17
Show Gist options
  • Select an option

  • Save Neophen/27a694155c430acfb8e9be3433887a47 to your computer and use it in GitHub Desktop.

Select an option

Save Neophen/27a694155c430acfb8e9be3433887a47 to your computer and use it in GitHub Desktop.

Revisions

  1. Neophen revised this gist Mar 30, 2024. 1 changed file with 26 additions and 0 deletions.
    26 changes: 26 additions & 0 deletions x-counter.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,26 @@
    export class XCounter extends HTMLElement {
    connectedCallback() {
    this.inputElement = this.querySelector('input') ?? this.querySelector('textarea')
    if (!this.inputElement) {
    throw new Error('<x-counter>: requires an <input> or a <textarea> element')
    }

    this.counterElement = this.querySelector('[x-counter-value]')
    if (!this.counterElement) {
    throw new Error('<x-counter>: requires an element with the [x-counter-value] attribute')
    }

    this.inputElement.addEventListener('input', this.onInput)
    this.onInput()
    }

    disconnectedCallback() {
    this.inputElement?.removeEventListener('input', this.onInput)
    }

    onInput = () => {
    this.counterElement.textContent = this.inputElement?.value?.length ?? 0
    }
    }

    customElements.define('x-counter', XCounter)
  2. Neophen revised this gist Mar 30, 2024. No changes.
  3. Neophen revised this gist Mar 30, 2024. No changes.
  4. Neophen created this gist Mar 30, 2024.
    44 changes: 44 additions & 0 deletions marko_image.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,44 @@
    export class MarkoNativeShare extends HTMLElement {
    pictureElement?: HTMLPictureElement | null
    images?: HTMLImageElement[] | null
    loaded = false

    connectedCallback() {
    this.pictureElement = this.querySelector('picture')
    if (!this.pictureElement) {
    throw new Error('<x-image>: requires a <picture> element')
    }

    this.images = Array.from(this.pictureElement.querySelectorAll('img'))
    if (this.images.length === 0) {
    throw new Error('<x-image>: requires an <img> element inside <picture>')
    }

    const complete = this.images.some((image) => image.complete)

    if (complete) {
    this.onLoad()
    } else {
    this.images.forEach((image) => {
    image.addEventListener('load', this.onLoad)
    })
    }
    }

    disconnectedCallback() {
    this.onLoad()
    }

    onLoad = () => {
    if (this.loaded || !this.pictureElement) return
    this.loaded = true

    this.images?.forEach((image) => image.removeEventListener('load', this.onLoad))

    this.pictureElement?.style.setProperty('--preview-image', 'none')
    this.pictureElement = null
    this.images = null
    }
    }

    customElements.define('marko-image', MarkoNativeShare)
    52 changes: 52 additions & 0 deletions x_image.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,52 @@
    import { ViewHook } from 'phoenix_live_view'

    const XImage: Partial<ViewHook> & {
    pictureElement?: HTMLPictureElement
    image?: HTMLImageElement | null
    init: () => void
    onLoad: () => void
    } = {
    mounted() {
    this.init()
    },
    updated() {
    this.destroyed?.()
    this.init()
    },
    destroyed() {
    if (!this.image) return

    this.image.removeEventListener('load', this.onLoad)
    this.image = undefined
    this.pictureElement = undefined
    },

    // ___________________________________________________________________________________________________________________
    init() {
    this.pictureElement = this.el
    if (!(this.pictureElement instanceof HTMLPictureElement)) return
    this.onLoad = this.onLoad.bind(this)

    this.image = this.pictureElement.querySelector('img')
    if (!this.image) return

    if (this.image.complete) {
    this.onLoad()
    return
    }

    this.image.addEventListener('load', this.onLoad)
    },

    onLoad() {
    if (!this.pictureElement) return

    if (this.image) {
    this.image.removeEventListener('load', this.onLoad)
    }

    this.pictureElement.style.setProperty('--preview-image', 'none')
    }
    }

    export default XImage