Skip to content

Instantly share code, notes, and snippets.

@leevigraham
Last active October 18, 2018 11:24
Show Gist options
  • Select an option

  • Save leevigraham/0bfc1a5740f9cd528cb1fcfb97635f4b to your computer and use it in GitHub Desktop.

Select an option

Save leevigraham/0bfc1a5740f9cd528cb1fcfb97635f4b to your computer and use it in GitHub Desktop.

Revisions

  1. leevigraham revised this gist Apr 16, 2018. 2 changed files with 19 additions and 32 deletions.
    22 changes: 13 additions & 9 deletions example.html
    Original file line number Diff line number Diff line change
    @@ -1,12 +1,16 @@
    <flyout v-cloak>
    <button slot="reference"
    slot-scope="props"
    <div slot-scope="props">
    <button
    v-on:click="props.toggle()"
    v-bind:class="(props.isActive ? 'bg-green': 'bg-red')"></button>
    <div slot-scope="props"
    v-show="props.isActive"
    class="list-reset bg-white border p-4 shadow z-10"
    >
    Drop Down Content
    </ol>
    v-bind:class="'border-2 p-1 ' + (props.isActive ? 'bg-green': 'bg-red')"
    data-reference
    ></button>
    <div
    v-show="props.isActive"
    class="list-reset bg-white border p-4 shadow z-10"
    data-popper
    >
    Dropdown Content
    </div>
    </div>
    </flyout>
    29 changes: 6 additions & 23 deletions flyout.vue
    Original file line number Diff line number Diff line change
    @@ -1,18 +1,11 @@
    <script>
    # Renderless Flyout component
    # See: https://adamwathan.me/renderless-components-in-vuejs/
    import Popper from 'popper.js'
    export default {
    name: 'flyout',
    data: function () {
    return {
    isActive: false,
    referenceElement: null,
    popperElement: null,
    popper: null,
    popperOptions:
    {
    placement: 'bottom-start',
    @@ -29,36 +22,26 @@
    }
    }
    },
    render (createElement) {
    this.referenceVnode = this.$scopedSlots.reference({
    isActive: this.isActive,
    toggle: this.toggle,
    })
    this.popperVnode = this.$scopedSlots.default({
    render () {
    return this.$scopedSlots.default({
    isActive: this.isActive,
    toggle: this.toggle
    })
    return createElement('div', [this.referenceVnode, this.popperVnode])
    },
    created () {
    this.referenceVnode = null
    this.popperVnode = null
    },
    created () {},
    destroyed () {
    this.destroyPopper()
    },
    mounted () {
    this.referenceElement = this.referenceVnode.elm
    this.popperElement = this.popperVnode.elm
    this.referenceElement = this.$el.querySelectorAll('[data-reference]')[0]
    this.popperElement = this.$el.querySelectorAll('[data-popper]')[0]
    this.popper = null
    },
    watch: {
    isActive: function (isActive) {
    (isActive) ? this.createPopper() : this.destroyPopper()
    }
    },
    computed: {},
    methods: {
    toggle () {
    this.isActive = !this.isActive
  2. leevigraham created this gist Apr 16, 2018.
    12 changes: 12 additions & 0 deletions example.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    <flyout v-cloak>
    <button slot="reference"
    slot-scope="props"
    v-on:click="props.toggle()"
    v-bind:class="(props.isActive ? 'bg-green': 'bg-red')"></button>
    <div slot-scope="props"
    v-show="props.isActive"
    class="list-reset bg-white border p-4 shadow z-10"
    >
    Drop Down Content
    </ol>
    </flyout>
    99 changes: 99 additions & 0 deletions flyout.vue
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,99 @@
    <script>
    # Renderless Flyout component
    # See: https://adamwathan.me/renderless-components-in-vuejs/
    import Popper from 'popper.js'
    export default {
    name: 'flyout',
    data: function () {
    return {
    isActive: false,
    referenceElement: null,
    popperElement: null,
    popper: null,
    popperOptions:
    {
    placement: 'bottom-start',
    modifiers: {
    arrow: {enabled: false},
    preventOverflow: {
    boundariesElement: 'viewport'
    },
    flip: {
    behavior: ['bottom-start', 'bottom-end', 'top-start', 'top-end'],
    boundariesElement: 'viewport'
    }
    }
    }
    }
    },
    render (createElement) {
    this.referenceVnode = this.$scopedSlots.reference({
    isActive: this.isActive,
    toggle: this.toggle,
    })
    this.popperVnode = this.$scopedSlots.default({
    isActive: this.isActive,
    toggle: this.toggle
    })
    return createElement('div', [this.referenceVnode, this.popperVnode])
    },
    created () {
    this.referenceVnode = null
    this.popperVnode = null
    },
    destroyed () {
    this.destroyPopper()
    },
    mounted () {
    this.referenceElement = this.referenceVnode.elm
    this.popperElement = this.popperVnode.elm
    },
    watch: {
    isActive: function (isActive) {
    (isActive) ? this.createPopper() : this.destroyPopper()
    }
    },
    computed: {},
    methods: {
    toggle () {
    this.isActive = !this.isActive
    },
    createPopper () {
    if (this.popper) {
    return
    }
    this.popper = new Popper(
    this.referenceElement,
    this.popperElement,
    this.popperOptions
    )
    document.addEventListener('click', this.handleDocumentClick)
    },
    destroyPopper () {
    if (!this.popper) {
    return
    }
    this.popper.destroy()
    this.popper = null
    document.removeEventListener('click', this.handleDocumentClick)
    },
    handleDocumentClick (e) {
    let target = e.target
    if (
    this.referenceElement === target ||
    this.popperElement === target ||
    this.referenceElement.contains(target) ||
    this.popperElement.contains(target)
    ) {
    return
    }
    this.isActive = false
    }
    }
    }
    </script>