Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/web-haptics/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ Show or hide the haptic feedback toggle switch.

### `WebHaptics.isSupported`

Static boolean — `true` if the device supports the Vibration API.
Static boolean — `true` if the device supports haptics (iPhone and Android). Returns `false` on iPad/iPadOS, desktop, and other non-mobile platforms.

## License

Expand Down
33 changes: 29 additions & 4 deletions packages/web-haptics/src/lib/web-haptics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,38 @@ export class WebHaptics {
this.showSwitch = options?.showSwitch ?? false;
}

static readonly isSupported: boolean =
private static readonly supportsVibrationAPI: boolean =
typeof navigator !== "undefined" && typeof navigator.vibrate === "function";

private static readonly isMobileDevice: boolean = (() => {
if (typeof navigator === "undefined") return false;
if (navigator.maxTouchPoints <= 0) return false;

if ("userAgentData" in navigator) {
return (navigator.userAgentData as { mobile: boolean }).mobile === true;
}

// Safari & Firefox fallback
const userAgent = navigator.userAgent;
if (/Android|iPhone|iPod/.test(userAgent)) return true;

return false;
})();

private static readonly needsTouchFallback = WebHaptics.isMobileDevice && !WebHaptics.supportsVibrationAPI;

static readonly isSupported: boolean = WebHaptics.isMobileDevice;

async trigger(
input: HapticInput = [{ duration: 25, intensity: 0.7 }],
options?: TriggerOptions,
): Promise<void> {

if (!WebHaptics.isSupported && !this.debug) {
console.warn(`[web-haptics] Haptics not supported on this device.`,);
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this would get too verbose for your liking. Happy to remove

return;
}

const normalized = normalizeInput(input);
if (!normalized) return;

Expand Down Expand Up @@ -186,11 +211,11 @@ export class WebHaptics {
}
}

if (WebHaptics.isSupported) {
if (WebHaptics.supportsVibrationAPI) {
navigator.vibrate(toVibratePattern(vibrations, defaultIntensity));
}

if (!WebHaptics.isSupported || this.debug) {
if (WebHaptics.needsTouchFallback || this.debug) {
this.ensureDOM();
if (!this.hapticLabel) return;

Expand Down Expand Up @@ -222,7 +247,7 @@ export class WebHaptics {

cancel(): void {
this.stopPattern();
if (WebHaptics.isSupported) {
if (WebHaptics.supportsVibrationAPI) {
navigator.vibrate(0);
}
}
Expand Down
2 changes: 1 addition & 1 deletion site/src/surfaces/docs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const methods = [
{
signature: "WebHaptics.isSupported: boolean",
description:
"Static property. Returns true if the device supports the Vibration API.",
"Static property. Returns true if the device supports haptics (iPhone and Android). Returns false on iPad, desktops, and other non-mobile platforms.",
},
];

Expand Down