Simal UI

Usage

Installing and wiring @simal/ui into a consumer, and the three ways it fails silently.

The package ships untranspiled TypeScript with platform splits intact. A consumer's bundler has to be told about both, and about which packages must stay single-instance.

Install

A private git dependency, pinned by tag. Never published to public npm.

"@simal/ui": "git+ssh://git@github.com/rara-ventures/simal-ui.git#semver:^0.1.0"

EAS Build needs its own credential for this — EXPO_TOKEN does not cover git access. Put a GitHub PAT with repo read into EAS secrets before the first cloud build.

Peer dependencies

These are peers, not dependencies, and the distinction is load-bearing: a duplicate instance of any of them fails silently rather than loudly. Two uniwind instances produce unstyled components with a green build.

react  react-native  expo  uniwind  tailwindcss
react-native-reanimated  react-native-gesture-handler
react-native-safe-area-context  react-native-svg

expo-router  (optional — only Bar, LargeTitleHeader and
              AdaptiveSearchHeader need it, and only to
              configure a native header)

Bundler configuration

Three things, all of which fail silently if missed — the build stays green and the components render unstyled.

Tailwind content globs

The package's classNames live in node_modules, which Tailwind does not scan by default. Miss this and every component renders unstyled.

@source "../node_modules/@simal/ui/src/**/*.{js,jsx,ts,tsx}";

Metro

The source is untranspiled, so Metro must transform it, and package exports must be on for the subpath entries to resolve.

config.resolver.unstable_enablePackageExports = true;

Aliases

If you alias anything to this package, point the alias at the bare specifier (@simal/ui/nativewindui), never at a path inside node_modules. A file-path alias bypasses the exports map, and under pnpm it follows a symlink into the content-addressed store.

Theme persistence

The package does not own device storage. Wrap the app in ThemeStorageProvider and hand it two callbacks. Without it the theme toggle still works for the session; it just does not survive a reload. This is what keeps react-native-mmkv out of the dependency tree entirely.

import { ThemeStorageProvider } from '@simal/ui';

<ThemeStorageProvider
  getStoredTheme={() => storage.getString('SELECTED_THEME') as ColorSchemeType}
  setStoredTheme={theme => storage.set('SELECTED_THEME', theme)}
>
  <App />
</ThemeStorageProvider>;

On this page