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
- VuiButton — button
- VuiButtonGroup — button group with single selection
- VuiCheckbox — checkbox
- VuiDialog — dialog / confirm box
- VuiFlex — flex layout helper
- VuiFlyover — side flyover panel (resizable)
- VuiIcon — SVG icon
- VuiIconLabel — icon with label
- VuiInput — text input
- VuiLayout — split-pane layout
- VuiLoading — loading spinner
- VuiModal — modal window
- VuiPopover — popover
- VuiProgress — progress bar
- VuiRadio — radio
- VuiSelect — select dropdown (single/multiple, searchable options via slot)
- VuiSlider — horizontal scroller
- VuiSwitch — switch
- VuiTab — tabs
- VuiToast — toast notification
- VuiTooltip — tooltip
Install
npm i vine-uiUsage
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 manuallymount
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/
