diff --git a/AGENTS.md b/AGENTS.md index 86a2fc02f..af8d32445 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -22,6 +22,7 @@ Detailed guides for specific subsystems live in `contrib/claude/`: - [`contrib/claude/agent.md`](contrib/claude/agent.md) — Agent orchestration framework (tools, handoffs, execution) - [`contrib/claude/app-arborescence.md`](contrib/claude/app-arborescence.md) — Frontend app folder layout (pages, routes at resource folders, loaders, skeletons, _components, _lib, _locales) - [`contrib/claude/relay.md`](contrib/claude/relay.md) — Frontend Relay client (queries, fragments, mutations, pagination) +- [`contrib/claude/hooks.md`](contrib/claude/hooks.md) — Custom hooks (_lib placement, awaitable useMutation primitive, auto error handling) - [`contrib/claude/react-components.md`](contrib/claude/react-components.md) — React component shape (file/export, props, configure vs data via hooks, naming/suffix taxonomy, error props) - [`contrib/claude/ui.md`](contrib/claude/ui.md) — @probo/ui v2 kit (Base UI headless, Tailwind, tailwind-variants, flat folders, bundle-safe skeletons) - [`contrib/claude/v2-tokens.md`](contrib/claude/v2-tokens.md) — v2 design tokens (color, typography, radius, shadow scales; native spacing) diff --git a/contrib/claude/forms.md b/contrib/claude/forms.md index 1441f001f..475fdcc24 100644 --- a/contrib/claude/forms.md +++ b/contrib/claude/forms.md @@ -32,8 +32,8 @@ Server-side errors map onto the `Form` `errors` prop in **every** tier (see [Ser Most forms need nothing more. Base UI validates native HTML constraints, and `` renders the message. Use `match` to supply your own copy (and i18n) per validity state. ```tsx -import { Form } from "@base-ui-components/react/form"; -import { Field } from "@base-ui-components/react/field"; +import { Form } from "@base-ui/react/form"; +import { Field } from "@base-ui/react/field"; import { useTranslation } from "react-i18next"; export function CreateMeasureForm({ onSubmit }: CreateMeasureFormProps) { @@ -78,7 +78,7 @@ Async `validate` (e.g. a uniqueness check) is supported; note Base UI does not b When validation is complex or needs specific messages, parse a zod schema in `onFormSubmit` and feed the flattened field errors to `Form`'s `errors` prop. This keeps a single typed schema as the source of truth **without** pulling in react-hook-form. ```tsx -import { Form } from "@base-ui-components/react/form"; +import { Form } from "@base-ui/react/form"; import { z } from "zod"; const schema = z.object({ diff --git a/contrib/claude/react-components.md b/contrib/claude/react-components.md index 4e45be935..af2754571 100644 --- a/contrib/claude/react-components.md +++ b/contrib/claude/react-components.md @@ -17,6 +17,7 @@ These rules are the **source of truth**. Where existing code (e.g. `apps/console | Routing, navigation, URL state, auth | [`contrib/claude/routing.md`](routing.md) | | Client state (Relay / URL / local / context / zustand) | [`contrib/claude/state-management.md`](state-management.md) | | Permission-gated UI | [`contrib/claude/permissions.md`](permissions.md) | +| Custom hooks, `_lib` placement, mutation hooks | [`contrib/claude/hooks.md`](hooks.md) | ## Destructuring diff --git a/contrib/claude/ui.md b/contrib/claude/ui.md index 6979ad5d6..71bc8fa02 100644 --- a/contrib/claude/ui.md +++ b/contrib/claude/ui.md @@ -22,11 +22,11 @@ These rules are the **source of truth**. The legacy tree (`Atoms/`, `Molecules/` | Styling | **Tailwind v4** with the Radix-scale tokens (`bg-sand-3`, `text-sand-12`, `rounded-3`, `text-4`, …). | | Variants API | **`tailwind-variants`** only — `import { tv } from "tailwind-variants"`. | | Class composition | **Do not use `clsx` or `tailwind-merge`.** All conditional styling goes through `tv` variants and slots. | -| Headless primitives | **Base UI** (`@base-ui-components/react`). We **style** these primitives; we do not re-implement their behavior. | +| Headless primitives | **Base UI** (`@base-ui/react`). We **style** these primitives; we do not re-implement their behavior. | Preview components with Storybook from `packages/ui`: `npm run dev` (Storybook on port 6006). -> Base UI is migrating its package name from `@base-ui-components/react` to `@base-ui/react`. Import from whichever name the installed version publishes; examples below use `@base-ui-components/react`. +> Base UI is published as `@base-ui/react` (the earlier `@base-ui-components/react` name is frozen at an RC — do not use it). Import parts from per-component subpaths, e.g. `@base-ui/react/dialog`. ## Headless primitives: style, don't re-implement @@ -57,7 +57,7 @@ export function Dialog({ trigger, ref, children }: Props) { ```tsx // Good — thin styling over Base UI; consumers use the lib's open/onOpenChange directly -import { Dialog as BaseDialog } from "@base-ui-components/react/dialog"; +import { Dialog as BaseDialog } from "@base-ui/react/dialog"; import { tv } from "tailwind-variants"; const dialog = tv({ @@ -457,13 +457,13 @@ const imageCard = tv({ slots: { shell: "...", image: "...", text: "..." } }); ## User feedback (toasts) -Transient feedback for an action's outcome uses **Base UI's Toast** (`@base-ui-components/react/toast`) — never `alert`, a hand-rolled banner, or a `console.log`. As with every other primitive, we **style** Base UI's toast; we do not build our own toast system. The legacy kit `useToast` / `Toaster` is non-compliant and is being removed — do not use it in v2. +Transient feedback for an action's outcome uses **Base UI's Toast** (`@base-ui/react/toast`) — never `alert`, a hand-rolled banner, or a `console.log`. As with every other primitive, we **style** Base UI's toast; we do not build our own toast system. The legacy kit `useToast` / `Toaster` is non-compliant and is being removed — do not use it in v2. The kit exposes a styled **`Toaster`** (a `Toast.Portal` + `Toast.Viewport` rendering styled `Toast.Root`s, keyed off each toast's `type`). Mount Base UI's `Toast.Provider` and the `Toaster` **once** at the app root; everything else queues toasts through Base UI's manager. ```tsx // app root — Base UI provider + the kit's styled viewport, mounted once -import { Toast } from "@base-ui-components/react/toast"; +import { Toast } from "@base-ui/react/toast"; import { Toaster } from "@probo/ui"; @@ -475,7 +475,7 @@ import { Toaster } from "@probo/ui"; Queue a toast with `Toast.useToastManager().add(...)` — the same API Base UI exposes. Use `type` to drive the styled variant. ```tsx -import { Toast } from "@base-ui-components/react/toast"; +import { Toast } from "@base-ui/react/toast"; function CreateMeasureButton() { const toast = Toast.useToastManager();