Vue.js composition API wrappers for popular utility libraries enabling seamless integration of third-party tools
—
Drawing, progress indication, and QR code generation for enhanced user experience and visual feedback.
Interactive drawing and sketching using drauu library with canvas integration.
/**
* Interactive drawing and sketching with canvas integration
* @param target - Target element (canvas or container) for drawing
* @param options - Drawing configuration options
* @returns Drawing control interface and event handlers
*/
function useDrauu(
target: MaybeComputedElementRef,
options?: UseDrauuOptions
): UseDrauuReturn;
interface UseDrauuReturn {
/** The drauu instance for direct access */
drauuInstance: Ref<Drauu | undefined>;
/** Load SVG drawing data */
load: (svg: string) => void;
/** Export current drawing as SVG string */
dump: () => string | undefined;
/** Clear all drawings */
clear: () => void;
/** Cancel current drawing operation */
cancel: () => void;
/** Undo last drawing action */
undo: () => boolean | undefined;
/** Redo previously undone action */
redo: () => boolean | undefined;
/** Whether undo is available */
canUndo: ShallowRef<boolean>;
/** Whether redo is available */
canRedo: ShallowRef<boolean>;
/** Current brush configuration */
brush: Ref<Brush>;
/** Drawing state change events */
onChanged: EventHookOn;
/** Drawing commit events */
onCommitted: EventHookOn;
/** Drawing start events */
onStart: EventHookOn;
/** Drawing end events */
onEnd: EventHookOn;
/** Drawing cancel events */
onCanceled: EventHookOn;
}
type UseDrauuOptions = Omit<Options, 'el'>;
// drauu library types
interface Options {
brush?: Brush;
acceptsInputTypes?: InputType[];
coordinate?: CoordinateType;
coordinateScale?: number | false;
coordinateTransform?: boolean | CoordinateTransform;
}
interface Brush {
mode?: DrawingMode;
color?: string;
size?: number;
cornerRadius?: number;
dasharray?: string | undefined;
arrowEnd?: boolean;
arrowStart?: boolean;
}
type DrawingMode = 'draw' | 'line' | 'rectangle' | 'ellipse' | 'stylus';
type InputType = 'mouse' | 'touch' | 'pen';
type CoordinateType = 'relative' | 'absolute';Usage Examples:
import { useDrauu } from "@vueuse/integrations/useDrauu";
import { ref, onMounted } from 'vue';
// Basic drawing setup
const canvasRef = ref<HTMLCanvasElement>();
const {
drauuInstance,
brush,
clear,
undo,
redo,
canUndo,
canRedo,
dump,
load,
onChanged
} = useDrauu(canvasRef, {
brush: {
mode: 'draw',
color: '#000000',
size: 3
}
});
// Change brush settings
const changeBrushColor = (color: string) => {
brush.value.color = color;
};
const changeBrushSize = (size: number) => {
brush.value.size = size;
};
const changeBrushMode = (mode: DrawingMode) => {
brush.value.mode = mode;
};
// Drawing tools
const clearCanvas = () => clear();
const undoLastAction = () => undo();
const redoAction = () => redo();
// Save and load drawings
const saveDrawing = () => {
const svgData = dump();
if (svgData) {
localStorage.setItem('saved-drawing', svgData);
}
};
const loadDrawing = () => {
const svgData = localStorage.getItem('saved-drawing');
if (svgData) {
load(svgData);
}
};
// Listen to drawing changes
onChanged(() => {
console.log('Drawing changed');
// Auto-save or validation logic
});
// Advanced brush configuration
const setupAdvancedBrush = () => {
brush.value = {
mode: 'line',
color: '#ff0000',
size: 5,
dasharray: '5,5', // Dashed line
arrowEnd: true, // Arrow at end
cornerRadius: 2 // Rounded corners
};
};
// Multiple drawing modes
const drawingModes = [
{ name: 'Pen', mode: 'draw' },
{ name: 'Line', mode: 'line' },
{ name: 'Rectangle', mode: 'rectangle' },
{ name: 'Ellipse', mode: 'ellipse' },
{ name: 'Stylus', mode: 'stylus' }
];Progress bar indication using NProgress library with reactive state management.
/**
* Progress bar indication with reactive state management
* @param currentProgress - Current progress value (0-1 or null)
* @param options - NProgress configuration options
* @returns Progress control interface
*/
function useNProgress(
currentProgress?: MaybeRefOrGetter<number | null | undefined>,
options?: UseNProgressOptions
): {
/** Whether progress bar is currently showing */
isLoading: WritableComputedRef<boolean>;
/** Current progress value */
progress: Ref<number | null | undefined>;
/** Start progress indication */
start: () => NProgress;
/** Complete progress and hide bar */
done: (force?: boolean) => NProgress;
/** Remove progress bar from DOM */
remove: () => void;
};
type UseNProgressOptions = Partial<NProgressOptions>;
// NProgress configuration options
interface NProgressOptions {
/** Minimum progress value */
minimum?: number;
/** Animation template */
template?: string;
/** Easing function */
easing?: string;
/** Animation speed */
speed?: number;
/** Trickle animation */
trickle?: boolean;
/** Trickle speed */
trickleSpeed?: number;
/** Show spinner */
showSpinner?: boolean;
/** Barber pole moving animation */
barberPole?: boolean;
/** Parent element selector */
parent?: string;
}Usage Examples:
import { useNProgress } from "@vueuse/integrations/useNProgress";
import { ref } from 'vue';
// Basic progress indication
const { isLoading, start, done } = useNProgress();
// Show progress during async operations
const fetchData = async () => {
start();
try {
const response = await fetch('/api/data');
const data = await response.json();
return data;
} finally {
done();
}
};
// Controlled progress
const uploadProgress = ref(0);
const { progress, isLoading } = useNProgress(uploadProgress, {
minimum: 0.1,
speed: 200,
showSpinner: false
});
const simulateUpload = () => {
uploadProgress.value = 0;
const interval = setInterval(() => {
uploadProgress.value += 0.1;
if (uploadProgress.value >= 1) {
clearInterval(interval);
uploadProgress.value = null; // Hide progress bar
}
}, 100);
};
// Router integration
import { useRoute } from 'vue-router';
const route = useRoute();
const { start, done } = useNProgress();
// Show progress on route changes
watch(() => route.path, () => {
start();
nextTick(() => done());
});
// Custom configuration
const { start, done } = useNProgress(undefined, {
minimum: 0.2,
easing: 'ease',
speed: 500,
trickle: true,
trickleSpeed: 200,
showSpinner: true,
barberPole: true,
template: '<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'
});
// Global loading state
const globalLoading = ref(false);
const { isLoading: nprogress } = useNProgress();
// Sync with global state
watch(globalLoading, (loading) => {
nprogress.value = loading;
});QR code generation using qrcode library with reactive updates.
/**
* QR code generation with reactive updates
* @param text - Text content to encode in QR code
* @param options - QR code generation options
* @returns Reactive data URL for QR code image
*/
function useQRCode(
text: MaybeRefOrGetter<string>,
options?: QRCode.QRCodeToDataURLOptions
): ShallowRef<string>;
// QR code generation options
namespace QRCode {
interface QRCodeToDataURLOptions {
/** Error correction level */
errorCorrectionLevel?: 'low' | 'medium' | 'quartile' | 'high';
/** QR code type (auto-detected if not specified) */
type?: 'image/png' | 'image/jpeg' | 'image/webp';
/** Rendered image quality (0.0 to 1.0) */
quality?: number;
/** Margin around QR code in modules */
margin?: number;
/** Scale factor for image size */
scale?: number;
/** Image width in pixels (overrides scale) */
width?: number;
/** Color options */
color?: {
/** Dark color (foreground) */
dark?: string;
/** Light color (background) */
light?: string;
};
}
}Usage Examples:
import { useQRCode } from "@vueuse/integrations/useQRCode";
import { ref, computed } from 'vue';
// Basic QR code generation
const text = ref('https://example.com');
const qrCode = useQRCode(text);
// QR code will be a data URL string like:
// "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAK..."
// Dynamic QR code
const userInput = ref('');
const qrCodeUrl = useQRCode(userInput, {
width: 200,
margin: 2,
color: {
dark: '#000000',
light: '#FFFFFF'
}
});
// Contact information QR code
const contactInfo = computed(() => {
return [
'BEGIN:VCARD',
'VERSION:3.0',
'FN:John Doe',
'TEL:+1234567890',
'EMAIL:john@example.com',
'URL:https://johndoe.com',
'END:VCARD'
].join('\n');
});
const contactQR = useQRCode(contactInfo, {
errorCorrectionLevel: 'medium',
width: 300
});
// WiFi QR code
const wifiConfig = computed(() => {
const ssid = 'MyWiFi';
const password = 'MyPassword';
const security = 'WPA';
return `WIFI:T:${security};S:${ssid};P:${password};;`;
});
const wifiQR = useQRCode(wifiConfig);
// Custom styling options
const styledQR = useQRCode('Custom styled QR code', {
width: 250,
margin: 3,
color: {
dark: '#1a365d', // Dark blue
light: '#f7fafc' // Light gray
},
errorCorrectionLevel: 'high'
});
// Multiple QR codes with different options
const qrCodes = [
{
name: 'Website',
text: ref('https://example.com'),
options: { width: 150, color: { dark: '#2563eb' } }
},
{
name: 'Email',
text: ref('mailto:contact@example.com'),
options: { width: 150, color: { dark: '#dc2626' } }
},
{
name: 'Phone',
text: ref('tel:+1234567890'),
options: { width: 150, color: { dark: '#059669' } }
}
].map(item => ({
...item,
qrCode: useQRCode(item.text, item.options)
}));
// Download QR code
const downloadQRCode = (dataUrl: string, filename: string) => {
const link = document.createElement('a');
link.download = filename;
link.href = dataUrl;
link.click();
};Template Usage Examples:
<template>
<div class="qr-code-examples">
<!-- Basic QR code display -->
<div>
<h3>Website QR Code</h3>
<img :src="qrCode" alt="QR Code" />
</div>
<!-- Dynamic QR code generator -->
<div>
<h3>Generate QR Code</h3>
<input v-model="userInput" placeholder="Enter text or URL" />
<div v-if="userInput">
<img :src="qrCodeUrl" alt="Generated QR Code" />
<button @click="downloadQRCode(qrCodeUrl, 'qrcode.png')">
Download QR Code
</button>
</div>
</div>
<!-- Multiple QR codes -->
<div class="qr-grid">
<div v-for="item in qrCodes" :key="item.name" class="qr-item">
<h4>{{ item.name }}</h4>
<img :src="item.qrCode" :alt="`${item.name} QR Code`" />
</div>
</div>
</div>
</template>
<style>
.qr-code-examples {
display: flex;
flex-direction: column;
gap: 20px;
}
.qr-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
}
.qr-item {
text-align: center;
padding: 16px;
border: 1px solid #e2e8f0;
border-radius: 8px;
}
.qr-item img {
max-width: 100%;
height: auto;
}
</style>Install with Tessl CLI
npx tessl i tessl/npm-vueuse--integrations