npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

vue-popper-utilities

v1.0.5

Published

Wrapper around popperjs and Vue to build interactive and beautiful custom, dropdown, multi level dropdown, tooltips.

Downloads

3

Readme

Vue Popper Utilites

vue-popper-utilities is a wrapper around popperjs@core for Vue.js for creating any custom popup, dropdown, multi level dropdown with nested child dropdowns, tooltip etc.

vt

Key Features:

  • Vue 3 compatible!
  • Fully written in Typescript with full types support.
  • Global event bus. Only one event listener no matter how many popups are initiated in a single page. Permormance won't drop if there are many components are on a page.
  • Fully customizable. It is possible to make any kind of custom popup using the package.
  • Predefined components like Dropdown, DropdownChild, Tooltip for covering most of the use case.
  • Keyboard navigation between multiple children dropdowns.
  • transition and animation capability using vue default Transition component.

Please check the demo here

Getting started

<script setup>
import { Dropdown, DropdownItem, DropdownChild } from 'vue-popper-utilities';
import 'vue-popper-utilities/style.css';
</script>

<template>
    <Dropdown trigger="click" :offset="[0, 8]" placement="right-start">
        <template #reference="{ isOpen }">
            <button class="test-btn" :class="[isOpen ? 'active' : '']">
                Test button
            </button>
        </template>

        <template v-slot="{ isOpen, hide }">
            <DropdownItem v-for="x in 6" :key="x">
                {{ `Item ${x}` }}
            </DropdownItem>

            <DropdownChild trigger="hover">
                <template #reference>
                    <button>Item child 1</button>
                </template>

                <div class="dropdown-child-1-container">
                    <DropdownItem v-for="y in 2" :key="y">
                        {{ `Item child ${y}` }}
                    </DropdownItem>
                </div>
            </DropdownChild>

            <button @click="hide()">Hide manually</button>
        </template>
    </Dropdown>
</template>

Installation

npm i vue-popper-utilities

Usage

Global registration

import { createApp } from 'vue';
import App from './App.vue';

import {
    Popup,
    Dropdown,
    DropdownChild,
    DropdownItem,
    Tooltip,
} from 'vue-popper-utilities';
import 'vue-popper-utilities/style.css';

const app = createApp(App);
app.component('Popup', Popup)
    .component('Dropdown', Dropdown)
    .component('DropdownChild', DropdownChild)
    .component('DropdownItem', DropdownItem)
    .component('Tooltip', Tooltip)
    .mount('#app');

Use directly inside a component

<script setup>
import { Popup } from 'vue-popper-utilities';
import 'vue-popper-utilities/style.css';
</script>

Popup.vue

This is the base component of the popper. All other components are the extraction of this component.

Normal usage

<Popup>
    <template #reference>
        <button>Popup button</button>
    </template>

    <div>Popup content</div>
</Popup>

Opening popper dynamically with v-model

<Popup v-model="show" reference="#popup-reference">
    <div>Popup content</div>
</Popup>

Props

| Name | Type | Default | Description | | ----------------------- | --------------------------------------------------------------------------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | trigger | String | click | trigger of the popup. possible values are click, hover, focus. | | placement | Placement | bottom-start | Placement of the popup element with respect to reference. | | offset | Array [number, number] Popper offset | [0, 4] | Offset of the popper relative to the reference. | | strategy | String Strategy | absolute | Positioning strategy. possible values are absolute or fixed. | | options | Options | undefined | Can be used for having more fine control over, how the popup will aprear. Most of the times above props will work fine.This props has high priority over placement, offset and strategy props. setting this will override other values. Values are calculated by deep comparing i.e; if value exists on the options prop it will take from options prop. Otherwise if value exists on the other props, it will take other props. Otherwise it will take from default values. | | on-first-update | Function | undefined | Callback function to run after the first update of the popper.js. | | model-value | Boolean | undefined | Can be used to control popup dynamically from a variable. IMPORTANT: reference props must be required with this prop to work. | | reference | Element or String or null | null | if popup is controlled by v-model, reference element is the target element where to glue in the popup. It's value can be any HTML element or any valid css selector. IMPORTANT: must be required with v-model. | | is-dynamic-reference | Boolean | false | Sometimes the reference element can be conditionally added or removed from the DOM. while using with v-model, It may not exist on the DOM during the initialization of the popper. In that case, popup will not show. To rectify this scenerio, settings this prop to true will destroy old popper, related event listeners. Then it will reinitialize new popper again on every open request. | | hide-on-click-outside | Boolean | true | Will hide the popup on clicking outside of the popup content. | | arrow | Boolean | false | whether to show arrow on the popup. | | arrow-class | String | undefined | css class of the arrow element. | | ref-class | String | undefined | css class of the reference element. | | popup-class | String | undefined | css class of the popup element. | | disabled | Boolean | false | disable the component. | | local-event-listener | Boolean | false | This package implements global event bus to listen on the events to optimize the performance. One event listener on the body element listen to all the event interactions. if any parent element uses event.stopPropagation(), it will not work with global event bus. So it is highly recommend not to use event.stopPropagation() on any parent element. If in case, it is absolutely needed to use stop propagation, this prop should set to true. In that case, event listeners will be registered locally. For every component, it will register two event listeners. | | force-show | Boolean | false | set it to true to show the popup. Note: Need to reset before using again. | | force-hide | Boolean | false | set it to true to hide the popup. Note: Need to reset before using again. | | same-width-as-reference | Boolean | false | setting it to true will make the popup width to be equal to the width of the reference element (setting width with popup-class prop will override this value). | | transition-name | String | undefined | transition name of the popup element. It uses vue.js Transition component. for details see here. | | enter-from-class | String | undefined | enter-from-class of vue Transition. | | enter-to-class | String | undefined | enter-to-class of vue Transition. | | enter-active-class | String | undefined | enter-active-class of vue Transition. | | leave-from-class | String | undefined | leave-from-class of vue Transition. | | leave-to-class | String | undefined | leave-to-class of vue Transition. | | leave-active-class | String | undefined | leave-active-class of vue Transition. |

Events

ready emitted when popper instance is created. event data are popper instance, popup element and reference element.

emit('ready', popper.value, popper_el.value, ref_el.value);

// typescript definition
(e: 'ready', popper: Instance, popperEl: Element | null, refEl: Element | VirtualElement | null ): void;

update:model-value emitted if v-model is set.

emit('update:model-value', isPopperOpen.value);

// typescript definition
(e: 'update:model-value', isPopperOpen: boolean): void;

show emitted when popup is shown.

emit('show');

// typescript definition
(e: 'show'): void;

hide emitted when popup is hidden.

emit('hide');

// typescript definition
(e: 'hide'): void;

destroy emitted when popper instance is destroyed.

emit('destroy');

// typescript definition
(e: 'destroy'): void;

create-error emitted when popper is falied to initialize.

emit('create-error', popper_el.value, ref_el.value);

// typescript definition
( e: 'create-error', popperEl: Element | null, refEl: Element | VirtualElement | null ): void;

Slots

reference reference element is rendered in this slot

Slot props:

  • isOpen {boolean} whether the popup is open
<template #reference="{ isOpen }">
    <button class="test-btn" :class="[isOpen ? 'active' : '']">
        Test button
    </button>
</template>

default popup element is rendered in this slot

Slot props:

  • isOpen {boolean} whether the popup is open
  • show {function} show the popup
  • hide {function} hide the popup
<template #default="{ isOpen, show, hide }">
    <button class="show-btn" :class="[isOpen ? 'active' : '']" @click="show">
        Show
    </button>

    <button class="hide-btn" @click="hide">
        Hide
    </button>
</template>

Expose

Popup.vue exposes following properties:

  • isPopperOpen {boolean} whether the popup open
  • show {function} show the popup
  • hide {function} hide the popup
  • el {HTMLElement} root element of the popper
<script setup>
import { ref, onMounted } from 'vue';
const popperUtilities = ref(null);

onMounted(() => {
    console.log(popperUtilities.value?.isPopperOpen.value); // boolean
    console.log(popperUtilities.value?.el.value); // HTML element
    console.log(popperUtilities.value?.show); // Function
    console.log(popperUtilities.value?.hide); // Function
});
</script>

<template>
    <Popup ref="popperUtilities">
        <template #reference>Ref el</template>
        <div>Popup content</div>
    </Popup>
</template>

Dropdown.vue

This is the base Dropdown component. Technically any custom dropdown element can be rendered inside the popup, but it is recommended to use only DropdownItem.vue, DropdowChildren.vue as top level children for keyboard navigation. Any custom dropdown item will be skipped by keyboard navigation. If you want to render anything other than the dropdown, try Popup.vue instead.

<script setup>
import { Dropdown, DropdownItem, DropdownChild } from 'vue-popper-utilities';
import 'vue-popper-utilities/style.css';

const onItemClick = (x) => {
    console.log(`Dropdown item ${x} has been clicked`)
}
</script>

<template>
    <Dropdown trigger="click" :offset="[0, 8]" placement="right-start">
        <template #reference="{ isOpen }">
            <button class="test-btn" :class="[isOpen ? 'active' : '']">
                Test button
            </button>
        </template>

        <template v-slot="{ isOpen, hide }">
            <DropdownItem v-for="x in 6" :key="x" @click="onItemClick(x)">
                {{ `Item ${x}` }}
            </DropdownItem>

            <DropdownChild trigger="hover" :offset="[0, 0]" :hide-parent-on-item-click="false">
                <template #reference>
                    <button>Item child 1</button>
                </template>

                <div class="dropdown-child-1-container">
                    <DropdownItem v-for="y in 2" :key="y">
                        {{ `Item child ${y}` }}
                    </DropdownItem>
                </div>
            </DropdownChild>

            // this button will be skipped by keyboard navigation.
            // As this top level child is not either of DropdownItem or DropdownChild component
            <button @click="hide()">Hide manually</button>
        </template>
    </Dropdown>
</template>

If don't care about keyboard navigation, you can ignore good and bad example below. If you want to style the wrapper container of the dropdown popup, use dropdown-class prop rather than wrapping it with a html element. Because for the keyboard navigation, it will seach for dropdown items and child items on the top level.

Bad ❌

<Dropdown>
    <template #reference>...</template>

    <template #default>
        // bad. we should not wrap the dropdown container with other element
        <div class="dropdown-wrapper">
            <DropdownItem>...</DropdownItem>
            <DropdownItem>...</DropdownItem>
        </div>
    </template>
</Dropdown>

Good ✅

// now we can style the dropdown wrapper element by `dropdown-class` props
<Dropdown dropdown-class="dropdown-wrapper">
    <template #reference>...</template>

    <template #default>
        // good. DropdownItem and DropdownChild is now top level child.
        <DropdownItem>...</DropdownItem>
        <DropdownChild>...</DropdownChild>
    </template>
</Dropdown>

Props

Same as props of Popup.vue

Additional Props: | Name | Type | Default | Description | | ------------------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | hide-on-item-click | Boolean | true | whether to hide the dropdown on any item click. | | hide-parent-on-item-click | Boolean | true | This prop is only applicable for dropdown children. if set to false, all parent dropdowns will not be hidden after close. | | keyboard-navigation | Boolean | true | enable keyboard navigation. | | dropdown-class | String | undefined | css classes to be appened on the dropdown container. |

Events

Same as events of Popup.vue

Slots

Same as slots of Popup.vue

Expose

Same as expose of Popup.vue

DropdownChild.vue

This is the base DropdownChild component. Technically any custom dropdown element can be rendered inside the popup, but it is recommended to use only DropdownItem.vue, DropdowChildren.vue as top level children for keyboard navigation. Any custom dropdown item will be skipped by keyboard navigation. If you want to render anything other than the dropdown, try Popup.vue instead. If you want to customize the wrapper container of the dropdown popup, use dropdown-class prop.

Props

Same as events of Dropdown.vue

Additional Props:

| Name | Type | Default | Description | | ----------------- | ------- | ----------- | --------------------------------------------------------------- | | child-arrow | Boolean | true | whether to show a arrow at the end for the dropdown child item. | | child-arrow-class | String | undefined | css class to apply on the arrow. |

Events

Same as events of Dropdown.vue

Slots

Same as slots of Dropdown.vue

Additional Slots:

child-arrow arrow at end of dropdown children. any custom icon or element can be rendered here. If not used and child-arrow prop is set to true, then default arrow will be rendered.

Slot props:

  • isOpen {boolean} whether the popup is open

Expose

Same as expose of Dropdown.vue

DropdownItem.vue

This component has no api

Tooltip.vue

This component will render a tooltip on the target element. by default, trigger for this component is hover and placement is bottom. But can be customized throught props.

<Tooltip
    text="Lorem ipsum dolor sit amet consectetur adipisicing elit. Perspiciatis veritatis autem deserunt"
>
    <template #reference>
        <button class="tooltip-btn" >
            {{ `Tootlip button` }}
        </button>
    </template>
</Tooltip>

Props

Same as props of Popup.vue

Additional Props: | Name | Type | Default | Description | | ------------------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | text | String | undefined | Text content of the tooltip. if custom tooltip content is required, use default slot instead. |

Events

Same as events of Popup.vue

Slots

Same as slots of Popup.vue

Expose

Same as expose of Popup.vue

Styling

This package comes with minimal css implementation to make it unstyled as much possible. Using props like ref-class, popup-class, dropdown-class etc, it is possible to style as per your own theme.

Default styling can be changed through customizing the css variables. Default css variables are as listed.

--skn-popper-active-item-bg: #e6e6e6;
--skn-popper-active-item-hover: #fafafa;
--skn-popper-z-index: 1133;
--skn-popper-arrow-width: 12px;
--skn-popper-arrow-height: 12px;
--skn-popper-arrow-transform-plus: 6px;
--skn-popper-arrow-transform-minus: -6px;

--skn-popper-tooltip-bg: #121212;
--skn-popper-tooltip-color: #ffffff;
--skn-popper-tooltip-padding: 16px;
--skn-popper-tooltip-max-width: 320px;

--skn-popper-dropdown-container-background: #ffffff;
--skn-popper-dropdown-container-border: 1px solid #e6e6e6;
--skn-popper-dropdown-container-box-shadow: 0px 8px 10px 1px rgba(0, 0, 0, 0.14),
    0px 3px 14px 2px rgba(0, 0, 0, 0.12), 0px 5px 5px -3px rgba(0, 0, 0, 0.2);

we can also customize through css styling.

<style scoped>
:deep(.skn-popper .skn-popper__reference) {
    /* add custom styling here */
}
</style>

Bugs and new feature

Please create an issue on this repository for any bugs or any feature request.

License

This is open source project under MIT license.