neetoUI-RN is the library that drives the experience in all neeto product's React Native application built at BigBinary.
Documentation
Storybook is the documentation: https://neetoui-rn.onrender.com/
Every component has a story next to its source, and the Docs section covers
getting started and the theme tokens.
Installation
yarn add @bigbinary/neetoui-rn @gorhom/bottom-sheet @shopify/flash-list react-native-edge-to-edge react-native-gesture-handler react-native-nitro-modules react-native-reanimated react-native-safe-area-context react-native-svg react-native-toast-message react-native-unistyles
Navigate to iOS folder and run:
pod install
All the native components will be linked automatically.
Jest
The package ships untranspiled TypeScript, so consuming apps have to let Jest transform it instead of skipping it as a dependency:
// jest.config.js
transformIgnorePatterns: [
"node_modules/(?!(@react-native|@bigbinary|@gorhom|@shopify|react-native|react-native-[^/]+)/)",
],
Without this, tests fail on the first import with a syntax error.
Getting Started
Theming
Themes are registered through Unistyles. Call configureNeetoUI from your app's
entry point (index.js), before anything else imports a screen:
import { configureNeetoUI } from "@bigbinary/neetoui-rn/unistyles";
configureNeetoUI();
The library ships both a light and a dark theme, and pins the light one by
default — it does not follow the device colour scheme. An app that has not
designed its own screens for dark mode only half-follows: token-styled surfaces
go dark while anything painted from a literal colour stays light, which shows up
as dark text on dark backgrounds and a dark status bar under a dark-content
bar style.
Once your screens are ready for it, opt in:
configureNeetoUI({ adaptiveThemes: true });
The opt-in is honoured even though importing the library root registers the
defaults first, so it works from index.js regardless of module evaluation
order.
Fonts
theme.fonts uses Inter (SIL Open Font License, see
assets/licenses/Inter-OFL.txt). Link the bundled files from the app's
react-native.config.js:
module.exports = {
assets: ["./node_modules/@bigbinary/neetoui-rn/assets/fonts"],
};
Then run npx react-native-asset, and check that UIAppFonts in Info.plist
and android/app/src/main/assets/fonts list only the Inter-*.ttf files.
Upgrading from 3.x, which bundled SF Pro: re-run npx react-native-asset so the
SFProText-*.ttf files are unlinked, drop any font option passed to
configureNeetoUI, and move styles that hardcode "SFProText-*" names to
theme.fonts.
Tablet layout
The pieces a two- or three-pane tablet shell is built from. The shell itself, its navigation and any persisted widths stay in the app.
useTabletLayout()returns{ width, height, isTablet, isLandscape }.isTabletis true when the window's short side is at leastTABLET_MIN_SHORT_SIDE(600dp), so a landscape phone stays on the phone layout.isTabletWindow({ width, height })is the same check for use outside a component.NavRailis the icon rail:links({ key, label, Icon, activeOn? }),activeRoute,onNavigate, plusheaderandfooterslots.NavRailItemframes a footer slot; give itonPressfor a button, or leave it off to wrap content that handles its own press.ResizeHandledrags the column to its left. The parent owns the width as a reanimated shared value and sizes itsAnimated.Viewfrom it; the handle callsonCommitwith the settled width andonReseton a double tap. PassaccessibilityValue({ min, max, now }) so screen readers can read the width; they adjust it in 20pt steps.clampListWidthkeeps a width insideLIST_WIDTH_RANGEand is a worklet.CenteredSheetshows a phone screen as aCENTERED_SHEET_WIDTHcard over the pane, with a scrim that callsonClose. Name it withaccessibilityLabel.
Constants: RAIL_WIDTH, LIST_WIDTH_DEFAULT, LIST_WIDTH_RANGE,
RESIZE_HANDLE_WIDTH, CENTERED_SHEET_WIDTH, TABLET_MIN_SHORT_SIDE.
react-native-safe-area-context
We are using SafeAreaView from
react-native-safe-area-context
in our ParentView component to handle safe area. Follow the instructions under
SafeAreaProvider for the ParentView component to work.
SafeAreaProvider
You should add SafeAreaProvider in your app root component. You may need to
add it in other places like the root of modals and routes when using
react-native-screens.
Note that providers should not be inside a View that is animated with
Animated or inside a ScrollView since it can cause very frequent updates.
Example
import { SafeAreaProvider } from "react-native-safe-area-context";
function App() {
return <SafeAreaProvider>...</SafeAreaProvider>;
}
Development
Install all the dependencies by executing following command.
yarn
New components go in src/components/<Name>/, are exported from src/index.ts,
and carry a colocated <Name>.stories.tsx plus __tests__/.
| Task | Command |
|---|---|
| Storybook (web) | yarn storybook |
| Build Storybook | yarn build-storybook |
| Tests | yarn test |
| Types | yarn typecheck |
| Lint | yarn lint |
| On-device harness | see example/ |
yarn build-storybook writes static files to storybook-static/.
Auto Publish to NPM
neetoUI-RN version gets patched, auto-incremented and auto-published to npm on
new commit to main branch. You can checkout the publish workflow in Github
actions to get a live update.
Testing with yalc package manager
To publish locally
yarn build && rm -rf ~/.yalc/packages && yalc publish --private
or
yarn yalc:publish
To install local yalc version of library in any app.
rm -rf .yalc && yalc add @bigbinary/neetoui-rn && rm -rf node_modules && yarn
Learn more about contributing to this repository
https://github.com/bigbinary/neeto-ui-rn/blob/main/CONTRIBUTING.md