@bearmenu/ui 0.1.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.
Files changed (207) hide show
  1. package/dist/chunk-2CUFS5LF.js +80 -0
  2. package/dist/chunk-3GWWZKX7.js +33 -0
  3. package/dist/chunk-3VMDCCCX.js +10 -0
  4. package/dist/chunk-4AVS6CV4.js +89 -0
  5. package/dist/chunk-4JOV7FXW.js +17 -0
  6. package/dist/chunk-4KOMHDZD.js +89 -0
  7. package/dist/chunk-4UO73SKC.js +26 -0
  8. package/dist/chunk-7H54PTVH.js +116 -0
  9. package/dist/chunk-CW24PLDW.js +24 -0
  10. package/dist/chunk-EBAMCZDW.js +112 -0
  11. package/dist/chunk-ERMIA7NP.js +106 -0
  12. package/dist/chunk-ESO2EM3L.js +46 -0
  13. package/dist/chunk-EUHEIWHZ.js +32 -0
  14. package/dist/chunk-FEK5XGZW.js +8 -0
  15. package/dist/chunk-NKHH23YK.js +31 -0
  16. package/dist/chunk-R47NEOSI.js +78 -0
  17. package/dist/chunk-UXAYXRFN.js +69 -0
  18. package/dist/chunk-X6GATUI2.js +19 -0
  19. package/dist/components/accordion.d.ts +9 -0
  20. package/dist/components/accordion.js +53 -0
  21. package/dist/components/alert-dialog.d.ts +23 -0
  22. package/dist/components/alert-dialog.js +98 -0
  23. package/dist/components/alert.d.ts +11 -0
  24. package/dist/components/alert.js +52 -0
  25. package/dist/components/aspect-ratio.d.ts +6 -0
  26. package/dist/components/aspect-ratio.js +2 -0
  27. package/dist/components/avatar.d.ts +8 -0
  28. package/dist/components/avatar.js +47 -0
  29. package/dist/components/badge.d.ts +13 -0
  30. package/dist/components/badge.js +3 -0
  31. package/dist/components/breadcrumb.d.ts +14 -0
  32. package/dist/components/breadcrumb.js +96 -0
  33. package/dist/components/button.d.ts +16 -0
  34. package/dist/components/button.js +4 -0
  35. package/dist/components/calendar.d.ts +11 -0
  36. package/dist/components/calendar.js +56 -0
  37. package/dist/components/card.d.ts +13 -0
  38. package/dist/components/card.js +4 -0
  39. package/dist/components/carousel.d.ts +24 -0
  40. package/dist/components/carousel.js +198 -0
  41. package/dist/components/checkbox.d.ts +6 -0
  42. package/dist/components/checkbox.js +25 -0
  43. package/dist/components/collapsible.d.ts +8 -0
  44. package/dist/components/collapsible.js +26 -0
  45. package/dist/components/command.d.ts +84 -0
  46. package/dist/components/command.js +4 -0
  47. package/dist/components/currency-input.d.ts +17 -0
  48. package/dist/components/currency-input.js +121 -0
  49. package/dist/components/dialog.d.ts +22 -0
  50. package/dist/components/dialog.js +3 -0
  51. package/dist/components/drawer.d.ts +27 -0
  52. package/dist/components/drawer.js +85 -0
  53. package/dist/components/dropdown-menu.d.ts +28 -0
  54. package/dist/components/dropdown-menu.js +211 -0
  55. package/dist/components/empty-state.d.ts +22 -0
  56. package/dist/components/empty-state.js +81 -0
  57. package/dist/components/form.d.ts +28 -0
  58. package/dist/components/form.js +97 -0
  59. package/dist/components/haptic-button.d.ts +12 -0
  60. package/dist/components/haptic-button.js +17 -0
  61. package/dist/components/input-otp.d.ts +14 -0
  62. package/dist/components/input-otp.js +62 -0
  63. package/dist/components/input.d.ts +6 -0
  64. package/dist/components/input.js +3 -0
  65. package/dist/components/label.d.ts +8 -0
  66. package/dist/components/label.js +3 -0
  67. package/dist/components/lazy-markdown.d.ts +11 -0
  68. package/dist/components/lazy-markdown.js +13 -0
  69. package/dist/components/link-button.d.ts +30 -0
  70. package/dist/components/link-button.js +17 -0
  71. package/dist/components/markdown-renderer.d.ts +11 -0
  72. package/dist/components/markdown-renderer.js +10 -0
  73. package/dist/components/multi-select-combobox.d.ts +23 -0
  74. package/dist/components/multi-select-combobox.js +114 -0
  75. package/dist/components/pagination.d.ts +18 -0
  76. package/dist/components/pagination.js +101 -0
  77. package/dist/components/popover.d.ts +8 -0
  78. package/dist/components/popover.js +3 -0
  79. package/dist/components/progress.d.ts +6 -0
  80. package/dist/components/progress.js +30 -0
  81. package/dist/components/radio-group.d.ts +7 -0
  82. package/dist/components/radio-group.js +30 -0
  83. package/dist/components/rating.d.ts +15 -0
  84. package/dist/components/rating.js +120 -0
  85. package/dist/components/scroll-area.d.ts +7 -0
  86. package/dist/components/scroll-area.js +44 -0
  87. package/dist/components/search-bar.d.ts +17 -0
  88. package/dist/components/search-bar.js +92 -0
  89. package/dist/components/searchable-select.d.ts +22 -0
  90. package/dist/components/searchable-select.js +104 -0
  91. package/dist/components/select.d.ts +15 -0
  92. package/dist/components/select.js +129 -0
  93. package/dist/components/separator.d.ts +6 -0
  94. package/dist/components/separator.js +25 -0
  95. package/dist/components/sheet.d.ts +29 -0
  96. package/dist/components/sheet.js +96 -0
  97. package/dist/components/skeleton-card.d.ts +13 -0
  98. package/dist/components/skeleton-card.js +154 -0
  99. package/dist/components/skeleton.d.ts +6 -0
  100. package/dist/components/skeleton.js +3 -0
  101. package/dist/components/slider.d.ts +6 -0
  102. package/dist/components/slider.js +24 -0
  103. package/dist/components/sliding-panels.d.ts +19 -0
  104. package/dist/components/sliding-panels.js +75 -0
  105. package/dist/components/sonner.d.ts +6 -0
  106. package/dist/components/sonner.js +23 -0
  107. package/dist/components/sticky-container.d.ts +44 -0
  108. package/dist/components/sticky-container.js +39 -0
  109. package/dist/components/switch.d.ts +6 -0
  110. package/dist/components/switch.js +31 -0
  111. package/dist/components/table.d.ts +12 -0
  112. package/dist/components/table.js +81 -0
  113. package/dist/components/tabs.d.ts +12 -0
  114. package/dist/components/tabs.js +55 -0
  115. package/dist/components/text.d.ts +31 -0
  116. package/dist/components/text.js +3 -0
  117. package/dist/components/textarea.d.ts +6 -0
  118. package/dist/components/textarea.js +23 -0
  119. package/dist/components/toast.d.ts +18 -0
  120. package/dist/components/toast.js +3 -0
  121. package/dist/components/toaster.d.ts +5 -0
  122. package/dist/components/toaster.js +25 -0
  123. package/dist/components/toggle-group.d.ts +12 -0
  124. package/dist/components/toggle-group.js +72 -0
  125. package/dist/components/toggle.d.ts +13 -0
  126. package/dist/components/toggle.js +3 -0
  127. package/dist/components/tooltip.d.ts +9 -0
  128. package/dist/components/tooltip.js +26 -0
  129. package/dist/components/use-mobile.d.ts +3 -0
  130. package/dist/components/use-mobile.js +19 -0
  131. package/dist/components/use-toast.d.ts +42 -0
  132. package/dist/components/use-toast.js +2 -0
  133. package/dist/hooks/use-haptic.d.ts +22 -0
  134. package/dist/hooks/use-haptic.js +2 -0
  135. package/dist/hooks/use-mobile.d.ts +3 -0
  136. package/dist/hooks/use-mobile.js +19 -0
  137. package/dist/hooks/use-mounted-theme.d.ts +6 -0
  138. package/dist/hooks/use-mounted-theme.js +18 -0
  139. package/dist/hooks/use-sticky.d.ts +18 -0
  140. package/dist/hooks/use-sticky.js +2 -0
  141. package/dist/lib/utils.d.ts +5 -0
  142. package/dist/lib/utils.js +2 -0
  143. package/package.json +203 -0
  144. package/src/components/accordion.tsx +57 -0
  145. package/src/components/alert-dialog.tsx +116 -0
  146. package/src/components/alert.tsx +57 -0
  147. package/src/components/aspect-ratio.tsx +9 -0
  148. package/src/components/avatar.tsx +49 -0
  149. package/src/components/badge.tsx +38 -0
  150. package/src/components/breadcrumb.tsx +102 -0
  151. package/src/components/button.tsx +94 -0
  152. package/src/components/calendar.tsx +60 -0
  153. package/src/components/card.tsx +67 -0
  154. package/src/components/carousel.tsx +230 -0
  155. package/src/components/checkbox.tsx +27 -0
  156. package/src/components/collapsible.tsx +28 -0
  157. package/src/components/command.tsx +148 -0
  158. package/src/components/currency-input.tsx +158 -0
  159. package/src/components/dialog.tsx +103 -0
  160. package/src/components/drawer.tsx +99 -0
  161. package/src/components/dropdown-menu.tsx +228 -0
  162. package/src/components/empty-state.tsx +118 -0
  163. package/src/components/form.tsx +152 -0
  164. package/src/components/haptic-button.tsx +19 -0
  165. package/src/components/input-otp.tsx +70 -0
  166. package/src/components/input.tsx +23 -0
  167. package/src/components/label.tsx +20 -0
  168. package/src/components/lazy-markdown.tsx +20 -0
  169. package/src/components/link-button.tsx +40 -0
  170. package/src/components/markdown-renderer.tsx +20 -0
  171. package/src/components/multi-select-combobox.tsx +148 -0
  172. package/src/components/pagination.tsx +106 -0
  173. package/src/components/popover.tsx +30 -0
  174. package/src/components/progress.tsx +27 -0
  175. package/src/components/radio-group.tsx +37 -0
  176. package/src/components/rating.tsx +136 -0
  177. package/src/components/scroll-area.tsx +45 -0
  178. package/src/components/search-bar.tsx +113 -0
  179. package/src/components/searchable-select.tsx +134 -0
  180. package/src/components/select.tsx +152 -0
  181. package/src/components/separator.tsx +25 -0
  182. package/src/components/sheet.tsx +121 -0
  183. package/src/components/skeleton-card.tsx +282 -0
  184. package/src/components/skeleton.tsx +17 -0
  185. package/src/components/slider.tsx +24 -0
  186. package/src/components/sliding-panels.tsx +99 -0
  187. package/src/components/sonner.tsx +25 -0
  188. package/src/components/sticky-container.tsx +88 -0
  189. package/src/components/switch.tsx +28 -0
  190. package/src/components/table.tsx +90 -0
  191. package/src/components/tabs.tsx +72 -0
  192. package/src/components/text.test.tsx +192 -0
  193. package/src/components/text.tsx +114 -0
  194. package/src/components/textarea.tsx +22 -0
  195. package/src/components/toast.tsx +129 -0
  196. package/src/components/toaster.tsx +31 -0
  197. package/src/components/toggle-group.tsx +69 -0
  198. package/src/components/toggle.tsx +46 -0
  199. package/src/components/tooltip.tsx +29 -0
  200. package/src/components/use-mobile.tsx +19 -0
  201. package/src/components/use-toast.ts +180 -0
  202. package/src/globals.css +409 -0
  203. package/src/hooks/use-haptic.ts +118 -0
  204. package/src/hooks/use-mobile.ts +19 -0
  205. package/src/hooks/use-mounted-theme.ts +20 -0
  206. package/src/hooks/use-sticky.ts +47 -0
  207. package/src/lib/utils.ts +6 -0
@@ -0,0 +1,118 @@
1
+ "use client";
2
+
3
+ import { useEffect, useState } from "react";
4
+
5
+ type HapticStyle = "light" | "medium" | "heavy" | "success" | "warning" | "error" | "selection";
6
+
7
+ interface HapticAPI {
8
+ isSupported: boolean;
9
+ platform: "ios" | "android" | "desktop" | "unknown";
10
+ trigger: (style: HapticStyle) => void;
11
+ }
12
+
13
+ export const useHaptic = (): HapticAPI => {
14
+ const [platform, setPlatform] = useState<"ios" | "android" | "desktop" | "unknown">("unknown");
15
+ const [isSupported, setIsSupported] = useState(false);
16
+
17
+ useEffect(() => {
18
+ // Detect platform
19
+ const userAgent = navigator.userAgent.toLowerCase();
20
+ const isIOS = /iphone|ipad|ipod/.test(userAgent);
21
+ const isAndroid = /android/.test(userAgent);
22
+
23
+ if (isIOS) {
24
+ setPlatform("ios");
25
+ } else if (isAndroid) {
26
+ setPlatform("android");
27
+ } else if (/windows|mac|linux/.test(userAgent)) {
28
+ setPlatform("desktop");
29
+ }
30
+
31
+ // Check if any haptic API is available
32
+ const hasVibration = "vibrate" in navigator;
33
+ const hasTelegram = typeof window !== "undefined" && window.Telegram?.WebApp?.HapticFeedback;
34
+
35
+ setIsSupported(hasVibration || !!hasTelegram);
36
+ }, []);
37
+
38
+ const trigger = (style: HapticStyle) => {
39
+ // Try Telegram API first (works on both iOS and Android in Telegram)
40
+ if (typeof window !== "undefined" && window.Telegram?.WebApp?.HapticFeedback) {
41
+ triggerTelegramHaptic(style);
42
+ return;
43
+ }
44
+
45
+ // Fallback to Vibration API (Android, some browsers)
46
+ if ("vibrate" in navigator) {
47
+ triggerVibrationAPI(style);
48
+ return;
49
+ }
50
+
51
+ // No haptic support - silently fail
52
+ console.debug("Haptic feedback not supported on this device");
53
+ };
54
+
55
+ return { isSupported, platform, trigger };
56
+ };
57
+
58
+ // Telegram Haptic API implementation
59
+ function triggerTelegramHaptic(style: HapticStyle) {
60
+ const telegram = window.Telegram?.WebApp?.HapticFeedback;
61
+ if (!telegram) return;
62
+
63
+ switch (style) {
64
+ case "light":
65
+ telegram.impactOccurred("light");
66
+ break;
67
+ case "medium":
68
+ telegram.impactOccurred("medium");
69
+ break;
70
+ case "heavy":
71
+ telegram.impactOccurred("heavy");
72
+ break;
73
+ case "success":
74
+ telegram.notificationOccurred("success");
75
+ break;
76
+ case "warning":
77
+ telegram.notificationOccurred("warning");
78
+ break;
79
+ case "error":
80
+ telegram.notificationOccurred("error");
81
+ break;
82
+ case "selection":
83
+ telegram.selectionChanged();
84
+ break;
85
+ }
86
+ }
87
+
88
+ // Vibration API implementation (Android)
89
+ function triggerVibrationAPI(style: HapticStyle) {
90
+ if (!("vibrate" in navigator)) return;
91
+
92
+ const patterns: Record<HapticStyle, number | number[]> = {
93
+ light: 10,
94
+ medium: 20,
95
+ heavy: 50,
96
+ success: [10, 50, 10],
97
+ warning: [20, 100, 20],
98
+ error: [50, 100, 50],
99
+ selection: 5,
100
+ };
101
+
102
+ navigator.vibrate(patterns[style]);
103
+ }
104
+
105
+ // Extend Window interface for TypeScript
106
+ declare global {
107
+ interface Window {
108
+ Telegram?: {
109
+ WebApp?: {
110
+ HapticFeedback?: {
111
+ impactOccurred: (style: "light" | "medium" | "heavy") => void;
112
+ notificationOccurred: (type: "success" | "warning" | "error") => void;
113
+ selectionChanged: () => void;
114
+ };
115
+ };
116
+ };
117
+ }
118
+ }
@@ -0,0 +1,19 @@
1
+ import * as React from "react";
2
+
3
+ const MOBILE_BREAKPOINT = 768;
4
+
5
+ export function useIsMobile() {
6
+ const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);
7
+
8
+ React.useEffect(() => {
9
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
10
+ const onChange = () => {
11
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
12
+ };
13
+ mql.addEventListener("change", onChange);
14
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
15
+ return () => mql.removeEventListener("change", onChange);
16
+ }, []);
17
+
18
+ return !!isMobile;
19
+ }
@@ -0,0 +1,20 @@
1
+ import { useSyncExternalStore } from "react";
2
+ import { useTheme } from "next-themes";
3
+
4
+ // A stable no-op subscribe that never notifies — we only care about the snapshot
5
+ const subscribe = () => () => {};
6
+
7
+ // Client: always mounted
8
+ const getClientSnapshot = () => true;
9
+
10
+ // Server: never mounted
11
+ const getServerSnapshot = () => false;
12
+
13
+ export function useMountedTheme() {
14
+ const mounted = useSyncExternalStore(subscribe, getClientSnapshot, getServerSnapshot);
15
+ const { resolvedTheme } = useTheme();
16
+ return {
17
+ mounted,
18
+ isDark: mounted && resolvedTheme === "dark",
19
+ };
20
+ }
@@ -0,0 +1,47 @@
1
+ "use client";
2
+
3
+ import { useEffect, useRef, useState } from "react";
4
+
5
+ /**
6
+ * Hook to detect when a sticky element becomes "stuck"
7
+ * Uses IntersectionObserver with a sentinel element to detect sticky state
8
+ *
9
+ * @returns An object with:
10
+ * - isSticky: boolean indicating if element is currently stuck
11
+ * - ref: ref to attach to the sticky element
12
+ * - sentinelRef: ref for the sentinel element (place 1px above sticky element)
13
+ */
14
+ export function useSticky() {
15
+ const [isSticky, setIsSticky] = useState(false);
16
+ const sentinelRef = useRef<HTMLDivElement>(null);
17
+ const stickyRef = useRef<HTMLDivElement>(null);
18
+
19
+ useEffect(() => {
20
+ const sentinel = sentinelRef.current;
21
+ if (!sentinel) return;
22
+
23
+ const observer = new IntersectionObserver(
24
+ ([entry]) => {
25
+ // When sentinel is not visible (scrolled past), element is stuck
26
+ setIsSticky(!entry.isIntersecting);
27
+ },
28
+ {
29
+ threshold: [0],
30
+ // Negative top margin to detect when element reaches sticky position
31
+ rootMargin: "-1px 0px 0px 0px",
32
+ }
33
+ );
34
+
35
+ observer.observe(sentinel);
36
+
37
+ return () => {
38
+ observer.disconnect();
39
+ };
40
+ }, []);
41
+
42
+ return {
43
+ isSticky,
44
+ ref: stickyRef,
45
+ sentinelRef,
46
+ };
47
+ }
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }