Skip to content

Mobile Tokens

Token mapping for React Native / NativeWind mobile applications (stock-app-mobile, customer-app, buyer-app).

NativeWind / Tailwind Config

The mobile apps use NativeWind (Tailwind CSS for React Native). Add these to tailwind.config.js:

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './app/**/*.{ts,tsx}',
    './components/**/*.{ts,tsx}',
  ],
  presets: [require('nativewind/preset')],
  theme: {
    extend: {
      colors: {
        brand: {
          DEFAULT: '#2D6B4A',
          hover: '#245A3E',
          light: '#E8F0EC',
          subtle: '#F0F5F2',
        },
        success: '#2D7D46',
        warning: '#D4910A',
        danger: {
          DEFAULT: '#C4463A',
          light: '#FCEAE8',
        },
        info: '#2563EB',
        surface: {
          body: '#FAFAF7',
          card: '#FFFFFF',
          inset: '#F3F1EC',
          hover: '#EDEAE3',
        },
        border: {
          DEFAULT: '#E5E2DB',
          strong: '#D4D0C8',
        },
        text: {
          1: '#1A1816',
          2: '#57534E',
          3: '#A8A29E',
        },
      },
      fontFamily: {
        sans: ['PlusJakartaSans-Regular'],
        'sans-medium': ['PlusJakartaSans-Medium'],
        'sans-semibold': ['PlusJakartaSans-SemiBold'],
        'sans-bold': ['PlusJakartaSans-Bold'],
        display: ['Lora-Regular'],
        'display-italic': ['Lora-Italic'],
        mono: ['JetBrainsMono-Regular'],
        'mono-medium': ['JetBrainsMono-Medium'],
        'mono-semibold': ['JetBrainsMono-SemiBold'],
        'mono-bold': ['JetBrainsMono-Bold'],
      },
      borderRadius: {
        sm: 4,
        md: 8,
        lg: 12,
        xl: 16,
        '2xl': 20,
      },
    },
  },
  plugins: [],
}

StyleSheet Constants

For cases where NativeWind is not used (e.g., animated components, third-party library styling):

ts
import { StyleSheet, Platform } from 'react-native'

export const BumiColors = {
  brand: '#2D6B4A',
  brandHover: '#245A3E',
  brandLight: '#E8F0EC',

  success: '#2D7D46',
  warning: '#D4910A',
  danger: '#C4463A',
  dangerLight: '#FCEAE8',
  info: '#2563EB',

  bgBody: '#FAFAF7',
  bgCard: '#FFFFFF',
  bgInset: '#F3F1EC',
  bgHover: '#EDEAE3',

  border: '#E5E2DB',
  borderStrong: '#D4D0C8',

  text1: '#1A1816',
  text2: '#57534E',
  text3: '#A8A29E',
} as const

export const BumiSpacing = {
  xs: 4,
  sm: 8,
  md: 12,
  base: 16,
  lg: 20,
  xl: 24,
  '2xl': 32,
  '3xl': 40,
  '4xl': 48,
} as const

export const BumiRadius = {
  sm: 4,
  md: 8,
  lg: 12,
  xl: 16,
  '2xl': 20,
  full: 9999,
} as const

export const BumiTypography = StyleSheet.create({
  heading1: {
    fontFamily: 'Lora-Regular',
    fontSize: 28,
    lineHeight: 34,
    color: BumiColors.text1,
  },
  heading2: {
    fontFamily: 'PlusJakartaSans-Bold',
    fontSize: 20,
    lineHeight: 28,
    color: BumiColors.text1,
  },
  heading3: {
    fontFamily: 'PlusJakartaSans-SemiBold',
    fontSize: 16,
    lineHeight: 24,
    color: BumiColors.text1,
  },
  body: {
    fontFamily: 'PlusJakartaSans-Regular',
    fontSize: 14,
    lineHeight: 22,
    color: BumiColors.text1,
  },
  bodySmall: {
    fontFamily: 'PlusJakartaSans-Regular',
    fontSize: 13,
    lineHeight: 20,
    color: BumiColors.text2,
  },
  label: {
    fontFamily: 'PlusJakartaSans-SemiBold',
    fontSize: 11,
    lineHeight: 16,
    letterSpacing: 0.5,
    textTransform: 'uppercase',
    color: BumiColors.text2,
  },
  mono: {
    fontFamily: 'JetBrainsMono-Regular',
    fontSize: 13,
    lineHeight: 20,
    color: BumiColors.text1,
  },
  monoBold: {
    fontFamily: 'JetBrainsMono-SemiBold',
    fontSize: 13,
    lineHeight: 20,
    color: BumiColors.text1,
  },
})

export const BumiShadows = Platform.select({
  ios: {
    sm: { shadowColor: '#1C1A14', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.06, shadowRadius: 3 },
    md: { shadowColor: '#1C1A14', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.06, shadowRadius: 6 },
    lg: { shadowColor: '#1C1A14', shadowOffset: { width: 0, height: 10 }, shadowOpacity: 0.06, shadowRadius: 15 },
  },
  android: {
    sm: { elevation: 2 },
    md: { elevation: 4 },
    lg: { elevation: 8 },
  },
})

Expo-Specific Values

ts
import { Platform, StatusBar } from 'react-native'
import Constants from 'expo-constants'

export const BumiLayout = {
  /** Safe area top inset (notch + status bar) */
  safeAreaTop: Constants.statusBarHeight ?? 0,

  /** Bottom tab bar height including safe area */
  tabBarHeight: Platform.select({ ios: 83, android: 64 }) ?? 64,

  /** Standard header height */
  headerHeight: 56,

  /** Bottom sheet handle area height */
  sheetHandleHeight: 32,

  /** Minimum touch target (WCAG) */
  minTouchTarget: 44,

  /** Screen horizontal padding */
  screenPadding: 16,

  /** Card content padding */
  cardPadding: 16,

  /** Status bar style */
  statusBarStyle: 'dark-content' as const,
} as const

Font Loading (Expo)

ts
import { useFonts } from 'expo-font'

export function useLoadFonts() {
  const [loaded] = useFonts({
    'PlusJakartaSans-Regular': require('../assets/fonts/PlusJakartaSans-Regular.ttf'),
    'PlusJakartaSans-Medium': require('../assets/fonts/PlusJakartaSans-Medium.ttf'),
    'PlusJakartaSans-SemiBold': require('../assets/fonts/PlusJakartaSans-SemiBold.ttf'),
    'PlusJakartaSans-Bold': require('../assets/fonts/PlusJakartaSans-Bold.ttf'),
    'PlusJakartaSans-ExtraBold': require('../assets/fonts/PlusJakartaSans-ExtraBold.ttf'),
    'Lora-Regular': require('../assets/fonts/Lora-Regular.ttf'),
    'Lora-Italic': require('../assets/fonts/Lora-Italic.ttf'),
    'JetBrainsMono-Regular': require('../assets/fonts/JetBrainsMono-Regular.ttf'),
    'JetBrainsMono-Medium': require('../assets/fonts/JetBrainsMono-Medium.ttf'),
    'JetBrainsMono-SemiBold': require('../assets/fonts/JetBrainsMono-SemiBold.ttf'),
    'JetBrainsMono-Bold': require('../assets/fonts/JetBrainsMono-Bold.ttf'),
  })
  return loaded
}

Font files

Font files should be placed in assets/fonts/ at the app root. Download from Google Fonts and include the specific weights listed above.

React Native specifics

  • React Native does not support CSS font-weight natively --- use separate font family names for each weight
  • letterSpacing in React Native uses absolute pixels, not em units
  • textTransform is supported but may behave differently on Android

RetailOS - Sistem ERP Retail Modern untuk Indonesia