directix 1.4.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,13 +4,13 @@
4
4
  [![npm downloads](https://img.shields.io/npm/dm/directix.svg)](https://www.npmjs.com/package/directix)
5
5
  [![GitHub license](https://img.shields.io/github/license/saqqdy/directix)](https://github.com/saqqdy/directix/blob/master/LICENSE)
6
6
 
7
- **[中文文档](README_CN.md)**
7
+ **English** | **[中文文档](README_CN.md)**
8
8
 
9
9
  A comprehensive, easy-to-use, and high-performance Vue custom directives library supporting both Vue 2 and Vue 3.
10
10
 
11
11
  ## Features
12
12
 
13
- - 🎯 **Comprehensive** - 40 commonly used directives and 40 composables
13
+ - 🎯 **Comprehensive** - 57 commonly used directives and 57 composables
14
14
  - 🔄 **Vue 2/3 Compatible** - Single codebase supports both Vue 2 and Vue 3
15
15
  - 📦 **Tree-shakable** - Import only what you need
16
16
  - 🔒 **TypeScript** - Full TypeScript support with type definitions
@@ -22,12 +22,12 @@ A comprehensive, easy-to-use, and high-performance Vue custom directives library
22
22
 
23
23
  ## Online Demo
24
24
 
25
- Try it online with StackBlitz:
25
+ Try it online with StackBlitz or CodeSandbox:
26
26
 
27
- | Demo | Link |
28
- |------|------|
29
- | Vue 3 | [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/saqqdy/directix/tree/master/examples/vue3) |
30
- | Vue 2 | [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/saqqdy/directix/tree/master/examples/vue2) |
27
+ | Demo | StackBlitz | CodeSandbox |
28
+ |------|------------|-------------|
29
+ | 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) |
30
+ | 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) |
31
31
 
32
32
  ## Installation
33
33
 
@@ -128,6 +128,66 @@ const { run: debouncedSearch } = useDebounce({ handler: search, wait: 500 })
128
128
 
129
129
  See the [Composables](#composables) section below for all available composables.
130
130
 
131
+ ## Nuxt Integration
132
+
133
+ Directix provides a Nuxt module for seamless integration with Nuxt 3 applications.
134
+
135
+ ### Installation
136
+
137
+ The Nuxt module is included in the main package. Simply add it to your `nuxt.config.ts`:
138
+
139
+ ```typescript
140
+ // nuxt.config.ts
141
+ export default defineNuxtConfig({
142
+ modules: ['directix/nuxt'],
143
+
144
+ directix: {
145
+ // Enable/disable the module (default: true)
146
+ enabled: true,
147
+
148
+ // Only include specific directives (optional)
149
+ include: ['v-click-outside', 'v-copy', 'v-debounce'],
150
+
151
+ // Or exclude specific directives (optional)
152
+ exclude: ['v-ripple'],
153
+
154
+ // Default options for directives (optional)
155
+ directiveOptions: {
156
+ 'v-permission': {
157
+ config: {
158
+ getPermissions: () => ['read', 'write']
159
+ }
160
+ }
161
+ },
162
+
163
+ // Auto-import composables (default: true)
164
+ autoImportComposables: true
165
+ }
166
+ })
167
+ ```
168
+
169
+ ### Usage in Nuxt
170
+
171
+ Directives are automatically registered and composables are auto-imported:
172
+
173
+ ```vue
174
+ <template>
175
+ <div v-click-outside="handleClose">
176
+ <button v-copy="text">Copy</button>
177
+ </div>
178
+ </template>
179
+
180
+ <script setup>
181
+ // Composables are auto-imported, no need to import manually
182
+ const { copy, copied } = useCopy({ source: text })
183
+ const { isHovering } = useHover({ onEnter: handleEnter })
184
+ </script>
185
+ ```
186
+
187
+ ### SSR Compatibility
188
+
189
+ Directives that are not SSR-compatible will only run on the client side. The Nuxt module handles this automatically.
190
+
131
191
  ## Available Directives
132
192
 
133
193
  ### Event Directives
@@ -214,6 +274,38 @@ See the [Composables](#composables) section below for all available composables.
214
274
  | `v-countdown` | Countdown timer display | ✅ |
215
275
  | `v-print` | Print element content | ❌ |
216
276
  | `v-watermark` | Watermark overlay | ✅ |
277
+ | `v-skeleton` | Skeleton loading placeholder | ✅ |
278
+ | `v-progress` | Progress bar animation | ❌ |
279
+ | `v-counter` | Animated number counter | ✅ |
280
+
281
+ ### Gesture Directives
282
+
283
+ | Directive | Description | SSR |
284
+ |-----------|-------------|-----|
285
+ | `v-pan` | Pan/drag gesture | ❌ |
286
+ | `v-pinch` | Pinch/zoom gesture | ❌ |
287
+ | `v-rotate-gesture` | Rotation gesture | ❌ |
288
+
289
+ ### Visual Effect Directives
290
+
291
+ | Directive | Description | SSR |
292
+ |-----------|-------------|-----|
293
+ | `v-blur` | Background blur overlay | ❌ |
294
+ | `v-fade` | Fade in/out transition | ✅ |
295
+ | `v-parallax` | Parallax scrolling effect | ❌ |
296
+ | `v-lottie` | Lottie animation player | ❌ |
297
+ | `v-typewriter` | Typewriter animation | ✅ |
298
+ | `v-click-wave` | Click wave effect | ❌ |
299
+
300
+ ### Data Directives
301
+
302
+ | Directive | Description | SSR |
303
+ |-----------|-------------|-----|
304
+ | `v-export` | Export data (CSV/JSON/HTML) | ❌ |
305
+ | `v-highlight` | Keyword highlighting | ✅ |
306
+ | `v-emoji` | Emoji input filter | ❌ |
307
+ | `v-context-menu` | Right-click context menu | ❌ |
308
+ | `v-fullscreen` | Fullscreen toggle | ❌ |
217
309
 
218
310
  > ✅ = SSR compatible | ❌ = Not SSR compatible
219
311
 
@@ -290,6 +382,23 @@ Every directive has a corresponding composable function for use with the Composi
290
382
  | `useCountdown` | Countdown timer |
291
383
  | `usePrint` | Print content |
292
384
  | `useWatermark` | Watermark overlay |
385
+ | `useSkeleton` | Skeleton loading state |
386
+ | `useProgress` | Progress bar control |
387
+ | `useCounter` | Animated number counter |
388
+ | `usePan` | Pan gesture detection |
389
+ | `usePinch` | Pinch gesture detection |
390
+ | `useRotateGesture` | Rotation gesture detection |
391
+ | `useBlur` | Blur overlay control |
392
+ | `useFade` | Fade transition control |
393
+ | `useParallax` | Parallax scrolling |
394
+ | `useLottie` | Lottie animation control |
395
+ | `useTypewriter` | Typewriter effect |
396
+ | `useExport` | Data export utilities |
397
+ | `useHighlight` | Keyword highlighting |
398
+ | `useEmoji` | Emoji filtering |
399
+ | `useContextMenu` | Context menu control |
400
+ | `useFullscreen` | Fullscreen mode control |
401
+ | `useClickWave` | Click wave effect |
293
402
 
294
403
  ### Composable Usage Example
295
404
 
@@ -343,12 +452,19 @@ Detect clicks outside an element, useful for closing dropdowns, modals, etc.
343
452
 
344
453
  <script setup>
345
454
  import { ref } from 'vue'
455
+ import { useClickOutside } from 'directix'
346
456
 
347
457
  const show = ref(false)
348
458
 
349
459
  function closeDropdown() {
350
460
  show.value = false
351
461
  }
462
+
463
+ // Composable usage
464
+ const containerRef = ref()
465
+ useClickOutside(containerRef, () => {
466
+ show.value = false
467
+ })
352
468
  </script>
353
469
  ```
354
470
 
@@ -368,6 +484,9 @@ Copy text to clipboard with a simple directive.
368
484
  </template>
369
485
 
370
486
  <script setup>
487
+ import { ref } from 'vue'
488
+ import { useCopy } from 'directix'
489
+
371
490
  const textToCopy = 'Hello, World!'
372
491
 
373
492
  function handleSuccess(text) {
@@ -377,6 +496,10 @@ function handleSuccess(text) {
377
496
  function handleError(error) {
378
497
  console.error('Copy failed:', error)
379
498
  }
499
+
500
+ // Composable usage
501
+ const sourceText = ref('Hello World')
502
+ const { copy, copied } = useCopy({ source: sourceText })
380
503
  </script>
381
504
  ```
382
505
 
@@ -397,9 +520,17 @@ Debounce event handlers to limit execution frequency.
397
520
  </template>
398
521
 
399
522
  <script setup>
523
+ import { useDebounce } from 'directix'
524
+
400
525
  function handleInput(event) {
401
526
  console.log('Debounced input:', event.target.value)
402
527
  }
528
+
529
+ // Composable usage
530
+ const { run: debouncedSearch, cancel } = useDebounce({
531
+ handler: (query) => fetchResults(query),
532
+ wait: 500
533
+ })
403
534
  </script>
404
535
  ```
405
536
 
@@ -422,9 +553,17 @@ Throttle event handlers to limit execution frequency.
422
553
  </template>
423
554
 
424
555
  <script setup>
556
+ import { useThrottle } from 'directix'
557
+
425
558
  function handleClick() {
426
559
  console.log('Throttled click')
427
560
  }
561
+
562
+ // Composable usage
563
+ const { run: throttledScroll, cancel } = useThrottle({
564
+ handler: (position) => updatePosition(position),
565
+ wait: 100
566
+ })
428
567
  </script>
429
568
  ```
430
569
 
@@ -440,6 +579,13 @@ Auto focus an element when mounted.
440
579
  <!-- With options -->
441
580
  <input v-focus="{ focus: true, refocus: true }" />
442
581
  </template>
582
+
583
+ <script setup>
584
+ import { useFocus } from 'directix'
585
+
586
+ // Composable usage
587
+ const { focus, blur, hasFocus } = useFocus()
588
+ </script>
443
589
  ```
444
590
 
445
591
  ### v-permission
@@ -466,7 +612,7 @@ Control element visibility based on user permissions.
466
612
  </template>
467
613
 
468
614
  <script setup>
469
- import { configurePermission } from 'directix'
615
+ import { configurePermission, usePermission } from 'directix'
470
616
 
471
617
  configurePermission({
472
618
  getPermissions: () => ['read', 'write'],
@@ -476,6 +622,10 @@ configurePermission({
476
622
  editor: ['read', 'write', 'edit']
477
623
  }
478
624
  })
625
+
626
+ // Composable usage
627
+ const { hasPermission, hasAnyPermission, hasAllPermissions } = usePermission()
628
+ const canEdit = hasPermission('edit')
479
629
  </script>
480
630
  ```
481
631
 
@@ -491,6 +641,16 @@ Lazy load images when they enter the viewport.
491
641
  <!-- With placeholder and error image -->
492
642
  <img v-lazy="{ src: imageUrl, placeholder: '/placeholder.png', error: '/error.png' }" />
493
643
  </template>
644
+
645
+ <script setup>
646
+ import { useLazy } from 'directix'
647
+
648
+ // Composable usage
649
+ const { load, state, loaded } = useLazy({
650
+ src: 'image.jpg',
651
+ preload: 100
652
+ })
653
+ </script>
494
654
  ```
495
655
 
496
656
  ### v-mask
@@ -508,6 +668,16 @@ Input masking for formatted input.
508
668
  <!-- SSN -->
509
669
  <input v-mask="{ mask: '###-##-####', placeholder: '_' }" placeholder="SSN" />
510
670
  </template>
671
+
672
+ <script setup>
673
+ import { useMask } from 'directix'
674
+
675
+ // Composable usage
676
+ const { maskedValue, unmaskedValue, update } = useMask({
677
+ mask: '(###) ###-####',
678
+ value: '1234567890'
679
+ })
680
+ </script>
511
681
  ```
512
682
 
513
683
  ### v-loading
@@ -524,6 +694,19 @@ Show loading overlay on elements.
524
694
  Content with locked scroll
525
695
  </div>
526
696
  </template>
697
+
698
+ <script setup>
699
+ import { ref } from 'vue'
700
+ import { useLoading } from 'directix'
701
+
702
+ const isLoading = ref(true)
703
+
704
+ // Composable usage
705
+ const { show, hide, setText } = useLoading({
706
+ text: 'Loading...',
707
+ lock: true
708
+ })
709
+ </script>
527
710
  ```
528
711
 
529
712
  ### v-sanitize
@@ -538,6 +721,16 @@ Sanitize HTML content to prevent XSS attacks.
538
721
  <!-- With custom allowed tags -->
539
722
  <div v-sanitize="{ html: userContent, allowedTags: ['b', 'i', 'u'] }"></div>
540
723
  </template>
724
+
725
+ <script setup>
726
+ import { useSanitize } from 'directix'
727
+
728
+ // Composable usage
729
+ const { sanitize, setAllowedTags } = useSanitize({
730
+ allowedTags: ['b', 'i', 'u', 'a']
731
+ })
732
+ const cleanHtml = sanitize(dirtyHtml)
733
+ </script>
541
734
  ```
542
735
 
543
736
  ### v-tooltip
@@ -554,6 +747,16 @@ Display tooltips on hover or click.
554
747
  Click me
555
748
  </button>
556
749
  </template>
750
+
751
+ <script setup>
752
+ import { useTooltip } from 'directix'
753
+
754
+ // Composable usage
755
+ const { show, hide, updateContent, updatePosition } = useTooltip({
756
+ content: 'Tooltip content',
757
+ placement: 'top'
758
+ })
759
+ </script>
557
760
  ```
558
761
 
559
762
  ### v-image-preview
@@ -568,6 +771,15 @@ Preview images with zoom and gesture support.
568
771
  <!-- With options -->
569
772
  <img v-image-preview="{ src: 'thumbnail.jpg', previewSrc: 'full.jpg', enablePinchZoom: true }" />
570
773
  </template>
774
+
775
+ <script setup>
776
+ import { useImagePreview } from 'directix'
777
+
778
+ // Composable usage
779
+ const { open, close, zoom, rotate } = useImagePreview({
780
+ enablePinchZoom: true
781
+ })
782
+ </script>
571
783
  ```
572
784
 
573
785
  ### v-draggable
@@ -582,6 +794,16 @@ Make elements draggable.
582
794
  <!-- With constraints -->
583
795
  <div v-draggable="{ axis: 'x', bounds: 'parent' }">Horizontal drag only</div>
584
796
  </template>
797
+
798
+ <script setup>
799
+ import { useDraggable } from 'directix'
800
+
801
+ // Composable usage
802
+ const { position, isDragging, reset } = useDraggable({
803
+ axis: 'x',
804
+ bounds: 'parent'
805
+ })
806
+ </script>
585
807
  ```
586
808
 
587
809
  ### v-uppercase / v-lowercase / v-capitalcase
@@ -594,6 +816,15 @@ Transform text case.
594
816
  <input v-lowercase placeholder="Auto lowercase" />
595
817
  <input v-capitalcase placeholder="Capitalize first letter" />
596
818
  </template>
819
+
820
+ <script setup>
821
+ import { useUppercase, useLowercase, useCapitalcase } from 'directix'
822
+
823
+ // Composable usage
824
+ const { transform: toUppercase } = useUppercase()
825
+ const { transform: toLowercase } = useLowercase()
826
+ const { transform: toCapitalcase } = useCapitalcase()
827
+ </script>
597
828
  ```
598
829
 
599
830
  ### v-truncate
@@ -608,6 +839,14 @@ Truncate text with ellipsis.
608
839
  <!-- With options -->
609
840
  <p v-truncate="{ length: 100, suffix: '...', position: 'end' }">Long text...</p>
610
841
  </template>
842
+
843
+ <script setup>
844
+ import { useTruncate } from 'directix'
845
+
846
+ // Composable usage
847
+ const { truncate } = useTruncate({ length: 100, suffix: '...' })
848
+ const shortText = truncate(longText)
849
+ </script>
611
850
  ```
612
851
 
613
852
  ### v-touch
@@ -622,6 +861,8 @@ Detect touch gestures.
622
861
  </template>
623
862
 
624
863
  <script setup>
864
+ import { useTouch } from 'directix'
865
+
625
866
  function handleSwipe(direction) {
626
867
  console.log('Swiped:', direction) // 'left', 'right', 'up', 'down'
627
868
  }
@@ -629,6 +870,11 @@ function handleSwipe(direction) {
629
870
  function handlePinch(scale) {
630
871
  console.log('Pinched:', scale)
631
872
  }
873
+
874
+ // Composable usage
875
+ const { onSwipe, onPinch, onRotate } = useTouch({
876
+ onSwipe: handleSwipe
877
+ })
632
878
  </script>
633
879
  ```
634
880
 
@@ -644,6 +890,13 @@ Trim input whitespace.
644
890
  <!-- Trim on input -->
645
891
  <input v-trim="{ position: 'both', event: 'input' }" />
646
892
  </template>
893
+
894
+ <script setup>
895
+ import { useTrim } from 'directix'
896
+
897
+ // Composable usage
898
+ const { trim, trimLeft, trimRight } = useTrim({ position: 'both' })
899
+ </script>
647
900
  ```
648
901
 
649
902
  ### v-money
@@ -654,6 +907,14 @@ Currency format input.
654
907
  <template>
655
908
  <input v-money="{ prefix: '$', precision: 2 }" placeholder="Enter amount" />
656
909
  </template>
910
+
911
+ <script setup>
912
+ import { useMoney } from 'directix'
913
+
914
+ // Composable usage
915
+ const { format, parse } = useMoney({ prefix: '$', precision: 2 })
916
+ const formatted = format(1234.56) // "$1,234.56"
917
+ </script>
657
918
  ```
658
919
 
659
920
  ### v-number
@@ -664,6 +925,13 @@ Number format input.
664
925
  <template>
665
926
  <input v-number="{ precision: 2, min: 0, max: 100 }" placeholder="Enter number" />
666
927
  </template>
928
+
929
+ <script setup>
930
+ import { useNumber } from 'directix'
931
+
932
+ // Composable usage
933
+ const { format, parse } = useNumber({ precision: 2, min: 0, max: 100 })
934
+ </script>
667
935
  ```
668
936
 
669
937
  ### v-click-delay
@@ -680,9 +948,17 @@ Delay click execution to prevent double clicks.
680
948
  </template>
681
949
 
682
950
  <script setup>
951
+ import { useClickDelay } from 'directix'
952
+
683
953
  function handleClick() {
684
954
  console.log('Clicked (delayed)')
685
955
  }
956
+
957
+ // Composable usage
958
+ const { run: delayedClick, cancel } = useClickDelay({
959
+ handler: handleClick,
960
+ delay: 300
961
+ })
686
962
  </script>
687
963
  ```
688
964
 
@@ -703,6 +979,8 @@ Countdown timer display.
703
979
  </template>
704
980
 
705
981
  <script setup>
982
+ import { useCountdown } from 'directix'
983
+
706
984
  function handleTick(remaining) {
707
985
  console.log('Remaining:', remaining)
708
986
  }
@@ -710,6 +988,13 @@ function handleTick(remaining) {
710
988
  function handleComplete() {
711
989
  console.log('Countdown complete!')
712
990
  }
991
+
992
+ // Composable usage
993
+ const { start, pause, reset, remaining } = useCountdown({
994
+ time: 60,
995
+ onTick: handleTick,
996
+ onComplete: handleComplete
997
+ })
713
998
  </script>
714
999
  ```
715
1000
 
@@ -725,6 +1010,13 @@ Text ellipsis overflow with tooltip.
725
1010
  <!-- With custom lines -->
726
1011
  <div v-ellipsis="{ lines: 2 }">Multi-line text with ellipsis</div>
727
1012
  </template>
1013
+
1014
+ <script setup>
1015
+ import { useEllipsis } from 'directix'
1016
+
1017
+ // Composable usage
1018
+ const { isEllipsisActive, checkEllipsis } = useEllipsis({ lines: 1 })
1019
+ </script>
728
1020
  ```
729
1021
 
730
1022
  ### v-hotkey
@@ -743,6 +1035,8 @@ Keyboard shortcut binding.
743
1035
  </template>
744
1036
 
745
1037
  <script setup>
1038
+ import { useHotkey } from 'directix'
1039
+
746
1040
  function handleSave() {
747
1041
  console.log('Saving...')
748
1042
  }
@@ -750,6 +1044,11 @@ function handleSave() {
750
1044
  function handleCopy() {
751
1045
  console.log('Copying...')
752
1046
  }
1047
+
1048
+ // Composable usage
1049
+ const { bind, unbind, unbindAll } = useHotkey({
1050
+ 'ctrl+s': handleSave
1051
+ })
753
1052
  </script>
754
1053
  ```
755
1054
 
@@ -766,6 +1065,19 @@ Print element content.
766
1065
  <!-- Print self -->
767
1066
  <div v-print="{ self: true }">Click to print this content</div>
768
1067
  </template>
1068
+
1069
+ <script setup>
1070
+ import { ref } from 'vue'
1071
+ import { usePrint } from 'directix'
1072
+
1073
+ const printRef = ref()
1074
+
1075
+ // Composable usage
1076
+ const { print, printElement } = usePrint({
1077
+ onBefore: () => console.log('Printing...'),
1078
+ onComplete: () => console.log('Printed!')
1079
+ })
1080
+ </script>
769
1081
  ```
770
1082
 
771
1083
  ### v-pull-refresh
@@ -785,10 +1097,17 @@ Pull to refresh functionality.
785
1097
  </template>
786
1098
 
787
1099
  <script setup>
1100
+ import { usePullRefresh } from 'directix'
1101
+
788
1102
  async function handleRefresh() {
789
1103
  // Fetch new data
790
1104
  await fetchData()
791
1105
  }
1106
+
1107
+ // Composable usage
1108
+ const { isLoading, disable, enable } = usePullRefresh({
1109
+ handler: handleRefresh
1110
+ })
792
1111
  </script>
793
1112
  ```
794
1113
 
@@ -809,9 +1128,17 @@ Swipe gesture detection with mouse support.
809
1128
  </template>
810
1129
 
811
1130
  <script setup>
1131
+ import { useSwipe } from 'directix'
1132
+
812
1133
  function handleSwipe(direction) {
813
1134
  console.log('Swiped:', direction) // 'left', 'right', 'up', 'down'
814
1135
  }
1136
+
1137
+ // Composable usage
1138
+ const { direction, lengthX, lengthY } = useSwipe({
1139
+ onSwipe: handleSwipe,
1140
+ threshold: 50
1141
+ })
815
1142
  </script>
816
1143
  ```
817
1144
 
@@ -830,6 +1157,14 @@ Virtual list for rendering large datasets efficiently.
830
1157
 
831
1158
  <script setup>
832
1159
  const list = Array.from({ length: 10000 }, (_, i) => ({ id: i, name: `Item ${i}` }))
1160
+
1161
+ import { useVirtualList } from 'directix'
1162
+
1163
+ // Composable usage
1164
+ const { list, containerProps, wrapperProps, scrollTo } = useVirtualList(
1165
+ largeList,
1166
+ { itemHeight: 50 }
1167
+ )
833
1168
  </script>
834
1169
  ```
835
1170
 
@@ -849,6 +1184,575 @@ Watermark overlay.
849
1184
  Content with watermark
850
1185
  </div>
851
1186
  </template>
1187
+
1188
+ <script setup>
1189
+ import { useWatermark } from 'directix'
1190
+
1191
+ // Composable usage
1192
+ const { show, hide, update } = useWatermark({
1193
+ content: 'Confidential',
1194
+ fontSize: 16,
1195
+ color: '#ccc'
1196
+ })
1197
+ </script>
1198
+ ```
1199
+
1200
+ ### v-blur
1201
+
1202
+ Background blur overlay effect.
1203
+
1204
+ ```vue
1205
+ <template>
1206
+ <!-- Simple blur -->
1207
+ <div v-blur="isBlurred">Content behind blur</div>
1208
+
1209
+ <!-- With radius -->
1210
+ <div v-blur="15">Blur with 15px radius</div>
1211
+
1212
+ <!-- With options -->
1213
+ <div v-blur="{
1214
+ visible: isBlurred,
1215
+ radius: 20,
1216
+ overlayColor: 'rgba(255, 255, 255, 0.3)',
1217
+ lockScroll: true
1218
+ }">
1219
+ Content
1220
+ </div>
1221
+ </template>
1222
+
1223
+ <script setup>
1224
+ import { ref } from 'vue'
1225
+ import { useBlur } from 'directix'
1226
+
1227
+ const isBlurred = ref(false)
1228
+
1229
+ // Composable usage
1230
+ const { show, hide, toggle } = useBlur({
1231
+ radius: 10,
1232
+ overlayColor: 'rgba(0, 0, 0, 0.5)'
1233
+ })
1234
+ </script>
1235
+ ```
1236
+
1237
+ ### v-fade
1238
+
1239
+ Fade in/out transition effect.
1240
+
1241
+ ```vue
1242
+ <template>
1243
+ <!-- Toggle visibility with fade -->
1244
+ <div v-fade="isVisible">Fade content</div>
1245
+
1246
+ <!-- Fade in only -->
1247
+ <div v-fade="'in'">Fade in</div>
1248
+
1249
+ <!-- With options -->
1250
+ <div v-fade="{
1251
+ visible: isVisible,
1252
+ duration: 500,
1253
+ easing: 'ease-in-out',
1254
+ onComplete: () => console.log('Fade complete')
1255
+ }">
1256
+ Content
1257
+ </div>
1258
+ </template>
1259
+
1260
+ <script setup>
1261
+ import { ref } from 'vue'
1262
+ import { useFade } from 'directix'
1263
+
1264
+ const isVisible = ref(true)
1265
+
1266
+ // Composable usage
1267
+ const { fadeIn, fadeOut, toggle } = useFade({
1268
+ duration: 300,
1269
+ easing: 'ease'
1270
+ })
1271
+ </script>
1272
+ ```
1273
+
1274
+ ### v-parallax
1275
+
1276
+ Parallax scrolling effect.
1277
+
1278
+ ```vue
1279
+ <template>
1280
+ <!-- Simple parallax -->
1281
+ <div v-parallax>Parallax content</div>
1282
+
1283
+ <!-- With speed factor -->
1284
+ <div v-parallax="0.3">Slower parallax</div>
1285
+
1286
+ <!-- With options -->
1287
+ <div v-parallax="{
1288
+ speed: 0.5,
1289
+ reverse: true,
1290
+ mobileBreakpoint: 768
1291
+ }">
1292
+ Reverse parallax, disabled on mobile
1293
+ </div>
1294
+ </template>
1295
+
1296
+ <script setup>
1297
+ import { useParallax } from 'directix'
1298
+
1299
+ // Composable usage
1300
+ const { offset, progress, enabled } = useParallax({
1301
+ speed: 0.5,
1302
+ reverse: false
1303
+ })
1304
+ </script>
1305
+ ```
1306
+
1307
+ ### v-lottie
1308
+
1309
+ Lottie animation player.
1310
+
1311
+ ```vue
1312
+ <template>
1313
+ <!-- With URL -->
1314
+ <div v-lottie="'https://assets.example.com/animation.json'"></div>
1315
+
1316
+ <!-- With animation data -->
1317
+ <div v-lottie="animationData"></div>
1318
+
1319
+ <!-- With options -->
1320
+ <div v-lottie="{
1321
+ animationData: animationData,
1322
+ autoplay: true,
1323
+ loop: true,
1324
+ speed: 1.5,
1325
+ onComplete: () => console.log('Done')
1326
+ }"></div>
1327
+ </template>
1328
+
1329
+ <script setup>
1330
+ import animationData from './animation.json'
1331
+ import { useLottie } from 'directix'
1332
+
1333
+ // Composable usage
1334
+ const { play, pause, stop, setSpeed, setDirection } = useLottie({
1335
+ animationData,
1336
+ autoplay: true,
1337
+ loop: true
1338
+ })
1339
+ </script>
1340
+ ```
1341
+
1342
+ ### v-typewriter
1343
+
1344
+ Typewriter animation effect.
1345
+
1346
+ ```vue
1347
+ <template>
1348
+ <!-- Simple usage -->
1349
+ <span v-typewriter="'Hello, World!'"></span>
1350
+
1351
+ <!-- With options -->
1352
+ <span v-typewriter="{
1353
+ text: 'Typing animation',
1354
+ speed: 100,
1355
+ cursor: '_',
1356
+ onComplete: () => console.log('Done!')
1357
+ }"></span>
1358
+
1359
+ <!-- Loop mode -->
1360
+ <span v-typewriter="{
1361
+ text: 'Loop animation',
1362
+ loop: true,
1363
+ deleteDelay: 1000
1364
+ }"></span>
1365
+ </template>
1366
+
1367
+ <script setup>
1368
+ import { useTypewriter } from 'directix'
1369
+
1370
+ // Composable usage
1371
+ const { start, stop, pause, resume } = useTypewriter({
1372
+ text: 'Hello World',
1373
+ speed: 50,
1374
+ loop: false
1375
+ })
1376
+ </script>
1377
+ ```
1378
+
1379
+ ### v-export
1380
+
1381
+ Export data (CSV/JSON/HTML/TXT).
1382
+
1383
+ ```vue
1384
+ <template>
1385
+ <button v-export="exportData">Export CSV</button>
1386
+
1387
+ <button v-export="{ data: tableData, format: 'json', filename: 'my-data' }">
1388
+ Export JSON
1389
+ </button>
1390
+
1391
+ <button v-export="{
1392
+ data: tableData,
1393
+ format: 'csv',
1394
+ columns: ['name', 'email'],
1395
+ headers: { name: 'Name', email: 'Email Address' }
1396
+ }">
1397
+ Export with custom columns
1398
+ </button>
1399
+ </template>
1400
+
1401
+ <script setup>
1402
+ const tableData = [
1403
+ { name: 'John', email: 'john@example.com', age: 30 },
1404
+ { name: 'Jane', email: 'jane@example.com', age: 25 }
1405
+ ]
1406
+
1407
+ import { useExport } from 'directix'
1408
+
1409
+ // Composable usage
1410
+ const { exportCSV, exportJSON, exportHTML } = useExport()
1411
+ </script>
1412
+ ```
1413
+
1414
+ ### v-highlight
1415
+
1416
+ Keyword highlighting.
1417
+
1418
+ ```vue
1419
+ <template>
1420
+ <p v-highlight="'important'">This is an important message.</p>
1421
+
1422
+ <p v-highlight="['Vue', 'React']">Vue and React are popular frameworks.</p>
1423
+
1424
+ <p v-highlight="{
1425
+ keywords: 'highlight',
1426
+ className: 'my-highlight',
1427
+ style: 'background: yellow; color: black;',
1428
+ caseSensitive: true
1429
+ }">
1430
+ This will highlight the word.
1431
+ </p>
1432
+ </template>
1433
+
1434
+ <script setup>
1435
+ import { useHighlight } from 'directix'
1436
+
1437
+ // Composable usage
1438
+ const { highlight, clear } = useHighlight({
1439
+ keywords: ['important', 'key'],
1440
+ className: 'highlight'
1441
+ })
1442
+ </script>
1443
+ ```
1444
+
1445
+ ### v-emoji
1446
+
1447
+ Emoji input filter.
1448
+
1449
+ ```vue
1450
+ <template>
1451
+ <!-- Strip all emojis -->
1452
+ <input v-emoji type="text" />
1453
+
1454
+ <!-- Strip emojis with replacement -->
1455
+ <input v-emoji="{ strip: true, replacement: '*' }" type="text" />
1456
+
1457
+ <!-- Allow specific emojis -->
1458
+ <input v-emoji="{ allowList: ['😊', '👍'] }" type="text" />
1459
+
1460
+ <!-- Block specific emojis -->
1461
+ <input v-emoji="{ blockList: ['🚫', '❌'] }" type="text" />
1462
+ </template>
1463
+
1464
+ <script setup>
1465
+ import { useEmoji } from 'directix'
1466
+
1467
+ // Composable usage
1468
+ const { stripEmojis, containsEmoji } = useEmoji({
1469
+ strip: true,
1470
+ allowList: ['😊', '👍']
1471
+ })
1472
+ </script>
1473
+ ```
1474
+
1475
+ ### v-context-menu
1476
+
1477
+ Right-click context menu.
1478
+
1479
+ ```vue
1480
+ <template>
1481
+ <div v-context-menu="menuItems">Right click here</div>
1482
+ <div v-context-menu="{ items: menuItems, width: 200 }">Custom width</div>
1483
+ </template>
1484
+
1485
+ <script setup>
1486
+ import { useContextMenu } from 'directix'
1487
+
1488
+ const menuItems = [
1489
+ { label: 'Copy', handler: () => console.log('Copy') },
1490
+ { label: 'Paste', handler: () => console.log('Paste') },
1491
+ { divider: true, label: '' },
1492
+ { label: 'Delete', handler: () => console.log('Delete') }
1493
+ ]
1494
+
1495
+ // Composable usage
1496
+ const { show, hide, setItems } = useContextMenu({
1497
+ items: menuItems
1498
+ })
1499
+ </script>
1500
+ ```
1501
+
1502
+ ### v-fullscreen
1503
+
1504
+ Fullscreen toggle.
1505
+
1506
+ ```vue
1507
+ <template>
1508
+ <div v-fullscreen>
1509
+ Content to show in fullscreen
1510
+ <button @click="$el.toggleFullscreen()">Toggle</button>
1511
+ </div>
1512
+
1513
+ <div v-fullscreen="{ fullscreenClass: 'my-fullscreen' }">
1514
+ Custom fullscreen class
1515
+ </div>
1516
+ </template>
1517
+
1518
+ <script setup>
1519
+ import { useFullscreen } from 'directix'
1520
+
1521
+ // Composable usage
1522
+ const { isFullscreen, enter, exit, toggle } = useFullscreen({
1523
+ onEnter: () => console.log('Entered fullscreen'),
1524
+ onExit: () => console.log('Exited fullscreen')
1525
+ })
1526
+ </script>
1527
+ ```
1528
+
1529
+ ### v-skeleton
1530
+
1531
+ Skeleton loading placeholder.
1532
+
1533
+ ```vue
1534
+ <template>
1535
+ <!-- Basic usage -->
1536
+ <div v-skeleton="isLoading">Content here</div>
1537
+
1538
+ <!-- With options -->
1539
+ <div v-skeleton="{ loading: isLoading, animation: 'pulse', width: 200, height: 20 }">
1540
+ Content here
1541
+ </div>
1542
+ </template>
1543
+
1544
+ <script setup>
1545
+ import { ref } from 'vue'
1546
+ import { useSkeleton } from 'directix'
1547
+
1548
+ const isLoading = ref(true)
1549
+
1550
+ // Composable usage
1551
+ const { show, hide, update } = useSkeleton({
1552
+ animation: 'wave',
1553
+ color: '#e8e8e8'
1554
+ })
1555
+ </script>
1556
+ ```
1557
+
1558
+ ### v-progress
1559
+
1560
+ Progress bar animation.
1561
+
1562
+ ```vue
1563
+ <template>
1564
+ <div v-progress="50">Progress at 50%</div>
1565
+
1566
+ <div v-progress="{
1567
+ value: progressValue,
1568
+ color: '#42b883',
1569
+ height: 8,
1570
+ showText: true
1571
+ }">
1572
+ Content
1573
+ </div>
1574
+
1575
+ <div v-progress="{ indeterminate: true }">
1576
+ Loading...
1577
+ </div>
1578
+ </template>
1579
+
1580
+ <script setup>
1581
+ import { ref } from 'vue'
1582
+ import { useProgress } from 'directix'
1583
+
1584
+ const progressValue = ref(50)
1585
+
1586
+ // Composable usage
1587
+ const { setProgress, start, finish, fail } = useProgress({
1588
+ color: '#42b883',
1589
+ height: 4
1590
+ })
1591
+ </script>
1592
+ ```
1593
+
1594
+ ### v-counter
1595
+
1596
+ Animated number counter.
1597
+
1598
+ ```vue
1599
+ <template>
1600
+ <span v-counter="1000">0</span>
1601
+
1602
+ <span v-counter="{
1603
+ value: 10000,
1604
+ duration: 3000,
1605
+ decimals: 2,
1606
+ useGrouping: true
1607
+ }">0</span>
1608
+
1609
+ <span v-counter="{
1610
+ value: targetValue,
1611
+ formatter: (v) => '$' + v.toFixed(2)
1612
+ }">0</span>
1613
+ </template>
1614
+
1615
+ <script setup>
1616
+ import { ref } from 'vue'
1617
+ import { useCounter } from 'directix'
1618
+
1619
+ const targetValue = ref(1000)
1620
+
1621
+ // Composable usage
1622
+ const { start, pause, reset, update } = useCounter({
1623
+ startValue: 0,
1624
+ endValue: 1000,
1625
+ duration: 2000,
1626
+ formatter: (v) => `$${v.toFixed(2)}`
1627
+ })
1628
+ </script>
1629
+ ```
1630
+
1631
+ ### v-click-wave
1632
+
1633
+ Click wave effect.
1634
+
1635
+ ```vue
1636
+ <template>
1637
+ <button v-click-wave>Click me</button>
1638
+ <button v-click-wave="'rgba(255, 255, 255, 0.3)'">Custom color</button>
1639
+ <button v-click-wave="{ color: 'red', duration: 400 }">Custom options</button>
1640
+ </template>
1641
+
1642
+ <script setup>
1643
+ import { ref } from 'vue'
1644
+ import { useClickWave } from 'directix'
1645
+
1646
+ // Composable usage
1647
+ const buttonRef = ref(null)
1648
+ const { bind, trigger } = useClickWave({
1649
+ color: 'currentColor',
1650
+ duration: 500
1651
+ })
1652
+
1653
+ // Bind to element on mount
1654
+ onMounted(() => bind(buttonRef.value))
1655
+ </script>
1656
+ ```
1657
+
1658
+ ### v-pan
1659
+
1660
+ Pan/drag gesture.
1661
+
1662
+ ```vue
1663
+ <template>
1664
+ <div v-pan="handlePan">Swipe me</div>
1665
+
1666
+ <div v-pan="{
1667
+ onPan: handlePan,
1668
+ direction: 'horizontal',
1669
+ threshold: 20
1670
+ }">
1671
+ Horizontal only
1672
+ </div>
1673
+ </template>
1674
+
1675
+ <script setup>
1676
+ import { usePan } from 'directix'
1677
+
1678
+ function handlePan(e) {
1679
+ console.log('Direction:', e.direction)
1680
+ console.log('Distance:', e.distance)
1681
+ }
1682
+
1683
+ // Composable usage
1684
+ const { isPanning, deltaX, deltaY } = usePan({
1685
+ onPan: handlePan,
1686
+ direction: 'horizontal'
1687
+ })
1688
+ </script>
1689
+ ```
1690
+
1691
+ ### v-pinch
1692
+
1693
+ Pinch/zoom gesture.
1694
+
1695
+ ```vue
1696
+ <template>
1697
+ <div v-pinch="handlePinch">Pinch to zoom</div>
1698
+
1699
+ <div v-pinch="{
1700
+ onPinch: handlePinch,
1701
+ enableTransform: true,
1702
+ minScale: 0.5,
1703
+ maxScale: 3
1704
+ }">
1705
+ Pinch to scale
1706
+ </div>
1707
+ </template>
1708
+
1709
+ <script setup>
1710
+ import { usePinch } from 'directix'
1711
+
1712
+ function handlePinch(e) {
1713
+ console.log('Scale:', e.scale)
1714
+ console.log('Center:', e.centerX, e.centerY)
1715
+ }
1716
+
1717
+ // Composable usage
1718
+ const { scale, isPinching } = usePinch({
1719
+ onPinch: handlePinch,
1720
+ minScale: 0.5,
1721
+ maxScale: 3
1722
+ })
1723
+ </script>
1724
+ ```
1725
+
1726
+ ### v-rotate-gesture
1727
+
1728
+ Rotation gesture.
1729
+
1730
+ ```vue
1731
+ <template>
1732
+ <div v-rotate-gesture="handleRotate">Rotate with two fingers</div>
1733
+
1734
+ <div v-rotate-gesture="{
1735
+ onRotate: handleRotate,
1736
+ enableTransform: true
1737
+ }">
1738
+ Rotate with transform
1739
+ </div>
1740
+ </template>
1741
+
1742
+ <script setup>
1743
+ import { useRotateGesture } from 'directix'
1744
+
1745
+ function handleRotate(e) {
1746
+ console.log('Rotation:', e.rotation)
1747
+ console.log('Angle:', e.angle)
1748
+ }
1749
+
1750
+ // Composable usage
1751
+ const { angle, isRotating } = useRotateGesture({
1752
+ onRotate: handleRotate,
1753
+ enableTransform: true
1754
+ })
1755
+ </script>
852
1756
  ```
853
1757
 
854
1758
  ## API Reference