react-native-guidelines — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited react-native-guidelines (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
This skill provides conventions for React Native/Expo mobile development.
useMemo, useCallback, or React.memoapps/mobile/src/
├── components/
│ ├── ui/ # Design system primitives (Button, Input, Card, etc.)
│ │ └── [ComponentName]/
│ │ ├── [ComponentName].tsx
│ │ ├── [ComponentName].test.tsx
│ │ ├── [ComponentName].stories.tsx
│ │ └── index.ts
│ └── common/ # Shared business components (Avatar, MessageBubble, etc.)
├── features/ # Feature-specific code
│ └── [feature-name]/
│ ├── components/
│ ├── hooks/
│ └── screens/
├── hooks/ # App-wide shared hooks
├── screens/ # Top-level screens (navigation entry points)
└── lib/ # Utilities, constants, typesEvery component must be a folder with:
ComponentName.tsx - ImplementationComponentName.test.tsx - Unit tests (required)ComponentName.stories.tsx - Storybook story (required for ui/common)index.ts - Barrel exportimport { View, Text, Pressable } from 'react-native';
export interface ButtonProps {
label: string;
onPress: () => void;
variant?: 'primary' | 'secondary';
disabled?: boolean;
}
export function Button({ label, onPress, variant = 'primary', disabled = false }: ButtonProps) {
return (
<Pressable
className={`px-4 py-2 rounded-lg ${variant === 'primary' ? 'bg-accent' : 'bg-background'} ${disabled ? 'opacity-50' : ''}`}
onPress={onPress}
disabled={disabled}
>
<Text className={`text-center font-medium ${variant === 'primary' ? 'text-background' : 'text-foreground'}`}>
{label}
</Text>
</Pressable>
);
}index.ts)export { Button } from './Button';
export type { ButtonProps } from './Button';[ComponentName]Props and exportedUse uniwind (NativeWind) classes only. StyleSheet.create() is FORBIDDEN.
| Rule | Status |
|---|---|
| Use uniwind className prop | Required |
| Inline classNames | Required |
| Use theme colors | Required |
| StyleSheet.create() | Forbidden |
| Inline style prop | Forbidden (except dynamic values) |
| Hardcoded color values | Forbidden |
Colors must come from theme in global.css:
| Class | Usage |
|---|---|
bg-background / text-background | Main background |
bg-foreground / text-foreground | Main text |
bg-accent / text-accent | Accent/highlight |
Never use hardcoded colors like bg-white, text-black, bg-blue-500.
<View className="flex-1 bg-background p-4">
<Text className="text-lg font-bold text-foreground">Title</Text>
</View>// Hardcoded colors
<View className="bg-white">
// StyleSheet.create
const styles = StyleSheet.create({ container: { flex: 1 } });
// Inline style
<View style={{ flex: 1, backgroundColor: 'white' }} />| Hook Type | Location |
|---|---|
| Component-specific | Inside component folder |
| Feature-shared | features/[feature]/hooks/ |
| App-wide | hooks/ |
export interface UseAuthReturn {
user: User | null;
login: (email: string, password: string) => Promise<void>;
isLoading: boolean;
}
export function useAuth(): UseAuthReturn {
// implementation
}import { render, screen, fireEvent } from '@testing-library/react-native';
import { Button } from './Button';
describe('Button', () => {
it('renders label correctly', () => {
render(<Button label="Click me" onPress={() => {}} />);
expect(screen.getByText('Click me')).toBeOnTheScreen();
});
it('calls onPress when pressed', () => {
const onPress = jest.fn();
render(<Button label="Click me" onPress={onPress} />);
fireEvent.press(screen.getByText('Click me'));
expect(onPress).toHaveBeenCalledTimes(1);
});
});# .maestro/flows/auth/login.yaml
appId: com.sunsay.attune
---
- launchApp
- tapOn: "Email"
- inputText: "[email protected]"
- tapOn: "Sign In"
- assertVisible: "Welcome"Required for ui/ and common/ components:
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
title: 'ui/Button',
component: Button,
args: {
label: 'Button',
onPress: () => console.log('pressed'),
},
};
export default meta;
type Story = StoryObj<typeof Button>;
export const Primary: Story = { args: { variant: 'primary' } };
export const Disabled: Story = { args: { disabled: true } };| Item | Convention | Example |
|---|---|---|
| Component folder | PascalCase | Button/ |
| Component file | PascalCase | Button.tsx |
| Hook file | camelCase | useAuth.ts |
| Feature folder | kebab-case | features/user-profile/ |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.