@bearmenu/ui 0.8.14 → 0.8.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -48,7 +48,6 @@ import { Input } from "@bearmenu/ui/components/input";
48
48
  | Dropdown Menu | `@bearmenu/ui/components/dropdown-menu` |
49
49
  | Empty State | `@bearmenu/ui/components/empty-state` |
50
50
  | Form | `@bearmenu/ui/components/form` |
51
- | Haptic Button | `@bearmenu/ui/components/haptic-button` |
52
51
  | Input | `@bearmenu/ui/components/input` |
53
52
  | Input OTP | `@bearmenu/ui/components/input-otp` |
54
53
  | Label | `@bearmenu/ui/components/label` |
@@ -1,4 +1,4 @@
1
- import { useHaptic } from './chunk-R47NEOSI.js';
1
+ import { useHaptic } from './chunk-V4E333QS.js';
2
2
  import { cn } from './chunk-FEK5XGZW.js';
3
3
  import { __objRest, __spreadProps, __spreadValues } from './chunk-MMUBH76A.js';
4
4
  import * as React from 'react';
@@ -78,7 +78,7 @@ var Button = React.forwardRef(
78
78
  size,
79
79
  fullWidth,
80
80
  asChild = false,
81
- haptic = true,
81
+ haptic = false,
82
82
  hapticStyle = "light",
83
83
  isLoading = false,
84
84
  disabled,
@@ -1,4 +1,4 @@
1
- import { useState, useEffect } from 'react';
1
+ import { useState, useEffect, useCallback } from 'react';
2
2
 
3
3
  var useHaptic = () => {
4
4
  const [platform, setPlatform] = useState("unknown");
@@ -17,9 +17,9 @@ var useHaptic = () => {
17
17
  }
18
18
  const hasVibration = "vibrate" in navigator;
19
19
  const hasTelegram = typeof window !== "undefined" && ((_b = (_a = window.Telegram) == null ? void 0 : _a.WebApp) == null ? void 0 : _b.HapticFeedback);
20
- setIsSupported(hasVibration || !!hasTelegram);
20
+ setIsSupported(hasVibration || !!hasTelegram || supportsSwitchHaptic());
21
21
  }, []);
22
- const trigger = (style) => {
22
+ const trigger = useCallback((style) => {
23
23
  var _a, _b;
24
24
  if (typeof window !== "undefined" && ((_b = (_a = window.Telegram) == null ? void 0 : _a.WebApp) == null ? void 0 : _b.HapticFeedback)) {
25
25
  triggerTelegramHaptic(style);
@@ -29,8 +29,12 @@ var useHaptic = () => {
29
29
  triggerVibrationAPI(style);
30
30
  return;
31
31
  }
32
+ if (supportsSwitchHaptic()) {
33
+ triggerSwitchHaptic();
34
+ return;
35
+ }
32
36
  console.debug("Haptic feedback not supported on this device");
33
- };
37
+ }, []);
34
38
  return { isSupported, platform, trigger };
35
39
  };
36
40
  function triggerTelegramHaptic(style) {
@@ -74,5 +78,26 @@ function triggerVibrationAPI(style) {
74
78
  };
75
79
  navigator.vibrate(patterns[style]);
76
80
  }
81
+ var hapticSwitch = null;
82
+ function supportsSwitchHaptic() {
83
+ return typeof HTMLInputElement !== "undefined" && "switch" in HTMLInputElement.prototype;
84
+ }
85
+ function getHapticSwitch() {
86
+ if (hapticSwitch == null ? void 0 : hapticSwitch.isConnected) return hapticSwitch;
87
+ const label = document.createElement("label");
88
+ const input = document.createElement("input");
89
+ input.type = "checkbox";
90
+ input.setAttribute("switch", "");
91
+ input.tabIndex = -1;
92
+ label.setAttribute("aria-hidden", "true");
93
+ label.style.cssText = "position:fixed;top:0;left:0;width:1px;height:1px;overflow:hidden;opacity:0;pointer-events:none";
94
+ label.appendChild(input);
95
+ document.body.appendChild(label);
96
+ hapticSwitch = label;
97
+ return label;
98
+ }
99
+ function triggerSwitchHaptic() {
100
+ getHapticSwitch().click();
101
+ }
77
102
 
78
103
  export { useHaptic };
@@ -1,5 +1,5 @@
1
- import { buttonVariants } from '../chunk-F76NCVVR.js';
2
- import '../chunk-R47NEOSI.js';
1
+ import { buttonVariants } from '../chunk-5FCC5L5F.js';
2
+ import '../chunk-V4E333QS.js';
3
3
  import { cn } from '../chunk-FEK5XGZW.js';
4
4
  import { __objRest, __spreadProps, __spreadValues } from '../chunk-MMUBH76A.js';
5
5
  import * as React from 'react';
@@ -9,6 +9,10 @@ declare const buttonVariants: (props?: ({
9
9
  } & class_variance_authority_types.ClassProp) | undefined) => string;
10
10
  interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
11
11
  asChild?: boolean;
12
+ /**
13
+ * Off by default. Haptics are for actions that change state — a save, a
14
+ * toggle, a destructive confirm — not for every button, so each site opts in.
15
+ */
12
16
  haptic?: boolean;
13
17
  hapticStyle?: "light" | "medium" | "heavy";
14
18
  isLoading?: boolean;
@@ -1,4 +1,4 @@
1
- export { Button, buttonVariants } from '../chunk-F76NCVVR.js';
2
- import '../chunk-R47NEOSI.js';
1
+ export { Button, buttonVariants } from '../chunk-5FCC5L5F.js';
2
+ import '../chunk-V4E333QS.js';
3
3
  import '../chunk-FEK5XGZW.js';
4
4
  import '../chunk-MMUBH76A.js';
@@ -1,5 +1,5 @@
1
- import { buttonVariants, Button } from '../chunk-F76NCVVR.js';
2
- import '../chunk-R47NEOSI.js';
1
+ import { buttonVariants, Button } from '../chunk-5FCC5L5F.js';
2
+ import '../chunk-V4E333QS.js';
3
3
  import { cn } from '../chunk-FEK5XGZW.js';
4
4
  import { __objRest, __spreadValues, __spreadProps } from '../chunk-MMUBH76A.js';
5
5
  import * as React from 'react';
@@ -1,5 +1,5 @@
1
- import { Button } from '../chunk-F76NCVVR.js';
2
- import '../chunk-R47NEOSI.js';
1
+ import { Button } from '../chunk-5FCC5L5F.js';
2
+ import '../chunk-V4E333QS.js';
3
3
  import { cn } from '../chunk-FEK5XGZW.js';
4
4
  import { __objRest, __spreadProps, __spreadValues } from '../chunk-MMUBH76A.js';
5
5
  import * as React from 'react';
@@ -1,8 +1,8 @@
1
1
  import { Popover, PopoverTrigger, PopoverContent } from '../chunk-2ADCZXZJ.js';
2
2
  import { Command, CommandInput, CommandList, CommandLoading, CommandEmpty, CommandGroup, CommandItem } from '../chunk-MCOHLWRS.js';
3
3
  import '../chunk-PDTPO6NG.js';
4
- import { Button } from '../chunk-F76NCVVR.js';
5
- import '../chunk-R47NEOSI.js';
4
+ import { Button } from '../chunk-5FCC5L5F.js';
5
+ import '../chunk-V4E333QS.js';
6
6
  import { cn } from '../chunk-FEK5XGZW.js';
7
7
  import '../chunk-MMUBH76A.js';
8
8
  import * as React from 'react';
@@ -1,5 +1,5 @@
1
- import { Button } from '../chunk-F76NCVVR.js';
2
- import '../chunk-R47NEOSI.js';
1
+ import { Button } from '../chunk-5FCC5L5F.js';
2
+ import '../chunk-V4E333QS.js';
3
3
  import { Text } from '../chunk-ZLMRVBD7.js';
4
4
  import { cn } from '../chunk-FEK5XGZW.js';
5
5
  import { __objRest, __spreadProps, __spreadValues } from '../chunk-MMUBH76A.js';
@@ -2,8 +2,8 @@ import { resolveEventEntryFee } from '../chunk-DNSXMHYX.js';
2
2
  import { Separator } from '../chunk-NWZGSLPU.js';
3
3
  import { EventPosterFallback } from '../chunk-FDITZ2VM.js';
4
4
  import { Skeleton } from '../chunk-XBBEX4SF.js';
5
- import { Button } from '../chunk-F76NCVVR.js';
6
- import '../chunk-R47NEOSI.js';
5
+ import { Button } from '../chunk-5FCC5L5F.js';
6
+ import '../chunk-V4E333QS.js';
7
7
  import { cn } from '../chunk-FEK5XGZW.js';
8
8
  import { __spreadProps, __spreadValues, __objRest } from '../chunk-MMUBH76A.js';
9
9
  import * as React from 'react';
@@ -3,8 +3,8 @@ import { resolveEventEntryFee } from '../chunk-DNSXMHYX.js';
3
3
  import { Separator } from '../chunk-NWZGSLPU.js';
4
4
  import { EventPosterFallback } from '../chunk-FDITZ2VM.js';
5
5
  import { Skeleton } from '../chunk-XBBEX4SF.js';
6
- import { buttonVariants } from '../chunk-F76NCVVR.js';
7
- import '../chunk-R47NEOSI.js';
6
+ import { buttonVariants } from '../chunk-5FCC5L5F.js';
7
+ import '../chunk-V4E333QS.js';
8
8
  import { cn } from '../chunk-FEK5XGZW.js';
9
9
  import { __objRest, __spreadValues } from '../chunk-MMUBH76A.js';
10
10
  import { memo, useState } from 'react';
@@ -1,5 +1,5 @@
1
- import { DIMENSION_ORDER, VenueGradeDimensions } from '../chunk-ZQ53AGML.js';
2
1
  import { VenueQuotes } from '../chunk-43RC7MHY.js';
2
+ import { DIMENSION_ORDER, VenueGradeDimensions } from '../chunk-ZQ53AGML.js';
3
3
  import { StoryProvider, StorySegments, StoryPanel } from '../chunk-F6FMZJDG.js';
4
4
  import { GlassGround } from '../chunk-ICOU5QHT.js';
5
5
  import { Separator } from '../chunk-NWZGSLPU.js';
@@ -1,5 +1,5 @@
1
- import { Button } from '../chunk-F76NCVVR.js';
2
- import '../chunk-R47NEOSI.js';
1
+ import { Button } from '../chunk-5FCC5L5F.js';
2
+ import '../chunk-V4E333QS.js';
3
3
  import '../chunk-FEK5XGZW.js';
4
4
  import { __objRest, __spreadProps, __spreadValues } from '../chunk-MMUBH76A.js';
5
5
  import * as React from 'react';
@@ -3,8 +3,8 @@ import { HueChip } from '../chunk-CLLY6XB3.js';
3
3
  import { Separator } from '../chunk-NWZGSLPU.js';
4
4
  import { PhotoGround, PHOTO_GROUND } from '../chunk-CNJQUHCU.js';
5
5
  import { Skeleton } from '../chunk-XBBEX4SF.js';
6
- import { buttonVariants } from '../chunk-F76NCVVR.js';
7
- import '../chunk-R47NEOSI.js';
6
+ import { buttonVariants } from '../chunk-5FCC5L5F.js';
7
+ import '../chunk-V4E333QS.js';
8
8
  import { cn } from '../chunk-FEK5XGZW.js';
9
9
  import { __objRest, __spreadValues } from '../chunk-MMUBH76A.js';
10
10
  import { Wallet } from 'lucide-react';
@@ -1,7 +1,7 @@
1
1
  import { Separator } from '../chunk-NWZGSLPU.js';
2
2
  import { Skeleton } from '../chunk-XBBEX4SF.js';
3
- import { Button } from '../chunk-F76NCVVR.js';
4
- import '../chunk-R47NEOSI.js';
3
+ import { Button } from '../chunk-5FCC5L5F.js';
4
+ import '../chunk-V4E333QS.js';
5
5
  import { cn } from '../chunk-FEK5XGZW.js';
6
6
  import { __objRest, __spreadValues } from '../chunk-MMUBH76A.js';
7
7
  import { useState } from 'react';
@@ -2,8 +2,8 @@ import { Popover, PopoverTrigger, PopoverContent } from '../chunk-2ADCZXZJ.js';
2
2
  import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from '../chunk-MCOHLWRS.js';
3
3
  import '../chunk-PDTPO6NG.js';
4
4
  import { Checkbox } from '../chunk-NMEVJT5Q.js';
5
- import { Button } from '../chunk-F76NCVVR.js';
6
- import '../chunk-R47NEOSI.js';
5
+ import { Button } from '../chunk-5FCC5L5F.js';
6
+ import '../chunk-V4E333QS.js';
7
7
  import { Badge } from '../chunk-P43B3ONY.js';
8
8
  import { cn } from '../chunk-FEK5XGZW.js';
9
9
  import '../chunk-MMUBH76A.js';
@@ -1,5 +1,5 @@
1
- import { buttonVariants } from '../chunk-F76NCVVR.js';
2
- import '../chunk-R47NEOSI.js';
1
+ import { buttonVariants } from '../chunk-5FCC5L5F.js';
2
+ import '../chunk-V4E333QS.js';
3
3
  import { cn } from '../chunk-FEK5XGZW.js';
4
4
  import { __objRest, __spreadValues, __spreadProps } from '../chunk-MMUBH76A.js';
5
5
  import { ChevronsLeftIcon, ChevronLeftIcon, ChevronRightIcon, ChevronsRightIcon, MoreHorizontalIcon } from 'lucide-react';
@@ -1,6 +1,6 @@
1
- import { OVERLAY_PILL } from '../chunk-EZG2NELX.js';
2
1
  import { HOVER_IMAGE_MOTION, HOVER_IMAGE_WRAPPER, HOVER_MOTION, HOVER_LIFT_GRID_GROUP } from '../chunk-XCB3F6SF.js';
3
2
  import { NEUTRAL_ICON_FILTER } from '../chunk-LQWGZIYA.js';
3
+ import { OVERLAY_PILL } from '../chunk-EZG2NELX.js';
4
4
  import { GradeAtom } from '../chunk-DJD3EMPK.js';
5
5
  import { showsGradeAtom } from '../chunk-I5V446BX.js';
6
6
  import { Separator } from '../chunk-NWZGSLPU.js';
@@ -1,8 +1,8 @@
1
1
  import { Popover, PopoverTrigger, PopoverContent } from '../chunk-2ADCZXZJ.js';
2
2
  import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from '../chunk-MCOHLWRS.js';
3
3
  import '../chunk-PDTPO6NG.js';
4
- import { Button } from '../chunk-F76NCVVR.js';
5
- import '../chunk-R47NEOSI.js';
4
+ import { Button } from '../chunk-5FCC5L5F.js';
5
+ import '../chunk-V4E333QS.js';
6
6
  import { cn } from '../chunk-FEK5XGZW.js';
7
7
  import '../chunk-MMUBH76A.js';
8
8
  import * as React from 'react';
@@ -1,5 +1,5 @@
1
- import { Button } from '../chunk-F76NCVVR.js';
2
- import '../chunk-R47NEOSI.js';
1
+ import { Button } from '../chunk-5FCC5L5F.js';
2
+ import '../chunk-V4E333QS.js';
3
3
  import { cn } from '../chunk-FEK5XGZW.js';
4
4
  import '../chunk-MMUBH76A.js';
5
5
  import * as React from 'react';
@@ -1,2 +1,2 @@
1
- export { useHaptic } from '../chunk-R47NEOSI.js';
1
+ export { useHaptic } from '../chunk-V4E333QS.js';
2
2
  import '../chunk-MMUBH76A.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bearmenu/ui",
3
- "version": "0.8.14",
3
+ "version": "0.8.15",
4
4
  "description": "BearMenu design system — shared UI tokens, primitives, and components",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -79,6 +79,10 @@ const buttonVariants = cva(
79
79
  export interface ButtonProps
80
80
  extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
81
81
  asChild?: boolean;
82
+ /**
83
+ * Off by default. Haptics are for actions that change state — a save, a
84
+ * toggle, a destructive confirm — not for every button, so each site opts in.
85
+ */
82
86
  haptic?: boolean;
83
87
  hapticStyle?: "light" | "medium" | "heavy";
84
88
  isLoading?: boolean;
@@ -92,7 +96,7 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
92
96
  size,
93
97
  fullWidth,
94
98
  asChild = false,
95
- haptic = true,
99
+ haptic = false,
96
100
  hapticStyle = "light",
97
101
  isLoading = false,
98
102
  disabled,
@@ -0,0 +1,80 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { act, renderHook } from "@testing-library/react";
3
+ import { useHaptic } from "./use-haptic";
4
+
5
+ const hapticSwitch = () => document.body.querySelector<HTMLInputElement>("input[type=checkbox][switch]");
6
+
7
+ describe("useHaptic", () => {
8
+ afterEach(() => {
9
+ vi.restoreAllMocks();
10
+ });
11
+
12
+ describe("on iOS Safari (no Vibration API, switch supported)", () => {
13
+ beforeEach(() => {
14
+ Object.defineProperty(HTMLInputElement.prototype, "switch", { value: false, configurable: true });
15
+ });
16
+
17
+ afterEach(() => {
18
+ Reflect.deleteProperty(HTMLInputElement.prototype, "switch");
19
+ hapticSwitch()?.parentElement?.remove();
20
+ });
21
+
22
+ it("reports support", () => {
23
+ const { result } = renderHook(() => useHaptic());
24
+ expect(result.current.isSupported).toBe(true);
25
+ });
26
+
27
+ it("toggles one hidden switch through its label on every trigger", () => {
28
+ const { result } = renderHook(() => useHaptic());
29
+
30
+ act(() => result.current.trigger("light"));
31
+ const input = hapticSwitch();
32
+ expect(input).not.toBeNull();
33
+ expect(input?.checked).toBe(true);
34
+ expect(input?.parentElement?.getAttribute("aria-hidden")).toBe("true");
35
+
36
+ act(() => result.current.trigger("light"));
37
+ expect(document.body.querySelectorAll("input[switch]")).toHaveLength(1);
38
+ expect(input?.checked).toBe(false);
39
+ });
40
+
41
+ it("collapses every style to the one tick WebKit has", () => {
42
+ const { result } = renderHook(() => useHaptic());
43
+
44
+ act(() => result.current.trigger("heavy"));
45
+ expect(hapticSwitch()?.checked).toBe(true);
46
+ act(() => result.current.trigger("success"));
47
+ expect(hapticSwitch()?.checked).toBe(false);
48
+ });
49
+ });
50
+
51
+ describe("without any haptic API", () => {
52
+ it("reports no support and renders no switch", () => {
53
+ const debug = vi.spyOn(console, "debug").mockImplementation(() => {});
54
+ const { result } = renderHook(() => useHaptic());
55
+
56
+ expect(result.current.isSupported).toBe(false);
57
+ act(() => result.current.trigger("light"));
58
+ expect(hapticSwitch()).toBeNull();
59
+ expect(debug).toHaveBeenCalled();
60
+ });
61
+ });
62
+
63
+ describe("with the Vibration API", () => {
64
+ afterEach(() => {
65
+ Reflect.deleteProperty(navigator, "vibrate");
66
+ });
67
+
68
+ it("prefers navigator.vibrate over the switch", () => {
69
+ const vibrate = vi.fn();
70
+ Object.defineProperty(navigator, "vibrate", { value: vibrate, configurable: true });
71
+ Object.defineProperty(HTMLInputElement.prototype, "switch", { value: false, configurable: true });
72
+ const { result } = renderHook(() => useHaptic());
73
+
74
+ act(() => result.current.trigger("medium"));
75
+ expect(vibrate).toHaveBeenCalledWith(20);
76
+ expect(hapticSwitch()).toBeNull();
77
+ Reflect.deleteProperty(HTMLInputElement.prototype, "switch");
78
+ });
79
+ });
80
+ });
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { useEffect, useState } from "react";
3
+ import { useCallback, useEffect, useState } from "react";
4
4
 
5
5
  type HapticStyle = "light" | "medium" | "heavy" | "success" | "warning" | "error" | "selection";
6
6
 
@@ -32,10 +32,10 @@ export const useHaptic = (): HapticAPI => {
32
32
  const hasVibration = "vibrate" in navigator;
33
33
  const hasTelegram = typeof window !== "undefined" && window.Telegram?.WebApp?.HapticFeedback;
34
34
 
35
- setIsSupported(hasVibration || !!hasTelegram);
35
+ setIsSupported(hasVibration || !!hasTelegram || supportsSwitchHaptic());
36
36
  }, []);
37
37
 
38
- const trigger = (style: HapticStyle) => {
38
+ const trigger = useCallback((style: HapticStyle) => {
39
39
  // Try Telegram API first (works on both iOS and Android in Telegram)
40
40
  if (typeof window !== "undefined" && window.Telegram?.WebApp?.HapticFeedback) {
41
41
  triggerTelegramHaptic(style);
@@ -48,9 +48,15 @@ export const useHaptic = (): HapticAPI => {
48
48
  return;
49
49
  }
50
50
 
51
+ // iOS Safari has no Vibration API; the switch toggle is the only haptic it exposes
52
+ if (supportsSwitchHaptic()) {
53
+ triggerSwitchHaptic();
54
+ return;
55
+ }
56
+
51
57
  // No haptic support - silently fail
52
58
  console.debug("Haptic feedback not supported on this device");
53
- };
59
+ }, []);
54
60
 
55
61
  return { isSupported, platform, trigger };
56
62
  };
@@ -102,6 +108,41 @@ function triggerVibrationAPI(style: HapticStyle) {
102
108
  navigator.vibrate(patterns[style]);
103
109
  }
104
110
 
111
+ // Switch implementation (iOS 18+ Safari and home-screen PWAs)
112
+ //
113
+ // WebKit plays the system "toggle" haptic when an `<input type="checkbox" switch>`
114
+ // flips through its label, and a programmatic `label.click()` counts. One hidden
115
+ // switch appended to the body doubles as a haptic trigger. It is the only haptic
116
+ // WebKit exposes, so every style collapses to that one tick here.
117
+ // https://github.com/ionic-team/ionic-framework/issues/29942
118
+ let hapticSwitch: HTMLLabelElement | null = null;
119
+
120
+ function supportsSwitchHaptic(): boolean {
121
+ return typeof HTMLInputElement !== "undefined" && "switch" in HTMLInputElement.prototype;
122
+ }
123
+
124
+ function getHapticSwitch(): HTMLLabelElement {
125
+ if (hapticSwitch?.isConnected) return hapticSwitch;
126
+
127
+ const label = document.createElement("label");
128
+ const input = document.createElement("input");
129
+ input.type = "checkbox";
130
+ input.setAttribute("switch", "");
131
+ input.tabIndex = -1;
132
+ label.setAttribute("aria-hidden", "true");
133
+ label.style.cssText =
134
+ "position:fixed;top:0;left:0;width:1px;height:1px;overflow:hidden;opacity:0;pointer-events:none";
135
+ label.appendChild(input);
136
+ document.body.appendChild(label);
137
+
138
+ hapticSwitch = label;
139
+ return label;
140
+ }
141
+
142
+ function triggerSwitchHaptic() {
143
+ getHapticSwitch().click();
144
+ }
145
+
105
146
  // Extend Window interface for TypeScript
106
147
  declare global {
107
148
  interface Window {
@@ -1,12 +0,0 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ButtonProps } from './button.js';
3
- import 'class-variance-authority/types';
4
- import 'react';
5
- import 'class-variance-authority';
6
-
7
- interface HapticButtonProps extends ButtonProps {
8
- hapticStyle?: "light" | "medium" | "heavy";
9
- }
10
- declare function HapticButton({ hapticStyle, onClick, ...props }: HapticButtonProps): react_jsx_runtime.JSX.Element;
11
-
12
- export { HapticButton };
@@ -1,17 +0,0 @@
1
- import { Button } from '../chunk-F76NCVVR.js';
2
- import { useHaptic } from '../chunk-R47NEOSI.js';
3
- import '../chunk-FEK5XGZW.js';
4
- import { __objRest, __spreadProps, __spreadValues } from '../chunk-MMUBH76A.js';
5
- import { jsx } from 'react/jsx-runtime';
6
-
7
- function HapticButton(_a) {
8
- var _b = _a, { hapticStyle = "light", onClick } = _b, props = __objRest(_b, ["hapticStyle", "onClick"]);
9
- const { trigger } = useHaptic();
10
- const handleClick = (e) => {
11
- trigger(hapticStyle);
12
- onClick == null ? void 0 : onClick(e);
13
- };
14
- return /* @__PURE__ */ jsx(Button, __spreadProps(__spreadValues({}, props), { onClick: handleClick, haptic: false }));
15
- }
16
-
17
- export { HapticButton };
@@ -1,41 +0,0 @@
1
- import type { Meta, StoryObj } from "@storybook/react";
2
- import { HapticButton } from "./haptic-button";
3
-
4
- const meta = {
5
- title: "Components/HapticButton",
6
- component: HapticButton,
7
- tags: ["autodocs"],
8
- } satisfies Meta<typeof HapticButton>;
9
-
10
- export default meta;
11
- type Story = StoryObj<typeof meta>;
12
-
13
- export const Light: Story = {
14
- render: () => <HapticButton hapticStyle="light">Light Haptic</HapticButton>,
15
- };
16
-
17
- export const Medium: Story = {
18
- render: () => (
19
- <HapticButton hapticStyle="medium" variant="secondary">
20
- Medium Haptic
21
- </HapticButton>
22
- ),
23
- };
24
-
25
- export const Heavy: Story = {
26
- render: () => (
27
- <HapticButton hapticStyle="heavy" variant="destructive">
28
- Heavy Haptic
29
- </HapticButton>
30
- ),
31
- };
32
-
33
- export const AllStyles: Story = {
34
- render: () => (
35
- <div className="flex gap-3">
36
- <HapticButton hapticStyle="light">Light</HapticButton>
37
- <HapticButton hapticStyle="medium" variant="secondary">Medium</HapticButton>
38
- <HapticButton hapticStyle="heavy" variant="outline">Heavy</HapticButton>
39
- </div>
40
- ),
41
- };
@@ -1,19 +0,0 @@
1
- "use client";
2
-
3
- import { Button, type ButtonProps } from "./button";
4
- import { useHaptic } from "../hooks/use-haptic";
5
-
6
- interface HapticButtonProps extends ButtonProps {
7
- hapticStyle?: "light" | "medium" | "heavy";
8
- }
9
-
10
- export function HapticButton({ hapticStyle = "light", onClick, ...props }: HapticButtonProps) {
11
- const { trigger } = useHaptic();
12
-
13
- const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
14
- trigger(hapticStyle);
15
- onClick?.(e);
16
- };
17
-
18
- return <Button {...props} onClick={handleClick} haptic={false} />;
19
- }