directix 1.4.0 → 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 +853 -8
- package/dist/index.cjs +6024 -511
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2587 -110
- package/dist/index.iife.js +6006 -513
- package/dist/index.iife.js.map +1 -1
- package/dist/index.iife.min.js +2 -2
- package/dist/index.mjs +6007 -514
- 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
|
|
@@ -18,15 +18,16 @@ A comprehensive, easy-to-use, and high-performance Vue custom directives library
|
|
|
18
18
|
- 📦 **Multiple Formats** - ESM, CJS, and IIFE (CDN) formats available
|
|
19
19
|
- ⚡ **Zero Dependencies** - Lightweight with minimal bundle size
|
|
20
20
|
- 🎨 **Composables** - Every directive has a corresponding composable for Composition API
|
|
21
|
+
- 🔧 **Utility Exports** - Export `configurePermission`, `getPermissionConfig` and other utilities for advanced usage
|
|
21
22
|
|
|
22
23
|
## Online Demo
|
|
23
24
|
|
|
24
|
-
Try it online with StackBlitz:
|
|
25
|
+
Try it online with StackBlitz or CodeSandbox:
|
|
25
26
|
|
|
26
|
-
| Demo |
|
|
27
|
-
|
|
28
|
-
| Vue 3 | [](https://stackblitz.com/github/saqqdy/directix/tree/master/examples/vue3) |
|
|
29
|
-
| 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) |
|
|
30
31
|
|
|
31
32
|
## Installation
|
|
32
33
|
|
|
@@ -213,6 +214,38 @@ See the [Composables](#composables) section below for all available composables.
|
|
|
213
214
|
| `v-countdown` | Countdown timer display | ✅ |
|
|
214
215
|
| `v-print` | Print element content | ❌ |
|
|
215
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 | ❌ |
|
|
216
249
|
|
|
217
250
|
> ✅ = SSR compatible | ❌ = Not SSR compatible
|
|
218
251
|
|
|
@@ -289,6 +322,23 @@ Every directive has a corresponding composable function for use with the Composi
|
|
|
289
322
|
| `useCountdown` | Countdown timer |
|
|
290
323
|
| `usePrint` | Print content |
|
|
291
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 |
|
|
292
342
|
|
|
293
343
|
### Composable Usage Example
|
|
294
344
|
|
|
@@ -342,12 +392,19 @@ Detect clicks outside an element, useful for closing dropdowns, modals, etc.
|
|
|
342
392
|
|
|
343
393
|
<script setup>
|
|
344
394
|
import { ref } from 'vue'
|
|
395
|
+
import { useClickOutside } from 'directix'
|
|
345
396
|
|
|
346
397
|
const show = ref(false)
|
|
347
398
|
|
|
348
399
|
function closeDropdown() {
|
|
349
400
|
show.value = false
|
|
350
401
|
}
|
|
402
|
+
|
|
403
|
+
// Composable usage
|
|
404
|
+
const containerRef = ref()
|
|
405
|
+
useClickOutside(containerRef, () => {
|
|
406
|
+
show.value = false
|
|
407
|
+
})
|
|
351
408
|
</script>
|
|
352
409
|
```
|
|
353
410
|
|
|
@@ -367,6 +424,9 @@ Copy text to clipboard with a simple directive.
|
|
|
367
424
|
</template>
|
|
368
425
|
|
|
369
426
|
<script setup>
|
|
427
|
+
import { ref } from 'vue'
|
|
428
|
+
import { useCopy } from 'directix'
|
|
429
|
+
|
|
370
430
|
const textToCopy = 'Hello, World!'
|
|
371
431
|
|
|
372
432
|
function handleSuccess(text) {
|
|
@@ -376,6 +436,10 @@ function handleSuccess(text) {
|
|
|
376
436
|
function handleError(error) {
|
|
377
437
|
console.error('Copy failed:', error)
|
|
378
438
|
}
|
|
439
|
+
|
|
440
|
+
// Composable usage
|
|
441
|
+
const sourceText = ref('Hello World')
|
|
442
|
+
const { copy, copied } = useCopy({ source: sourceText })
|
|
379
443
|
</script>
|
|
380
444
|
```
|
|
381
445
|
|
|
@@ -396,9 +460,17 @@ Debounce event handlers to limit execution frequency.
|
|
|
396
460
|
</template>
|
|
397
461
|
|
|
398
462
|
<script setup>
|
|
463
|
+
import { useDebounce } from 'directix'
|
|
464
|
+
|
|
399
465
|
function handleInput(event) {
|
|
400
466
|
console.log('Debounced input:', event.target.value)
|
|
401
467
|
}
|
|
468
|
+
|
|
469
|
+
// Composable usage
|
|
470
|
+
const { run: debouncedSearch, cancel } = useDebounce({
|
|
471
|
+
handler: (query) => fetchResults(query),
|
|
472
|
+
wait: 500
|
|
473
|
+
})
|
|
402
474
|
</script>
|
|
403
475
|
```
|
|
404
476
|
|
|
@@ -421,9 +493,17 @@ Throttle event handlers to limit execution frequency.
|
|
|
421
493
|
</template>
|
|
422
494
|
|
|
423
495
|
<script setup>
|
|
496
|
+
import { useThrottle } from 'directix'
|
|
497
|
+
|
|
424
498
|
function handleClick() {
|
|
425
499
|
console.log('Throttled click')
|
|
426
500
|
}
|
|
501
|
+
|
|
502
|
+
// Composable usage
|
|
503
|
+
const { run: throttledScroll, cancel } = useThrottle({
|
|
504
|
+
handler: (position) => updatePosition(position),
|
|
505
|
+
wait: 100
|
|
506
|
+
})
|
|
427
507
|
</script>
|
|
428
508
|
```
|
|
429
509
|
|
|
@@ -439,6 +519,13 @@ Auto focus an element when mounted.
|
|
|
439
519
|
<!-- With options -->
|
|
440
520
|
<input v-focus="{ focus: true, refocus: true }" />
|
|
441
521
|
</template>
|
|
522
|
+
|
|
523
|
+
<script setup>
|
|
524
|
+
import { useFocus } from 'directix'
|
|
525
|
+
|
|
526
|
+
// Composable usage
|
|
527
|
+
const { focus, blur, hasFocus } = useFocus()
|
|
528
|
+
</script>
|
|
442
529
|
```
|
|
443
530
|
|
|
444
531
|
### v-permission
|
|
@@ -465,7 +552,7 @@ Control element visibility based on user permissions.
|
|
|
465
552
|
</template>
|
|
466
553
|
|
|
467
554
|
<script setup>
|
|
468
|
-
import { configurePermission } from 'directix'
|
|
555
|
+
import { configurePermission, usePermission } from 'directix'
|
|
469
556
|
|
|
470
557
|
configurePermission({
|
|
471
558
|
getPermissions: () => ['read', 'write'],
|
|
@@ -475,6 +562,10 @@ configurePermission({
|
|
|
475
562
|
editor: ['read', 'write', 'edit']
|
|
476
563
|
}
|
|
477
564
|
})
|
|
565
|
+
|
|
566
|
+
// Composable usage
|
|
567
|
+
const { hasPermission, hasAnyPermission, hasAllPermissions } = usePermission()
|
|
568
|
+
const canEdit = hasPermission('edit')
|
|
478
569
|
</script>
|
|
479
570
|
```
|
|
480
571
|
|
|
@@ -490,6 +581,16 @@ Lazy load images when they enter the viewport.
|
|
|
490
581
|
<!-- With placeholder and error image -->
|
|
491
582
|
<img v-lazy="{ src: imageUrl, placeholder: '/placeholder.png', error: '/error.png' }" />
|
|
492
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>
|
|
493
594
|
```
|
|
494
595
|
|
|
495
596
|
### v-mask
|
|
@@ -507,6 +608,16 @@ Input masking for formatted input.
|
|
|
507
608
|
<!-- SSN -->
|
|
508
609
|
<input v-mask="{ mask: '###-##-####', placeholder: '_' }" placeholder="SSN" />
|
|
509
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>
|
|
510
621
|
```
|
|
511
622
|
|
|
512
623
|
### v-loading
|
|
@@ -523,6 +634,19 @@ Show loading overlay on elements.
|
|
|
523
634
|
Content with locked scroll
|
|
524
635
|
</div>
|
|
525
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>
|
|
526
650
|
```
|
|
527
651
|
|
|
528
652
|
### v-sanitize
|
|
@@ -537,6 +661,16 @@ Sanitize HTML content to prevent XSS attacks.
|
|
|
537
661
|
<!-- With custom allowed tags -->
|
|
538
662
|
<div v-sanitize="{ html: userContent, allowedTags: ['b', 'i', 'u'] }"></div>
|
|
539
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>
|
|
540
674
|
```
|
|
541
675
|
|
|
542
676
|
### v-tooltip
|
|
@@ -553,6 +687,16 @@ Display tooltips on hover or click.
|
|
|
553
687
|
Click me
|
|
554
688
|
</button>
|
|
555
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>
|
|
556
700
|
```
|
|
557
701
|
|
|
558
702
|
### v-image-preview
|
|
@@ -567,6 +711,15 @@ Preview images with zoom and gesture support.
|
|
|
567
711
|
<!-- With options -->
|
|
568
712
|
<img v-image-preview="{ src: 'thumbnail.jpg', previewSrc: 'full.jpg', enablePinchZoom: true }" />
|
|
569
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>
|
|
570
723
|
```
|
|
571
724
|
|
|
572
725
|
### v-draggable
|
|
@@ -581,6 +734,16 @@ Make elements draggable.
|
|
|
581
734
|
<!-- With constraints -->
|
|
582
735
|
<div v-draggable="{ axis: 'x', bounds: 'parent' }">Horizontal drag only</div>
|
|
583
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>
|
|
584
747
|
```
|
|
585
748
|
|
|
586
749
|
### v-uppercase / v-lowercase / v-capitalcase
|
|
@@ -593,6 +756,15 @@ Transform text case.
|
|
|
593
756
|
<input v-lowercase placeholder="Auto lowercase" />
|
|
594
757
|
<input v-capitalcase placeholder="Capitalize first letter" />
|
|
595
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>
|
|
596
768
|
```
|
|
597
769
|
|
|
598
770
|
### v-truncate
|
|
@@ -607,6 +779,14 @@ Truncate text with ellipsis.
|
|
|
607
779
|
<!-- With options -->
|
|
608
780
|
<p v-truncate="{ length: 100, suffix: '...', position: 'end' }">Long text...</p>
|
|
609
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>
|
|
610
790
|
```
|
|
611
791
|
|
|
612
792
|
### v-touch
|
|
@@ -621,6 +801,8 @@ Detect touch gestures.
|
|
|
621
801
|
</template>
|
|
622
802
|
|
|
623
803
|
<script setup>
|
|
804
|
+
import { useTouch } from 'directix'
|
|
805
|
+
|
|
624
806
|
function handleSwipe(direction) {
|
|
625
807
|
console.log('Swiped:', direction) // 'left', 'right', 'up', 'down'
|
|
626
808
|
}
|
|
@@ -628,6 +810,11 @@ function handleSwipe(direction) {
|
|
|
628
810
|
function handlePinch(scale) {
|
|
629
811
|
console.log('Pinched:', scale)
|
|
630
812
|
}
|
|
813
|
+
|
|
814
|
+
// Composable usage
|
|
815
|
+
const { onSwipe, onPinch, onRotate } = useTouch({
|
|
816
|
+
onSwipe: handleSwipe
|
|
817
|
+
})
|
|
631
818
|
</script>
|
|
632
819
|
```
|
|
633
820
|
|
|
@@ -643,6 +830,13 @@ Trim input whitespace.
|
|
|
643
830
|
<!-- Trim on input -->
|
|
644
831
|
<input v-trim="{ position: 'both', event: 'input' }" />
|
|
645
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>
|
|
646
840
|
```
|
|
647
841
|
|
|
648
842
|
### v-money
|
|
@@ -653,6 +847,14 @@ Currency format input.
|
|
|
653
847
|
<template>
|
|
654
848
|
<input v-money="{ prefix: '$', precision: 2 }" placeholder="Enter amount" />
|
|
655
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>
|
|
656
858
|
```
|
|
657
859
|
|
|
658
860
|
### v-number
|
|
@@ -663,6 +865,13 @@ Number format input.
|
|
|
663
865
|
<template>
|
|
664
866
|
<input v-number="{ precision: 2, min: 0, max: 100 }" placeholder="Enter number" />
|
|
665
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>
|
|
666
875
|
```
|
|
667
876
|
|
|
668
877
|
### v-click-delay
|
|
@@ -679,9 +888,17 @@ Delay click execution to prevent double clicks.
|
|
|
679
888
|
</template>
|
|
680
889
|
|
|
681
890
|
<script setup>
|
|
891
|
+
import { useClickDelay } from 'directix'
|
|
892
|
+
|
|
682
893
|
function handleClick() {
|
|
683
894
|
console.log('Clicked (delayed)')
|
|
684
895
|
}
|
|
896
|
+
|
|
897
|
+
// Composable usage
|
|
898
|
+
const { run: delayedClick, cancel } = useClickDelay({
|
|
899
|
+
handler: handleClick,
|
|
900
|
+
delay: 300
|
|
901
|
+
})
|
|
685
902
|
</script>
|
|
686
903
|
```
|
|
687
904
|
|
|
@@ -702,6 +919,8 @@ Countdown timer display.
|
|
|
702
919
|
</template>
|
|
703
920
|
|
|
704
921
|
<script setup>
|
|
922
|
+
import { useCountdown } from 'directix'
|
|
923
|
+
|
|
705
924
|
function handleTick(remaining) {
|
|
706
925
|
console.log('Remaining:', remaining)
|
|
707
926
|
}
|
|
@@ -709,6 +928,13 @@ function handleTick(remaining) {
|
|
|
709
928
|
function handleComplete() {
|
|
710
929
|
console.log('Countdown complete!')
|
|
711
930
|
}
|
|
931
|
+
|
|
932
|
+
// Composable usage
|
|
933
|
+
const { start, pause, reset, remaining } = useCountdown({
|
|
934
|
+
time: 60,
|
|
935
|
+
onTick: handleTick,
|
|
936
|
+
onComplete: handleComplete
|
|
937
|
+
})
|
|
712
938
|
</script>
|
|
713
939
|
```
|
|
714
940
|
|
|
@@ -724,6 +950,13 @@ Text ellipsis overflow with tooltip.
|
|
|
724
950
|
<!-- With custom lines -->
|
|
725
951
|
<div v-ellipsis="{ lines: 2 }">Multi-line text with ellipsis</div>
|
|
726
952
|
</template>
|
|
953
|
+
|
|
954
|
+
<script setup>
|
|
955
|
+
import { useEllipsis } from 'directix'
|
|
956
|
+
|
|
957
|
+
// Composable usage
|
|
958
|
+
const { isEllipsisActive, checkEllipsis } = useEllipsis({ lines: 1 })
|
|
959
|
+
</script>
|
|
727
960
|
```
|
|
728
961
|
|
|
729
962
|
### v-hotkey
|
|
@@ -742,6 +975,8 @@ Keyboard shortcut binding.
|
|
|
742
975
|
</template>
|
|
743
976
|
|
|
744
977
|
<script setup>
|
|
978
|
+
import { useHotkey } from 'directix'
|
|
979
|
+
|
|
745
980
|
function handleSave() {
|
|
746
981
|
console.log('Saving...')
|
|
747
982
|
}
|
|
@@ -749,6 +984,11 @@ function handleSave() {
|
|
|
749
984
|
function handleCopy() {
|
|
750
985
|
console.log('Copying...')
|
|
751
986
|
}
|
|
987
|
+
|
|
988
|
+
// Composable usage
|
|
989
|
+
const { bind, unbind, unbindAll } = useHotkey({
|
|
990
|
+
'ctrl+s': handleSave
|
|
991
|
+
})
|
|
752
992
|
</script>
|
|
753
993
|
```
|
|
754
994
|
|
|
@@ -765,6 +1005,19 @@ Print element content.
|
|
|
765
1005
|
<!-- Print self -->
|
|
766
1006
|
<div v-print="{ self: true }">Click to print this content</div>
|
|
767
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>
|
|
768
1021
|
```
|
|
769
1022
|
|
|
770
1023
|
### v-pull-refresh
|
|
@@ -784,10 +1037,17 @@ Pull to refresh functionality.
|
|
|
784
1037
|
</template>
|
|
785
1038
|
|
|
786
1039
|
<script setup>
|
|
1040
|
+
import { usePullRefresh } from 'directix'
|
|
1041
|
+
|
|
787
1042
|
async function handleRefresh() {
|
|
788
1043
|
// Fetch new data
|
|
789
1044
|
await fetchData()
|
|
790
1045
|
}
|
|
1046
|
+
|
|
1047
|
+
// Composable usage
|
|
1048
|
+
const { isLoading, disable, enable } = usePullRefresh({
|
|
1049
|
+
handler: handleRefresh
|
|
1050
|
+
})
|
|
791
1051
|
</script>
|
|
792
1052
|
```
|
|
793
1053
|
|
|
@@ -808,9 +1068,17 @@ Swipe gesture detection with mouse support.
|
|
|
808
1068
|
</template>
|
|
809
1069
|
|
|
810
1070
|
<script setup>
|
|
1071
|
+
import { useSwipe } from 'directix'
|
|
1072
|
+
|
|
811
1073
|
function handleSwipe(direction) {
|
|
812
1074
|
console.log('Swiped:', direction) // 'left', 'right', 'up', 'down'
|
|
813
1075
|
}
|
|
1076
|
+
|
|
1077
|
+
// Composable usage
|
|
1078
|
+
const { direction, lengthX, lengthY } = useSwipe({
|
|
1079
|
+
onSwipe: handleSwipe,
|
|
1080
|
+
threshold: 50
|
|
1081
|
+
})
|
|
814
1082
|
</script>
|
|
815
1083
|
```
|
|
816
1084
|
|
|
@@ -829,6 +1097,14 @@ Virtual list for rendering large datasets efficiently.
|
|
|
829
1097
|
|
|
830
1098
|
<script setup>
|
|
831
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
|
+
)
|
|
832
1108
|
</script>
|
|
833
1109
|
```
|
|
834
1110
|
|
|
@@ -848,6 +1124,575 @@ Watermark overlay.
|
|
|
848
1124
|
Content with watermark
|
|
849
1125
|
</div>
|
|
850
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>
|
|
851
1696
|
```
|
|
852
1697
|
|
|
853
1698
|
## API Reference
|