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

@classic-homes/native

v0.1.2

Published

Native device APIs for iOS and Android using Capacitor

Readme

@classic-homes/native

Native device APIs for iOS and Android mobile apps. Uses Capacitor for native functionality with web fallbacks.

Installation

npm install @classic-homes/native

Peer Dependencies

Install the Capacitor plugins you need:

# Core (required)
npm install @capacitor/core

# Optional plugins
npm install @capacitor/camera
npm install @capacitor/geolocation
npm install @capacitor/preferences
npm install @capacitor/haptics
npm install @capacitor/device
npm install @capacitor/network
npm install @capacitor/push-notifications
npm install @capacitor/app
npm install @capgo/capacitor-native-biometric

Quick Start

Initialize

import { initNative, getPlatformInfo } from '@classic-homes/native';

// Initialize at app startup
const platform = initNative({
  debug: import.meta.env.DEV,
  geolocationDefaults: {
    enableHighAccuracy: true,
    timeout: 10000,
  },
});

console.log(platform.isNative); // true on iOS/Android
console.log(platform.platform); // 'ios', 'android', or 'web'

React Usage

import { useGeolocation, useCamera, NativeGuard } from '@classic-homes/native/react';

function LocationTracker() {
  const { position, isLoading, getCurrentPosition, startWatching, stopWatching } = useGeolocation();

  return (
    <NativeGuard native fallback={<p>Native features not available</p>}>
      <div>
        {isLoading && <p>Getting location...</p>}
        {position && (
          <p>
            Lat: {position.coords.latitude}, Lng: {position.coords.longitude}
            (accuracy: {position.coords.accuracy}m)
          </p>
        )}
        <button onClick={() => getCurrentPosition()}>Get Location</button>
        <button onClick={() => startWatching()}>Start Watching</button>
      </div>
    </NativeGuard>
  );
}

function PhotoCapture() {
  const { photo, takePhoto, pickFromGallery } = useCamera({ quality: 90 });

  return (
    <div>
      {photo && <img src={photo.webPath || photo.dataUrl} alt="Captured" />}
      <button onClick={() => takePhoto()}>Take Photo</button>
      <button onClick={() => pickFromGallery()}>Choose from Gallery</button>
    </div>
  );
}

Svelte Usage

<script lang="ts">
  import { useGeolocation, useCamera, usePlatformCheck } from '@classic-homes/native/svelte';

  const geo = useGeolocation({ enableHighAccuracy: true });
  const camera = useCamera({ quality: 90 });
  const platform = usePlatformCheck();
</script>

{#if platform.isNative}
  <div>
    {#if geo.isLoading}
      <p>Getting location...</p>
    {:else if geo.position}
      <p>Lat: {geo.position.coords.latitude}</p>
    {/if}
    <button onclick={() => geo.getCurrentPosition()}>Get Location</button>
    <button onclick={() => geo.startWatching()}>Start Watching</button>
  </div>
{:else}
  <p>Native features not available</p>
{/if}

{#if camera.photo}
  <img src={camera.photo.webPath || camera.photo.dataUrl} alt="Captured" />
{/if}
<button onclick={() => camera.takePhoto()}>Take Photo</button>

Available Features

| Feature | Hook/Composable | iOS | Android | Web Fallback | | ------------------ | ---------------------- | ---------------- | -------------- | -------------- | | Camera | useCamera | Native | Native | File input | | Geolocation | useGeolocation | GPS | GPS | Navigator API | | Secure Storage | useSecureStorage | Keychain | EncryptedPrefs | localStorage | | Biometrics | useBiometrics | Face ID/Touch ID | Fingerprint | WebAuthn | | Haptics | useHaptics | Native | Native | Vibration API | | Device Info | useDevice | Native | Native | UA parsing | | Network Status | useNetwork | Native | Native | Navigator API | | Push Notifications | usePushNotifications | APNs | FCM | Web Push | | App Lifecycle | useAppLifecycle | Native | Native | Visibility API |

API Reference

Platform Detection

import {
  getPlatformInfo,
  isNative,
  isWeb,
  isIOS,
  isAndroid,
  isMobile,
} from '@classic-homes/native';

const info = getPlatformInfo();
// { platform: 'ios', shellType: 'capacitor', isNative: true, isMobile: true }

if (isNative()) {
  // Running in Capacitor
}

Geolocation

// React
const {
  position, // Current position
  isLoading, // Loading state
  isWatching, // Whether watching
  error, // Error state
  getCurrentPosition,
  startWatching,
  stopWatching,
  checkPermissions,
  requestPermissions,
} = useGeolocation({
  enableHighAccuracy: true,
  timeout: 10000,
  maximumAge: 0,
});

// Get once
const pos = await getCurrentPosition();

// Watch continuously
await startWatching();
// ... later
await stopWatching();

Camera

const {
  photo, // Last captured photo
  isLoading,
  error,
  takePhoto,
  pickFromGallery,
  checkPermissions,
  requestPermissions,
} = useCamera({
  quality: 90,
  allowEditing: false,
  resultType: 'dataUrl', // 'base64' | 'uri' | 'dataUrl'
});

const photo = await takePhoto();
console.log(photo.dataUrl); // data:image/jpeg;base64,...

Biometrics

const {
  isAvailable, // Whether biometrics available
  availability, // Detailed info
  isLoading,
  error,
  checkAvailability,
  authenticate,
} = useBiometrics();

if (isAvailable) {
  const result = await authenticate({
    reason: 'Confirm your identity',
    allowDeviceCredential: true,
  });

  if (result.verified) {
    // Authentication successful
  }
}

Secure Storage

const { isLoading, error, get, set, remove, clear, keys } = useSecureStorage();

await set('auth_token', 'your-token');
const token = await get('auth_token');
await remove('auth_token');

Haptics

const { isAvailable, impact, notification, vibrate } = useHaptics();

await impact('medium'); // 'light' | 'medium' | 'heavy'
await notification('success'); // 'success' | 'warning' | 'error'
await vibrate(300); // duration in ms

Network

const {
  status, // Full status object
  isConnected, // Boolean
  connectionType, // 'wifi' | 'cellular' | 'none' | 'unknown'
  refresh,
} = useNetwork();

App Lifecycle

const {
  isActive, // Whether app is active
  launchUrl, // URL that launched the app
  exitApp, // Android only
  minimizeApp, // Android only
} = useAppLifecycle({
  onStateChange: (state) => {
    if (!state.isActive) {
      // App went to background
    }
  },
  onUrlOpen: (event) => {
    // Handle deep link
    console.log('Opened:', event.url);
  },
});

Push Notifications

const {
  token,
  isRegistered,
  permissionState,
  register,
  unregister,
  requestPermissions,
  createChannel,
} = usePushNotifications({
  onNotificationReceived: (notification) => {
    console.log('Received:', notification);
  },
  onNotificationAction: (action) => {
    console.log('User tapped:', action);
  },
});

await requestPermissions();
await register();
console.log('Token:', token?.value);

Conditional Rendering

React

import { NativeGuard, usePlatformCheck } from '@classic-homes/native/react';

// Component-based
<NativeGuard native>
  <MobileFeatures />
</NativeGuard>

<NativeGuard platform="ios">
  <ApplePayButton />
</NativeGuard>

<NativeGuard feature="camera">
  <PhotoButton />
</NativeGuard>

// Hook-based
const { isNative, isIOS, isFeatureAvailable } = usePlatformCheck();

if (isNative && await isFeatureAvailable('camera')) {
  // Show camera button
}

Svelte

<script lang="ts">
  import { usePlatformCheck } from '@classic-homes/native/svelte';

  const platform = usePlatformCheck();

  // Check feature availability (async)
  let cameraAvailable = $state(false);
  $effect(() => {
    platform.isFeatureAvailable('camera').then((available) => {
      cameraAvailable = available;
    });
  });
</script>

{#if platform.isNative}
  <MobileFeatures />
{/if}

{#if cameraAvailable}
  <PhotoButton />
{/if}

Error Handling

import {
  isPermissionDeniedError,
  isUserCancelledError,
  isFeatureUnavailableError,
} from '@classic-homes/native';

try {
  await getCurrentPosition();
} catch (error) {
  if (isPermissionDeniedError(error)) {
    // Show settings prompt
    console.log('Please enable location in settings');
  } else if (isUserCancelledError(error)) {
    // User cancelled, no action needed
  } else if (isFeatureUnavailableError(error)) {
    // Feature not available on this device
  }
}

TypeScript Support

This package includes TypeScript declarations for:

  • @classic-homes/native - Main entry
  • @classic-homes/native/core - Core utilities
  • @classic-homes/native/react - React hooks and components

Svelte Note: The @classic-homes/native/svelte subpath does not include TypeScript declarations due to Svelte 5 runes ($state, $derived) not being supported by TypeScript's declaration emitter. The Svelte composables work correctly at runtime and include JSDoc comments for IDE support.

License

MIT