@therealtinhtute/baroiplayer 1.0.4 → 1.0.5

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.
@@ -0,0 +1,131 @@
1
+ import React, { useState, useRef, useEffect, forwardRef } from 'react';
2
+ import { cn } from '../lib/utils';
3
+
4
+ interface TooltipProviderProps {
5
+ children: React.ReactNode;
6
+ delayDuration?: number;
7
+ }
8
+
9
+ const TooltipProvider: React.FC<TooltipProviderProps> = ({ children, delayDuration = 0 }) => {
10
+ return <>{children}</>;
11
+ };
12
+
13
+ interface TooltipProps {
14
+ children: React.ReactNode;
15
+ content: React.ReactNode;
16
+ delayDuration?: number;
17
+ sideOffset?: number;
18
+ }
19
+
20
+ const Tooltip: React.FC<TooltipProps> = ({ children, content, delayDuration = 0, sideOffset = 0 }) => {
21
+ const [isOpen, setIsOpen] = useState(false);
22
+ const [position, setPosition] = useState({ top: 0, left: 0 });
23
+ const triggerRef = useRef<HTMLDivElement>(null);
24
+ const timeoutRef = useRef<NodeJS.Timeout>();
25
+
26
+ const updatePosition = () => {
27
+ if (triggerRef.current) {
28
+ const rect = triggerRef.current.getBoundingClientRect();
29
+ setPosition({
30
+ top: rect.bottom + sideOffset,
31
+ left: rect.left + rect.width / 2
32
+ });
33
+ }
34
+ };
35
+
36
+ const showTooltip = () => {
37
+ if (timeoutRef.current) {
38
+ clearTimeout(timeoutRef.current);
39
+ }
40
+
41
+ if (delayDuration > 0) {
42
+ timeoutRef.current = setTimeout(() => {
43
+ setIsOpen(true);
44
+ updatePosition();
45
+ }, delayDuration);
46
+ } else {
47
+ setIsOpen(true);
48
+ updatePosition();
49
+ }
50
+ };
51
+
52
+ const hideTooltip = () => {
53
+ if (timeoutRef.current) {
54
+ clearTimeout(timeoutRef.current);
55
+ }
56
+ setIsOpen(false);
57
+ };
58
+
59
+ useEffect(() => {
60
+ if (isOpen) {
61
+ updatePosition();
62
+ window.addEventListener('scroll', updatePosition);
63
+ window.addEventListener('resize', updatePosition);
64
+
65
+ return () => {
66
+ window.removeEventListener('scroll', updatePosition);
67
+ window.removeEventListener('resize', updatePosition);
68
+ };
69
+ }
70
+ }, [isOpen]);
71
+
72
+ useEffect(() => {
73
+ return () => {
74
+ if (timeoutRef.current) {
75
+ clearTimeout(timeoutRef.current);
76
+ }
77
+ };
78
+ }, []);
79
+
80
+ return (
81
+ <TooltipProvider delayDuration={delayDuration}>
82
+ <div
83
+ ref={triggerRef}
84
+ onMouseEnter={showTooltip}
85
+ onMouseLeave={hideTooltip}
86
+ onFocus={showTooltip}
87
+ onBlur={hideTooltip}
88
+ >
89
+ {children}
90
+ </div>
91
+
92
+ {isOpen && (
93
+ <div
94
+ className={cn(
95
+ 'fixed z-50 px-3 py-2 text-sm bg-popover text-popover-foreground shadow-md rounded-md border',
96
+ 'max-w-xs break-words pointer-events-none'
97
+ )}
98
+ style={{
99
+ top: `${position.top}px`,
100
+ left: `${position.left}px`,
101
+ transform: 'translateX(-50%)'
102
+ }}
103
+ >
104
+ {content}
105
+ </div>
106
+ )}
107
+ </TooltipProvider>
108
+ );
109
+ };
110
+
111
+ interface TooltipContentProps {
112
+ children: React.ReactNode;
113
+ className?: string;
114
+ }
115
+
116
+ const TooltipContent: React.FC<TooltipContentProps> = ({ children, className }) => {
117
+ return <div className={cn('z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md', className)}>
118
+ {children}
119
+ </div>;
120
+ };
121
+
122
+ interface TooltipTriggerProps {
123
+ children: React.ReactNode;
124
+ asChild?: boolean;
125
+ }
126
+
127
+ const TooltipTrigger: React.FC<TooltipTriggerProps> = ({ children, asChild = false }) => {
128
+ return <>{children}</>;
129
+ };
130
+
131
+ export { Tooltip, TooltipContent, TooltipTrigger, TooltipProvider };
@@ -0,0 +1,125 @@
1
+ import { useState, useEffect } from 'react';
2
+
3
+ interface DeviceInfo {
4
+ isMobile: boolean;
5
+ isTablet: boolean;
6
+ isDesktop: boolean;
7
+ userAgent: string;
8
+ screenWidth: number;
9
+ screenHeight: number;
10
+ }
11
+
12
+ export function useDeviceInfo(): DeviceInfo {
13
+ const [deviceInfo, setDeviceInfo] = useState<DeviceInfo>(() => {
14
+ if (typeof window === 'undefined') {
15
+ return {
16
+ isMobile: false,
17
+ isTablet: false,
18
+ isDesktop: true,
19
+ userAgent: '',
20
+ screenWidth: 1920,
21
+ screenHeight: 1080
22
+ };
23
+ }
24
+
25
+ const userAgent = navigator.userAgent;
26
+ const screenWidth = window.innerWidth;
27
+ const screenHeight = window.innerHeight;
28
+
29
+ const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent) && screenWidth < 768;
30
+ const isTablet = /iPad|Android/i.test(userAgent) && screenWidth >= 768 && screenWidth < 1024;
31
+ const isDesktop = !isMobile && !isTablet;
32
+
33
+ return {
34
+ isMobile,
35
+ isTablet,
36
+ isDesktop,
37
+ userAgent,
38
+ screenWidth,
39
+ screenHeight
40
+ };
41
+ });
42
+
43
+ useEffect(() => {
44
+ if (typeof window === 'undefined') return;
45
+
46
+ const handleResize = () => {
47
+ const userAgent = navigator.userAgent;
48
+ const screenWidth = window.innerWidth;
49
+ const screenHeight = window.innerHeight;
50
+
51
+ const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent) && screenWidth < 768;
52
+ const isTablet = /iPad|Android/i.test(userAgent) && screenWidth >= 768 && screenWidth < 1024;
53
+ const isDesktop = !isMobile && !isTablet;
54
+
55
+ setDeviceInfo({
56
+ isMobile,
57
+ isTablet,
58
+ isDesktop,
59
+ userAgent,
60
+ screenWidth,
61
+ screenHeight
62
+ });
63
+ };
64
+
65
+ window.addEventListener('resize', handleResize);
66
+ return () => window.removeEventListener('resize', handleResize);
67
+ }, []);
68
+
69
+ return deviceInfo;
70
+ }
71
+
72
+ export function useContainerQuery(): boolean {
73
+ const [isSmall, setIsSmall] = useState(false);
74
+
75
+ useEffect(() => {
76
+ if (typeof window === 'undefined') return;
77
+
78
+ const checkSize = () => {
79
+ setIsSmall(window.innerWidth < 640);
80
+ };
81
+
82
+ checkSize();
83
+ window.addEventListener('resize', checkSize);
84
+ return () => window.removeEventListener('resize', checkSize);
85
+ }, []);
86
+
87
+ return isSmall;
88
+ }
89
+
90
+ export function useMobileOptimizations() {
91
+ const deviceInfo = useDeviceInfo();
92
+ const [isTouch, setIsTouch] = useState(false);
93
+
94
+ useEffect(() => {
95
+ setIsTouch('ontouchstart' in window || navigator.maxTouchPoints > 0);
96
+ }, []);
97
+
98
+ return {
99
+ ...deviceInfo,
100
+ isTouch,
101
+ preferReducedMotion: window.matchMedia('(prefers-reduced-motion: reduce)').matches,
102
+ prefersDarkScheme: window.matchMedia('(prefers-color-scheme: dark)').matches
103
+ };
104
+ }
105
+
106
+ export function useHapticFeedback() {
107
+ const deviceInfo = useDeviceInfo();
108
+
109
+ const triggerHaptic = (type: 'light' | 'medium' | 'heavy' = 'light') => {
110
+ if (!deviceInfo.isMobile || !('vibrate' in navigator)) return;
111
+
112
+ const patterns = {
113
+ light: [10],
114
+ medium: [20],
115
+ heavy: [50]
116
+ };
117
+
118
+ navigator.vibrate(patterns[type]);
119
+ };
120
+
121
+ return {
122
+ triggerHaptic,
123
+ supported: deviceInfo.isMobile && 'vibrate' in navigator
124
+ };
125
+ }
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import * as React from "react";
3
- import { useDeviceInfo, useHapticFeedback } from "@rp/ui/hooks/use-mobile";
3
+ import { useDeviceInfo, useHapticFeedback } from "./use-mobile";
4
4
  // Default configuration
5
5
  const defaultConfig = {
6
6
  enabledGestures: ['tap', 'double-tap', 'long-press', 'swipe-left', 'swipe-right', 'swipe-up', 'swipe-down', 'pinch-in', 'pinch-out'],