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 +852 -8
- package/dist/index.cjs +4998 -618
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1629 -17
- package/dist/index.iife.js +4889 -529
- package/dist/index.iife.js.map +1 -1
- package/dist/index.iife.min.js +2 -2
- package/dist/index.mjs +4890 -530
- package/dist/index.mjs.map +1 -1
- package/package.json +65 -5
package/README.md
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/directix)
|
|
5
5
|
[](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** -
|
|
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 |
|
|
28
|
-
|
|
29
|
-
| Vue 3 | [](https://stackblitz.com/github/saqqdy/directix/tree/master/examples/vue3) |
|
|
30
|
-
| Vue 2 | [](https://stackblitz.com/github/saqqdy/directix/tree/master/examples/vue2) |
|
|
27
|
+
| Demo | StackBlitz | CodeSandbox |
|
|
28
|
+
|------|------------|-------------|
|
|
29
|
+
| Vue 3 | [](https://stackblitz.com/github/saqqdy/directix/tree/master/examples/vue3) | [](https://codesandbox.io/p/sandbox/github/saqqdy/directix/tree/master/examples/vue3) |
|
|
30
|
+
| Vue 2 | [](https://stackblitz.com/github/saqqdy/directix/tree/master/examples/vue2) | [](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
|