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

@sigx/lynx-safe-area

v0.1.3

Published

Safe area insets (notch, home indicator, status bar, keyboard) for sigx-lynx

Readme

@sigx/lynx-safe-area

Safe-area insets (notch, home indicator, status bar, navigation bar, keyboard) for sigx-lynx. Native publisher on iOS + Android emits insets every time they change; the JS side surfaces them as a reactive BG signal, four per-edge SharedValues for MT-driven layout, and CSS variables for utility-class styling.

Mirrors React Native's react-native-safe-area-context API where it makes sense, but built for sigx-lynx's two-thread model so layout-bound insets don't bounce through the bridge.

Install

pnpm add @sigx/lynx-safe-area

Then declare it in your sigx.lynx.config.ts so prebuild auto-links the native publisher:

import { defineLynxConfig } from '@sigx/lynx-cli/config';

export default defineLynxConfig({
    modules: [
        // ...
        '@sigx/lynx-safe-area',
    ],
});

sigx prebuild then copies SafeAreaPublisher.swift / SafeAreaPublisher.kt into your ios/ and android/ source trees and registers them in the auto-generated GeneratedLifecyclePublishers.{swift,kt} so they attach to every LynxView before first paint. No additional native wiring required.

Quick start

Wrap your app once, anywhere above the views that need insets:

import { defineApp } from '@sigx/lynx';
import { SafeAreaProvider, SafeAreaView } from '@sigx/lynx-safe-area';

defineApp(() => () => (
    <SafeAreaProvider>
        <SafeAreaView edges={['top', 'bottom']} class="bg-base-100 flex-1">
            <PageContent />
        </SafeAreaView>
    </SafeAreaProvider>
));

<SafeAreaView> reactively applies the current insets as padding (default) or margin to the configured edges. Inset-aware first paint: insets are seeded synchronously from lynx.__globalProps before render, so there's no flash of unsafe content.

API

<SafeAreaProvider>

Provides the context that hooks consume. Mount once at the app root.

| Prop | Type | Notes | | ------- | --------------------------------- | ------------------------------------------- | | class | string | Forwarded to the host <view>. | | style | Record<string, string \| number> | Merged after the auto-injected CSS vars. |

The host view exposes the current insets as CSS variables (--sat, --sar, --sab, --sal, --safe-area-keyboard) — handy for utility-class consumers:

<SafeAreaProvider>
    <view class="pt-[var(--sat)] pb-[var(--sab)]">…</view>
</SafeAreaProvider>

<SafeAreaView>

Drop-in container that applies insets as padding or margin.

| Prop | Type | Default | | ------- | --------------------------------- | -------------------------------- | | edges | ('top' \| 'right' \| 'bottom' \| 'left')[] | All four sides | | mode | 'padding' \| 'margin' | 'padding' | | class | string | — | | style | Record<string, string \| number> | Merged after inset styles |

Implementation note: applies insets via inline style (BG signal), not via useAnimatedStyle. setStyleProperties writes that affect layout fire after the first layout pass, and children that capture their frame eagerly (notably <scroll-view>) don't reflow when insets arrive that way. Inline style avoids the timing trap.

useSafeAreaInsets()

function useSafeAreaInsets(): PrimitiveSignal<EdgeInsets> | Computed<EdgeInsets>;

Returns a BG-side reactive signal of EdgeInsets. Components calling this re-render on every inset change (rotation, keyboard show/hide, split-view resize on iPad).

const insets = useSafeAreaInsets();
return () => <view style={{ paddingTop: `${insets.value.top}px` }}>…</view>;

If no <SafeAreaProvider> is in scope, returns a signal seeded with ZERO_INSETS and warns in dev (so test/storybook fragments degrade gracefully instead of throwing).

useSafeAreaSharedValues()

function useSafeAreaSharedValues(): {
    top: SharedValue<number>;
    right: SharedValue<number>;
    bottom: SharedValue<number>;
    left: SharedValue<number>;
} | null;

Per-edge SharedValues for MT-driven useAnimatedStyle bindings. Use when an animation or gesture worklet needs the current inset on MT without a BG round-trip. Returns null outside of <SafeAreaProvider>.

useSafeAreaFrame(viewportWidth, viewportHeight)

function useSafeAreaFrame(
    viewportWidth: number,
    viewportHeight: number,
): Computed<{ x: number; y: number; width: number; height: number }>;

Computed inner safe frame — (x, y) origin and width/height of the rect inside the insets. Useful for absolute-positioned overlays and modal bounds that need to know "the visible content rect", not just inset deltas.

viewportWidth/viewportHeight are caller-supplied (typically a one-time read via @sigx/lynx-device-info); the safe-area module deliberately doesn't pull device-info as a transitive dependency.

useSafeAreaInsetsMT()

function useSafeAreaInsetsMT(): EdgeInsets;

Synchronous read from inside a 'main thread'-marked worklet. Reads lynx.__globalProps directly — there's no signal subscription, so callers re-evaluate per worklet invocation rather than reactively. For declarative MT-driven layout the recommended path is <SafeAreaView> (which composes useSafeAreaSharedValues() with useAnimatedStyle).

Types

interface EdgeInsets {
    top: number;
    right: number;
    bottom: number;
    left: number;
    /** IME (soft keyboard) height when visible, 0 when hidden. */
    keyboard: number;
    /** Status-bar height. Often equal to `top`, but on notched devices the
     *  safe-area top includes the notch and `statusBar` is the smaller
     *  status-only inset. */
    statusBar: number;
    /** Navigation-bar height (Android gesture/3-button nav at bottom). */
    navigationBar: number;
}

const ZERO_INSETS: EdgeInsets;

All values are in dp/pt (logical pixels), not raw pixels.

Lower-level escape hatches

import { readGlobalSafeArea, GLOBAL_PROPS_KEY } from '@sigx/lynx-safe-area';
  • readGlobalSafeArea() — synchronous one-shot read from lynx.__globalProps. Returns EdgeInsets (zeros if the publisher hasn't run yet). What <SafeAreaProvider> uses to seed initial values.
  • GLOBAL_PROPS_KEY — the key the native publisher writes under. Exported for tests/debugging.

CSS variables

The provider's host view exposes these on the element style — descendant selectors inherit them via the cascade:

| Variable | Maps to | | ----------------------- | ---------------------------------------- | | --sat | insets.top (in px) | | --sar | insets.right | | --sab | insets.bottom | | --sal | insets.left | | --safe-area-keyboard | insets.keyboard |

Works uniformly across iOS and Android — upstream's env(safe-area-inset-*) is iOS-only, so this is what you reach for if you're using DaisyUI/Tailwind utilities like pt-[var(--sat)].

How it works

┌──────────────────────────────────────┐
│ Native (iOS UIView / Android View)   │
│ - SafeAreaPublisher attached to      │
│   LynxView at construction           │
│ - On each insets/keyboard change:    │
│   ┌──────────────────────────────┐   │
│   │ updateGlobalProps({safeArea})│   │
│   │ + emit 'safeAreaChanged'     │   │
│   └──────────────────────────────┘   │
└──────────────────────────────────────┘
                    │
                    ▼
┌──────────────────────────────────────┐
│ JS (BG thread)                       │
│ ┌─────────────────┐ ┌──────────────┐ │
│ │ readGlobal-     │ │ Global-      │ │
│ │ SafeArea() seed │ │ EventEmitter │ │
│ │ (sync, before   │ │ subscription │ │
│ │  first render)  │ │              │ │
│ └────────┬────────┘ └──────┬───────┘ │
│          │                 │         │
│          ▼                 ▼         │
│      ┌──────────────────────────┐    │
│      │ runOnMainThread worklet  │    │
│      │ writes 4 per-edge SVs    │    │
│      └────────────┬─────────────┘    │
│                   │                  │
│                   ▼                  │
│   SharedValue diff → BG signal       │
│   mirror → computed → re-render      │
│   useSafeAreaInsets() consumers      │
└──────────────────────────────────────┘

Why SharedValues for the four edges but a plain signal for keyboard/statusBar/navigationBar? The four edges drive layout (<SafeAreaView> wants to write padding from a worklet on every flush) and the SV bridge is the right tool for that. The extras are informational — keyboard already lives in bottom on iOS, statusBar/navigationBar are decorative — so the SV plumbing isn't worth the cost there.

A custom safeAreaChanged event is used instead of upstream's onGlobalPropsChanged because the upstream event-name conventions have churned across Lynx releases and we want the contract in our hands.

Reference app

examples/lynx-one/my-sigx-app/src/App.tsx mounts <SafeAreaProvider> and a <SafeAreaView> for the page chrome — useful as a copy-paste reference and as the smoke-test target when porting the publisher to a new platform.