


Build a TypeScript App for Native and Web, Following the Repo's Rules
Use when working on a TypeScript app that runs on native and web. The AI follows the repo's scripts and folder layout, reuses shared components, marks on-screen text for translation, and tests every affected platform before finishing.
To use this AI rule
## Run Tests, Lint, and Builds Through the Repo's Scripts
Treat the package manifest and repository scripts as the source of truth for supported versions and commands. Prefer current supported APIs, and replace legacy or deprecated patterns when the affected scope makes that safe.
Use package-manager scripts for:
- starting the development server and each supported platform;
- unit tests, linting, type checking, and formatting;
- web builds and native-project generation.
Never invoke the underlying test, lint, type-check, or formatting tools directly when repository scripts exist. The scripts may supply configuration or preparation that direct commands omit.
Do not run localization extraction or compilation commands when CI owns those jobs. Add or update translatable source strings, then let the scheduled pipeline update catalogs and runtime translations.
Before changing code, identify the target platforms, the canonical script for verification, and whether generated artifacts are owned locally or by automation.
## Put New Screens and Components in the Right Folders
Place shared, platform-neutral UI elements in `components`. Place full-page routes in `screens`. Use `features` for larger capabilities that combine context, data access, components, and utilities across multiple screens.
For a complex screen with private components or state, create a screen directory and co-locate those dependencies. Do not promote code to a shared folder until more than one consumer needs it.
Keep server-state hooks, simple UI preferences, session state, and persistence in clear state modules, or co-locate feature-specific state with its consumer. Avoid large files that mix unrelated responsibilities.
Use `lib` for reusable utilities, API clients, formatters, and constants that do not belong to a feature. Avoid adding new top-level source directories when an established responsibility already fits.
Do not add new work to legacy view directories. Preserve existing legacy code unless migration is part of the task, but put new screens, components, and features in the current structure.
Use PascalCase for component names and camelCase for ordinary files, directories, variables, and functions. A substantial module may use an `index.tsx` entry with sibling components, hooks, and utilities; keep a small component in one file.
Co-locate optional feature documentation and tests with larger modules. Write comments to explain why a decision exists, not what the code already states. Use docblocks for named declarations, block comments for multiline explanations, and line comments only for short notes.
## Build the UI With the Design System and Existing Components
Use the established design system before creating raw styles or duplicate components. Combine theme-independent atoms, theme atoms, and exceptional raw styles in that order:
1. flex and layout atoms;
2. spacing atoms;
3. typography atoms;
4. theme colors and surfaces;
5. narrowly scoped raw styles.
Use platform style utilities for conditional styling and breakpoint hooks for responsive layout. Keep platform conditions inside style composition rather than scattering them through component logic.
Before creating a control, search the shared component library for a suitable button, dialog, menu, text field, or typography primitive. Follow its compound API and existing canonical usages.
For component declarations:
- prefer fragment shorthand unless a keyed fragment is required;
- prefer function declarations;
- destructure props in the parameter list;
- use explicit inline prop types when they remain readable;
- give optional props reasonable defaults;
- keep reusable components platform-neutral when possible.
Use uncontrolled text fields with `defaultValue` when the platform architecture performs poorly with controlled input. Use controlled values only when the behavior truly requires them.
User-generated text may contain emoji even when examples do not. Enable the typography system's emoji-safe behavior for user content and omit it only for known static text.
## Mark Every On-Screen String for Translation
Wrap every user-facing string with the project's translation macro or translation component. Add translator comments or context when a word has multiple meanings, such as a noun and verb sharing one spelling.
Use the modern macro entry point supported by the translation framework. Alias its translation function when another subsystem, such as theming, already uses the same short variable name.
Use the translation framework's pluralization features for counts and its date formatter for dates and times. Framework formatting must rerun when the active language changes; direct locale formatting often does not.
Prefer typographically correct Unicode punctuation in user-facing text. Apply the project's punctuation conventions consistently, including quotation marks and dash spacing.
Do not hand-edit generated locale output, and do not run CI-owned extraction or compilation tasks locally. Source changes should contain the wrapped messages and enough context for accurate translation.
## Handle Server Data, Navigation, and Platform-Specific Files
Use the established server-state query library for remote data and context-style state for simple UI preferences. Expose preferences through paired read and update hooks.
Build query keys with the shared key helper and an object of arguments. The key root should match the hook name. Use consistent names for query hooks, mutation hooks, and cache-only mutation helpers.
Choose stale times from shared constants. For cursor pagination, use an infinite query, return the response cursor as the next-page parameter, and flatten pages only at the consumption boundary.
When persisted query data changes shape, increment its persisted version so stale serialized data is discarded and refetched.
For mutation failures:
- inform users about expected network failures without duplicating them in error logs;
- handle typed protocol or API errors explicitly;
- send unexpected failures to structured logging with a safe message.
Use typed route parameters and the project's navigation helper or hook. Keep route configuration, route definitions, and route types synchronized.
Represent platform implementations with filename suffixes such as `.web`, `.native`, `.ios`, and `.android`. Import the base module path and let the bundler select the implementation. Never use conditional runtime imports to choose platform files.
Prefer grouping platform variants behind one module directory. Use runtime platform flags only for behavior, not module resolution. Use the repository's absolute import alias instead of deep relative traversal.
## Avoid Dialog-Close Timing Bugs and Needless Memoization
Run every action that must occur after a dialog closes inside the dialog control's close callback. Closing first and then immediately navigating, opening another overlay, updating affected state, or invoking a parent callback can race the close animation.
The required sequence is:
1. call the close method;
2. provide a callback to that method;
3. perform navigation, overlay opening, state updates, or parent callbacks inside it.
Respect platform-specific compound components. A dialog handle or menu container item may be native-only, while a close control or menu divider may be web-only. Test the platforms that exercise each branch.
When automatic compiler memoization is enabled, do not add `useMemo` or `useCallback` preemptively. Use them only for a concrete referential-stability requirement, such as an effect dependency or a non-React library contract.
Do not trade readability for speculative optimization. Measure a real issue or satisfy an explicit stability requirement before adding manual memoization.
## Test Every Affected Platform Before Calling the Work Done
Before completion:
1. confirm every interactive element has an accessible label and useful hint where needed;
2. confirm all user-facing strings are localized and ambiguous messages include context;
3. verify styling uses design-system atoms, theme values, and platform utilities consistently;
4. verify server state, UI preferences, and session state use their intended mechanisms;
5. confirm an existing shared component was not duplicated;
6. confirm props and route parameters have explicit types;
7. expose stable test identifiers where end-to-end tests need them;
8. run the repository scripts for tests, linting, type checking, and formatting;
9. test all affected native and web behaviors.
Review the diff for new legacy-directory usage, conditional platform imports, direct edits to generated localization files, uncontrolled-versus-controlled input regressions, and post-dialog race conditions.
Report any platform or canonical script that could not run, including the missing prerequisite. Do not claim cross-platform completion from a single-platform check.
