npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

hinge_devices

v0.3.0

Published

A unified posture, hinge and display model for foldable devices. Posture-first, capability-driven, and safe to add to any app.

Readme

hinge_devices — React Native

A unified posture, hinge and display model for foldable devices.

Posture-first, capability-driven, and safe to add to any app — on a device that doesn't fold, this package reports a rigid device and does nothing else.

The same name and the same model ship to npm for React Native and pub.dev for Flutter. Both implementations run the conformance vectors in spec/posture_vectors.json, so tabletop means the same thing on both.

Install

npm install hinge_devices
cd ios && pod install   # no-op: there is no iOS native module yet

New Architecture only (React Native 0.76+). The legacy bridge would double the native surface and the testing matrix for a shrinking audience.

Layout by posture

import { useCoarsePosture, CoarsePosture } from 'hinge_devices';

function App() {
  const posture = useCoarsePosture();

  switch (posture) {
    case CoarsePosture.Closed:
      return <CompactLayout />;
    case CoarsePosture.HalfOpen:
      return <TabletopLayout />;
    case CoarsePosture.Open:
      return <FullLayout />;
  }
}

Do not switch on FoldPosture directly

FoldPosture has seven values and a hierarchy. Matching one exactly is the easiest way to break your app:

// WRONG — silently drops flipClosed, so a shut Flip renders its opened layout
if (posture === FoldPosture.Closed) return <CompactLayout />;
return <FullLayout />;

A Galaxy Z Flip on its cover screen reports flipClosed, not closed. Use useCoarsePosture(), or the isClosed() / isHalfOpened() helpers. When you need the fine-grained value, match it before falling through:

const { posture } = useFoldableDevice();

if (posture === FoldPosture.Tabletop) return <TabletopLayout />;
if (posture === FoldPosture.Book) return <BookLayout />;

switch (coarsePosture(posture)) { /* ... */ }

Branch on capabilities, never on brand

const capabilities = useFoldableCapabilities();

if (capabilities?.hingeAngleSensor) { /* offer an angle-driven effect */ }
if (capabilities?.outerDisplay)     { /* offer a cover-screen mode */ }

// Capabilities this package version has no field for are still readable:
if (capability(capabilities, 'someFutureCapability')) { /* ... */ }

Hinge angle is for effects, not layout

import { useHingeAngle } from 'hinge_devices';

const angle = useHingeAngle({ enabled: true, throttleMs: 16 });

Angle updates are opt-in and reference counted, so two components can each ask for them and the first to unmount will not cut the sensor out from under the second.

Check the resolution before you build an angle effect

Nothing in Android's API says whether a hinge sensor sweeps through intermediate values or only fires at fixed positions, and no vendor documents it. It varies by device, and it decides whether a continuous effect is buildable at all.

A Galaxy Z Flip 5 reports exactly three values — 0, 90, 180 — however slowly you fold it.

const { hinge } = useFoldableDevice();

if (supportsContinuousEffects(hinge)) {
  return <AngleDrivenEffect />;
}
return <PostureDrivenLayout />;   // meaningful on every foldable

hinge.resolution is continuous, detents or unknown, sourced from a quirks table measured on real hardware. unknown is not optimistic — assuming a smooth sweep and being wrong produces an effect that visibly snaps. See doc/devices.md.

Develop without a foldable

import { setTestPosture, resetTestDevice } from 'hinge_devices/testing';
import { FoldPosture } from 'hinge_devices';

setTestPosture(FoldPosture.Tabletop);   // every posture, one call away
resetTestDevice();                      // back to live

The same override path works from a debug menu in your own app, so what a test exercises is what you can exercise by hand.

Platform support

| Platform | Posture | Angle | Notes | |---|---|---|---| | Android 11+ | ✅ | ✅ | FoldingFeature + TYPE_HINGE_ANGLE | | Android 7–10 | ✅ | ❌ | folding feature only | | iOS | — | — | reports rigid; iPhone Duo support is next |

There is no iOS native module yet, so TurboModuleRegistry.get returns null and the package reports a rigid device. That is deliberate: adding it to a cross-platform app today is safe.

Design notes

  • The platform reports facts; TypeScript derives meaning. Native code sends a folding feature, a sensor reading, window metrics. Posture derivation, normalisation and deduplication happen in TS, so the rules are identical to the Dart implementation and testable without a device.
  • The Android hardware code is shared with the Flutter package. The hinge sensor, window observer and display source live in core-android/ and are vendored into both; CI fails if the copies drift. A bug found on real hardware is fixed once.
  • A closed angle beats the folding feature; everything else is the reverse. A Flip on its cover screen still reports a feature, so a fresh closed angle wins.
  • A missing signal is null, never a default. 0 means fully closed, which is a very different claim from "we don't know".

Versioning

Major and minor are shared with the Dart package, so one version number describes one API on both frameworks; patch is independent. See VERSIONING.md.

"hinge_devices": "~0.3.0"

License

BSD-3-Clause.