directix 1.4.1 → 1.5.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
 
@@ -214,6 +214,38 @@ See the [Composables](#composables) section below for all available composables.
214
214
  | `v-countdown` | Countdown timer display | ✅ |
215
215
  | `v-print` | Print element content | ❌ |
216
216
  | `v-watermark` | Watermark overlay | ✅ |
217
+ | `v-skeleton` | Skeleton loading placeholder | ✅ |
218
+ | `v-progress` | Progress bar animation | ❌ |
219
+ | `v-counter` | Animated number counter | ✅ |
220
+
221
+ ### Gesture Directives
222
+
223
+ | Directive | Description | SSR |
224
+ |-----------|-------------|-----|
225
+ | `v-pan` | Pan/drag gesture | ❌ |
226
+ | `v-pinch` | Pinch/zoom gesture | ❌ |
227
+ | `v-rotate-gesture` | Rotation gesture | ❌ |
228
+
229
+ ### Visual Effect Directives
230
+
231
+ | Directive | Description | SSR |
232
+ |-----------|-------------|-----|
233
+ | `v-blur` | Background blur overlay | ❌ |
234
+ | `v-fade` | Fade in/out transition | ✅ |
235
+ | `v-parallax` | Parallax scrolling effect | ❌ |
236
+ | `v-lottie` | Lottie animation player | ❌ |
237
+ | `v-typewriter` | Typewriter animation | ✅ |
238
+ | `v-click-wave` | Click wave effect | ❌ |
239
+
240
+ ### Data Directives
241
+
242
+ | Directive | Description | SSR |
243
+ |-----------|-------------|-----|
244
+ | `v-export` | Export data (CSV/JSON/HTML) | ❌ |
245
+ | `v-highlight` | Keyword highlighting | ✅ |
246
+ | `v-emoji` | Emoji input filter | ❌ |
247
+ | `v-context-menu` | Right-click context menu | ❌ |
248
+ | `v-fullscreen` | Fullscreen toggle | ❌ |
217
249
 
218
250
  > ✅ = SSR compatible | ❌ = Not SSR compatible
219
251
 
@@ -290,6 +322,23 @@ Every directive has a corresponding composable function for use with the Composi
290
322
  | `useCountdown` | Countdown timer |
291
323
  | `usePrint` | Print content |
292
324
  | `useWatermark` | Watermark overlay |
325
+ | `useSkeleton` | Skeleton loading state |
326
+ | `useProgress` | Progress bar control |
327
+ | `useCounter` | Animated number counter |
328
+ | `usePan` | Pan gesture detection |
329
+ | `usePinch` | Pinch gesture detection |
330
+ | `useRotateGesture` | Rotation gesture detection |
331
+ | `useBlur` | Blur overlay control |
332
+ | `useFade` | Fade transition control |
333
+ | `useParallax` | Parallax scrolling |
334
+ | `useLottie` | Lottie animation control |
335
+ | `useTypewriter` | Typewriter effect |
336
+ | `useExport` | Data export utilities |
337
+ | `useHighlight` | Keyword highlighting |
338
+ | `useEmoji` | Emoji filtering |
339
+ | `useContextMenu` | Context menu control |
340
+ | `useFullscreen` | Fullscreen mode control |
341
+ | `useClickWave` | Click wave effect |
293
342
 
294
343
  ### Composable Usage Example
295
344
 
@@ -343,12 +392,19 @@ Detect clicks outside an element, useful for closing dropdowns, modals, etc.
343
392
 
344
393
  <script setup>
345
394
  import { ref } from 'vue'
395
+ import { useClickOutside } from 'directix'
346
396
 
347
397
  const show = ref(false)
348
398
 
349
399
  function closeDropdown() {
350
400
  show.value = false
351
401
  }
402
+
403
+ // Composable usage
404
+ const containerRef = ref()
405
+ useClickOutside(containerRef, () => {
406
+ show.value = false
407
+ })
352
408
  </script>
353
409
  ```
354
410
 
@@ -368,6 +424,9 @@ Copy text to clipboard with a simple directive.
368
424
  </template>
369
425
 
370
426
  <script setup>
427
+ import { ref } from 'vue'
428
+ import { useCopy } from 'directix'
429
+
371
430
  const textToCopy = 'Hello, World!'
372
431
 
373
432
  function handleSuccess(text) {
@@ -377,6 +436,10 @@ function handleSuccess(text) {
377
436
  function handleError(error) {
378
437
  console.error('Copy failed:', error)
379
438
  }
439
+
440
+ // Composable usage
441
+ const sourceText = ref('Hello World')
442
+ const { copy, copied } = useCopy({ source: sourceText })
380
443
  </script>
381
444
  ```
382
445
 
@@ -397,9 +460,17 @@ Debounce event handlers to limit execution frequency.
397
460
  </template>
398
461
 
399
462
  <script setup>
463
+ import { useDebounce } from 'directix'
464
+
400
465
  function handleInput(event) {
401
466
  console.log('Debounced input:', event.target.value)
402
467
  }
468
+
469
+ // Composable usage
470
+ const { run: debouncedSearch, cancel } = useDebounce({
471
+ handler: (query) => fetchResults(query),
472
+ wait: 500
473
+ })
403
474
  </script>
404
475
  ```
405
476
 
@@ -422,9 +493,17 @@ Throttle event handlers to limit execution frequency.
422
493
  </template>
423
494
 
424
495
  <script setup>
496
+ import { useThrottle } from 'directix'
497
+
425
498
  function handleClick() {
426
499
  console.log('Throttled click')
427
500
  }
501
+
502
+ // Composable usage
503
+ const { run: throttledScroll, cancel } = useThrottle({
504
+ handler: (position) => updatePosition(position),
505
+ wait: 100
506
+ })
428
507
  </script>
429
508
  ```
430
509
 
@@ -440,6 +519,13 @@ Auto focus an element when mounted.
440
519
  <!-- With options -->
441
520
  <input v-focus="{ focus: true, refocus: true }" />
442
521
  </template>
522
+
523
+ <script setup>
524
+ import { useFocus } from 'directix'
525
+
526
+ // Composable usage
527
+ const { focus, blur, hasFocus } = useFocus()
528
+ </script>
443
529
  ```
444
530
 
445
531
  ### v-permission
@@ -466,7 +552,7 @@ Control element visibility based on user permissions.
466
552
  </template>
467
553
 
468
554
  <script setup>
469
- import { configurePermission } from 'directix'
555
+ import { configurePermission, usePermission } from 'directix'
470
556
 
471
557
  configurePermission({
472
558
  getPermissions: () => ['read', 'write'],
@@ -476,6 +562,10 @@ configurePermission({
476
562
  editor: ['read', 'write', 'edit']
477
563
  }
478
564
  })
565
+
566
+ // Composable usage
567
+ const { hasPermission, hasAnyPermission, hasAllPermissions } = usePermission()
568
+ const canEdit = hasPermission('edit')
479
569
  </script>
480
570
  ```
481
571
 
@@ -491,6 +581,16 @@ Lazy load images when they enter the viewport.
491
581
  <!-- With placeholder and error image -->
492
582
  <img v-lazy="{ src: imageUrl, placeholder: '/placeholder.png', error: '/error.png' }" />
493
583
  </template>
584
+
585
+ <script setup>
586
+ import { useLazy } from 'directix'
587
+
588
+ // Composable usage
589
+ const { load, state, loaded } = useLazy({
590
+ src: 'image.jpg',
591
+ preload: 100
592
+ })
593
+ </script>
494
594
  ```
495
595
 
496
596
  ### v-mask
@@ -508,6 +608,16 @@ Input masking for formatted input.
508
608
  <!-- SSN -->
509
609
  <input v-mask="{ mask: '###-##-####', placeholder: '_' }" placeholder="SSN" />
510
610
  </template>
611
+
612
+ <script setup>
613
+ import { useMask } from 'directix'
614
+
615
+ // Composable usage
616
+ const { maskedValue, unmaskedValue, update } = useMask({
617
+ mask: '(###) ###-####',
618
+ value: '1234567890'
619
+ })
620
+ </script>
511
621
  ```
512
622
 
513
623
  ### v-loading
@@ -524,6 +634,19 @@ Show loading overlay on elements.
524
634
  Content with locked scroll
525
635
  </div>
526
636
  </template>
637
+
638
+ <script setup>
639
+ import { ref } from 'vue'
640
+ import { useLoading } from 'directix'
641
+
642
+ const isLoading = ref(true)
643
+
644
+ // Composable usage
645
+ const { show, hide, setText } = useLoading({
646
+ text: 'Loading...',
647
+ lock: true
648
+ })
649
+ </script>
527
650
  ```
528
651
 
529
652
  ### v-sanitize
@@ -538,6 +661,16 @@ Sanitize HTML content to prevent XSS attacks.
538
661
  <!-- With custom allowed tags -->
539
662
  <div v-sanitize="{ html: userContent, allowedTags: ['b', 'i', 'u'] }"></div>
540
663
  </template>
664
+
665
+ <script setup>
666
+ import { useSanitize } from 'directix'
667
+
668
+ // Composable usage
669
+ const { sanitize, setAllowedTags } = useSanitize({
670
+ allowedTags: ['b', 'i', 'u', 'a']
671
+ })
672
+ const cleanHtml = sanitize(dirtyHtml)
673
+ </script>
541
674
  ```
542
675
 
543
676
  ### v-tooltip
@@ -554,6 +687,16 @@ Display tooltips on hover or click.
554
687
  Click me
555
688
  </button>
556
689
  </template>
690
+
691
+ <script setup>
692
+ import { useTooltip } from 'directix'
693
+
694
+ // Composable usage
695
+ const { show, hide, updateContent, updatePosition } = useTooltip({
696
+ content: 'Tooltip content',
697
+ placement: 'top'
698
+ })
699
+ </script>
557
700
  ```
558
701
 
559
702
  ### v-image-preview
@@ -568,6 +711,15 @@ Preview images with zoom and gesture support.
568
711
  <!-- With options -->
569
712
  <img v-image-preview="{ src: 'thumbnail.jpg', previewSrc: 'full.jpg', enablePinchZoom: true }" />
570
713
  </template>
714
+
715
+ <script setup>
716
+ import { useImagePreview } from 'directix'
717
+
718
+ // Composable usage
719
+ const { open, close, zoom, rotate } = useImagePreview({
720
+ enablePinchZoom: true
721
+ })
722
+ </script>
571
723
  ```
572
724
 
573
725
  ### v-draggable
@@ -582,6 +734,16 @@ Make elements draggable.
582
734
  <!-- With constraints -->
583
735
  <div v-draggable="{ axis: 'x', bounds: 'parent' }">Horizontal drag only</div>
584
736
  </template>
737
+
738
+ <script setup>
739
+ import { useDraggable } from 'directix'
740
+
741
+ // Composable usage
742
+ const { position, isDragging, reset } = useDraggable({
743
+ axis: 'x',
744
+ bounds: 'parent'
745
+ })
746
+ </script>
585
747
  ```
586
748
 
587
749
  ### v-uppercase / v-lowercase / v-capitalcase
@@ -594,6 +756,15 @@ Transform text case.
594
756
  <input v-lowercase placeholder="Auto lowercase" />
595
757
  <input v-capitalcase placeholder="Capitalize first letter" />
596
758
  </template>
759
+
760
+ <script setup>
761
+ import { useUppercase, useLowercase, useCapitalcase } from 'directix'
762
+
763
+ // Composable usage
764
+ const { transform: toUppercase } = useUppercase()
765
+ const { transform: toLowercase } = useLowercase()
766
+ const { transform: toCapitalcase } = useCapitalcase()
767
+ </script>
597
768
  ```
598
769
 
599
770
  ### v-truncate
@@ -608,6 +779,14 @@ Truncate text with ellipsis.
608
779
  <!-- With options -->
609
780
  <p v-truncate="{ length: 100, suffix: '...', position: 'end' }">Long text...</p>
610
781
  </template>
782
+
783
+ <script setup>
784
+ import { useTruncate } from 'directix'
785
+
786
+ // Composable usage
787
+ const { truncate } = useTruncate({ length: 100, suffix: '...' })
788
+ const shortText = truncate(longText)
789
+ </script>
611
790
  ```
612
791
 
613
792
  ### v-touch
@@ -622,6 +801,8 @@ Detect touch gestures.
622
801
  </template>
623
802
 
624
803
  <script setup>
804
+ import { useTouch } from 'directix'
805
+
625
806
  function handleSwipe(direction) {
626
807
  console.log('Swiped:', direction) // 'left', 'right', 'up', 'down'
627
808
  }
@@ -629,6 +810,11 @@ function handleSwipe(direction) {
629
810
  function handlePinch(scale) {
630
811
  console.log('Pinched:', scale)
631
812
  }
813
+
814
+ // Composable usage
815
+ const { onSwipe, onPinch, onRotate } = useTouch({
816
+ onSwipe: handleSwipe
817
+ })
632
818
  </script>
633
819
  ```
634
820
 
@@ -644,6 +830,13 @@ Trim input whitespace.
644
830
  <!-- Trim on input -->
645
831
  <input v-trim="{ position: 'both', event: 'input' }" />
646
832
  </template>
833
+
834
+ <script setup>
835
+ import { useTrim } from 'directix'
836
+
837
+ // Composable usage
838
+ const { trim, trimLeft, trimRight } = useTrim({ position: 'both' })
839
+ </script>
647
840
  ```
648
841
 
649
842
  ### v-money
@@ -654,6 +847,14 @@ Currency format input.
654
847
  <template>
655
848
  <input v-money="{ prefix: '$', precision: 2 }" placeholder="Enter amount" />
656
849
  </template>
850
+
851
+ <script setup>
852
+ import { useMoney } from 'directix'
853
+
854
+ // Composable usage
855
+ const { format, parse } = useMoney({ prefix: '$', precision: 2 })
856
+ const formatted = format(1234.56) // "$1,234.56"
857
+ </script>
657
858
  ```
658
859
 
659
860
  ### v-number
@@ -664,6 +865,13 @@ Number format input.
664
865
  <template>
665
866
  <input v-number="{ precision: 2, min: 0, max: 100 }" placeholder="Enter number" />
666
867
  </template>
868
+
869
+ <script setup>
870
+ import { useNumber } from 'directix'
871
+
872
+ // Composable usage
873
+ const { format, parse } = useNumber({ precision: 2, min: 0, max: 100 })
874
+ </script>
667
875
  ```
668
876
 
669
877
  ### v-click-delay
@@ -680,9 +888,17 @@ Delay click execution to prevent double clicks.
680
888
  </template>
681
889
 
682
890
  <script setup>
891
+ import { useClickDelay } from 'directix'
892
+
683
893
  function handleClick() {
684
894
  console.log('Clicked (delayed)')
685
895
  }
896
+
897
+ // Composable usage
898
+ const { run: delayedClick, cancel } = useClickDelay({
899
+ handler: handleClick,
900
+ delay: 300
901
+ })
686
902
  </script>
687
903
  ```
688
904
 
@@ -703,6 +919,8 @@ Countdown timer display.
703
919
  </template>
704
920
 
705
921
  <script setup>
922
+ import { useCountdown } from 'directix'
923
+
706
924
  function handleTick(remaining) {
707
925
  console.log('Remaining:', remaining)
708
926
  }
@@ -710,6 +928,13 @@ function handleTick(remaining) {
710
928
  function handleComplete() {
711
929
  console.log('Countdown complete!')
712
930
  }
931
+
932
+ // Composable usage
933
+ const { start, pause, reset, remaining } = useCountdown({
934
+ time: 60,
935
+ onTick: handleTick,
936
+ onComplete: handleComplete
937
+ })
713
938
  </script>
714
939
  ```
715
940
 
@@ -725,6 +950,13 @@ Text ellipsis overflow with tooltip.
725
950
  <!-- With custom lines -->
726
951
  <div v-ellipsis="{ lines: 2 }">Multi-line text with ellipsis</div>
727
952
  </template>
953
+
954
+ <script setup>
955
+ import { useEllipsis } from 'directix'
956
+
957
+ // Composable usage
958
+ const { isEllipsisActive, checkEllipsis } = useEllipsis({ lines: 1 })
959
+ </script>
728
960
  ```
729
961
 
730
962
  ### v-hotkey
@@ -743,6 +975,8 @@ Keyboard shortcut binding.
743
975
  </template>
744
976
 
745
977
  <script setup>
978
+ import { useHotkey } from 'directix'
979
+
746
980
  function handleSave() {
747
981
  console.log('Saving...')
748
982
  }
@@ -750,6 +984,11 @@ function handleSave() {
750
984
  function handleCopy() {
751
985
  console.log('Copying...')
752
986
  }
987
+
988
+ // Composable usage
989
+ const { bind, unbind, unbindAll } = useHotkey({
990
+ 'ctrl+s': handleSave
991
+ })
753
992
  </script>
754
993
  ```
755
994
 
@@ -766,6 +1005,19 @@ Print element content.
766
1005
  <!-- Print self -->
767
1006
  <div v-print="{ self: true }">Click to print this content</div>
768
1007
  </template>
1008
+
1009
+ <script setup>
1010
+ import { ref } from 'vue'
1011
+ import { usePrint } from 'directix'
1012
+
1013
+ const printRef = ref()
1014
+
1015
+ // Composable usage
1016
+ const { print, printElement } = usePrint({
1017
+ onBefore: () => console.log('Printing...'),
1018
+ onComplete: () => console.log('Printed!')
1019
+ })
1020
+ </script>
769
1021
  ```
770
1022
 
771
1023
  ### v-pull-refresh
@@ -785,10 +1037,17 @@ Pull to refresh functionality.
785
1037
  </template>
786
1038
 
787
1039
  <script setup>
1040
+ import { usePullRefresh } from 'directix'
1041
+
788
1042
  async function handleRefresh() {
789
1043
  // Fetch new data
790
1044
  await fetchData()
791
1045
  }
1046
+
1047
+ // Composable usage
1048
+ const { isLoading, disable, enable } = usePullRefresh({
1049
+ handler: handleRefresh
1050
+ })
792
1051
  </script>
793
1052
  ```
794
1053
 
@@ -809,9 +1068,17 @@ Swipe gesture detection with mouse support.
809
1068
  </template>
810
1069
 
811
1070
  <script setup>
1071
+ import { useSwipe } from 'directix'
1072
+
812
1073
  function handleSwipe(direction) {
813
1074
  console.log('Swiped:', direction) // 'left', 'right', 'up', 'down'
814
1075
  }
1076
+
1077
+ // Composable usage
1078
+ const { direction, lengthX, lengthY } = useSwipe({
1079
+ onSwipe: handleSwipe,
1080
+ threshold: 50
1081
+ })
815
1082
  </script>
816
1083
  ```
817
1084
 
@@ -830,6 +1097,14 @@ Virtual list for rendering large datasets efficiently.
830
1097
 
831
1098
  <script setup>
832
1099
  const list = Array.from({ length: 10000 }, (_, i) => ({ id: i, name: `Item ${i}` }))
1100
+
1101
+ import { useVirtualList } from 'directix'
1102
+
1103
+ // Composable usage
1104
+ const { list, containerProps, wrapperProps, scrollTo } = useVirtualList(
1105
+ largeList,
1106
+ { itemHeight: 50 }
1107
+ )
833
1108
  </script>
834
1109
  ```
835
1110
 
@@ -849,6 +1124,575 @@ Watermark overlay.
849
1124
  Content with watermark
850
1125
  </div>
851
1126
  </template>
1127
+
1128
+ <script setup>
1129
+ import { useWatermark } from 'directix'
1130
+
1131
+ // Composable usage
1132
+ const { show, hide, update } = useWatermark({
1133
+ content: 'Confidential',
1134
+ fontSize: 16,
1135
+ color: '#ccc'
1136
+ })
1137
+ </script>
1138
+ ```
1139
+
1140
+ ### v-blur
1141
+
1142
+ Background blur overlay effect.
1143
+
1144
+ ```vue
1145
+ <template>
1146
+ <!-- Simple blur -->
1147
+ <div v-blur="isBlurred">Content behind blur</div>
1148
+
1149
+ <!-- With radius -->
1150
+ <div v-blur="15">Blur with 15px radius</div>
1151
+
1152
+ <!-- With options -->
1153
+ <div v-blur="{
1154
+ visible: isBlurred,
1155
+ radius: 20,
1156
+ overlayColor: 'rgba(255, 255, 255, 0.3)',
1157
+ lockScroll: true
1158
+ }">
1159
+ Content
1160
+ </div>
1161
+ </template>
1162
+
1163
+ <script setup>
1164
+ import { ref } from 'vue'
1165
+ import { useBlur } from 'directix'
1166
+
1167
+ const isBlurred = ref(false)
1168
+
1169
+ // Composable usage
1170
+ const { show, hide, toggle } = useBlur({
1171
+ radius: 10,
1172
+ overlayColor: 'rgba(0, 0, 0, 0.5)'
1173
+ })
1174
+ </script>
1175
+ ```
1176
+
1177
+ ### v-fade
1178
+
1179
+ Fade in/out transition effect.
1180
+
1181
+ ```vue
1182
+ <template>
1183
+ <!-- Toggle visibility with fade -->
1184
+ <div v-fade="isVisible">Fade content</div>
1185
+
1186
+ <!-- Fade in only -->
1187
+ <div v-fade="'in'">Fade in</div>
1188
+
1189
+ <!-- With options -->
1190
+ <div v-fade="{
1191
+ visible: isVisible,
1192
+ duration: 500,
1193
+ easing: 'ease-in-out',
1194
+ onComplete: () => console.log('Fade complete')
1195
+ }">
1196
+ Content
1197
+ </div>
1198
+ </template>
1199
+
1200
+ <script setup>
1201
+ import { ref } from 'vue'
1202
+ import { useFade } from 'directix'
1203
+
1204
+ const isVisible = ref(true)
1205
+
1206
+ // Composable usage
1207
+ const { fadeIn, fadeOut, toggle } = useFade({
1208
+ duration: 300,
1209
+ easing: 'ease'
1210
+ })
1211
+ </script>
1212
+ ```
1213
+
1214
+ ### v-parallax
1215
+
1216
+ Parallax scrolling effect.
1217
+
1218
+ ```vue
1219
+ <template>
1220
+ <!-- Simple parallax -->
1221
+ <div v-parallax>Parallax content</div>
1222
+
1223
+ <!-- With speed factor -->
1224
+ <div v-parallax="0.3">Slower parallax</div>
1225
+
1226
+ <!-- With options -->
1227
+ <div v-parallax="{
1228
+ speed: 0.5,
1229
+ reverse: true,
1230
+ mobileBreakpoint: 768
1231
+ }">
1232
+ Reverse parallax, disabled on mobile
1233
+ </div>
1234
+ </template>
1235
+
1236
+ <script setup>
1237
+ import { useParallax } from 'directix'
1238
+
1239
+ // Composable usage
1240
+ const { offset, progress, enabled } = useParallax({
1241
+ speed: 0.5,
1242
+ reverse: false
1243
+ })
1244
+ </script>
1245
+ ```
1246
+
1247
+ ### v-lottie
1248
+
1249
+ Lottie animation player.
1250
+
1251
+ ```vue
1252
+ <template>
1253
+ <!-- With URL -->
1254
+ <div v-lottie="'https://assets.example.com/animation.json'"></div>
1255
+
1256
+ <!-- With animation data -->
1257
+ <div v-lottie="animationData"></div>
1258
+
1259
+ <!-- With options -->
1260
+ <div v-lottie="{
1261
+ animationData: animationData,
1262
+ autoplay: true,
1263
+ loop: true,
1264
+ speed: 1.5,
1265
+ onComplete: () => console.log('Done')
1266
+ }"></div>
1267
+ </template>
1268
+
1269
+ <script setup>
1270
+ import animationData from './animation.json'
1271
+ import { useLottie } from 'directix'
1272
+
1273
+ // Composable usage
1274
+ const { play, pause, stop, setSpeed, setDirection } = useLottie({
1275
+ animationData,
1276
+ autoplay: true,
1277
+ loop: true
1278
+ })
1279
+ </script>
1280
+ ```
1281
+
1282
+ ### v-typewriter
1283
+
1284
+ Typewriter animation effect.
1285
+
1286
+ ```vue
1287
+ <template>
1288
+ <!-- Simple usage -->
1289
+ <span v-typewriter="'Hello, World!'"></span>
1290
+
1291
+ <!-- With options -->
1292
+ <span v-typewriter="{
1293
+ text: 'Typing animation',
1294
+ speed: 100,
1295
+ cursor: '_',
1296
+ onComplete: () => console.log('Done!')
1297
+ }"></span>
1298
+
1299
+ <!-- Loop mode -->
1300
+ <span v-typewriter="{
1301
+ text: 'Loop animation',
1302
+ loop: true,
1303
+ deleteDelay: 1000
1304
+ }"></span>
1305
+ </template>
1306
+
1307
+ <script setup>
1308
+ import { useTypewriter } from 'directix'
1309
+
1310
+ // Composable usage
1311
+ const { start, stop, pause, resume } = useTypewriter({
1312
+ text: 'Hello World',
1313
+ speed: 50,
1314
+ loop: false
1315
+ })
1316
+ </script>
1317
+ ```
1318
+
1319
+ ### v-export
1320
+
1321
+ Export data (CSV/JSON/HTML/TXT).
1322
+
1323
+ ```vue
1324
+ <template>
1325
+ <button v-export="exportData">Export CSV</button>
1326
+
1327
+ <button v-export="{ data: tableData, format: 'json', filename: 'my-data' }">
1328
+ Export JSON
1329
+ </button>
1330
+
1331
+ <button v-export="{
1332
+ data: tableData,
1333
+ format: 'csv',
1334
+ columns: ['name', 'email'],
1335
+ headers: { name: 'Name', email: 'Email Address' }
1336
+ }">
1337
+ Export with custom columns
1338
+ </button>
1339
+ </template>
1340
+
1341
+ <script setup>
1342
+ const tableData = [
1343
+ { name: 'John', email: 'john@example.com', age: 30 },
1344
+ { name: 'Jane', email: 'jane@example.com', age: 25 }
1345
+ ]
1346
+
1347
+ import { useExport } from 'directix'
1348
+
1349
+ // Composable usage
1350
+ const { exportCSV, exportJSON, exportHTML } = useExport()
1351
+ </script>
1352
+ ```
1353
+
1354
+ ### v-highlight
1355
+
1356
+ Keyword highlighting.
1357
+
1358
+ ```vue
1359
+ <template>
1360
+ <p v-highlight="'important'">This is an important message.</p>
1361
+
1362
+ <p v-highlight="['Vue', 'React']">Vue and React are popular frameworks.</p>
1363
+
1364
+ <p v-highlight="{
1365
+ keywords: 'highlight',
1366
+ className: 'my-highlight',
1367
+ style: 'background: yellow; color: black;',
1368
+ caseSensitive: true
1369
+ }">
1370
+ This will highlight the word.
1371
+ </p>
1372
+ </template>
1373
+
1374
+ <script setup>
1375
+ import { useHighlight } from 'directix'
1376
+
1377
+ // Composable usage
1378
+ const { highlight, clear } = useHighlight({
1379
+ keywords: ['important', 'key'],
1380
+ className: 'highlight'
1381
+ })
1382
+ </script>
1383
+ ```
1384
+
1385
+ ### v-emoji
1386
+
1387
+ Emoji input filter.
1388
+
1389
+ ```vue
1390
+ <template>
1391
+ <!-- Strip all emojis -->
1392
+ <input v-emoji type="text" />
1393
+
1394
+ <!-- Strip emojis with replacement -->
1395
+ <input v-emoji="{ strip: true, replacement: '*' }" type="text" />
1396
+
1397
+ <!-- Allow specific emojis -->
1398
+ <input v-emoji="{ allowList: ['😊', '👍'] }" type="text" />
1399
+
1400
+ <!-- Block specific emojis -->
1401
+ <input v-emoji="{ blockList: ['🚫', '❌'] }" type="text" />
1402
+ </template>
1403
+
1404
+ <script setup>
1405
+ import { useEmoji } from 'directix'
1406
+
1407
+ // Composable usage
1408
+ const { stripEmojis, containsEmoji } = useEmoji({
1409
+ strip: true,
1410
+ allowList: ['😊', '👍']
1411
+ })
1412
+ </script>
1413
+ ```
1414
+
1415
+ ### v-context-menu
1416
+
1417
+ Right-click context menu.
1418
+
1419
+ ```vue
1420
+ <template>
1421
+ <div v-context-menu="menuItems">Right click here</div>
1422
+ <div v-context-menu="{ items: menuItems, width: 200 }">Custom width</div>
1423
+ </template>
1424
+
1425
+ <script setup>
1426
+ import { useContextMenu } from 'directix'
1427
+
1428
+ const menuItems = [
1429
+ { label: 'Copy', handler: () => console.log('Copy') },
1430
+ { label: 'Paste', handler: () => console.log('Paste') },
1431
+ { divider: true, label: '' },
1432
+ { label: 'Delete', handler: () => console.log('Delete') }
1433
+ ]
1434
+
1435
+ // Composable usage
1436
+ const { show, hide, setItems } = useContextMenu({
1437
+ items: menuItems
1438
+ })
1439
+ </script>
1440
+ ```
1441
+
1442
+ ### v-fullscreen
1443
+
1444
+ Fullscreen toggle.
1445
+
1446
+ ```vue
1447
+ <template>
1448
+ <div v-fullscreen>
1449
+ Content to show in fullscreen
1450
+ <button @click="$el.toggleFullscreen()">Toggle</button>
1451
+ </div>
1452
+
1453
+ <div v-fullscreen="{ fullscreenClass: 'my-fullscreen' }">
1454
+ Custom fullscreen class
1455
+ </div>
1456
+ </template>
1457
+
1458
+ <script setup>
1459
+ import { useFullscreen } from 'directix'
1460
+
1461
+ // Composable usage
1462
+ const { isFullscreen, enter, exit, toggle } = useFullscreen({
1463
+ onEnter: () => console.log('Entered fullscreen'),
1464
+ onExit: () => console.log('Exited fullscreen')
1465
+ })
1466
+ </script>
1467
+ ```
1468
+
1469
+ ### v-skeleton
1470
+
1471
+ Skeleton loading placeholder.
1472
+
1473
+ ```vue
1474
+ <template>
1475
+ <!-- Basic usage -->
1476
+ <div v-skeleton="isLoading">Content here</div>
1477
+
1478
+ <!-- With options -->
1479
+ <div v-skeleton="{ loading: isLoading, animation: 'pulse', width: 200, height: 20 }">
1480
+ Content here
1481
+ </div>
1482
+ </template>
1483
+
1484
+ <script setup>
1485
+ import { ref } from 'vue'
1486
+ import { useSkeleton } from 'directix'
1487
+
1488
+ const isLoading = ref(true)
1489
+
1490
+ // Composable usage
1491
+ const { show, hide, update } = useSkeleton({
1492
+ animation: 'wave',
1493
+ color: '#e8e8e8'
1494
+ })
1495
+ </script>
1496
+ ```
1497
+
1498
+ ### v-progress
1499
+
1500
+ Progress bar animation.
1501
+
1502
+ ```vue
1503
+ <template>
1504
+ <div v-progress="50">Progress at 50%</div>
1505
+
1506
+ <div v-progress="{
1507
+ value: progressValue,
1508
+ color: '#42b883',
1509
+ height: 8,
1510
+ showText: true
1511
+ }">
1512
+ Content
1513
+ </div>
1514
+
1515
+ <div v-progress="{ indeterminate: true }">
1516
+ Loading...
1517
+ </div>
1518
+ </template>
1519
+
1520
+ <script setup>
1521
+ import { ref } from 'vue'
1522
+ import { useProgress } from 'directix'
1523
+
1524
+ const progressValue = ref(50)
1525
+
1526
+ // Composable usage
1527
+ const { setProgress, start, finish, fail } = useProgress({
1528
+ color: '#42b883',
1529
+ height: 4
1530
+ })
1531
+ </script>
1532
+ ```
1533
+
1534
+ ### v-counter
1535
+
1536
+ Animated number counter.
1537
+
1538
+ ```vue
1539
+ <template>
1540
+ <span v-counter="1000">0</span>
1541
+
1542
+ <span v-counter="{
1543
+ value: 10000,
1544
+ duration: 3000,
1545
+ decimals: 2,
1546
+ useGrouping: true
1547
+ }">0</span>
1548
+
1549
+ <span v-counter="{
1550
+ value: targetValue,
1551
+ formatter: (v) => '$' + v.toFixed(2)
1552
+ }">0</span>
1553
+ </template>
1554
+
1555
+ <script setup>
1556
+ import { ref } from 'vue'
1557
+ import { useCounter } from 'directix'
1558
+
1559
+ const targetValue = ref(1000)
1560
+
1561
+ // Composable usage
1562
+ const { start, pause, reset, update } = useCounter({
1563
+ startValue: 0,
1564
+ endValue: 1000,
1565
+ duration: 2000,
1566
+ formatter: (v) => `$${v.toFixed(2)}`
1567
+ })
1568
+ </script>
1569
+ ```
1570
+
1571
+ ### v-click-wave
1572
+
1573
+ Click wave effect.
1574
+
1575
+ ```vue
1576
+ <template>
1577
+ <button v-click-wave>Click me</button>
1578
+ <button v-click-wave="'rgba(255, 255, 255, 0.3)'">Custom color</button>
1579
+ <button v-click-wave="{ color: 'red', duration: 400 }">Custom options</button>
1580
+ </template>
1581
+
1582
+ <script setup>
1583
+ import { ref } from 'vue'
1584
+ import { useClickWave } from 'directix'
1585
+
1586
+ // Composable usage
1587
+ const buttonRef = ref(null)
1588
+ const { bind, trigger } = useClickWave({
1589
+ color: 'currentColor',
1590
+ duration: 500
1591
+ })
1592
+
1593
+ // Bind to element on mount
1594
+ onMounted(() => bind(buttonRef.value))
1595
+ </script>
1596
+ ```
1597
+
1598
+ ### v-pan
1599
+
1600
+ Pan/drag gesture.
1601
+
1602
+ ```vue
1603
+ <template>
1604
+ <div v-pan="handlePan">Swipe me</div>
1605
+
1606
+ <div v-pan="{
1607
+ onPan: handlePan,
1608
+ direction: 'horizontal',
1609
+ threshold: 20
1610
+ }">
1611
+ Horizontal only
1612
+ </div>
1613
+ </template>
1614
+
1615
+ <script setup>
1616
+ import { usePan } from 'directix'
1617
+
1618
+ function handlePan(e) {
1619
+ console.log('Direction:', e.direction)
1620
+ console.log('Distance:', e.distance)
1621
+ }
1622
+
1623
+ // Composable usage
1624
+ const { isPanning, deltaX, deltaY } = usePan({
1625
+ onPan: handlePan,
1626
+ direction: 'horizontal'
1627
+ })
1628
+ </script>
1629
+ ```
1630
+
1631
+ ### v-pinch
1632
+
1633
+ Pinch/zoom gesture.
1634
+
1635
+ ```vue
1636
+ <template>
1637
+ <div v-pinch="handlePinch">Pinch to zoom</div>
1638
+
1639
+ <div v-pinch="{
1640
+ onPinch: handlePinch,
1641
+ enableTransform: true,
1642
+ minScale: 0.5,
1643
+ maxScale: 3
1644
+ }">
1645
+ Pinch to scale
1646
+ </div>
1647
+ </template>
1648
+
1649
+ <script setup>
1650
+ import { usePinch } from 'directix'
1651
+
1652
+ function handlePinch(e) {
1653
+ console.log('Scale:', e.scale)
1654
+ console.log('Center:', e.centerX, e.centerY)
1655
+ }
1656
+
1657
+ // Composable usage
1658
+ const { scale, isPinching } = usePinch({
1659
+ onPinch: handlePinch,
1660
+ minScale: 0.5,
1661
+ maxScale: 3
1662
+ })
1663
+ </script>
1664
+ ```
1665
+
1666
+ ### v-rotate-gesture
1667
+
1668
+ Rotation gesture.
1669
+
1670
+ ```vue
1671
+ <template>
1672
+ <div v-rotate-gesture="handleRotate">Rotate with two fingers</div>
1673
+
1674
+ <div v-rotate-gesture="{
1675
+ onRotate: handleRotate,
1676
+ enableTransform: true
1677
+ }">
1678
+ Rotate with transform
1679
+ </div>
1680
+ </template>
1681
+
1682
+ <script setup>
1683
+ import { useRotateGesture } from 'directix'
1684
+
1685
+ function handleRotate(e) {
1686
+ console.log('Rotation:', e.rotation)
1687
+ console.log('Angle:', e.angle)
1688
+ }
1689
+
1690
+ // Composable usage
1691
+ const { angle, isRotating } = useRotateGesture({
1692
+ onRotate: handleRotate,
1693
+ enableTransform: true
1694
+ })
1695
+ </script>
852
1696
  ```
853
1697
 
854
1698
  ## API Reference