Files
esign/.cursorrules
T
zeekay 76ce46705f ui: confine the Radix substrate to packages/ui and drop the dead shadcn copies
Radix was leaking out of the primitive layer into application code. Thirty
dialog components under apps/remix imported `@radix-ui/react-dialog` purely to
spell `Omit<DialogPrimitive.DialogProps, 'children'>`, and two more imported
`TooltipArrow` directly. Each of those is a place the UI substrate has to be
swapped when it changes, for no gain — the app never touched Radix behaviour,
only a type and one arrow element.

`packages/ui/primitives/dialog.tsx` now exports `DialogProps` and
`tooltip.tsx` exports `TooltipArrow`, so callers name the primitive, not the
library behind it. Radix imports outside packages/ui: 32 -> 0.

Eleven vendored shadcn primitives had no importers at all — aspect-ratio,
auto-sized-text, calendar, collapsible, context-menu, menubar,
navigation-menu, slider, toggle, a stray document-flow dialog and a
signature-pad Canvas class shadowed by skia-canvas. Dead component code reads
as supported API in review, so it is deleted rather than carried. That
retires eight Radix packages plus react-day-picker from packages/ui and
@radix-ui/react-tabs from apps/docs, which was declared and never imported:
28 declared Radix packages -> 19.

The embedding doc taught Tailwind classes in a snippet third parties copy into
their own apps; it now uses the same inline styles as the plain-HTML example
directly above it. `.cursorrules` told every AI touching this repo to write
"Shadcn UI, Radix, and Tailwind Aria" — it now points at @hanzo/gui and says
the inherited layer is to be replaced, not extended.

Verified: apps/remix typecheck 0 errors, client+server build green,
prisma 38/38.
2026-08-13 12:04:22 -07:00

83 lines
3.6 KiB
Plaintext

You are an expert in TypeScript, Node.js, Remix, React and @hanzo/gui.
Code Style and Structure:
- Write concise, technical TypeScript code with accurate examples
- Use functional and declarative programming patterns; avoid classes
- Prefer iteration and modularization over code duplication
- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
- Structure files: exported component, subcomponents, helpers, static content, types
Naming Conventions:
- Use lowercase with dashes for directories (e.g., components/auth-wizard)
- Favor named exports for components
TypeScript Usage:
- Use TypeScript for all code; prefer types over interfaces
- Use functional components with TypeScript interfaces
Syntax and Formatting:
- Create functions using `const fn = () => {}`
- Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements
- Use declarative JSX
- Never use 'use client'
- Never use 1 line if statements
Error Handling and Validation:
- Prioritize error handling: handle errors and edge cases early
- Use early returns and guard clauses
- Implement proper error logging and user-friendly messages
- Use Zod for form validation
- Model expected errors as return values in Server Actions
- Use error boundaries for unexpected errors
UI and Styling:
- @hanzo/gui is the only UI framework. It compiles to React Native, so the same
components run on web, iOS and Android. Do not add Tailwind classes, Radix
primitives, shadcn copies or any other UI library — each of those is DOM-only
and caps the app at the browser.
- Express layout and appearance as style props on @hanzo/ui / @hanzo/gui
components, never as class strings.
- packages/ui still carries a shadcn/Radix/Tailwind layer inherited from
upstream. It is being replaced, not extended: reuse what is there, add nothing
new to it.
- When using Lucide icons, prefer the longhand names, for example HomeIcon instead of Home
React forms
- Use zod for form validation react-hook-form for forms
- Look at TeamCreateDialog.tsx as an example of form usage
- Use <Form> <FormItem> elements, and also wrap the contents of form in a fieldset which should have the :disabled attribute when the form is loading
TRPC Specifics
- Every route should be in it's own file, example routers/teams/create-team.ts
- Every route should have a types file associated with it, example routers/teams/create-team.types.ts. These files should have the OpenAPI meta, and request/response zod schemas
- The request/response schemas should be named like Z[RouteName]RequestSchema and Z[RouteName]ResponseSchema
- Use create-team.ts and create-team.types.ts as an example when creating new routes.
- When creating the OpenAPI meta, only use GET and POST requests, do not use any other REST methods
- Deconstruct the input argument on it's one line of code.
Toast usage
- Use the t`string` macro from @lingui/react/macro to display toast messages
Remix/ReactRouter Usage
- Use (params: Route.Params) to get the params from the route
- Use (loaderData: Route.LoaderData) to get the loader data from the route
- When using loaderdata, deconstruct the data you need from the loader data inside the function body
- Do not use json() to return data, directly return the data
Translations
- Use <Trans>string</Trans> to display translations in jsx code, this should be imported from @lingui/react/macro
- Use the t`string` macro from @lingui/react/macro to display translations in typescript code
- t should be imported as const { t } = useLingui() where useLingui is imported from @lingui/react/macro
- String in constants should be using the t`string` macro