{"id":47728924,"url":"https://github.com/saqqdy/directix","last_synced_at":"2026-04-26T06:00:49.949Z","repository":{"id":347354667,"uuid":"1188633905","full_name":"saqqdy/directix","owner":"saqqdy","description":"A comprehensive, easy-to-use, and high-performance Vue custom directives library supporting both Vue 2 and Vue 3","archived":false,"fork":false,"pushed_at":"2026-04-19T12:30:32.000Z","size":7589,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-04-19T13:25:15.860Z","etag":null,"topics":["directives","v-click-delay","v-click-outside","v-copy","v-counter","v-fullscreen","v-hotkey","v-image-preview","v-infinite-scroll","v-lazy","v-loading","v-money","v-pan","v-permission","v-pinch","v-skeleton","v-typewriter","vue","vue2","vue3"],"latest_commit_sha":null,"homepage":"https://www.saqqdy.com/directix","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/saqqdy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-22T11:18:13.000Z","updated_at":"2026-04-19T12:30:37.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/saqqdy/directix","commit_stats":null,"previous_names":["saqqdy/directix"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/saqqdy/directix","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saqqdy%2Fdirectix","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saqqdy%2Fdirectix/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saqqdy%2Fdirectix/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saqqdy%2Fdirectix/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/saqqdy","download_url":"https://codeload.github.com/saqqdy/directix/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saqqdy%2Fdirectix/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32287398,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-25T18:29:39.964Z","status":"online","status_checked_at":"2026-04-26T02:00:05.962Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["directives","v-click-delay","v-click-outside","v-copy","v-counter","v-fullscreen","v-hotkey","v-image-preview","v-infinite-scroll","v-lazy","v-loading","v-money","v-pan","v-permission","v-pinch","v-skeleton","v-typewriter","vue","vue2","vue3"],"created_at":"2026-04-02T21:10:46.051Z","updated_at":"2026-04-26T06:00:49.937Z","avatar_url":"https://github.com/saqqdy.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Directix\n\n[![npm version](https://img.shields.io/npm/v/directix.svg)](https://www.npmjs.com/package/directix)\n[![npm downloads](https://img.shields.io/npm/dm/directix.svg)](https://www.npmjs.com/package/directix)\n[![GitHub license](https://img.shields.io/github/license/saqqdy/directix)](https://github.com/saqqdy/directix/blob/master/LICENSE)\n[![CI](https://github.com/saqqdy/directix/actions/workflows/ci.yml/badge.svg)](https://github.com/saqqdy/directix/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/saqqdy/directix/branch/master/graph/badge.svg)](https://codecov.io/gh/saqqdy/directix)\n\n**English** | **[中文文档](README_CN.md)**\n\nA comprehensive, easy-to-use, and high-performance Vue custom directives library supporting both Vue 2 and Vue 3.\n\n## Features\n\n- 🎯 **Comprehensive** - 57 commonly used directives and 57 composables\n- 🔄 **Vue 2/3 Compatible** - Single codebase supports both Vue 2 and Vue 3\n- 📦 **Tree-shakable** - Import only what you need\n- 🔒 **TypeScript** - Full TypeScript support with type definitions\n- 🚀 **SSR Friendly** - Multiple directives support SSR out of the box\n- 📦 **Multiple Formats** - ESM, CJS, and IIFE (CDN) formats available\n- ⚡ **Zero Dependencies** - Lightweight with minimal bundle size\n- 🎨 **Composables** - Every directive has a corresponding composable for Composition API\n- 🔧 **Utility Exports** - Export `configurePermission`, `getPermissionConfig` and other utilities for advanced usage\n- 🌐 **i18n Support** - Built-in internationalization with Chinese, English, and Japanese translations\n- 🔌 **Plugin System** - Extensible plugin architecture for community contributions\n\n## What's New in v1.10.0\n\n### Vue 3 Optimization Preview\n\nVue 3-specific optimizations leveraging the reactive system for better performance.\n\n```typescript\nimport { useLazyOptimized, useSuspenseDirective, teleportContent } from 'directix'\n\n// Optimized lazy loading with shallowRef\nconst { state, observe } = useLazyOptimized({\n  onLoad: (entry) =\u003e console.log('Visible!')\n})\n\n// Suspense-ready async directive\nconst { state, load } = useSuspenseDirective({\n  loader: () =\u003e fetchData()\n})\n\n// Teleport content to target\nteleportContent(element, { to: '#modal-container' })\n```\n\n### Mobile Optimization\n\nEnhanced touch gestures with haptic feedback and PWA support.\n\n```typescript\nimport { useEnhancedTouch, triggerHaptic, usePWA } from 'directix'\n\n// 12+ gesture types with haptic feedback\nconst { activeGesture, bind } = useEnhancedTouch({\n  feedback: { haptic: true, visual: true },\n  onSwipe: (e) =\u003e console.log(`Swiped ${e.direction}`),\n  onPinch: (e) =\u003e console.log(`Scale: ${e.scale}`),\n})\n\n// PWA support\nconst { isOnline, needsUpdate } = usePWA({ serviceWorker: { enabled: true } })\n```\n\n### Accessibility (A11y)\n\nComprehensive ARIA support, screen reader announcements, and keyboard navigation.\n\n```typescript\nimport { \n  applyAriaAttributes, \n  announce, \n  useKeyboardNavigation, \n  useFocusTrap \n} from 'directix'\n\n// Apply ARIA attributes\napplyAriaAttributes(element, {\n  role: 'button',\n  ariaLabel: 'Submit',\n  ariaDisabled: true,\n})\n\n// Screen reader announcements\nannounce('Form submitted successfully')\n\n// Keyboard navigation with focus trap\nconst { bind } = useKeyboardNavigation({ focusTrap: true, rovingTabindex: true })\n```\n\n### Security Enhancement\n\nAdvanced XSS protection, CSP compatibility, and security audit tools.\n\n```typescript\nimport { sanitizeHtml, SecurityAudit, getCSPNonce } from 'directix'\n\n// Advanced HTML sanitization\nconst clean = sanitizeHtml(userInput, {\n  allowedTags: ['b', 'i', 'p'],\n  detectDangerousPatterns: true,\n})\n\n// Security audit\nconst report = SecurityAudit.generateReport(htmlContent)\nconsole.log(SecurityAudit.formatReport(report, 'json'))\n\n// Check dependencies for vulnerabilities\nconst vulns = await SecurityAudit.checkDependencies()\n```\n\n## What's New in v1.9.0\n\n### Internationalization (i18n)\n\nFull i18n support for directive messages and documentation.\n\n```typescript\nimport { createI18n, setLocale } from 'directix'\n\n// Initialize with locale\ncreateI18n({\n  locale: 'en-US',\n  fallbackLocale: 'en-US',\n  messages: { 'en-US': enUS, 'zh-CN': zhCN, 'ja-JP': jaJP }\n})\n\n// Switch locale at runtime\nsetLocale('zh-CN')\n```\n\n### Unified Warning System\n\nImproved developer experience with structured error messages.\n\n```typescript\nimport { warn, directiveWarn, assertType } from 'directix'\n\n// Directive-specific warnings\ndirectiveWarn('debounce', 'errors.invalid_wait', { wait: 'abc' })\n\n// Type assertions\nassertType\u003cnumber\u003e(value, 'number', 'debounce', 'wait')\n```\n\n### Plugin System\n\nExtensible plugin architecture for community contributions.\n\n```typescript\nimport { definePlugin, getPluginManager } from 'directix'\n\nconst myPlugin = definePlugin({\n  meta: { name: 'my-plugin', version: '1.0.0' },\n  install(ctx) {\n    ctx.registerDirective('my-directive', vMyDirective)\n  }\n})\n\ngetPluginManager().register(myPlugin)\n```\n\n### Community Plugin Registry\n\nDiscover and install community plugins programmatically.\n\n```typescript\nimport { getPluginRegistry } from 'directix'\n\nconst registry = getPluginRegistry()\n\n// Search plugins\nconst results = await registry.search('animation')\n\n// Get all plugins\nconst plugins = await registry.getAll()\n\n// Install a plugin\nawait registry.install('directix-animate', manager)\n```\n\n### Timezone \u0026 Locale Utilities\n\nRegion-specific formatting for dates, numbers, and currencies.\n\n```typescript\nimport { getTimezoneInfo, formatDateLocale, formatCurrencyLocale } from 'directix'\n\n// Get timezone info\nconst tz = getTimezoneInfo() // { id: 'Asia/Shanghai', offset: 8, ... }\n\n// Format date by locale\nformatDateLocale(new Date()) // Auto-detects user locale\n\n// Format currency\nformatCurrencyLocale(99.99) // '$99.99' (US) or '99,99€' (DE)\n```\n\n### Vue DevTools Integration\n\nDebug directives directly in Vue DevTools.\n\n```typescript\nimport { enableDevtools, trackDirective } from 'directix'\n\n// Enable DevTools integration\nenableDevtools()\n\n// Track directive usage\ntrackDirective('debounce', { element: 'input' })\n```\n\n### Performance Monitoring\n\nMeasure directive performance with detailed metrics.\n\n```typescript\nimport { enablePerformance, getPerformanceReport } from 'directix'\n\n// Enable monitoring\nenablePerformance()\n\n// Get performance report\nconst report = getPerformanceReport()\n// [{ name: 'debounce', mount: { p50: 0.5ms, p95: 1.2ms }, ... }]\n```\n\n### Scenario Examples\n\n10+ real-world examples demonstrating directive combinations:\n\n- **Form Validation** - v-debounce, v-mask, v-trim, v-focus\n- **Permission Management** - v-permission, v-click-outside\n- **Image Gallery** - v-lazy, v-image-preview, v-swipe\n- **Infinite Scroll** - v-infinite-scroll, v-virtual-list, v-loading\n- **Rich Text Editor** - v-sanitize, v-highlight, v-emoji\n- **Gesture Interaction** - v-touch, v-swipe, v-pan, v-pinch\n- **Data Visualization** - v-progress, v-counter, v-countdown\n- **Drag \u0026 Sort** - v-draggable, v-intersect\n- **Print \u0026 Export** - v-print, v-export\n- **Fullscreen Media** - v-fullscreen, v-lottie\n\n## Online Demo\n\nTry it online with StackBlitz or CodeSandbox:\n\n| Demo | StackBlitz | CodeSandbox |\n|------|------------|-------------|\n| Vue 3 | [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/saqqdy/directix/tree/master/examples/vue3) | [![Open in CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/sandbox/github/saqqdy/directix/tree/master/examples/vue3) |\n| Vue 2 | [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/saqqdy/directix/tree/master/examples/vue2) | [![Open in CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/sandbox/github/saqqdy/directix/tree/master/examples/vue2) |\n\n## Playground\n\nTry the interactive [Playground](https://saqqdy.github.io/directix/playground/) to configure directives and generate code:\n\n- **57+ Directives** - Full coverage of all Directix directives\n- **Vue 2 \u0026 Vue 3** - Generate code for either version\n- **Composables** - Generate composable API code\n- **TypeScript Ready** - Full type definitions included\n- **Monaco Editor** - Full-featured code editor with syntax highlighting\n- **Live Preview** - See directive effects in real-time\n\nEach directive documentation page also includes a code generator for quick code snippets.\n\n## Installation\n\n```bash\n# npm\nnpm install directix\n\n# yarn\nyarn add directix\n\n# pnpm\npnpm add directix\n```\n\n### Vue 2 Support\n\nFor Vue 2.0-2.6, you need to install `@vue/composition-api`:\n\n```bash\nnpm install @vue/composition-api\n```\n\nVue 2.7+ has built-in Composition API support, so no additional dependencies are needed.\n\n## CDN\n\nYou can also use Directix via CDN:\n\n```html\n\u003c!-- Vue 3 --\u003e\n\u003cscript src=\"https://unpkg.com/vue@3/dist/vue.global.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"https://unpkg.com/directix/dist/index.iife.min.js\"\u003e\u003c/script\u003e\n\n\u003c!-- Vue 2.7+ --\u003e\n\u003cscript src=\"https://unpkg.com/vue@2/dist/vue.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"https://unpkg.com/directix/dist/index.iife.min.js\"\u003e\u003c/script\u003e\n```\n\nThe CDN build works seamlessly with both Vue 2 and Vue 3.\n\n## Requirements\n\n- Vue 2.0+ or Vue 3.0+\n- Node.js 12.20+ (for build tools)\n- For Vue 2.0-2.6: `@vue/composition-api` is required\n\n## Quick Start\n\n### Global Registration\n\n```typescript\n// Vue 3\nimport { createApp } from 'vue'\nimport Directix from 'directix'\n\nconst app = createApp(App)\napp.use(Directix)\n\n// Or register specific directives only\napp.use(Directix, {\n  directives: ['click-outside', 'copy', 'debounce']\n})\n```\n\n```typescript\n// Vue 2\nimport Vue from 'vue'\nimport Directix from 'directix'\n\nVue.use(Directix)\n```\n\n### On-Demand Import\n\n```typescript\nimport { vClickOutside, vCopy, vDebounce } from 'directix'\n\n// Vue 3\napp.directive('click-outside', vClickOutside)\napp.directive('copy', vCopy)\n\n// Vue 2\nVue.directive('click-outside', vClickOutside)\n```\n\n### Using Composables\n\nEvery directive has a corresponding composable for use with the Composition API:\n\n```typescript\nimport { useClickOutside, useCopy, useDebounce } from 'directix'\n\n// In setup() or \u003cscript setup\u003e\nconst { copy, copied } = useCopy({ source: textRef })\nconst { isHovering, bind } = useHover({ onEnter: handleEnter })\nconst { run: debouncedSearch } = useDebounce({ handler: search, wait: 500 })\n```\n\nSee the [Composables](#composables) section below for all available composables.\n\n## Nuxt Integration\n\nDirectix provides a Nuxt module for seamless integration with Nuxt 3 applications.\n\n### Installation\n\nThe Nuxt module is included in the main package. Simply add it to your `nuxt.config.ts`:\n\n```typescript\n// nuxt.config.ts\nexport default defineNuxtConfig({\n  modules: ['directix/nuxt'],\n  \n  directix: {\n    // Enable/disable the module (default: true)\n    enabled: true,\n    \n    // Only include specific directives (optional)\n    include: ['v-click-outside', 'v-copy', 'v-debounce'],\n    \n    // Or exclude specific directives (optional)\n    exclude: ['v-ripple'],\n    \n    // Default options for directives (optional)\n    directiveOptions: {\n      'v-permission': {\n        config: {\n          getPermissions: () =\u003e ['read', 'write']\n        }\n      }\n    },\n    \n    // Auto-import composables (default: true)\n    autoImportComposables: true\n  }\n})\n```\n\n### Usage in Nuxt\n\nDirectives are automatically registered and composables are auto-imported:\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv v-click-outside=\"handleClose\"\u003e\n    \u003cbutton v-copy=\"text\"\u003eCopy\u003c/button\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\n// Composables are auto-imported, no need to import manually\nconst { copy, copied } = useCopy({ source: text })\nconst { isHovering } = useHover({ onEnter: handleEnter })\n\u003c/script\u003e\n```\n\n### SSR Compatibility\n\nDirectives that are not SSR-compatible will only run on the client side. The Nuxt module handles this automatically.\n\n## Available Directives\n\n### Event Directives\n\n| Directive | Description | SSR |\n|-----------|-------------|-----|\n| `v-click-outside` | Detect clicks outside an element | ❌ |\n| `v-click-delay` | Delay click execution to prevent double clicks | ✅ |\n| `v-debounce` | Debounce event handlers | ✅ |\n| `v-throttle` | Throttle event handlers | ✅ |\n| `v-long-press` | Detect long press events | ❌ |\n| `v-hover` | Hover state detection | ❌ |\n| `v-hotkey` | Keyboard shortcut binding | ✅ |\n| `v-touch` | Touch gesture detection (swipe, pinch, rotate) | ❌ |\n| `v-swipe` | Swipe gesture detection with mouse support | ❌ |\n\n### Form Directives\n\n| Directive | Description | SSR |\n|-----------|-------------|-----|\n| `v-copy` | Copy text to clipboard | ❌ |\n| `v-focus` | Auto focus an element | ✅ |\n| `v-mask` | Input masking | ❌ |\n| `v-trim` | Trim input whitespace | ✅ |\n| `v-money` | Currency format input | ❌ |\n| `v-number` | Number format input | ❌ |\n| `v-ellipsis` | Text ellipsis overflow | ✅ |\n\n### Format Directives\n\n| Directive | Description | SSR |\n|-----------|-------------|-----|\n| `v-uppercase` | Convert text to uppercase | ✅ |\n| `v-lowercase` | Convert text to lowercase | ✅ |\n| `v-capitalcase` | Capitalize first letter | ✅ |\n| `v-truncate` | Truncate text with ellipsis | ✅ |\n\n### Visibility Directives\n\n| Directive | Description | SSR |\n|-----------|-------------|-----|\n| `v-lazy` | Lazy load images | ❌ |\n| `v-intersect` | Detect element intersection | ❌ |\n| `v-visible` | Control element visibility | ✅ |\n| `v-loading` | Show loading overlay | ✅ |\n\n### Scroll Directives\n\n| Directive | Description | SSR |\n|-----------|-------------|-----|\n| `v-scroll` | Scroll event handling | ❌ |\n| `v-infinite-scroll` | Infinite scrolling | ❌ |\n| `v-sticky` | Sticky positioning | ❌ |\n| `v-pull-refresh` | Pull to refresh functionality | ❌ |\n| `v-virtual-list` | Virtual list for large datasets | ❌ |\n\n### Security Directives\n\n| Directive | Description | SSR |\n|-----------|-------------|-----|\n| `v-permission` | Permission-based element control | ✅ |\n| `v-sanitize` | Sanitize HTML content | ✅ |\n\n### Effect Directives\n\n| Directive | Description | SSR |\n|-----------|-------------|-----|\n| `v-ripple` | Material design ripple effect | ❌ |\n| `v-draggable` | Make elements draggable | ❌ |\n\n### Observer Directives\n\n| Directive | Description | SSR |\n|-----------|-------------|-----|\n| `v-resize` | Element resize observer | ❌ |\n| `v-mutation` | DOM mutation observer | ❌ |\n\n### UI Directives\n\n| Directive | Description | SSR |\n|-----------|-------------|-----|\n| `v-tooltip` | Tooltip component | ❌ |\n| `v-image-preview` | Image preview with zoom | ❌ |\n| `v-countdown` | Countdown timer display | ✅ |\n| `v-print` | Print element content | ❌ |\n| `v-watermark` | Watermark overlay | ✅ |\n| `v-skeleton` | Skeleton loading placeholder | ✅ |\n| `v-progress` | Progress bar animation | ❌ |\n| `v-counter` | Animated number counter | ✅ |\n\n### Gesture Directives\n\n| Directive | Description | SSR |\n|-----------|-------------|-----|\n| `v-pan` | Pan/drag gesture | ❌ |\n| `v-pinch` | Pinch/zoom gesture | ❌ |\n| `v-rotate-gesture` | Rotation gesture | ❌ |\n\n### Visual Effect Directives\n\n| Directive | Description | SSR |\n|-----------|-------------|-----|\n| `v-blur` | Background blur overlay | ❌ |\n| `v-fade` | Fade in/out transition | ✅ |\n| `v-parallax` | Parallax scrolling effect | ❌ |\n| `v-lottie` | Lottie animation player | ❌ |\n| `v-typewriter` | Typewriter animation | ✅ |\n| `v-click-wave` | Click wave effect | ❌ |\n\n### Data Directives\n\n| Directive | Description | SSR |\n|-----------|-------------|-----|\n| `v-export` | Export data (CSV/JSON/HTML) | ❌ |\n| `v-highlight` | Keyword highlighting | ✅ |\n| `v-emoji` | Emoji input filter | ❌ |\n| `v-context-menu` | Right-click context menu | ❌ |\n| `v-fullscreen` | Fullscreen toggle | ❌ |\n\n\u003e ✅ = SSR compatible | ❌ = Not SSR compatible\n\n## Composables\n\nEvery directive has a corresponding composable function for use with the Composition API. All composables are exported from `directix`:\n\n### Event Composables\n\n| Composable | Description |\n|------------|-------------|\n| `useClickOutside` | Detect clicks outside an element |\n| `useClickDelay` | Delay click execution |\n| `useDebounce` | Debounce function calls |\n| `useThrottle` | Throttle function calls |\n| `useLongPress` | Detect long press gestures |\n| `useHover` | Track hover state |\n| `useHotkey` | Handle keyboard shortcuts |\n| `useTouch` | Detect touch gestures |\n| `useSwipe` | Detect swipe gestures |\n\n### Form Composables\n\n| Composable | Description |\n|------------|-------------|\n| `useCopy` | Copy text to clipboard |\n| `useFocus` | Manage element focus |\n| `useMask` | Input masking |\n| `useTrim` | Trim input whitespace |\n| `useMoney` | Currency formatting |\n| `useNumber` | Number formatting |\n| `useEllipsis` | Text ellipsis overflow |\n\n### Format Composables\n\n| Composable | Description |\n|------------|-------------|\n| `useUppercase` | Transform to uppercase |\n| `useLowercase` | Transform to lowercase |\n| `useCapitalcase` | Capitalize text |\n| `useTruncate` | Truncate text |\n\n### Visibility Composables\n\n| Composable | Description |\n|------------|-------------|\n| `useLazy` | Lazy load images |\n| `useIntersect` | Detect element intersection |\n| `useVisible` | Control element visibility |\n| `useLoading` | Show loading overlay |\n\n### Scroll Composables\n\n| Composable | Description |\n|------------|-------------|\n| `useScroll` | Track scroll position |\n| `useInfiniteScroll` | Infinite scrolling |\n| `useSticky` | Sticky positioning |\n| `usePullRefresh` | Pull to refresh |\n| `useVirtualList` | Virtual list for large datasets |\n\n### Other Composables\n\n| Composable | Description |\n|------------|-------------|\n| `usePermission` | Permission checking |\n| `useSanitize` | Sanitize HTML content |\n| `useRipple` | Material design ripple effect |\n| `useDraggable` | Make elements draggable |\n| `useResize` | Element resize observer |\n| `useMutation` | DOM mutation observer |\n| `useTooltip` | Tooltip control |\n| `useImagePreview` | Image preview with zoom |\n| `useCountdown` | Countdown timer |\n| `usePrint` | Print content |\n| `useWatermark` | Watermark overlay |\n| `useSkeleton` | Skeleton loading state |\n| `useProgress` | Progress bar control |\n| `useCounter` | Animated number counter |\n| `usePan` | Pan gesture detection |\n| `usePinch` | Pinch gesture detection |\n| `useRotateGesture` | Rotation gesture detection |\n| `useBlur` | Blur overlay control |\n| `useFade` | Fade transition control |\n| `useParallax` | Parallax scrolling |\n| `useLottie` | Lottie animation control |\n| `useTypewriter` | Typewriter effect |\n| `useExport` | Data export utilities |\n| `useHighlight` | Keyword highlighting |\n| `useEmoji` | Emoji filtering |\n| `useContextMenu` | Context menu control |\n| `useFullscreen` | Fullscreen mode control |\n| `useClickWave` | Click wave effect |\n\n### Composable Usage Example\n\n```vue\n\u003cscript setup\u003e\nimport { ref } from 'vue'\nimport { useCopy, useHover, useDebounce } from 'directix'\n\n// useCopy\nconst text = ref('Hello World')\nconst { copy, copied } = useCopy({ source: text })\n\n// useHover\nconst buttonRef = ref()\nconst { isHovering, bind } = useHover({\n  onEnter: () =\u003e console.log('Entered'),\n  onLeave: () =\u003e console.log('Left')\n})\n\n// useDebounce\nconst { run: debouncedSearch } = useDebounce({\n  handler: (query) =\u003e fetchResults(query),\n  wait: 500\n})\n\u003c/script\u003e\n\n\u003ctemplate\u003e\n  \u003cbutton @click=\"copy()\"\u003e\n    {{ copied ? 'Copied!' : 'Copy' }}\n  \u003c/button\u003e\n\n  \u003cbutton ref=\"buttonRef\" :class=\"{ active: isHovering }\"\u003e\n    Hover me\n  \u003c/button\u003e\n\u003c/template\u003e\n```\n\n## Usage Examples\n\n### v-click-outside\n\nDetect clicks outside an element, useful for closing dropdowns, modals, etc.\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv v-click-outside=\"closeDropdown\"\u003e\n    \u003cbutton @click=\"show = !show\"\u003eToggle\u003c/button\u003e\n    \u003cdiv v-if=\"show\"\u003eDropdown content\u003c/div\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { ref } from 'vue'\nimport { useClickOutside } from 'directix'\n\nconst show = ref(false)\n\nfunction closeDropdown() {\n  show.value = false\n}\n\n// Composable usage\nconst containerRef = ref()\nuseClickOutside(containerRef, () =\u003e {\n  show.value = false\n})\n\u003c/script\u003e\n```\n\n### v-copy\n\nCopy text to clipboard with a simple directive.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple usage --\u003e\n  \u003cbutton v-copy=\"textToCopy\"\u003eCopy to clipboard\u003c/button\u003e\n\n  \u003c!-- With callbacks --\u003e\n  \u003cbutton v-copy=\"{ value: text, onSuccess: handleSuccess, onError: handleError }\"\u003e\n    Copy with callback\n  \u003c/button\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { ref } from 'vue'\nimport { useCopy } from 'directix'\n\nconst textToCopy = 'Hello, World!'\n\nfunction handleSuccess(text) {\n  console.log('Copied:', text)\n}\n\nfunction handleError(error) {\n  console.error('Copy failed:', error)\n}\n\n// Composable usage\nconst sourceText = ref('Hello World')\nconst { copy, copied } = useCopy({ source: sourceText })\n\u003c/script\u003e\n```\n\n### v-debounce\n\nDebounce event handlers to limit execution frequency.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Default: 300ms --\u003e\n  \u003cinput v-debounce=\"handleInput\" /\u003e\n\n  \u003c!-- Custom wait time with modifier --\u003e\n  \u003cinput v-debounce:500ms=\"handleInput\" /\u003e\n\n  \u003c!-- With options object --\u003e\n  \u003cinput v-debounce=\"{ handler: handleInput, wait: 500, leading: true }\" /\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useDebounce } from 'directix'\n\nfunction handleInput(event) {\n  console.log('Debounced input:', event.target.value)\n}\n\n// Composable usage\nconst { run: debouncedSearch, cancel } = useDebounce({\n  handler: (query) =\u003e fetchResults(query),\n  wait: 500\n})\n\u003c/script\u003e\n```\n\n### v-throttle\n\nThrottle event handlers to limit execution frequency.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Default: 300ms --\u003e\n  \u003cbutton v-throttle=\"handleClick\"\u003eThrottled click\u003c/button\u003e\n\n  \u003c!-- Custom wait time with modifier --\u003e\n  \u003cbutton v-throttle:1s=\"handleClick\"\u003e1 second throttle\u003c/button\u003e\n\n  \u003c!-- With options object --\u003e\n  \u003cbutton v-throttle=\"{ handler: handleClick, wait: 1000, leading: true, trailing: false }\"\u003e\n    Throttle with options\n  \u003c/button\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useThrottle } from 'directix'\n\nfunction handleClick() {\n  console.log('Throttled click')\n}\n\n// Composable usage\nconst { run: throttledScroll, cancel } = useThrottle({\n  handler: (position) =\u003e updatePosition(position),\n  wait: 100\n})\n\u003c/script\u003e\n```\n\n### v-focus\n\nAuto focus an element when mounted.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple usage --\u003e\n  \u003cinput v-focus /\u003e\n\n  \u003c!-- With options --\u003e\n  \u003cinput v-focus=\"{ focus: true, refocus: true }\" /\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useFocus } from 'directix'\n\n// Composable usage\nconst { focus, blur, hasFocus } = useFocus()\n\u003c/script\u003e\n```\n\n### v-permission\n\nControl element visibility based on user permissions.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple permission check --\u003e\n  \u003cbutton v-permission=\"'admin'\"\u003eAdmin Only\u003c/button\u003e\n\n  \u003c!-- Multiple permissions (OR logic) --\u003e\n  \u003cbutton v-permission=\"['admin', 'editor']\"\u003eAdmin or Editor\u003c/button\u003e\n\n  \u003c!-- AND logic --\u003e\n  \u003cbutton v-permission=\"{ value: ['read', 'write'], mode: 'every' }\"\u003e\n    Requires both permissions\n  \u003c/button\u003e\n\n  \u003c!-- Disable instead of remove --\u003e\n  \u003cbutton v-permission=\"{ value: 'admin', action: 'disable' }\"\u003e\n    Disabled for non-admin\n  \u003c/button\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { configurePermission, usePermission } from 'directix'\n\nconfigurePermission({\n  getPermissions: () =\u003e ['read', 'write'],\n  getRoles: () =\u003e ['editor'],\n  roleMap: {\n    admin: ['*'],\n    editor: ['read', 'write', 'edit']\n  }\n})\n\n// Composable usage\nconst { hasPermission, hasAnyPermission, hasAllPermissions } = usePermission()\nconst canEdit = hasPermission('edit')\n\u003c/script\u003e\n```\n\n### v-lazy\n\nLazy load images when they enter the viewport.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple usage --\u003e\n  \u003cimg v-lazy=\"imageUrl\" /\u003e\n\n  \u003c!-- With placeholder and error image --\u003e\n  \u003cimg v-lazy=\"{ src: imageUrl, placeholder: '/placeholder.png', error: '/error.png' }\" /\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useLazy } from 'directix'\n\n// Composable usage\nconst { load, state, loaded } = useLazy({\n  src: 'image.jpg',\n  preload: 100\n})\n\u003c/script\u003e\n```\n\n### v-mask\n\nInput masking for formatted input.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Phone number --\u003e\n  \u003cinput v-mask=\"'(###) ###-####'\" placeholder=\"Phone\" /\u003e\n\n  \u003c!-- Date --\u003e\n  \u003cinput v-mask=\"'##/##/####'\" placeholder=\"MM/DD/YYYY\" /\u003e\n\n  \u003c!-- SSN --\u003e\n  \u003cinput v-mask=\"{ mask: '###-##-####', placeholder: '_' }\" placeholder=\"SSN\" /\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useMask } from 'directix'\n\n// Composable usage\nconst { maskedValue, unmaskedValue, update } = useMask({\n  mask: '(###) ###-####',\n  value: '1234567890'\n})\n\u003c/script\u003e\n```\n\n### v-loading\n\nShow loading overlay on elements.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple usage --\u003e\n  \u003cdiv v-loading=\"isLoading\"\u003eContent\u003c/div\u003e\n\n  \u003c!-- With options --\u003e\n  \u003cdiv v-loading=\"{ value: isLoading, text: 'Loading...', lock: true }\"\u003e\n    Content with locked scroll\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { ref } from 'vue'\nimport { useLoading } from 'directix'\n\nconst isLoading = ref(true)\n\n// Composable usage\nconst { show, hide, setText } = useLoading({\n  text: 'Loading...',\n  lock: true\n})\n\u003c/script\u003e\n```\n\n### v-sanitize\n\nSanitize HTML content to prevent XSS attacks.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple usage --\u003e\n  \u003cdiv v-sanitize=\"userContent\"\u003e\u003c/div\u003e\n\n  \u003c!-- With custom allowed tags --\u003e\n  \u003cdiv v-sanitize=\"{ html: userContent, allowedTags: ['b', 'i', 'u'] }\"\u003e\u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useSanitize } from 'directix'\n\n// Composable usage\nconst { sanitize, setAllowedTags } = useSanitize({\n  allowedTags: ['b', 'i', 'u', 'a']\n})\nconst cleanHtml = sanitize(dirtyHtml)\n\u003c/script\u003e\n```\n\n### v-tooltip\n\nDisplay tooltips on hover or click.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple usage --\u003e\n  \u003cbutton v-tooltip=\"'Tooltip content'\"\u003eHover me\u003c/button\u003e\n\n  \u003c!-- With options --\u003e\n  \u003cbutton v-tooltip=\"{ content: 'Tooltip', placement: 'bottom', trigger: 'click' }\"\u003e\n    Click me\n  \u003c/button\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useTooltip } from 'directix'\n\n// Composable usage\nconst { show, hide, updateContent, updatePosition } = useTooltip({\n  content: 'Tooltip content',\n  placement: 'top'\n})\n\u003c/script\u003e\n```\n\n### v-image-preview\n\nPreview images with zoom and gesture support.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple usage --\u003e\n  \u003cimg v-image-preview src=\"thumbnail.jpg\" data-preview=\"full.jpg\" /\u003e\n\n  \u003c!-- With options --\u003e\n  \u003cimg v-image-preview=\"{ src: 'thumbnail.jpg', previewSrc: 'full.jpg', enablePinchZoom: true }\" /\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useImagePreview } from 'directix'\n\n// Composable usage\nconst { open, close, zoom, rotate } = useImagePreview({\n  enablePinchZoom: true\n})\n\u003c/script\u003e\n```\n\n### v-draggable\n\nMake elements draggable.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple usage --\u003e\n  \u003cdiv v-draggable\u003eDrag me\u003c/div\u003e\n\n  \u003c!-- With constraints --\u003e\n  \u003cdiv v-draggable=\"{ axis: 'x', bounds: 'parent' }\"\u003eHorizontal drag only\u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useDraggable } from 'directix'\n\n// Composable usage\nconst { position, isDragging, reset } = useDraggable({\n  axis: 'x',\n  bounds: 'parent'\n})\n\u003c/script\u003e\n```\n\n### v-uppercase / v-lowercase / v-capitalcase\n\nTransform text case.\n\n```vue\n\u003ctemplate\u003e\n  \u003cinput v-uppercase placeholder=\"Auto uppercase\" /\u003e\n  \u003cinput v-lowercase placeholder=\"Auto lowercase\" /\u003e\n  \u003cinput v-capitalcase placeholder=\"Capitalize first letter\" /\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useUppercase, useLowercase, useCapitalcase } from 'directix'\n\n// Composable usage\nconst { transform: toUppercase } = useUppercase()\nconst { transform: toLowercase } = useLowercase()\nconst { transform: toCapitalcase } = useCapitalcase()\n\u003c/script\u003e\n```\n\n### v-truncate\n\nTruncate text with ellipsis.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple usage --\u003e\n  \u003cp v-truncate=\"50\"\u003eLong text here...\u003c/p\u003e\n\n  \u003c!-- With options --\u003e\n  \u003cp v-truncate=\"{ length: 100, suffix: '...', position: 'end' }\"\u003eLong text...\u003c/p\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useTruncate } from 'directix'\n\n// Composable usage\nconst { truncate } = useTruncate({ length: 100, suffix: '...' })\nconst shortText = truncate(longText)\n\u003c/script\u003e\n```\n\n### v-touch\n\nDetect touch gestures.\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv v-touch=\"{ onSwipe: handleSwipe, onPinch: handlePinch }\"\u003e\n    Swipe or pinch here\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useTouch } from 'directix'\n\nfunction handleSwipe(direction) {\n  console.log('Swiped:', direction) // 'left', 'right', 'up', 'down'\n}\n\nfunction handlePinch(scale) {\n  console.log('Pinched:', scale)\n}\n\n// Composable usage\nconst { onSwipe, onPinch, onRotate } = useTouch({\n  onSwipe: handleSwipe\n})\n\u003c/script\u003e\n```\n\n### v-trim\n\nTrim input whitespace.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Trim on blur (default) --\u003e\n  \u003cinput v-trim /\u003e\n\n  \u003c!-- Trim on input --\u003e\n  \u003cinput v-trim=\"{ position: 'both', event: 'input' }\" /\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useTrim } from 'directix'\n\n// Composable usage\nconst { trim, trimLeft, trimRight } = useTrim({ position: 'both' })\n\u003c/script\u003e\n```\n\n### v-money\n\nCurrency format input.\n\n```vue\n\u003ctemplate\u003e\n  \u003cinput v-money=\"{ prefix: '$', precision: 2 }\" placeholder=\"Enter amount\" /\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useMoney } from 'directix'\n\n// Composable usage\nconst { format, parse } = useMoney({ prefix: '$', precision: 2 })\nconst formatted = format(1234.56) // \"$1,234.56\"\n\u003c/script\u003e\n```\n\n### v-number\n\nNumber format input.\n\n```vue\n\u003ctemplate\u003e\n  \u003cinput v-number=\"{ precision: 2, min: 0, max: 100 }\" placeholder=\"Enter number\" /\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useNumber } from 'directix'\n\n// Composable usage\nconst { format, parse } = useNumber({ precision: 2, min: 0, max: 100 })\n\u003c/script\u003e\n```\n\n### v-click-delay\n\nDelay click execution to prevent double clicks.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Default: 300ms delay --\u003e\n  \u003cbutton v-click-delay=\"handleClick\"\u003eClick me\u003c/button\u003e\n\n  \u003c!-- Custom delay time --\u003e\n  \u003cbutton v-click-delay=\"{ handler: handleClick, delay: 500 }\"\u003e500ms delay\u003c/button\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useClickDelay } from 'directix'\n\nfunction handleClick() {\n  console.log('Clicked (delayed)')\n}\n\n// Composable usage\nconst { run: delayedClick, cancel } = useClickDelay({\n  handler: handleClick,\n  delay: 300\n})\n\u003c/script\u003e\n```\n\n### v-countdown\n\nCountdown timer display.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple usage --\u003e\n  \u003cspan v-countdown=\"{ time: 60 }\"\u003e\u003c/span\u003e\n\n  \u003c!-- With callbacks --\u003e\n  \u003cspan v-countdown=\"{ time: 60, onTick: handleTick, onComplete: handleComplete }\"\u003e\u003c/span\u003e\n\n  \u003c!-- Custom format --\u003e\n  \u003cspan v-countdown=\"{ time: 3600, format: 'mm:ss' }\"\u003e\u003c/span\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useCountdown } from 'directix'\n\nfunction handleTick(remaining) {\n  console.log('Remaining:', remaining)\n}\n\nfunction handleComplete() {\n  console.log('Countdown complete!')\n}\n\n// Composable usage\nconst { start, pause, reset, remaining } = useCountdown({\n  time: 60,\n  onTick: handleTick,\n  onComplete: handleComplete\n})\n\u003c/script\u003e\n```\n\n### v-ellipsis\n\nText ellipsis overflow with tooltip.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple usage --\u003e\n  \u003cdiv v-ellipsis style=\"width: 200px;\"\u003eLong text that will be truncated\u003c/div\u003e\n\n  \u003c!-- With custom lines --\u003e\n  \u003cdiv v-ellipsis=\"{ lines: 2 }\"\u003eMulti-line text with ellipsis\u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useEllipsis } from 'directix'\n\n// Composable usage\nconst { isEllipsisActive, checkEllipsis } = useEllipsis({ lines: 1 })\n\u003c/script\u003e\n```\n\n### v-hotkey\n\nKeyboard shortcut binding.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple usage --\u003e\n  \u003cdiv v-hotkey=\"{ 'ctrl+s': handleSave, 'ctrl+c': handleCopy }\"\u003e\n    Press Ctrl+S to save\n  \u003c/div\u003e\n\n  \u003c!-- With modifiers --\u003e\n  \u003cinput v-hotkey=\"{ 'enter': submit, 'escape': cancel }\" /\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useHotkey } from 'directix'\n\nfunction handleSave() {\n  console.log('Saving...')\n}\n\nfunction handleCopy() {\n  console.log('Copying...')\n}\n\n// Composable usage\nconst { bind, unbind, unbindAll } = useHotkey({\n  'ctrl+s': handleSave\n})\n\u003c/script\u003e\n```\n\n### v-print\n\nPrint element content.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple usage --\u003e\n  \u003cbutton v-print=\"printRef\"\u003ePrint\u003c/button\u003e\n  \u003cdiv ref=\"printRef\"\u003eContent to print\u003c/div\u003e\n\n  \u003c!-- Print self --\u003e\n  \u003cdiv v-print=\"{ self: true }\"\u003eClick to print this content\u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { ref } from 'vue'\nimport { usePrint } from 'directix'\n\nconst printRef = ref()\n\n// Composable usage\nconst { print, printElement } = usePrint({\n  onBefore: () =\u003e console.log('Printing...'),\n  onComplete: () =\u003e console.log('Printed!')\n})\n\u003c/script\u003e\n```\n\n### v-pull-refresh\n\nPull to refresh functionality.\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv v-pull-refresh=\"handleRefresh\" style=\"height: 400px; overflow: auto;\"\u003e\n    Pull down to refresh\n  \u003c/div\u003e\n\n  \u003c!-- With options --\u003e\n  \u003cdiv v-pull-refresh=\"{ handler: handleRefresh, threshold: 80, disabled: false }\"\u003e\n    Content\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { usePullRefresh } from 'directix'\n\nasync function handleRefresh() {\n  // Fetch new data\n  await fetchData()\n}\n\n// Composable usage\nconst { isLoading, disable, enable } = usePullRefresh({\n  handler: handleRefresh\n})\n\u003c/script\u003e\n```\n\n### v-swipe\n\nSwipe gesture detection with mouse support.\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv v-swipe=\"handleSwipe\" style=\"height: 200px;\"\u003e\n    Swipe in any direction\n  \u003c/div\u003e\n\n  \u003c!-- With options --\u003e\n  \u003cdiv v-swipe=\"{ onSwipe: handleSwipe, threshold: 50, enableMouse: true }\"\u003e\n    Swipe or drag with mouse\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useSwipe } from 'directix'\n\nfunction handleSwipe(direction) {\n  console.log('Swiped:', direction) // 'left', 'right', 'up', 'down'\n}\n\n// Composable usage\nconst { direction, lengthX, lengthY } = useSwipe({\n  onSwipe: handleSwipe,\n  threshold: 50\n})\n\u003c/script\u003e\n```\n\n### v-virtual-list\n\nVirtual list for rendering large datasets efficiently.\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv v-virtual-list=\"{ items: list, itemSize: 50 }\" style=\"height: 500px;\"\u003e\n    \u003ctemplate #default=\"{ item, index }\"\u003e\n      \u003cdiv :key=\"index\"\u003e{{ item.name }}\u003c/div\u003e\n    \u003c/template\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nconst list = Array.from({ length: 10000 }, (_, i) =\u003e ({ id: i, name: `Item ${i}` }))\n\nimport { useVirtualList } from 'directix'\n\n// Composable usage\nconst { list, containerProps, wrapperProps, scrollTo } = useVirtualList(\n  largeList,\n  { itemHeight: 50 }\n)\n\u003c/script\u003e\n```\n\n### v-watermark\n\nWatermark overlay.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple usage --\u003e\n  \u003cdiv v-watermark=\"'Confidential'\" style=\"width: 100%; height: 400px;\"\u003e\n    Protected content\n  \u003c/div\u003e\n\n  \u003c!-- With options --\u003e\n  \u003cdiv v-watermark=\"{ content: 'Draft', fontSize: 16, color: '#ccc', rotate: -20 }\"\u003e\n    Content with watermark\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useWatermark } from 'directix'\n\n// Composable usage\nconst { show, hide, update } = useWatermark({\n  content: 'Confidential',\n  fontSize: 16,\n  color: '#ccc'\n})\n\u003c/script\u003e\n```\n\n### v-blur\n\nBackground blur overlay effect.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple blur --\u003e\n  \u003cdiv v-blur=\"isBlurred\"\u003eContent behind blur\u003c/div\u003e\n\n  \u003c!-- With radius --\u003e\n  \u003cdiv v-blur=\"15\"\u003eBlur with 15px radius\u003c/div\u003e\n\n  \u003c!-- With options --\u003e\n  \u003cdiv v-blur=\"{\n    visible: isBlurred,\n    radius: 20,\n    overlayColor: 'rgba(255, 255, 255, 0.3)',\n    lockScroll: true\n  }\"\u003e\n    Content\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { ref } from 'vue'\nimport { useBlur } from 'directix'\n\nconst isBlurred = ref(false)\n\n// Composable usage\nconst { show, hide, toggle } = useBlur({\n  radius: 10,\n  overlayColor: 'rgba(0, 0, 0, 0.5)'\n})\n\u003c/script\u003e\n```\n\n### v-fade\n\nFade in/out transition effect.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Toggle visibility with fade --\u003e\n  \u003cdiv v-fade=\"isVisible\"\u003eFade content\u003c/div\u003e\n\n  \u003c!-- Fade in only --\u003e\n  \u003cdiv v-fade=\"'in'\"\u003eFade in\u003c/div\u003e\n\n  \u003c!-- With options --\u003e\n  \u003cdiv v-fade=\"{\n    visible: isVisible,\n    duration: 500,\n    easing: 'ease-in-out',\n    onComplete: () =\u003e console.log('Fade complete')\n  }\"\u003e\n    Content\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { ref } from 'vue'\nimport { useFade } from 'directix'\n\nconst isVisible = ref(true)\n\n// Composable usage\nconst { fadeIn, fadeOut, toggle } = useFade({\n  duration: 300,\n  easing: 'ease'\n})\n\u003c/script\u003e\n```\n\n### v-parallax\n\nParallax scrolling effect.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple parallax --\u003e\n  \u003cdiv v-parallax\u003eParallax content\u003c/div\u003e\n\n  \u003c!-- With speed factor --\u003e\n  \u003cdiv v-parallax=\"0.3\"\u003eSlower parallax\u003c/div\u003e\n\n  \u003c!-- With options --\u003e\n  \u003cdiv v-parallax=\"{\n    speed: 0.5,\n    reverse: true,\n    mobileBreakpoint: 768\n  }\"\u003e\n    Reverse parallax, disabled on mobile\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useParallax } from 'directix'\n\n// Composable usage\nconst { offset, progress, enabled } = useParallax({\n  speed: 0.5,\n  reverse: false\n})\n\u003c/script\u003e\n```\n\n### v-lottie\n\nLottie animation player.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- With URL --\u003e\n  \u003cdiv v-lottie=\"'https://assets.example.com/animation.json'\"\u003e\u003c/div\u003e\n\n  \u003c!-- With animation data --\u003e\n  \u003cdiv v-lottie=\"animationData\"\u003e\u003c/div\u003e\n\n  \u003c!-- With options --\u003e\n  \u003cdiv v-lottie=\"{\n    animationData: animationData,\n    autoplay: true,\n    loop: true,\n    speed: 1.5,\n    onComplete: () =\u003e console.log('Done')\n  }\"\u003e\u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport animationData from './animation.json'\nimport { useLottie } from 'directix'\n\n// Composable usage\nconst { play, pause, stop, setSpeed, setDirection } = useLottie({\n  animationData,\n  autoplay: true,\n  loop: true\n})\n\u003c/script\u003e\n```\n\n### v-typewriter\n\nTypewriter animation effect.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Simple usage --\u003e\n  \u003cspan v-typewriter=\"'Hello, World!'\"\u003e\u003c/span\u003e\n\n  \u003c!-- With options --\u003e\n  \u003cspan v-typewriter=\"{\n    text: 'Typing animation',\n    speed: 100,\n    cursor: '_',\n    onComplete: () =\u003e console.log('Done!')\n  }\"\u003e\u003c/span\u003e\n\n  \u003c!-- Loop mode --\u003e\n  \u003cspan v-typewriter=\"{\n    text: 'Loop animation',\n    loop: true,\n    deleteDelay: 1000\n  }\"\u003e\u003c/span\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useTypewriter } from 'directix'\n\n// Composable usage\nconst { start, stop, pause, resume } = useTypewriter({\n  text: 'Hello World',\n  speed: 50,\n  loop: false\n})\n\u003c/script\u003e\n```\n\n### v-export\n\nExport data (CSV/JSON/HTML/TXT).\n\n```vue\n\u003ctemplate\u003e\n  \u003cbutton v-export=\"exportData\"\u003eExport CSV\u003c/button\u003e\n\n  \u003cbutton v-export=\"{ data: tableData, format: 'json', filename: 'my-data' }\"\u003e\n    Export JSON\n  \u003c/button\u003e\n\n  \u003cbutton v-export=\"{\n    data: tableData,\n    format: 'csv',\n    columns: ['name', 'email'],\n    headers: { name: 'Name', email: 'Email Address' }\n  }\"\u003e\n    Export with custom columns\n  \u003c/button\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nconst tableData = [\n  { name: 'John', email: 'john@example.com', age: 30 },\n  { name: 'Jane', email: 'jane@example.com', age: 25 }\n]\n\nimport { useExport } from 'directix'\n\n// Composable usage\nconst { exportCSV, exportJSON, exportHTML } = useExport()\n\u003c/script\u003e\n```\n\n### v-highlight\n\nKeyword highlighting.\n\n```vue\n\u003ctemplate\u003e\n  \u003cp v-highlight=\"'important'\"\u003eThis is an important message.\u003c/p\u003e\n\n  \u003cp v-highlight=\"['Vue', 'React']\"\u003eVue and React are popular frameworks.\u003c/p\u003e\n\n  \u003cp v-highlight=\"{\n    keywords: 'highlight',\n    className: 'my-highlight',\n    style: 'background: yellow; color: black;',\n    caseSensitive: true\n  }\"\u003e\n    This will highlight the word.\n  \u003c/p\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useHighlight } from 'directix'\n\n// Composable usage\nconst { highlight, clear } = useHighlight({\n  keywords: ['important', 'key'],\n  className: 'highlight'\n})\n\u003c/script\u003e\n```\n\n### v-emoji\n\nEmoji input filter.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Strip all emojis --\u003e\n  \u003cinput v-emoji type=\"text\" /\u003e\n\n  \u003c!-- Strip emojis with replacement --\u003e\n  \u003cinput v-emoji=\"{ strip: true, replacement: '*' }\" type=\"text\" /\u003e\n\n  \u003c!-- Allow specific emojis --\u003e\n  \u003cinput v-emoji=\"{ allowList: ['😊', '👍'] }\" type=\"text\" /\u003e\n\n  \u003c!-- Block specific emojis --\u003e\n  \u003cinput v-emoji=\"{ blockList: ['🚫', '❌'] }\" type=\"text\" /\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useEmoji } from 'directix'\n\n// Composable usage\nconst { stripEmojis, containsEmoji } = useEmoji({\n  strip: true,\n  allowList: ['😊', '👍']\n})\n\u003c/script\u003e\n```\n\n### v-context-menu\n\nRight-click context menu.\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv v-context-menu=\"menuItems\"\u003eRight click here\u003c/div\u003e\n  \u003cdiv v-context-menu=\"{ items: menuItems, width: 200 }\"\u003eCustom width\u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useContextMenu } from 'directix'\n\nconst menuItems = [\n  { label: 'Copy', handler: () =\u003e console.log('Copy') },\n  { label: 'Paste', handler: () =\u003e console.log('Paste') },\n  { divider: true, label: '' },\n  { label: 'Delete', handler: () =\u003e console.log('Delete') }\n]\n\n// Composable usage\nconst { show, hide, setItems } = useContextMenu({\n  items: menuItems\n})\n\u003c/script\u003e\n```\n\n### v-fullscreen\n\nFullscreen toggle.\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv v-fullscreen\u003e\n    Content to show in fullscreen\n    \u003cbutton @click=\"$el.toggleFullscreen()\"\u003eToggle\u003c/button\u003e\n  \u003c/div\u003e\n\n  \u003cdiv v-fullscreen=\"{ fullscreenClass: 'my-fullscreen' }\"\u003e\n    Custom fullscreen class\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useFullscreen } from 'directix'\n\n// Composable usage\nconst { isFullscreen, enter, exit, toggle } = useFullscreen({\n  onEnter: () =\u003e console.log('Entered fullscreen'),\n  onExit: () =\u003e console.log('Exited fullscreen')\n})\n\u003c/script\u003e\n```\n\n### v-skeleton\n\nSkeleton loading placeholder.\n\n```vue\n\u003ctemplate\u003e\n  \u003c!-- Basic usage --\u003e\n  \u003cdiv v-skeleton=\"isLoading\"\u003eContent here\u003c/div\u003e\n\n  \u003c!-- With options --\u003e\n  \u003cdiv v-skeleton=\"{ loading: isLoading, animation: 'pulse', width: 200, height: 20 }\"\u003e\n    Content here\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { ref } from 'vue'\nimport { useSkeleton } from 'directix'\n\nconst isLoading = ref(true)\n\n// Composable usage\nconst { show, hide, update } = useSkeleton({\n  animation: 'wave',\n  color: '#e8e8e8'\n})\n\u003c/script\u003e\n```\n\n### v-progress\n\nProgress bar animation.\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv v-progress=\"50\"\u003eProgress at 50%\u003c/div\u003e\n\n  \u003cdiv v-progress=\"{\n    value: progressValue,\n    color: '#42b883',\n    height: 8,\n    showText: true\n  }\"\u003e\n    Content\n  \u003c/div\u003e\n\n  \u003cdiv v-progress=\"{ indeterminate: true }\"\u003e\n    Loading...\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { ref } from 'vue'\nimport { useProgress } from 'directix'\n\nconst progressValue = ref(50)\n\n// Composable usage\nconst { setProgress, start, finish, fail } = useProgress({\n  color: '#42b883',\n  height: 4\n})\n\u003c/script\u003e\n```\n\n### v-counter\n\nAnimated number counter.\n\n```vue\n\u003ctemplate\u003e\n  \u003cspan v-counter=\"1000\"\u003e0\u003c/span\u003e\n\n  \u003cspan v-counter=\"{\n    value: 10000,\n    duration: 3000,\n    decimals: 2,\n    useGrouping: true\n  }\"\u003e0\u003c/span\u003e\n\n  \u003cspan v-counter=\"{\n    value: targetValue,\n    formatter: (v) =\u003e '$' + v.toFixed(2)\n  }\"\u003e0\u003c/span\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { ref } from 'vue'\nimport { useCounter } from 'directix'\n\nconst targetValue = ref(1000)\n\n// Composable usage\nconst { start, pause, reset, update } = useCounter({\n  startValue: 0,\n  endValue: 1000,\n  duration: 2000,\n  formatter: (v) =\u003e `$${v.toFixed(2)}`\n})\n\u003c/script\u003e\n```\n\n### v-click-wave\n\nClick wave effect.\n\n```vue\n\u003ctemplate\u003e\n  \u003cbutton v-click-wave\u003eClick me\u003c/button\u003e\n  \u003cbutton v-click-wave=\"'rgba(255, 255, 255, 0.3)'\"\u003eCustom color\u003c/button\u003e\n  \u003cbutton v-click-wave=\"{ color: 'red', duration: 400 }\"\u003eCustom options\u003c/button\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { ref } from 'vue'\nimport { useClickWave } from 'directix'\n\n// Composable usage\nconst buttonRef = ref(null)\nconst { bind, trigger } = useClickWave({\n  color: 'currentColor',\n  duration: 500\n})\n\n// Bind to element on mount\nonMounted(() =\u003e bind(buttonRef.value))\n\u003c/script\u003e\n```\n\n### v-pan\n\nPan/drag gesture.\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv v-pan=\"handlePan\"\u003eSwipe me\u003c/div\u003e\n\n  \u003cdiv v-pan=\"{\n    onPan: handlePan,\n    direction: 'horizontal',\n    threshold: 20\n  }\"\u003e\n    Horizontal only\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { usePan } from 'directix'\n\nfunction handlePan(e) {\n  console.log('Direction:', e.direction)\n  console.log('Distance:', e.distance)\n}\n\n// Composable usage\nconst { isPanning, deltaX, deltaY } = usePan({\n  onPan: handlePan,\n  direction: 'horizontal'\n})\n\u003c/script\u003e\n```\n\n### v-pinch\n\nPinch/zoom gesture.\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv v-pinch=\"handlePinch\"\u003ePinch to zoom\u003c/div\u003e\n\n  \u003cdiv v-pinch=\"{\n    onPinch: handlePinch,\n    enableTransform: true,\n    minScale: 0.5,\n    maxScale: 3\n  }\"\u003e\n    Pinch to scale\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { usePinch } from 'directix'\n\nfunction handlePinch(e) {\n  console.log('Scale:', e.scale)\n  console.log('Center:', e.centerX, e.centerY)\n}\n\n// Composable usage\nconst { scale, isPinching } = usePinch({\n  onPinch: handlePinch,\n  minScale: 0.5,\n  maxScale: 3\n})\n\u003c/script\u003e\n```\n\n### v-rotate-gesture\n\nRotation gesture.\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv v-rotate-gesture=\"handleRotate\"\u003eRotate with two fingers\u003c/div\u003e\n\n  \u003cdiv v-rotate-gesture=\"{\n    onRotate: handleRotate,\n    enableTransform: true\n  }\"\u003e\n    Rotate with transform\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript setup\u003e\nimport { useRotateGesture } from 'directix'\n\nfunction handleRotate(e) {\n  console.log('Rotation:', e.rotation)\n  console.log('Angle:', e.angle)\n}\n\n// Composable usage\nconst { angle, isRotating } = useRotateGesture({\n  onRotate: handleRotate,\n  enableTransform: true\n})\n\u003c/script\u003e\n```\n\n## API Reference\n\n### DirectiveInstallOptions\n\n```typescript\ninterface DirectiveInstallOptions {\n  /** Register specific directives only */\n  directives?: string[]\n  /** Register all directives (default: true) */\n  all?: boolean\n  /** Global configuration for directives */\n  config?: Record\u003cstring, any\u003e\n}\n```\n\n### Directive Options\n\nEach directive accepts different options. See the [documentation](https://github.com/saqqdy/directix#usage-examples) for detailed API.\n\n## Roadmap\n\n### v1.7.1 (2026-04-11) - Bug Fixes \u0026 Improvements ✅\n\n- **Playground Fixes** - Monaco Editor loading, syntax highlighting, Vue version sync\n- **UI Improvements** - Removed redundant controls, unified documentation layout\n\n### v1.7.0 (2026-04-15) - Visual Configuration Tool ✅\n\n- **Online Playground** - Live editing environment with Vue 2/3 support\n- **Visual Configurator** - Interactive parameter configuration panel\n- **Code Generator** - Generate Vue 2/3/Composable/Nuxt code snippets\n- **Configuration Presets** - Quick-start templates for common use cases\n- **Monaco Editor** - CDN-loaded code editor with syntax highlighting\n- **Live Preview** - Real-time directive effect preview\n\n### v1.8.0 (2026-04-22) - Quality \u0026 Ecosystem ✅\n\n- **Test Coverage** - 90%+ unit test coverage, E2E testing with Playwright\n- **Performance Optimization** - Bundle size optimization, tree-shaking improvements\n- **VS Code Extension** - Autocompletion, hover documentation, code snippets\n- **CLI Tool** - `directix create`, `directix init`, `directix doctor`, `directix migrate`\n\n### v1.9.0 (Planned - 2026-04-29) - Documentation \u0026 Community\n\n- **Interactive Documentation** - Live editing with instant preview\n- **Real-world Examples** - 10+ practical scenario examples\n- **i18n Support** - English, Chinese, Japanese documentation\n- **Developer Experience** - Improved error messages, DevTools integration\n- **Plugin System** - Community extension support\n\n### v1.10.0 (Planned - 2026-05-06) - Vue 3 Optimization \u0026 Security\n\n- **Vue 3 Optimization Preview** - Suspense, Teleport support\n- **Mobile Optimization** - Touch gestures, PWA support\n- **Accessibility (A11y)** - ARIA attributes, keyboard navigation\n- **Security Enhancements** - XSS protection, CSP compatibility\n\n### v1.11.0 (Planned - 2026-05-13) - Stability \u0026 Enterprise\n\n- **Stability** - Browser compatibility, edge case fixes\n- **Performance Limits** - Bundle ≤ 25KB, memory optimization\n- **Enterprise Features** - Permissions, audit logs, config center\n- **v2.0 Migration Prep** - Migration tool, breaking changes warnings\n\n### v2.0.0 (Future)\n\n- Vue 3 exclusive optimizations\n- Web Components support\n\n## Browser Support\n\n| Browser | Version |\n|---------|---------|\n| Chrome | Latest |\n| Firefox | Latest |\n| Safari | Latest |\n| Edge | Latest |\n\n## Contributing\n\nContributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.\n\n## License\n\n[MIT](LICENSE) © 2024-present saqqdy\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaqqdy%2Fdirectix","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsaqqdy%2Fdirectix","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaqqdy%2Fdirectix/lists"}