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 🙏

© 2026 – Pkg Stats / Ryan Hefner

vine-ui

v4.0.0

Published

vine ui components

Readme

Vine UI

  • Lightweight UI components based on Vue 3.x
  • Zero dependencies, tree-shakable ESM, full TypeScript definitions

Preview Online

https://cenfun.github.io/vine-ui/

Components

Install

npm i vine-ui

Usage

ESM (recommended)

Named imports keep the bundle tree-shakable:

<script setup>
import { VuiButton, VuiInput } from 'vine-ui';
</script>

<template>
    <VuiInput v-model="text" placeholder="input" />
    <VuiButton primary @click="onClick">OK</VuiButton>
</template>

Options API

import { VuiButton, VuiInput } from 'vine-ui';

export default {
    components: {
        VuiButton,
        VuiInput
    }
}

Browser (UMD)

<script src="vine-ui.js"></script>
<script>
    const { VuiButton } = window['vine-ui'];
</script>

Utilities

Icons (icons, defaultIcons, setIcons)

import { icons, defaultIcons, setIcons } from 'vine-ui';

// all built-in icon names
console.log(Object.keys(defaultIcons)); // ['arrow-down', 'arrow-left', 'close', ...]

// icons is a mutable copy of defaultIcons, setIcons merges new/overridden icons into it
setIcons({
    'my-icon': '<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M8 2 L14 14 L2 14 Z"/></svg>'
});

// then use it in a template
// <VuiIcon icon="my-icon" />

Find free icons from https://cenfun.github.io/open-icons/

showToast

import { showToast } from 'vine-ui';

// types: success | error | info
showToast({ type: 'success', content: 'Saved successfully' });
showToast({ type: 'error', content: 'Something went wrong' });

// custom dismiss timeout in ms (default: 2000, 0 = keep until manually closed)
showToast({ type: 'info', content: 'Long message', timeout: 5000 });

// render into a custom container (defaults to a fixed container appended to body)
const container = document.getElementById('toast-area');
const { unmount } = showToast({ type: 'success', content: 'Hi' }, container);
// unmount(); // dismiss manually

mount

Programmatically render a component into a detached element (appended to body by default):

import { mount, VuiDialog } from 'vine-ui';

const { el, unmount } = mount(VuiDialog, {
    props: {
        message: 'Are you sure?',
        closeOnClickOut: false
    }
});

// el is appended to document.body and contains the rendered component

// remove it later
unmount();

initGlobalTooltips

Global tooltip handling for any element with a tooltip attribute (used by the docs site):

import { initGlobalTooltips } from 'vine-ui';

initGlobalTooltips(
    // onEnter: fired when hovering an element with a tooltip attribute
    (target) => {
        const text = target.getAttribute('tooltip');
        if (!text) {
            // optional: fall back to innerText when the text is truncated (ellipsis)
            if (target.clientWidth < target.scrollWidth) {
                tooltip.visible = true;
                tooltip.target = target;
                tooltip.text = target.innerText;
            }
            return;
        }
        tooltip.visible = true;
        tooltip.target = target;
        tooltip.text = text;
    },
    // onLeave: fired when the mouse leaves the element
    (target) => {
        tooltip.visible = false;
        tooltip.text = '';
    }
);

Then simply add attributes in templates:

<button tooltip="Delete this item">Delete</button>

Motion

Frame-based animation helper (extends EventTarget, data in e.detail):

import { Motion } from 'vine-ui';

// animate a single number from 0 to 100
const motion = new Motion({ duration: 300, from: 0, till: 100 });
motion.bind(Motion.MOVE, (e) => {
    el.style.opacity = e.detail / 100; // 0 → 1
});
motion.bind(Motion.END, () => {
    console.log('animation finished');
});
motion.start();

// animate multiple values at once (object mode)
new Motion({ from: { x: 0, y: 0 }, till: { x: 100, y: 50 } })
    .bind(Motion.MOVE, (e) => {
        el.style.transform = `translate(${e.detail.x}px, ${e.detail.y}px)`;
    })
    .start({ duration: 500 });

// custom easing function, e.g. ease-out
new Motion({
    duration: 400,
    from: 0,
    till: 300,
    easing: (k) => 1 - (1 - k) * (1 - k)
}).start();

// stop early or clean up
motion.stop();
motion.destroy();

Events: Motion.START, Motion.MOVE, Motion.END, Motion.STOP.

StartMoveEnd

Unified mouse / touch drag tracking (extends EventTarget):

import { StartMoveEnd } from 'vine-ui';

const sme = new StartMoveEnd(el, {
    inertia: true,      // enable touch inertia (fling)
    inertiaTime: 200    // sample window for velocity
});

sme.bind(StartMoveEnd.START, (e) => {
    console.log('start at', e.detail.startX, e.detail.startY);
});

sme.bind(StartMoveEnd.MOVE, (e) => {
    const d = e.detail;
    // moveX / moveY: offset from previous position
    // offsetX / offsetY: offset from start position
    el.style.transform = `translate(${d.offsetX}px, ${d.offsetY}px)`;
});

sme.bind(StartMoveEnd.END, (e) => {
    console.log('end');
});

// touch only, with inertia enabled
sme.bind(StartMoveEnd.INERTIA, (e) => {
    const d = e.detail;
    el.style.transform = `translate(${d.offsetX + d.touchInertiaX}px, ${d.offsetY + d.touchInertiaY}px)`;
});

// remove all listeners
sme.destroy();

Events: StartMoveEnd.START, StartMoveEnd.MOVE, StartMoveEnd.END, StartMoveEnd.INERTIA.

TypeScript

vine-ui ships complete type definitions (dist/vine-ui.d.ts) with typed props, events (including v-model) and slots.

Development

npm run dev     # run examples locally
npm run docs    # build static docs site (see examples/)
npm run build   # build library to dist/

Examples source: examples/