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

@atlure/ui

v0.9.0

Published

Atlure React Native component library: NativeWind primitives built on @atlure/tokens, shipped as untranspiled TypeScript source

Readme

@atlure/ui

React Native components for atlure-paw, styled with NativeWind against @atlure/tokens.

This package ships TypeScript source, not compiled output

exports points straight at ./src/index.ts and files includes src. That is deliberate and it is the one thing not to "fix".

NativeWind's className is a Babel-time JSX transform (jsxImportSource: "nativewind"). If this package were precompiled — by react-native-builder-bob, tsup or plain tsc — the JSX would be frozen against react/jsx-runtime, className would become a prop nobody reads, and every component would render unstyled with no error to explain why. The consuming app's Babel pipeline has to see the original JSX.

Consumer setup

Two steps, both required.

1. Add this package's source to your Tailwind content array. Classes live in files inside node_modules, so Tailwind will not find them otherwise and every utility used only by this package will be missing from the compiled output:

module.exports = {
  presets: [require("nativewind/preset"), require("@atlure/tailwind-preset")],
  content: ["./app/**/*.{ts,tsx}", "./node_modules/@atlure/ui/src/**/*.{ts,tsx}"],
};

The NativeWind preset must come first.

2. Let Metro transpile this package. Because it ships source, node_modules/@atlure/ui must not be excluded from the Babel transform. In a default Expo project it already is not.

Usage

import { Avatar, Button, Card, CardContent, Text } from "@atlure/ui";

export function SitterCard({ sitter, onOpen, openLabel }) {
  return (
    <Card onPress={onOpen} accessibilityLabel={openLabel}>
      <CardContent className="flex-row items-center gap-md">
        <Avatar name={sitter.displayName} src={sitter.avatarUrl} presence="online" />
        <Text variant="title">{sitter.displayName}</Text>
      </CardContent>
    </Card>
  );
}

Components: Text, Button, Card (CardHeader, CardContent, CardFooter), Input, Label, Badge, Avatar (AvatarGroup), Separator, Skeleton, Switch, Checkbox, Sheet, Select (SelectItem), Picker, Dialog, AlertDialog, Toast, MoneyLabel, DistanceLabel, DurationLabel, DateLabel, DateRangeLabel.

Overlays queue through a host, so the app root mounts it once, above the navigator:

<PortalHost>
  <ToastProvider bottomInset={insets.bottom}>
    <Navigator />
  </ToastProvider>
</PortalHost>

Dialog, AlertDialog and Toast throw a named error if that host is missing, rather than rendering nothing and leaving you to guess why.

Avatar accepts the image as either src or the older uri; src wins when both are set. uri is kept only so 0.3.0 consumers do not break, and goes away before 1.0.

Every user-facing string is a prop. This package contains no display copy, so i18n stays in the app. The one exception is MoneyLabel's per suffix, which renders the English words per hour, per night or per walk; a message catalogue is out of scope for v1, so this is the single string that must be revisited when translation lands.

Locale and number formatting

LocaleProvider carries a BCP-47 locale and a measurement system (metric by default, imperial opt-in); useLocale() reads it. Without a provider the defaults are en-IE and metric.

Every unit, currency symbol, separator and date order comes from Intl, never from a literal — so a price renders in its own currency regardless of the reader's locale, and 1 hr 30 mins becomes 1 Std. 30 Min. in de-DE. Money carries minor units, and the number of decimal places is read back from Intl for that currency rather than assumed to be two.

This requires Intl to be present. Hermes needs it switched on explicitly in the app's app.config.ts; that change belongs to the app, not to this package.

Variant recipes are shared, render layers are not

The cva recipes live in src/variants/ as standalone files with no React Native imports, and are also exported from @atlure/ui/variants:

import { buttonVariants, buttonLabelVariants } from "@atlure/ui/variants";

@atlure/ui-web imports the same recipes and applies them to DOM elements, so a variant's spacing and colour are defined once for both platforms and only the rendering differs. Consequently the class strings are restricted to the React Native-safe Tailwind subset:

| Not allowed | Use instead | |---|---| | space-x-*, space-y-* | gap-* | | divide-* | an explicit Separator | | grid, grid-cols-* | flex-row / flex-col | | descendant or sibling selectors | a class on the child | | implicit row direction | flex-row, always — React Native defaults to column |

Values come from the token scales (h-control-md, text-base, bg-primary, border-border/20). There is no raw hex anywhere in this package; to change a colour, edit packages/tokens/src/tokens.ts.

The barrel is generated

src/index.ts is emitted by scripts/generate-barrel.mjs from a directory walk of src, and is committed. Run pnpm build after adding a component — hand-editing it is pointless, since the next build overwrites it, and CI's git diff --exit-code fails if it is stale.

This exists because a hand-maintained barrel is a guaranteed merge conflict whenever two branches add a component. Modules under a hooks/ directory and any utils.ts are treated as internal and left out of the public surface.

Accessibility

Every interactive component sets accessibilityRole, accessibilityLabel and accessibilityState, and the matching aria-* alias. Both are needed: react-native-web, which Expo uses for the web build, ignores accessibilityState in favour of aria-*, so state such as "checked" would silently never be announced there.

Touch targets are guaranteed to reach 44px via hitSlop, computed from the controlHeight token rather than hard-coded — touchTargetHitSlop pads a 36px or 40px control out to the minimum without changing how it looks.

Tests

pnpm test runs Vitest with React Testing Library. react-native is aliased to react-native-web so components render into jsdom and can be queried by role and accessible name.

@atlure/tokens and @atlure/types are resolved to ../tokens/src and ../types/src for typechecking and testing, via paths in tsconfig.json and aliases in vitest.config.ts. Published consumers still get dist through those packages' exports; resolving to source here means this package's checks do not depend on either having been built first, and can never read a stale dist.

What that proves: press handling, disabled and loading behaviour, controlled toggle state, change propagation, accessible roles and names, and the barrel generator's output.

What it does not prove: that NativeWind resolves any of these class strings. That requires a device or simulator — a green test run here says nothing about styling.