@mallardbay/cursor-rules 1.0.29 → 1.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Defines best practices for building consistent, maintainable, and library-agnostic UI in Mallard Bay React Native projects
|
|
3
|
+
globs:
|
|
4
|
+
alwaysApply: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# UI Development Standards (React Native)
|
|
8
|
+
|
|
9
|
+
## Component Abstraction Layer
|
|
10
|
+
|
|
11
|
+
The mobile app uses NativeBase under the hood, but **all UI primitives must be accessed through custom wrapper components**. This abstraction enables switching to a different component library (e.g., Gluestack, Tamagui) with minimal churn.
|
|
12
|
+
|
|
13
|
+
### Import Rules
|
|
14
|
+
|
|
15
|
+
- **Never import directly from `native-base`** in feature code — always use the project's custom wrapper components
|
|
16
|
+
- **Never import from `~components/shared/ui`** — use the abstraction layer instead
|
|
17
|
+
- Wrapper components live in a dedicated directory (e.g., `src/components/primitives/` or the project's established equivalent)
|
|
18
|
+
- Only the wrapper component files themselves may import from `native-base`
|
|
19
|
+
|
|
20
|
+
### Wrapper Component Guidelines
|
|
21
|
+
|
|
22
|
+
- Each wrapper should expose a **stable, minimal API** — only pass through props the project actually uses
|
|
23
|
+
- Use TypeScript interfaces for wrapper props rather than re-exporting the library's prop types
|
|
24
|
+
- Keep wrappers thin — they should delegate to the underlying library, not add business logic
|
|
25
|
+
- Name wrappers after their semantic purpose (e.g., `AppText`, `AppButton`, `AppBox`) or match the library's naming if there's no ambiguity
|
|
26
|
+
- Document any NativeBase-specific behavior the wrapper intentionally hides or transforms
|
|
27
|
+
|
|
28
|
+
### Example Pattern
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
// src/components/primitives/AppButton.tsx — ✅ Correct
|
|
32
|
+
import { Button as NativeBaseButton } from "native-base"
|
|
33
|
+
|
|
34
|
+
export default function AppButton(props: AppButtonProps) {
|
|
35
|
+
return <NativeBaseButton {...props} />
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/features/booking/BookingCard.tsx — ✅ Correct
|
|
39
|
+
import AppButton from "~components/primitives/AppButton"
|
|
40
|
+
|
|
41
|
+
// src/features/booking/BookingCard.tsx — ❌ Wrong
|
|
42
|
+
import { Button } from "native-base"
|
|
43
|
+
import { Button } from "~components/shared/ui"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Theme Usage
|
|
47
|
+
|
|
48
|
+
Use theme values consistently across all components:
|
|
49
|
+
|
|
50
|
+
### Colors
|
|
51
|
+
|
|
52
|
+
- Use theme colors instead of hardcoded values
|
|
53
|
+
- Example: `theme.colors.primary[500]` instead of `'#3B82F6'`
|
|
54
|
+
|
|
55
|
+
### Spacing
|
|
56
|
+
|
|
57
|
+
- Use theme spacing values for margins and padding
|
|
58
|
+
- Example: `theme.space[4]` instead of numeric literals
|
|
59
|
+
|
|
60
|
+
### Typography
|
|
61
|
+
|
|
62
|
+
- Use theme typography settings for text styles
|
|
63
|
+
- Example: `theme.fontSizes.md` instead of hardcoded numbers
|
|
64
|
+
|
|
65
|
+
## Component Structure
|
|
66
|
+
|
|
67
|
+
Maintain clean and consistent component structure:
|
|
68
|
+
|
|
69
|
+
### Nesting
|
|
70
|
+
|
|
71
|
+
- Limit component nesting to maximum depth of 3
|
|
72
|
+
- Keep component hierarchy readable and maintainable
|
|
73
|
+
|
|
74
|
+
### Inline Styles
|
|
75
|
+
|
|
76
|
+
- Limit inline styles to maximum of 2 per component
|
|
77
|
+
- Prefer theme-based styling and style props
|
|
78
|
+
|
|
79
|
+
### Component Library
|
|
80
|
+
|
|
81
|
+
- Use the project's custom wrapper components (abstraction layer) for all UI primitives
|
|
82
|
+
- If a wrapper doesn't exist yet for a NativeBase component you need, create one in the primitives directory following the established pattern
|
|
83
|
+
- Keep wrapper components minimal and focused on API stability
|
|
84
|
+
|
|
85
|
+
## Platform Considerations
|
|
86
|
+
|
|
87
|
+
### React Native Specifics
|
|
88
|
+
|
|
89
|
+
- Use `StyleSheet.create` or NativeBase style props — avoid inline object styles
|
|
90
|
+
- Prefer `FlatList` / `SectionList` over mapping arrays for long lists
|
|
91
|
+
- Use platform-specific extensions (`.ios.tsx`, `.android.tsx`) only when behavior genuinely diverges
|
|
92
|
+
- Test on both iOS and Android
|
|
93
|
+
|
|
94
|
+
### Navigation
|
|
95
|
+
|
|
96
|
+
- Follow the project's established navigation patterns (React Navigation or equivalent)
|
|
97
|
+
- Keep screen components thin — delegate to feature components
|
|
98
|
+
|
|
99
|
+
### Performance
|
|
100
|
+
|
|
101
|
+
- Use `React.memo` for pure list item components
|
|
102
|
+
- Use `useCallback` for handlers passed to list items
|
|
103
|
+
- Use `useMemo` for expensive computations and filtered/sorted data
|
|
104
|
+
- Avoid anonymous functions in `renderItem` and event handlers
|
|
105
|
+
- Minimize bridge crossings by batching state updates
|
|
106
|
+
|
|
107
|
+
## Rendering Optimization
|
|
108
|
+
|
|
109
|
+
- Optimize component rendering
|
|
110
|
+
- Avoid unnecessary re-renders
|
|
111
|
+
- Move function definitions outside components or use `useCallback` for event handlers
|
|
112
|
+
- Use `useCallback` for functions passed as props to child components
|
|
113
|
+
- Use `useMemo` for expensive computations and complex data transformations
|
|
114
|
+
- Memoize filtered, sorted, or mapped arrays to avoid recalculation on every render
|
|
115
|
+
|
|
116
|
+
## File Patterns
|
|
117
|
+
|
|
118
|
+
These rules apply to all TypeScript and TSX files in the project.
|
|
119
|
+
|
|
120
|
+
## Components
|
|
121
|
+
|
|
122
|
+
- Keep components small and focused on a single responsibility
|
|
123
|
+
- Use functional components with hooks instead of class components
|
|
124
|
+
- Prefer `export default function BookingCard() {` over `function BookingCard(): React.ReactElement | null {` when defining components
|
|
@@ -14,13 +14,7 @@ alwaysApply: false
|
|
|
14
14
|
- Functions: camelCase
|
|
15
15
|
- Constants: UPPER_SNAKE_CASE
|
|
16
16
|
- Types: PascalCase
|
|
17
|
-
-
|
|
18
|
-
1. Imports
|
|
19
|
-
2. Constants
|
|
20
|
-
3. Exported functions / components
|
|
21
|
-
4. Helpers and other non-exported definitions
|
|
22
|
-
5. Types (when not imported)
|
|
23
|
-
- Exported members always come before non-exported members
|
|
17
|
+
- Types should be defined at the bottom of files
|
|
24
18
|
- PropTypes should be defined before component definitions
|
|
25
19
|
- Prefer using alias for importing components. Only use relative for tests or when there's a direct sibling
|
|
26
20
|
|
|
@@ -53,14 +53,13 @@ We do not chase 100% coverage for its own sake. If a test doesn’t meaningfully
|
|
|
53
53
|
|
|
54
54
|
### Mocking Guidelines
|
|
55
55
|
|
|
56
|
-
-
|
|
56
|
+
- Use mock helpers instead of inline mocks
|
|
57
|
+
- Follow existing patterns for:
|
|
57
58
|
- Entity mocks
|
|
58
59
|
- Apollo mocks
|
|
59
60
|
- Provider mocks
|
|
60
|
-
- **Mock data through Apollo mocks, not module mocks**—use Apollo mock providers to control query/mutation responses instead of mocking modules or components directly
|
|
61
61
|
- Keep mocks simple and maintainable
|
|
62
62
|
- **Do not use variable matchers for Apollo mocks**—match exact variables (e.g. avoid `expect.anything()` or `variables: {}`) so tests fail when the component passes incorrect variables to queries or mutations
|
|
63
|
-
- **Never mock `@mallardbay/lib-react-components`**—if truly unavoidable, stop and ask for approval first
|
|
64
63
|
|
|
65
64
|
### Test Utilities
|
|
66
65
|
|
|
@@ -14,13 +14,7 @@ Be as strictly as possible where it delivers clear value—specifically in preve
|
|
|
14
14
|
|
|
15
15
|
### File Organization
|
|
16
16
|
|
|
17
|
-
-
|
|
18
|
-
1. Imports
|
|
19
|
-
2. Constants
|
|
20
|
-
3. Exported functions / components
|
|
21
|
-
4. Helpers and other non-exported definitions
|
|
22
|
-
5. Types (when not imported)
|
|
23
|
-
- Exported members always come before non-exported members
|
|
17
|
+
- Place types at the bottom of files
|
|
24
18
|
- Define PropTypes before component definitions
|
|
25
19
|
|
|
26
20
|
## Best Practices
|
package/bin/setup-cursor.sh
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# setup-cursor.sh — frontend
|
|
2
|
+
# setup-cursor.sh — frontend, frontend-lib, frontend-mobile & backend layering with shared base
|
|
3
3
|
# Also generates CLAUDE.md for Claude Code and AGENTS.md for Codex
|
|
4
4
|
|
|
5
5
|
set -e
|
|
@@ -65,6 +65,7 @@ fi
|
|
|
65
65
|
SHARED_DIR="$SRC_DIR/.cursor/shared/rules"
|
|
66
66
|
FRONTEND_DIR="$SRC_DIR/.cursor/frontend/rules"
|
|
67
67
|
FRONTEND_LIB_DIR="$SRC_DIR/.cursor/frontend-lib/rules"
|
|
68
|
+
FRONTEND_MOBILE_DIR="$SRC_DIR/.cursor/frontend-mobile/rules"
|
|
68
69
|
BACKEND_DIR="$SRC_DIR/.cursor/backend/rules"
|
|
69
70
|
SHARED_SKILLS_DIR="$SRC_DIR/.cursor/shared/skills"
|
|
70
71
|
|
|
@@ -215,6 +216,10 @@ case "$ENV_TYPE" in
|
|
|
215
216
|
append_to_md_files "$FRONTEND_DIR"
|
|
216
217
|
append_to_md_files "$FRONTEND_LIB_DIR"
|
|
217
218
|
;;
|
|
219
|
+
frontend-mobile)
|
|
220
|
+
copy_rules "$FRONTEND_MOBILE_DIR"
|
|
221
|
+
append_to_md_files "$FRONTEND_MOBILE_DIR"
|
|
222
|
+
;;
|
|
218
223
|
*)
|
|
219
224
|
echo "Unknown environment type: $ENV_TYPE"
|
|
220
225
|
exit 1
|