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

stampd

v0.1.4

Published

React Native styling stamped at compile time — design tokens resolved to literal values in your bundle, zero runtime overhead, light/dark/high-contrast built in.

Downloads

19

Readme

stampd

React Native styling, stamped at compile time.

Design tokens resolved to literal values in your bundle — zero runtime overhead, full TypeScript, light / dark / high-contrast built in.

const Card = Styled.View({
  style: ({ theme }) => ({
    backgroundColor: theme.colors.surface,
    padding: theme.spacing.md,       // → 16
    borderRadius: theme.radius.md,   // → 8
  }),
});
// ↓ Babel output
const Card = (props) => (
  <View style={{ backgroundColor: theme.colors.surface, padding: 16, borderRadius: 8 }} {...props} />
);

Table of Contents


Quick Start

npm install stampd

1. Add the plugin to babel.config.js:

module.exports = {
  presets: ['babel-preset-expo'],
  plugins: ['module:stampd'],
};

2. Create stampd.config.ts at your project root:

import { createTheme } from 'stampd/theme';

const light = { primary: '#2563EB', background: '#F8FAFC', text: '#0F172A' };
const dark  = { primary: '#3B82F6', background: '#0F172A', text: '#F8FAFC' };

export const config = createTheme({
  tokens: {
    spacing:  { xs: 4, sm: 8, md: 16, lg: 24, xl: 32 },
    radius:   { sm: 4, md: 8, lg: 16, full: 9999 },
  },
  theme: {
    light: { colors: light },
    dark:  { colors: dark  },
  },
  fonts: {
    default: { size: 14, family: 'Inter' },
  },
});

3. Add stampd-types.d.ts to tsconfig.json:

{ "include": ["**/*.ts", "**/*.tsx", "stampd-types.d.ts"] }

4. Wrap your app:

import { StampdUIProvider } from 'stampd/context';
import { config } from './stampd.config';

export default function App() {
  return <StampdUIProvider config={config}><RootNavigator /></StampdUIProvider>;
}

5. Start building:

import { Styled } from 'stampd/styled';

const Button = Styled.TouchableOpacity({
  style: ({ theme }) => ({
    backgroundColor: theme.colors.primary,  // runtime — light/dark aware
    padding: theme.spacing.md,              // compile time → 16
    borderRadius: theme.radius.sm,          // compile time → 4
  }),
});

How it works

stampd runs as a Babel plugin during your build:

  1. Reads stampd.config.ts from your project root at compile time.
  2. Resolves every theme.spacing.md, theme.radius.sm, theme.fonts.sizes.lg, etc. to its literal value and hardcodes it in the bundle.
  3. Colors and other values that differ between light / dark are kept as runtime references — useStampdUI() is injected only when actually needed.
  4. Variants are hoisted to module-level constants, allocated once.
  5. Generates stampd-types.d.ts with inline literal types for full IDE autocomplete.

Installation

npm install stampd

Setup

1. babel.config.js

module.exports = function (api) {
  // Re-run Babel when stampd.config.ts changes
  const configPath = require('path').join(__dirname, 'stampd.config.ts');
  try {
    api.cache.using(() => require('fs').statSync(configPath).mtimeMs);
  } catch {
    api.cache(true);
  }

  return {
    presets: ['babel-preset-expo'],
    plugins: ['module:stampd'],
  };
};

Enable debug output to inspect generated code:

plugins: [['module:stampd', { debug: true }]],

2. stampd.config.ts

Create stampd.config.ts at the root of your project (next to package.json):

import { createTheme } from 'stampd/theme';

const lightColors = {
  primary:    '#2563EB',
  background: '#F8FAFC',
  surface:    '#FFFFFF',
  text:       '#0F172A',
  error:      '#DC2626',
};

const darkColors = {
  primary:    '#3B82F6',
  background: '#0F172A',
  surface:    '#1E293B',
  text:       '#F8FAFC',
  error:      '#EF4444',
};

export const config = createTheme({
  // Resolved at compile time — hardcoded in the bundle
  tokens: {
    spacing:  { xs: 4, sm: 8, md: 16, lg: 24, xl: 32 },
    radius:   { sm: 4, md: 8, lg: 16, full: 9999 },
    fontSize: { sm: 12, md: 14, lg: 16, xl: 20, xxl: 24 },
  },

  // Resolved at runtime — switch between light / dark / high-contrast
  theme: {
    light:        { colors: lightColors },
    dark:         { colors: darkColors },
    highContrast: { colors: { background: '#000000', text: '#FFFFFF' } }, // partial overrides
  },

  // Static font config — auto-injected into Text / TextInput
  fonts: {
    default: { size: 14, family: 'Inter' },
    sizes:   { sm: 12, md: 14, lg: 16, xl: 20 },
    family:  { inter: 'Inter', mono: 'JetBrainsMono' },
  },
});

createTheme validates at startup that dark has the same keys as light, warning if they diverge.


3. tsconfig.json

Include the auto-generated type file:

{
  "include": ["**/*.ts", "**/*.tsx", "stampd-types.d.ts"]
}

4. Wrap your app with StampdUIProvider

// App.tsx
import { StampdUIProvider } from 'stampd/context';
import { config } from './stampd.config';

export default function App() {
  return (
    <StampdUIProvider config={config}>
      <RootNavigator />
    </StampdUIProvider>
  );
}

Usage

Simple component

import { Styled } from 'stampd';

const Card = Styled.View({
  style: ({ theme }) => ({
    backgroundColor: theme.colors.surface,  // runtime — stays as ref
    padding: theme.spacing.md,              // compile time → 16
    borderRadius: theme.radius.md,          // compile time → 8
  }),
});

Compile-time output:

import { View } from 'react-native';

const Card = (props) => (
  <View
    style={[{ backgroundColor: theme.colors.surface }, { padding: 16, borderRadius: 8 }]}
    {...props}
  />
);

Static component (no runtime cost)

When there are no dynamic values, the output is a plain component — no context, no hook:

const Divider = Styled.View({
  style: {
    height: 1,
    backgroundColor: '#E2E8F0',
    marginVertical: 8,
  },
});

Text with default font auto-injected

Styled.Text and Styled.TextInput automatically receive fontFamily and fontSize from fonts.default as the base layer. Your component styles take precedence:

const Label = Styled.Text({
  style: ({ theme }) => ({
    color: theme.colors.text,
    fontWeight: '600',
  }),
});

Output:

<Text
  style={[
    { fontFamily: 'Inter', fontSize: 14 },   // ← auto from fonts.default
    { color: theme.colors.text, fontWeight: '600' },
  ]}
  {...props}
/>

Override per-component by setting fontFamily / fontSize in your style — the last item wins.


Variants

const Button = Styled.TouchableOpacity({
  style: ({ theme }) => ({
    backgroundColor: theme.colors.primary,
    paddingVertical: theme.spacing.sm,
    paddingHorizontal: theme.spacing.md,
    borderRadius: theme.radius.md,
    alignItems: 'center',
  }),
  variants: {
    variant: {
      outline: ({ theme }) => ({
        backgroundColor: 'transparent',
        borderWidth: 1,
        borderColor: theme.colors.primary,
      }),
      ghost: () => ({
        backgroundColor: 'transparent',
      }),
      danger: ({ theme }) => ({
        backgroundColor: theme.colors.error,
      }),
    },
    size: {
      sm: ({ theme }) => ({
        paddingVertical: theme.spacing.xs,
        paddingHorizontal: theme.spacing.sm,
      }),
      full: () => ({ width: '100%' as const }),
    },
  },
});

// Usage — types are fully inferred:
<Button variant="outline" size="sm" onPress={handlePress} />

Passing an invalid variant value (variant="invalid") is a TypeScript error.


Dynamic props

Any prop that is not a variant key is automatically forwarded and available in the style function:

const Tag = Styled.View({
  style: ({ theme, selected }) => ({
    backgroundColor: selected ? theme.colors.primary : theme.colors.surface,
    borderWidth: selected ? 0 : 1,
    paddingHorizontal: theme.spacing.sm,
    borderRadius: theme.radius.full,
  }),
});

<Tag selected={isActive} />

attrs — default props

const Input = Styled.TextInput({
  style: ({ theme }) => ({
    color: theme.colors.text,
    padding: theme.spacing.sm,
  }),
  attrs: {
    placeholderTextColor: '#94A3B8',
    autoCapitalize: 'none',
  },
});

Using theme.fonts

const Heading = Styled.Text({
  style: ({ theme }) => ({
    fontFamily: theme.fonts.family.inter,  // compile time → "Inter"
    fontSize: theme.fonts.sizes.xl,        // compile time → 20
    fontWeight: '700',
    color: theme.colors.text,
  }),
});

theme.fonts.* is resolved at compile time — literal values are hardcoded in the output.


StampdUIProvider & useStampdUI

Switching themes

import { useStampdUI, ThemeMode } from 'stampd/context';

function ThemeToggle() {
  const { themeMode, setThemeMode } = useStampdUI();

  return (
    <Pressable onPress={() =>
      setThemeMode(themeMode === ThemeMode.DARK ? ThemeMode.LIGHT : ThemeMode.DARK)
    }>
      <Text>Toggle theme</Text>
    </Pressable>
  );
}

| ThemeMode | Behavior | |------------------------|------------------------------------| | ThemeMode.SYSTEM | Follows device setting (default) | | ThemeMode.LIGHT | Always light | | ThemeMode.DARK | Always dark |


High contrast

const { highContrast, setHighContrast } = useStampdUI();

<Switch value={highContrast} onValueChange={setHighContrast} />

When enabled, the highContrast colors from stampd.config.ts are deep-merged on top of the active light / dark theme. Only the keys you define are overridden — everything else stays unchanged.


Font scale

import { useStampdUI, FontScaleMode } from 'stampd/context';

const { fontScale, fontScaleMode, setFontScaleMode } = useStampdUI();

| FontScaleMode | Behavior | |---------------------------|-----------------------------------------------| | FontScaleMode.SYSTEM | Follows device accessibility setting (default) | | FontScaleMode.FIXED_1 | Always 1× | | FontScaleMode.FIXED_1_5 | Always 1.5× | | FontScaleMode.FIXED_2 | Always 2× |


Accessing the theme directly

const { theme } = useStampdUI();

// theme.colors.primary, theme.spacing.md, theme.fonts.family.inter, ...

createTheme API

import { createTheme, InferTheme } from 'stampd/theme';

export const config = createTheme({
  // ── Compile-time tokens ──────────────────────────────────────────────────
  tokens: {
    spacing:  { xs: 4, sm: 8, md: 16, lg: 24, xl: 32 },
    radius:   { sm: 4, md: 8, lg: 16, full: 9999 },
    fontSize: { sm: 12, md: 14, lg: 16, xl: 20, xxl: 24 },
  },

  // ── Runtime theme ────────────────────────────────────────────────────────
  theme: {
    light:        { colors: lightColors },
    dark:         { colors: darkColors },
    highContrast: { colors: { background: '#000' } }, // DeepPartial — only overrides what's set
  },

  // ── Fonts ────────────────────────────────────────────────────────────────
  fonts: {
    default: { size: 14, family: 'Inter' },  // auto-injected in Text / TextInput
    sizes:   { sm: 12, md: 14, lg: 16, xl: 20 },
    family:  { inter: 'Inter', mono: 'JetBrainsMono' },
  },
});

// Infer the resolved theme type:
export type AppTheme = InferTheme<typeof config>;

Style priority

When multiple layers are applied, the last item wins (React Native style array behavior):

fonts.default  <  base style  <  variants  <  style prop passed by user

The user's style prop always wins over everything defined at component level.


Generated types — stampd-types.d.ts

On every build, stampd generates stampd-types.d.ts at your project root with inline literal types for full IDE autocomplete — no imports needed in your components:

// ⚡ Auto-generated by stampd — do not edit manually.
declare global {
  namespace StyledSystem {
    interface Theme {
      spacing:  { xs: 4; sm: 8; md: 16; lg: 24; xl: 32 };
      radius:   { sm: 4; md: 8; lg: 16; full: 9999 };
      fontSize: { sm: 12; md: 14; lg: 16; xl: 20; xxl: 24 };
      colors:   { primary: "#2563EB"; background: "#F8FAFC"; ... };
      fonts: {
        default: { size: 14; family: "Inter" };
        sizes:   { sm: 12; md: 14; lg: 16; xl: 20 };
        family:  { inter: "Inter"; mono: "JetBrainsMono" };
      };
    }
  }
}

The file is regenerated automatically when stampd.config.ts changes.


CLI — inspect generated output

Inspect exactly what the plugin emits for any file without running the full bundler:

node node_modules/stampd/dist/cli/runTransform.js <input> <output> [config]

# Example:
node node_modules/stampd/dist/cli/runTransform.js \
  src/screens/Login.tsx \
  /tmp/Login.out.js \
  stampd.config.ts

Add as a script in package.json:

{
  "scripts": {
    "transform": "node node_modules/stampd/dist/cli/runTransform.js"
  }
}

Supported components

Styled ships with typed factories for all standard React Native components:

| Component | Style type | |---------------------------------|---------------| | Styled.View | ViewStyle | | Styled.Text | TextStyle | | Styled.TextInput | TextStyle | | Styled.Image | ImageStyle | | Styled.ImageBackground | ViewStyle | | Styled.ScrollView | ViewStyle | | Styled.Pressable | ViewStyle | | Styled.TouchableOpacity | ViewStyle | | Styled.KeyboardAvoidingView | ViewStyle | | Styled.FlatList | ViewStyle | | Styled.SectionList | ViewStyle |


License

MIT