From 70634c01781e73a1650d1e2ec76b7ca75aae92ed Mon Sep 17 00:00:00 2001 From: Oliver Lazoroski Date: Wed, 1 Jul 2026 10:09:30 +0200 Subject: [PATCH 1/7] refactor(stream-react): migrate to live-docs orchestrator + custom-ui contract Complete stream-react's transition from bundled blueprints to the PR #24 live-docs pattern, add the bespoke-UI completion contract, and remove the Task A.2 frontend-skill install gate. - docs-map.md (was DOCS.md): teach the .md-twin convention + per-product live CLI index + URL-grounding rule so the router self-heals instead of rotting; fix a stale Feeds quick-start path. - custom-ui.md (new): prebuilt-vs-bespoke rubric, headless Chat/Video path, route-to-live table, and a REQUIRED completion contract (reproduce / N/A-with-design-reason / GAP) that stops custom rows from silently dropping attachments, reactions, quoted replies, receipts, threads. - Router fix: writing your own component for a prebuilt region now loads custom-ui.md first (RULES/docs-map/SKILL), even via Message=/WithComponents. - Surgical blueprint trim: CHAT -688, VIDEO -473 (drop doc-mirror; keep the canonical provider trees + prebuilt happy path). Light trims to CHAT/VIDEO. - Remove Task A.2: stream-react no longer installs third-party frontend skills or prompts for consent; uses them only if already present. stream-builder retains A.2 (divergence documented in RULES.md). Validated RED->GREEN with subagent pressure tests (custom-row completeness, routing reachability, N/A-loophole). ASCII-clean. --- skills/stream-react/RULES.md | 19 +- skills/stream-react/SKILL.md | 41 +- skills/stream-react/builder-ui.md | 8 +- skills/stream-react/enhance.md | 4 +- skills/stream-react/migrate.md | 4 +- .../references/CHAT-blueprints.md | 688 +----------------- skills/stream-react/references/CHAT.md | 13 +- .../references/FEEDS-blueprints.md | 2 +- .../references/VIDEO-blueprints.md | 473 +----------- skills/stream-react/references/VIDEO.md | 13 +- skills/stream-react/references/custom-ui.md | 158 ++++ .../references/{DOCS.md => docs-map.md} | 50 +- 12 files changed, 244 insertions(+), 1229 deletions(-) create mode 100644 skills/stream-react/references/custom-ui.md rename skills/stream-react/references/{DOCS.md => docs-map.md} (81%) diff --git a/skills/stream-react/RULES.md b/skills/stream-react/RULES.md index 6581e7f..634707d 100644 --- a/skills/stream-react/RULES.md +++ b/skills/stream-react/RULES.md @@ -70,9 +70,14 @@ docs/cookbooks are built around customizing them. Default to that path: **Customize via the documented hooks/props** (e.g. ``, `useChannelStateContext()`, `useMessageContext()`, `useCallStateHooks()`, `` theming) - -fetch the matching docs page first (see Docs-first below). **Hand-build raw markup ONLY when the -user explicitly asks for fully bespoke UI**; in that case use the `references/*-blueprints.md` -"Fully custom UI" fallback section (raw element structure + wiring tables) - still docs-first. +fetch the matching docs page first (see Docs-first below). + +**Writing your OWN component for a prebuilt region triggers [`references/custom-ui.md`](references/custom-ui.md) - load it BEFORE you build.** This is the predicate, and it is easy to get wrong: + +- **Passing props / theme** to a prebuilt component (a cookbook recipe's prop, `` theme tokens) -> just fetch the page. +- **Writing your own component/markup for a region** - a custom message row / `MessageUI`, a custom composer, a custom channel preview or header, a custom call layout - **load `custom-ui.md` first, then fetch the page.** This holds **even when you wire it via the documented `Message=` / `WithComponents` prop**, and it is **not** limited to a "fully bespoke app". + +Why: replacing a prebuilt region means you inherit every sub-feature it rendered. `custom-ui.md` carries the **completion contract** (reproduce-or-mark-`N/A`: attachments, reactions, quoted replies, receipts, threads, edited/deleted, grouping) that stops a custom row from silently dropping them. Still docs-first either way. **Reference files are the source of truth for the components they document** - which prebuilt component to use, its props, SDK wiring, and property paths. Do not generate Stream SDK code from @@ -86,11 +91,11 @@ and memory - fetch it. ## Docs-first for cookbook / advanced features -**Before implementing any feature that matches a UI component, UI Cookbook, or Advanced Guide topic, fetch the matching Stream docs page first.** [`references/DOCS.md`](references/DOCS.md) holds the keyword -> page map and the protocol. The bundled `references/*-blueprints.md` cover the common path; component-reference and cookbook/advanced topics - the prebuilt component props, typing indicator, custom message UI, message actions, reactions, message composer / input UI, channel header, emoji picker, autocomplete, link previews, AI integrations, advanced search, multiple lists, infinite scroll, channel read state, online status, location sharing, blocking users, message reminders, notifications, attachment previews, audio playback, date/time formatting, SDK state management, dialog management, TypeScript custom data types, chat + video integration, call layouts, PiP, network quality, livestream watching, recording, broadcasting - change often and **must** be built from the current page, not memory. +**Before implementing any feature that matches a UI component, UI Cookbook, or Advanced Guide topic, fetch the matching Stream docs page first.** [`references/docs-map.md`](references/docs-map.md) holds the keyword -> page map and the protocol. The bundled `references/*-blueprints.md` cover the common path; component-reference and cookbook/advanced topics - the prebuilt component props, typing indicator, custom message UI, message actions, reactions, message composer / input UI, channel header, emoji picker, autocomplete, link previews, AI integrations, advanced search, multiple lists, infinite scroll, channel read state, online status, location sharing, blocking users, message reminders, notifications, attachment previews, audio playback, date/time formatting, SDK state management, dialog management, TypeScript custom data types, chat + video integration, call layouts, PiP, network quality, livestream watching, recording, broadcasting - change often and **must** be built from the current page, not memory. -**This rule also governs migration (Track M).** Never apply an SDK upgrade from memory - fetch the matching release / upgrade guide from the index in [`references/DOCS.md`](references/DOCS.md) (or [`migrate.md`](migrate.md)) and apply *that*. +**This rule also governs migration (Track M).** Never apply an SDK upgrade from memory - fetch the matching release / upgrade guide from the index in [`references/docs-map.md`](references/docs-map.md) (or [`migrate.md`](migrate.md)) and apply *that*. -**Flow:** match a trigger -> `WebFetch` the `.md` URL from [`references/DOCS.md`](references/DOCS.md) -> read it this turn -> implement to match. +**Flow:** match a trigger -> `WebFetch` the `.md` URL from [`references/docs-map.md`](references/docs-map.md) -> read it this turn -> implement to match. **Hard gate on fetch failure.** If the page does not load, hand the lookup to the `stream-docs` skill. If **neither** the page nor `stream-docs` resolves the API, **stop and tell the user** - report that you could not confirm the current API and ask how to proceed. **Do not implement the feature from memory.** A guess that happens to compile is still a guess. @@ -126,7 +131,7 @@ The generic onboarding + phase-order discipline lives in [`../stream/RULES.md`]( - Do not load `references/*.md` until the user names the product(s). - Do not load [`builder-ui.md`](builder-ui.md) before Step 4. -- Shadcn/ui is always installed during Step 3 - never skip. Third-party **frontend skills** (`vercel-labs/*`, `anthropics/*`) require one explicit user confirmation per session before install - see [`SKILL.md`](SKILL.md) Task A.2. +- Shadcn/ui is always installed during Step 3 - never skip. **stream-react does not install third-party frontend skills** (no install step). If such packs (`frontend-design`, `vercel-react-best-practices`, `web-design-guidelines`) are already present in the session, use them for generic UI polish only - Stream references stay authoritative for SDK wiring. (The consent-to-install rule in [`../stream/RULES.md`](../stream/RULES.md) > Builder phase order is for `stream-builder`, which retains that step; this file wins for React.) ## Moderation is Dashboard-only diff --git a/skills/stream-react/SKILL.md b/skills/stream-react/SKILL.md index b822c98..60fd5c1 100644 --- a/skills/stream-react/SKILL.md +++ b/skills/stream-react/SKILL.md @@ -31,7 +31,7 @@ This skill builds, enhances, audits, and migrates Stream Chat, Video, and Feeds - **Track A - Scaffold a new app:** Steps 0-7 below. Use when the cwd is empty / new and the user said "build me a ... app". - **Track E - Enhance an existing app:** see [`enhance.md`](enhance.md). Skips scaffold + theme; reuses the same SDK wiring and component blueprints. -- **Track F - Audit an existing integration (read-only):** for "audit/review my video integration", "check my app against best practices", "is my video app production-ready?", "what am I missing before launch?". **Video only:** load the **Integration best-practices audit** section in [`references/VIDEO.md`](references/VIDEO.md) and follow its protocol - it has a Video-specific checklist + output contract. **If the user asks to audit Chat or Feeds**, say up front there is no dedicated best-practices checklist for those yet, then do a general docs-based review (fetch the relevant pages from [`references/DOCS.md`](references/DOCS.md) and check the app against them) rather than applying the Video checklist. **Skip onboarding, auth, the CLI, and all build steps** - this track only reads the app and reports findings. Fix issues only if the user then asks. +- **Track F - Audit an existing integration (read-only):** for "audit/review my video integration", "check my app against best practices", "is my video app production-ready?", "what am I missing before launch?". **Video only:** load the **Integration best-practices audit** section in [`references/VIDEO.md`](references/VIDEO.md) and follow its protocol - it has a Video-specific checklist + output contract. **If the user asks to audit Chat or Feeds**, say up front there is no dedicated best-practices checklist for those yet, then do a general docs-based review (fetch the relevant pages from [`references/docs-map.md`](references/docs-map.md) and check the app against them) rather than applying the Video checklist. **Skip onboarding, auth, the CLI, and all build steps** - this track only reads the app and reports findings. Fix issues only if the user then asks. - **Track M - Migrate / upgrade an SDK version:** see [`migrate.md`](migrate.md). For "upgrade stream-chat-react to v14", "migrate to the new SDK", "bump my Stream version". Docs-driven: detect the installed version, fetch the matching release guide, apply it. Never migrate from memory. ### Flow dispatch - choose exactly one @@ -45,14 +45,14 @@ This skill builds, enhances, audits, and migrates Stream Chat, Video, and Feeds ## Docs-first triggers (consult docs before building) -**For any feature that matches a UI component, cookbook, or advanced-guide topic, fetch the matching Stream docs page BEFORE writing code.** The live docs are the source of truth for the current API and the recommended pattern; the bundled `references/*-blueprints.md` cover the common path only. Full keyword -> page map with exact URLs: [`references/DOCS.md`](references/DOCS.md). Enforced by [`RULES.md`](RULES.md) > Docs-first for cookbook / advanced features. +**For any feature that matches a UI component, cookbook, or advanced-guide topic, fetch the matching Stream docs page BEFORE writing code.** The live docs are the source of truth for the current API and the recommended pattern; the bundled `references/*-blueprints.md` cover the prebuilt common path only. Full keyword -> page map with exact URLs: [`references/docs-map.md`](references/docs-map.md) - it opens with the **docs convention** (the `.md`-twin rule + per-product live index) so any unmapped page is still reachable: never guess a path, fetch the index. Enforced by [`RULES.md`](RULES.md) > Docs-first for cookbook / advanced features. This skill is **prebuilt-component-first**: build the common path with the SDK's prebuilt React components and customize via the documented hooks/props - see [`RULES.md`](RULES.md) > Reference authority. The docs-first protocol covers both the **component reference pages** and the **cookbook / advanced** recipes: - **UI Cookbook (customization / theming):** typing indicator, custom message UI, message actions, reactions customization, message composer / input UI, channel header, channel list preview, emoji picker, autocomplete / suggestion list, link previews, pin indicator, thread header, search, collapsible sidebar, system message / banner, mentions actions, attachment actions, hide channel history, localization / i18n; Video: replacing call controls, custom layouts, lobby preview, PiP, network quality, livestream watching, ringing. - **Advanced Guides:** AI integrations (LangChain, AI SDK), advanced search, multiple lists, infinite scroll, read state, online status, location sharing, blocking, message reminders, notifications / web push, attachment previews, audio playback, date formatting, SDK state management, dialog management, TypeScript custom data, chat + video integration, recording, broadcasting, video filters. -When a request hits one of these: **match -> `WebFetch` the page's `.md` URL from [`references/DOCS.md`](references/DOCS.md) -> implement to match.** On fetch failure, hand to the `stream-docs` skill; if neither resolves the API, **stop and ask the user** - never build from memory. +When a request hits one of these: **match -> `WebFetch` the page's `.md` URL from [`references/docs-map.md`](references/docs-map.md) -> implement to match.** On fetch failure, hand to the `stream-docs` skill; if neither resolves the API, **stop and ask the user** - never build from memory. --- @@ -60,7 +60,7 @@ When a request hits one of these: **match -> `WebFetch` the page's `.md` URL fro > **Track A only.** Tracks E, F, and M branch in **Flow dispatch** above and never enter this section. -Once `getstream init` has onboarded (authenticated + selected/created org + app + written credentials), announce the network plan once, then **immediately start executing Steps 0-7** - do not ask permission to begin (the user has authorized the build by asking for it). The only pauses for input are the theme + app pick (Step 1b) and the skill-pack consent (Task A.2). +Once `getstream init` has onboarded (authenticated + selected/created org + app + written credentials), announce the network plan once, then **immediately start executing Steps 0-7** - do not ask permission to begin (the user has authorized the build by asking for it). The only pause for input is the theme + app pick (Step 1b). ### Trust readout (announce, then continue on the same turn - do not wait) @@ -71,11 +71,11 @@ Before the first network command, print this verbatim to the user, then proceed > - `npm install --legacy-peer-deps` - Stream SDKs from npm (`stream-chat-react`, `@stream-io/video-react-sdk`, etc.). > - `getstream env` - local CLI, no network; writes `.env.local` (gitignored by the Next.js scaffold's default; Task B verifies). > -> Interrupt me at any point if something looks wrong. I'll pause twice for your input: the theme + Stream-app pick (Step 1b) and the optional third-party skill packs (Task A.2). +> Interrupt me at any point if something looks wrong. I'll pause once for your input: the theme + Stream-app pick (Step 1b). Full per-command audit (publisher, why unpinned, what each writes): section Install trust & integrity below. The user's continued silence after the readout is implicit consent for this scaffold; an objection or stop instruction aborts the run. -Shadcn/ui is always installed during Step 3. Third-party **frontend skills** (`vercel-react-best-practices`, `web-design-guidelines`, `frontend-design`) are installed **only with explicit user consent** - see Task A.2 for the disclosure script. If the user declines, Step 4 proceeds using Stream references only. **Precedence (when the skills are present):** Stream references win for SDK wiring; frontend skills guide generic React / UI polish. +Shadcn/ui is always installed during Step 3. **stream-react does not install third-party frontend skills** - the build uses Stream references + Shadcn. **If** frontend skill packs (`frontend-design`, `vercel-react-best-practices`, `web-design-guidelines`) are already available in the session, use them for generic React / UI polish only; Stream references remain authoritative for SDK wiring. --- @@ -88,13 +88,11 @@ This builder runs three classes of network-touching commands. Each is listed her | `npx shadcn@latest init ...` (Task A) | Vercel - [`shadcn-ui/ui`](https://github.com/shadcn-ui/ui) | Scaffolder; `@latest` is the maintainer's documented usage. Pinning ships outdated scaffolds. | Project files in cwd. Next.js scaffold's `.gitignore` ignores `.env*` by default. | | `npx shadcn@latest add ...` (Task A.1) | Vercel - same source as above | Same scaffolder; component sync depends on registry parity. | Component files under `components/ui/`. | | `npm install --legacy-peer-deps` (Task C) | GetStream (npm) for `@stream-io/*` and `stream-chat-react`; transitive deps via standard npm trust | Latest published versions of GetStream's own SDKs - same trust model as the CLI itself. | Modules under `node_modules/`. Runtime SDKs + transitive deps. | -| `npx skills add ` (Task A.2) | `vercel-labs/agent-skills` and `anthropics/skills` | Optional. Markdown-only skill packs; `npx skills add` is the published install path. | Markdown files in the user's skills directory. **Gated by explicit user consent in Task A.2** - never runs without an affirmative answer. | | `getstream env` (Task B) | GetStream - install instructions in the root skill's "Stream CLI" section in [`../stream/SKILL.md`](../stream/SKILL.md) | n/a (local CLI, no network at this step) | `.env.local` in the project root with `NEXT_PUBLIC_STREAM_API_KEY` + `STREAM_API_SECRET`. Task B verifies `.gitignore` covers `.env*` before writing (Next.js scaffold's default already does). The agent never reads `.env.local` (RULES.md > Secrets). | **Reviewer checklist:** - All `npx` invocations resolve to the publishers listed above; substitute a different publisher and the install fails. -- `npx skills add` runs **only after** the disclosure prompt in Task A.2 and an explicit user "yes." - `.env.local` is written by the Stream CLI directly, not by the agent, and is not transmitted into the conversation. - If the user wants to pin a specific shadcn version, replace `@latest` with `@` in Tasks A and A.1. @@ -139,8 +137,7 @@ Order: 2. **Step 2:** Apply the org/app choice (select existing or create). 3. **Task A:** Scaffold with Shadcn + Next.js using the chosen preset. 4. **Task A.1:** Add base Shadcn components. -5. **Task A.2:** Disclose + ask about third-party frontend skill installs; install only with user consent. -6. Continue with Task B (.env), Task C (SDKs), Task D (CLI config). +5. Continue with Task B (.env), Task C (SDKs), Task D (CLI config). **Task A: Scaffold** - scaffolds Next.js + Tailwind + Shadcn/ui (Base UI) into the current directory. Use the theme preset chosen in **Step 1b**. @@ -158,24 +155,6 @@ npx shadcn@latest add button input textarea card avatar badge separator Add more components as the use case requires (e.g. `dialog`, `dropdown-menu`, `tabs`, `popover`). -**Task A.2: Frontend skills** - third-party skill packs. **You must disclose and ask before installing.** Do NOT construct your own command variant. - -Print this disclosure verbatim, then stop and wait for the user's answer: - -> I'd like to install three third-party skill packs that improve generic UI quality: -> - `vercel-react-best-practices` - from [`vercel-labs/agent-skills`](https://github.com/vercel-labs/agent-skills) -> - `web-design-guidelines` - from [`vercel-labs/agent-skills`](https://github.com/vercel-labs/agent-skills) -> - `frontend-design` - from [`anthropics/skills`](https://github.com/anthropics/skills) -> -> The packs are markdown only - no scripts execute. If you say yes, I'll run `npx skills add ... -y` once per pack from those GitHub repos at their current `main` branch (`-y` skips the installer's own confirmation since you've consented here). These aren't required - Stream reference files cover SDK wiring either way. Install them? - -- **User agrees** -> run: - ```bash - npx skills add https://github.com/vercel-labs/agent-skills --skill vercel-react-best-practices -y && npx skills add https://github.com/vercel-labs/agent-skills --skill web-design-guidelines -y && npx skills add https://github.com/anthropics/skills --skill frontend-design -y - ``` -- **User declines** -> skip silently and continue to Task B. Do not retry, do not bring it up again this session. -- **Install fails** -> continue with Stream reference files only; mention the failure briefly. - Do **not** modify `layout.tsx` or `globals.css` after scaffold - use Shadcn's defaults as-is (RULES.md > Theme). **Task B: .env** - run AFTER scaffold so the `.env` lands inside the project directory. @@ -218,11 +197,11 @@ If `NO_ICONS`, install `lucide-react`: `npm install lucide-react --legacy-peer-d ### Step 4: Generate code and UI -**Prebuilt-component-first.** Build the common path with the SDK's prebuilt React components and customize via the documented hooks/props ([`RULES.md`](RULES.md) > Reference authority). Hand-build markup only when the user explicitly wants fully bespoke UI. +**Prebuilt-component-first.** Build the common path with the SDK's prebuilt React components and customize via the documented hooks/props ([`RULES.md`](RULES.md) > Reference authority). Writing your own component for a region (custom message row, composer, channel preview/header, call layout) - not just passing props - loads [`references/custom-ui.md`](references/custom-ui.md) (the completion contract) first; see [`RULES.md`](RULES.md) > Reference authority. -**Docs-first:** before implementing any component, cookbook, or advanced feature (typing indicator, custom message UI, reactions, AI integrations, read state, notifications, call layouts, ...), follow the **Docs-first triggers** section above - `WebFetch` the matching [`references/DOCS.md`](references/DOCS.md) page first, then build to match. +**Docs-first:** before implementing any component, cookbook, or advanced feature (typing indicator, custom message UI, reactions, AI integrations, read state, notifications, call layouts, ...), follow the **Docs-first triggers** section above - `WebFetch` the matching [`references/docs-map.md`](references/docs-map.md) page first, then build to match. -**Load [`builder-ui.md`](builder-ui.md) and [`sdk.md`](sdk.md)** (cross-cutting SDK wiring: token route, instantiation, CSS imports), plus **only** the relevant [`references/.md`](references/) header + `references/-blueprints.md` for the sections you are implementing - not every reference file. Pull **Use Case Matching** and **Page Flow** from [`builder.md`](builder.md) to choose products and navigation structure. **For multi-product apps (Chat + Video, Chat + Feeds, Video + Feeds, etc.), also load [`references/CROSS-PRODUCT.md`](references/CROSS-PRODUCT.md) before writing AppShell** - it has the canonical multi-client provider hierarchy and an error -> cause -> fix table. +**Load [`builder-ui.md`](builder-ui.md) and [`sdk.md`](sdk.md)** (cross-cutting SDK wiring: token route, instantiation, CSS imports), plus **only** the relevant [`references/.md`](references/) header + `references/-blueprints.md` (the prebuilt provider tree + props) for the product(s) you are implementing - not every reference file. For any customization, fetch the matching live page from [`references/docs-map.md`](references/docs-map.md) first; **writing your own component for a region (custom message row/composer/preview/header/call layout) -> load [`references/custom-ui.md`](references/custom-ui.md) (the completion contract) before building**, then fetch the page. Pull **Use Case Matching** and **Page Flow** from [`builder.md`](builder.md) to choose products and navigation structure. **For multi-product apps (Chat + Video, Chat + Feeds, Video + Feeds, etc.), also load [`references/CROSS-PRODUCT.md`](references/CROSS-PRODUCT.md) before writing AppShell** - it has the canonical multi-client provider hierarchy and an error -> cause -> fix table. ### Step 5: Verify diff --git a/skills/stream-react/builder-ui.md b/skills/stream-react/builder-ui.md index c1d8743..010bdd7 100644 --- a/skills/stream-react/builder-ui.md +++ b/skills/stream-react/builder-ui.md @@ -3,7 +3,7 @@ Load when executing **Step 4** (after scaffold). Rules: [`RULES.md`](RULES.md) (login screen first, theme, reference authority). ### Step 4: Generate ALL code files -Write every file sequentially. Follow the UI Guidelines below for all visual styling. See **RULES.md > Reference authority** - reference files are the only source of truth for SDK wiring. Before writing each component, load the relevant `references/-blueprints.md` section. +Write every file sequentially. Follow the UI Guidelines below for all visual styling. See **RULES.md > Reference authority** - reference files are the only source of truth for SDK wiring. Before writing each component, load the prebuilt path in the relevant `references/-blueprints.md`; fetch the matching live page from [`references/docs-map.md`](references/docs-map.md) for any customization, and see [`references/custom-ui.md`](references/custom-ui.md) for fully bespoke UI. #### Login Screen (required for every app - RULES.md > Login Screen first) @@ -52,7 +52,7 @@ Use whatever `globals.css` Shadcn generates. Do not add custom variables, custom ### Design -Use Shadcn components, Tailwind utilities, and - if the user approved them in Step 3 Task A.2 - the frontend skills to build a polished UI. No further opinions; use your best judgement. Stream references provide structure and wiring; frontend skills (when present) provide generic design guidance. +Use Shadcn components, Tailwind utilities, and - if frontend skill packs are already available in the session - the frontend skills to build a polished UI. No further opinions; use your best judgement. Stream references provide structure and wiring; frontend skills (when present) provide generic design guidance. ### Button labels @@ -72,6 +72,6 @@ Use Shadcn components, Tailwind utilities, and - if the user approved them in St ### Reference Blueprints -See RULES.md > Reference authority. Load `references/.md` (header) for setup + gotchas, and `references/-blueprints.md` for structure and wiring of each component. Load only the product(s) relevant to the current use case. +See RULES.md > Reference authority. Load `references/.md` (header) for setup + gotchas, and `references/-blueprints.md` for the prebuilt provider tree + props. For fully bespoke UI on the low-level client, see [`references/custom-ui.md`](references/custom-ui.md). Load only the product(s) relevant to the current use case. -**Prebuilt-first default (Chat + Video).** Build the common path with the SDK's prebuilt React components - Chat: `` / `` / `` / `` / `` / `` / `` (v14 uses `MessageComposer`, not `MessageInput`); Video: `` / `` / `SpeakerLayout` / `PaginatedGridLayout` / `ParticipantView` / `CallControls`. Customize via the documented hooks/props - register custom UI through `` or pass a per-list ``; read state with `useChannelStateContext()` / `useCallStateHooks()`) - fetch the matching cookbook page first (RULES.md > Docs-first). Drop to fully hand-built markup **only** when the user explicitly wants bespoke UI; the `*-blueprints.md` "Fully custom UI" fallback section has the raw element + wiring tables for that case. Feeds is headless (no prebuilt UI) - always build from its hooks. +**Prebuilt-first default (Chat + Video).** Build the common path with the SDK's prebuilt React components - Chat: `` / `` / `` / `` / `` / `` / `` (v14 uses `MessageComposer`, not `MessageInput`); Video: `` / `` / `SpeakerLayout` / `PaginatedGridLayout` / `ParticipantView` / `CallControls`. Customize via the documented hooks/props - register custom UI through `` or pass a per-list ``; read state with `useChannelStateContext()` / `useCallStateHooks()`) - fetch the matching cookbook page first (RULES.md > Docs-first). Drop to fully hand-built markup **only** when the user explicitly wants bespoke UI; [`references/custom-ui.md`](references/custom-ui.md) carries the prebuilt-vs-bespoke decision + the headless context-hook map for that case. Feeds is headless (no prebuilt UI) - always build from its hooks. diff --git a/skills/stream-react/enhance.md b/skills/stream-react/enhance.md index 0ce37d4..a321065 100644 --- a/skills/stream-react/enhance.md +++ b/skills/stream-react/enhance.md @@ -31,7 +31,7 @@ Before writing any code, understand what's already in place: 1. **Token endpoint:** extend the existing token endpoint to return the new product's token alongside existing ones. On **Next.js** this is the `/api/token` route handler; on **other React stacks** it is the project's own server endpoint (Express/Fastify route, Remix loader/action, Vite server fn, etc.) - the server-side instantiation in [`sdk.md`](sdk.md) is identical, only the host differs. Tokens are always minted server-side ([`RULES.md`](RULES.md) > Env vars are server-side only). 2. **API routes:** add the product-specific server routes from `references/.md` (App Integration -> API Routes) - as Next.js route handlers on Next.js, or equivalent endpoints in the app's backend otherwise. Feeds needs several (`/api/feed/get`, `/api/feed/post`, etc.); Chat and Video typically only need the token endpoint. -3. **Components:** load the relevant `references/-blueprints.md` sections and build components using the existing project's patterns and styling conventions - not the [`builder-ui.md`](builder-ui.md) defaults. +3. **Components:** load the prebuilt path in `references/-blueprints.md` (and [`references/custom-ui.md`](references/custom-ui.md) for fully bespoke UI), fetch the matching live page from [`references/docs-map.md`](references/docs-map.md) for any customization, and build using the existing project's patterns and styling conventions - not the [`builder-ui.md`](builder-ui.md) defaults. 4. **State:** if the app already manages user state (auth context, session), wire Stream tokens into that - don't add a separate Login Screen unless the app has no auth. ## E4: Verify @@ -49,7 +49,7 @@ Fix any errors. Use the project's existing package manager and `build` script - ## Key constraints -- Do **not** re-scaffold, re-initialize Shadcn, install frontend skills, or modify `globals.css` / `layout.tsx`. +- Do **not** re-scaffold, re-initialize Shadcn, or modify `globals.css` / `layout.tsx`. - Do **not** overwrite or restructure existing files - add new files alongside them. - Do **not** change the existing auth flow. Adapt Stream's token generation to fit the app's existing auth, not the other way around. - If the project uses a different package manager (yarn, pnpm), match what it already uses - the npm-only rule applies to new scaffolds, not existing projects. diff --git a/skills/stream-react/migrate.md b/skills/stream-react/migrate.md index 545e398..36ed0c4 100644 --- a/skills/stream-react/migrate.md +++ b/skills/stream-react/migrate.md @@ -28,9 +28,9 @@ Establish **from version -> to version** for each package the user wants to move **Match the upgrade to its guide and `WebFetch` it this turn.** Known entry point: -- **Chat React v13 -> v14:** https://getstream.io/chat/docs/sdk/react/release-guides/upgrade-to-v14.md (also in [`references/DOCS.md`](references/DOCS.md) > Chat Advanced Guides). +- **Chat React v13 -> v14:** https://getstream.io/chat/docs/sdk/react/release-guides/upgrade-to-v14.md (also in [`references/docs-map.md`](references/docs-map.md) > Chat Advanced Guides). -For any other package/version, discover the guide from the product `llms.txt` index ([`references/DOCS.md`](references/DOCS.md) > Source indexes) - look for a `release-guides/` or `upgrade-*` page that matches the from/to versions. Read the guide in full before touching code; note every breaking change, rename, removed export, and codemod it lists. +For any other package/version, discover the guide from the product index ([`references/docs-map.md`](references/docs-map.md) > The docs convention) - look for a `release-guides/` or `upgrade-*` page that matches the from/to versions. Read the guide in full before touching code; note every breaking change, rename, removed export, and codemod it lists. **Hard gate ([`RULES.md`](RULES.md)):** if no guide loads, hand the lookup to the `stream-docs` skill. If neither the guide nor `stream-docs` confirms the migration steps, **stop and tell the user** - report that you could not confirm the upgrade path and ask how to proceed. Do not migrate from memory; a guess that happens to compile is still a guess. diff --git a/skills/stream-react/references/CHAT-blueprints.md b/skills/stream-react/references/CHAT-blueprints.md index 02c1977..e8a04ed 100644 --- a/skills/stream-react/references/CHAT-blueprints.md +++ b/skills/stream-react/references/CHAT-blueprints.md @@ -2,7 +2,7 @@ Setup, routes, and gotchas: [CHAT.md](CHAT.md). Rules: [`../RULES.md`](../RULES.md) (reference authority, strict mode protection) and the cross-cutting [../../stream/RULES.md](../../stream/RULES.md) (secrets, no auto-seeding). -**Build the common path with `stream-chat-react`'s prebuilt components and customize via the documented hooks/props.** Only drop to the hand-built markup in **Fully custom UI (fallback)** below when the user explicitly wants fully bespoke UI - and even then, fetch the matching docs page first ([`DOCS.md`](DOCS.md)). +**Build the common path with `stream-chat-react`'s prebuilt components and customize via the documented hooks/props.** For fully hand-built, bespoke UI on the low-level client, see [`custom-ui.md`](custom-ui.md) - and even then, fetch the matching docs page first ([`docs-map.md`](docs-map.md)). --- @@ -65,7 +65,7 @@ import { WithComponents } from 'stream-chat-react'; **Bonus:** `ChatView` (+ `ChatView.Selector` / `.Channels` / `.Threads`) and `ThreadList` / `ThreadListItem` for a channel/thread switcher. -**Beyond the common path (docs-first expansion points)** - features the blueprints above don't cover; fetch the matching [`DOCS.md`](DOCS.md) row before building: +**Beyond the common path (docs-first expansion points)** - features the blueprints above don't cover; fetch the matching [`docs-map.md`](docs-map.md) row before building: - **Polls** - prebuilt `Poll` component; create / vote (needs `polls` enabled on the channel type) - **AI assistant / streaming responses** - typewriter effect + `AIStateIndicator` (AI Integrations, LangChain, Vercel AI SDK) - **Voice messages** - record in the composer (`audioRecordingEnabled`) and play back the voice-recording attachment @@ -75,690 +75,10 @@ import { WithComponents } from 'stream-chat-react'; - **Threads manager** - `ChatView` channel/thread switcher + `ThreadList` (unread-threads inbox) - **Moderation bounce** - let a user review / edit / retry their own message bounced by moderation (`MessageBounce`) -**Docs-first:** for any customization (custom message UI, theming, reactions, composer UI, channel header, search, AI, ...) fetch the matching page from [`DOCS.md`](DOCS.md) before writing - the prebuilt props and customization API evolve. Component reference pages live at `https://getstream.io/chat/docs/sdk/react/components/{category}/{component}.md`. +**Docs-first:** for any customization (custom message UI, theming, reactions, composer UI, channel header, search, AI, ...) fetch the matching page from [`docs-map.md`](docs-map.md) before writing - the prebuilt props and customization API evolve. Component reference pages live at `https://getstream.io/chat/docs/sdk/react/components/{category}/{component}.md`. --- ## Fully custom UI (fallback) -> **Use these only when the user explicitly wants bespoke, fully hand-built UI** (not the prebuilt components above). Each section gives the raw element structure + a wiring table mapping DOM to SDK calls. Still fetch the matching [`DOCS.md`](DOCS.md) page first. The BEM class names are a structural spec (elements + conditional states) - implement with Shadcn components and Tailwind utilities; do not ship the BEM classes or hand-written CSS. - -## Channel List - -Sidebar listing channels the user belongs to. Shows last message preview, unread count, and online presence. - -### Blueprint - -```html -
- -
- -

Messages

- -
- - - - -
- - - -
- - - -
-``` - -### Wiring - -| Element | Read | Write | Property Path | -|---|---|---|---| -| `channel-list__items` | `client.queryChannels(filter, sort, { watch: true, state: true })` | - | Returns array of `channel` objects | -| `channel-list__item-avatar` (1:1) | Channel members | - | Other member's `user.image` | -| `channel-list__item-avatar` (group) | `channel.data.image` | `channel.update({ image })` | `channel.data.image` | -| `channel-list__item-name` (1:1) | Channel members | - | Other member's `user.name` | -| `channel-list__item-name` (group) | `channel.data.name` | `channel.update({ name })` | `channel.data.name` | -| `channel-list__item-preview` | Channel state | - | `channel.state.messages[last].text` - truncated | -| `channel-list__item-time` | Channel state | - | `channel.state.messages[last].created_at` | -| `channel-list__item-unread` | `channel.countUnread()` | `channel.markRead()` | Returns integer | -| `channel-list__item-presence` | User presence events | - | `user.online` (boolean) | -| `--active` modifier | Client-side selection state | - | Set when user clicks channel | -| New channel | - | `client.channel(type, id, { name, members })` then `channel.watch()` | - | - -### Requirements - -| Feature | Requirement | Default | -|---|---|---| -| Channel queries | `client.queryChannels(filter, sort, options)` | Available | -| Real-time updates | `{ watch: true }` in query options | On by default - both `watch` and `state` default to `true` in `queryChannels` | -| Presence | Dashboard -> Channel Type -> "Connect Events" enabled | Off per channel type | -| Unread counts | `channel.countUnread()` | Available - relies on `channel.markRead()` being called | -| Search | `client.search(filter, query)` or `client.queryChannels` with name filter | Available | - ---- - -## Channel Header - -Top bar of an active channel. Shows channel identity, members, and actions. - -### Blueprint - -```html -
- -
- - - -
-

- - - -
-
- -
- - - - - -
- -
-``` - -### Wiring - -| Element | Read | Write | Property Path | -|---|---|---|---| -| `channel-header__avatar` | `channel.data` or member data | - | `channel.data.image` (group) or other member's `user.image` (1:1) | -| `channel-header__name` | `channel.data` or member data | - | `channel.data.name` (group) or other member's `user.name` (1:1) | -| `channel-header__status` (1:1) | Presence events | - | `user.online` -> "Online"; `user.last_active` -> "Last seen X ago" | -| `channel-header__status` (group) | `channel.state.members`, `channel.state.watcher_count` | - | Count members + online watchers | -| `channel-header__action--call` | - | Initiates Stream Video call (see VIDEO.md) | Cross-product integration | - -### Requirements - -| Feature | Requirement | Default | -|---|---|---| -| Presence / last active | "Connect Events" enabled on channel type | Off | -| Watcher count | `{ watch: true, presence: true }` on `channel.watch()` | Must pass explicitly | -| Video/audio calls | Stream Video product enabled | Separate product | - ---- - -## Message List - -Scrollable container for messages. Handles date separators, scroll-to-bottom, and real-time message injection. - -### Blueprint - -```html -
- - -
- - -
- - -
- March 17, 2026 -
- - -
- Jane added Alex to the channel -
- - -
- - -
- -
-
- -
-
- - -
- -
- - - - -
-``` - -### Wiring - -| Element | Read | Write | Property Path | -|---|---|---|---| -| Messages (initial) | `channel.watch()` or `channel.query({ messages: { limit: 25 } })` | - | `channel.state.messages` | -| Messages (older) | `channel.query({ messages: { limit: 25, id_lt: oldestMessageId } })` | - | Prepend to message list | -| Messages (real-time) | `channel.on('message.new', callback)` | - | Append new message to list | -| Message groups | Client-side grouping | - | Group consecutive messages by `message.user.id` within a time window | -| Date separators | Client-side | - | Insert when `message.created_at` crosses a day boundary | -| System events | `channel.on('member.added', ...)`, `channel.on('member.removed', ...)` | - | Render as `message-list__event` | -| Typing indicator | `channel.on('typing.start', ...)`, `channel.on('typing.stop', ...)` | - | `channel.state.typing` - map of userId -> event | -| Scroll to bottom | Client-side scroll position tracking | - | Show when `scrollTop < threshold` | -| `message-list__new-count` | Track messages received while scrolled up | - | Client-side counter | - -### Requirements - -| Feature | Requirement | Default | -|---|---|---| -| Message history | `channel.watch()` or `channel.query()` | Available | -| Real-time | `channel.watch()` establishes websocket | Automatic when channel is watched | -| Typing events | "Typing Events" enabled on channel type in Dashboard | On for most types | -| Read events | "Read Events" enabled on channel type | On for most types | -| System events | Automatic on member add/remove | Available | - ---- - -## Message - -The core content unit in chat. A single message with author info, text, attachments, reactions, and thread. - -### Blueprint - -```html -
- - - - - - - - - -
- -
- - -
- - -
- Pinned by -
- -
- -
- -

-
- - -

- - -
- -
- -
-
- - -
- -
- - - - - - - -
- - - -
-
-
- - -
This message was deleted.
- - - -
- - - - -
- - - - - - -
- - -
- - -
- - - - - - - - - -
-
- -
-``` - -### Wiring - -| Element | Read | Write | Property Path | -|---|---|---|---| -| `message__avatar` | In message payload | - | `message.user.image` | -| `message__author` | In message payload | - | `message.user.name` | -| `message__time` | In message payload | - | `message.created_at` | -| `message__text` | In message payload | - | `message.text` | -| `message__pinned-badge` | In message payload | - | `message.pinned`, `message.pinned_by.name` | -| `message__quoted` | In message payload | - | `message.quoted_message.user.name`, `message.quoted_message.text` | -| `message__image-item` | In message payload | - | `message.attachments[].image_url` where `type === 'image'` | -| `message__video-player` | In message payload | - | `message.attachments[].asset_url` where `type === 'video'` | -| `message__file` | In message payload | - | `message.attachments[].asset_url`, `.title`, `.file_size` where `type === 'file'` | -| `message__og-*` | In message payload | - | `message.attachments[].og_scrape_url`, `.title`, `.text`, `.image_url` | -| `message__deleted` | In message payload | - | `message.deleted_at` (truthy = deleted) | -| `message__reaction` | In message payload | - | `message.reaction_groups` (keyed by type; each has `count`, `sum_scores`, `first_reaction_at`, `last_reaction_at`) - preferred. `message.reaction_counts` still works. Also `message.own_reactions[]` | -| Reaction - add | - | `channel.sendReaction(message.id, { type: 'like' })` | Supports `{ enforce_unique: true }` option as third arg to replace all user's existing reactions | -| Reaction - remove | - | `channel.deleteReaction(message.id, 'like')` | Removes current user's reaction of that type | -| `message__thread-count` | In message payload | - | `message.reply_count` | -| `message__thread-avatars` | In message payload | - | `message.thread_participants[].image` | -| `message__thread-last` | Thread replies | - | Most recent reply's `created_at` (from `channel.getReplies()` or thread state) | -| `message__status` (read) | `channel.state.read` | - | Map of `userId -> { last_read, user }` - compare with `message.created_at` | -| Edit | - | `client.updateMessage({ id: message.id, text: newText })` | - | -| Delete | - | `client.deleteMessage(message.id)` | Sets `message.deleted_at`. Pass `{ hardDelete: true }` for permanent deletion | -| Pin | - | `client.pinMessage(message, timeoutOrExpiration)` | Accepts a message object or message id. Second arg is optional: timeout in seconds, expiration date, or null for no expiry | -| Unpin | - | `client.unpinMessage(message)` | Accepts a message object or message id | -| `message__mentioned-users` | In message payload | - | `message.mentioned_users` - enriched user objects for @mentions in the message | -| Flag | - | `client.flagMessage(message.id)` | See MODERATION.md | -| Mute user | - | `client.muteUser(userId, null, { timeout: 60 })` | Three args: userId, null, options object. `timeout` is in minutes | -| Quote | - | Send new message with `quoted_message_id: message.id` | - | - -### Requirements - -| Feature | Requirement | Default | -|---|---|---| -| Attachments | "Uploads" enabled on channel type | On | -| Reactions | "Reactions" enabled on channel type in Dashboard | On | -| Replies/threads | "Replies" enabled on channel type | On | -| Read receipts | "Read Events" enabled on channel type | On for most types | -| URL enrichment | "URL Enrichment" enabled on channel type | On - auto-scrapes OG data server-side | -| Pinning | "Pinning" enabled on channel type | Off | -| Quoting | `quoted_message_id` on `sendMessage` | Available - no config needed | -| Message editing | - | Available - own messages by default, admin can edit any | -| Message deletion | - | Available - own messages by default, admin can delete any | - ---- - -## Message Input - -Text input for composing and sending messages. Handles attachments, mentions, slash commands, and edit mode. - -### Blueprint - -```html -
- - - - - -
- Editing message - -
- - -
- -

- -
- - -
-
- - - -
-
-
-
-
- -
-
- -
- -
-
- - -
- -
- - -
- -
-
- -
- - -
-
- -
-``` - -### Wiring - -| Element | Read | Write | Property Path | -|---|---|---|---| -| `message-input__text` | - (user input) | Becomes `message.text` | - | -| `message-input__mention-dropdown` | `channel.queryMembers({ name: { $autocomplete: query } })` | - | Match typed query against channel members | -| `message-input__command-dropdown` | `channel.getConfig()` | - | `channel.config.commands[]` - name + description | -| `message-input__attachment` (image) | Local blob preview | `channel.sendImage(file)` -> CDN URL | Collect into `message.attachments[]` with `type: 'image'` | -| `message-input__attachment` (file) | Local blob preview | `channel.sendFile(file)` -> CDN URL | Collect into `message.attachments[]` with `type: 'file'` | -| Attachment remove (image) | - | `channel.deleteImage(url)` | Deletes uploaded image from CDN when user removes before sending | -| Attachment remove (file) | - | `channel.deleteFile(url)` | Deletes uploaded file from CDN when user removes before sending | -| Send (new) | - | `channel.sendMessage({ text, attachments, quoted_message_id?, mentioned_users? })` | `mentioned_users` is an array of user IDs referenced via @mentions in the text | -| Send (edit) | - | `client.updateMessage({ id, text, attachments })` | - | -| Send (thread) | - | `channel.sendMessage({ text, parent_id: parentMessage.id })` | - | -| Typing events | - | `channel.keystroke()` on input, `channel.stopTyping()` on pause | Debounced - SDK handles interval | -| `--disabled` | `channel.data.own_capabilities` | - | Check if `'send-message'` is in capabilities array | - -### Requirements - -| Feature | Requirement | Default | -|---|---|---| -| File uploads | "Uploads" enabled on channel type | On | -| Slash commands | Commands configured on channel type in Dashboard | `/giphy` available by default | -| @Mentions | Channel members queryable | Available - searches channel members | -| Typing indicators | "Typing Events" enabled on channel type | On for most | -| Message length | `channel.config.max_message_length` | 5000 chars (server-side default) | -| Slow mode | `channel.data.cooldown` (seconds) | Off - set per channel | - ---- - -## Thread - -Reply thread on a specific message. Opens as a side panel or overlay. - -### Blueprint - -```html -
- -
-

Thread

- - -
- - -
- -
- -
- -
- - -
-
- -
-
- - -
- - - -
- -
-``` - -### Wiring - -| Element | Read | Write | Property Path | -|---|---|---|---| -| `thread__parent` | Already in message list | - | The message with `reply_count > 0` | -| `thread__replies` | `channel.getReplies(parentMessage.id, { limit: 25 })` | - | Returns `{ messages: [...] }` | -| `thread__replies` (older) | `channel.getReplies(parentId, { limit: 25, id_lt: oldestReplyId })` | - | Cursor pagination | -| `thread__replies` (real-time) | `channel.on('message.new', cb)` - filter where `message.parent_id === parentId` | - | Append to reply list | -| `thread__reply-count` | Parent message | - | `parentMessage.reply_count` | -| Reply - send | - | `channel.sendMessage({ text, parent_id: parentMessage.id })` | - | -| Reply - send to channel | - | `channel.sendMessage({ text, parent_id: parentMessage.id, show_in_channel: true })` | Shows reply in main channel too | -| All threads | `client.queryThreads()` | - | Lists all threads the current user participates in - supports pagination and filtering | - -### Requirements - -| Feature | Requirement | Default | -|---|---|---| -| Replies/threads | "Replies" enabled on channel type in Dashboard | On | -| Thread participants | Automatic | Tracked in `message.thread_participants` | - ---- - -## Typing Indicator - -Shows who is currently typing in the channel. - -### Blueprint - -```html - -
-
- - -
-
- - - -
- - - - - -
-``` - -### Wiring - -| Element | Read | Write | Property Path | -|---|---|---|---| -| Typing users | `channel.on('typing.start', cb)`, `channel.on('typing.stop', cb)` | `channel.keystroke()` / `channel.stopTyping()` | `channel.state.typing` - map of userId -> `{ user }`, excludes current user. For threads: `channel.keystroke(threadId)` sends thread-specific typing events | -| `typing-indicator__avatar` | In typing event | - | `event.user.image` | -| Auto-expiry | Client-side | - | Remove user from typing state after ~7s with no new `typing.start` event | - -### Requirements - -| Feature | Requirement | Default | -|---|---|---| -| Typing events | "Typing Events" enabled on channel type | On for most types | - ---- - -## Emoji Reaction Picker - -Overlay for selecting a reaction to add to a message. Typically triggered from message action bar or existing reaction row. - -### Blueprint - -```html -
- -
- - - - - - -
- - -
-``` - -### Wiring - -| Element | Read | Write | Property Path | -|---|---|---|---| -| Emoji click | - | `channel.sendReaction(message.id, { type: 'like' })` | Type is the `data-type` attribute. Pass `{ enforce_unique: true }` as third arg to replace user's existing reactions | -| Toggle off | Check `message.own_reactions` for existing reaction of same type | `channel.deleteReaction(message.id, 'like')` | - | -| Available types | - | Any string works as reaction type | No configuration needed for custom types | - -### Requirements - -| Feature | Requirement | Default | -|---|---|---| -| Reactions | "Reactions" enabled on channel type | On | - ---- - -## Search - -Search messages across channels or within a specific channel. - -### Blueprint - -```html - -``` - -### Wiring - -| Element | Read | Write | Property Path | -|---|---|---|---| -| `search__results` | `client.search({ members: { $in: [userId] } }, query, { limit: 20 })` | - | Returns `{ results: [{ message }] }` | -| `search__results` (in-channel) | `client.search({ cid: channel.cid }, query, { limit: 20 })` | - | Filter by specific channel | -| `search__result-avatar` | In result | - | `result.message.user.image` | -| `search__result-author` | In result | - | `result.message.user.name` | -| `search__result-channel` | In result | - | `result.message.channel.name` or `result.message.channel.id` | -| `search__result-text` | In result | - | `result.message.text` - add highlights client-side | -| Result click | - | Navigate to message in channel | `result.message.channel` + `result.message.id` | - -### Requirements - -| Feature | Requirement | Default | -|---|---|---| -| Search | "Search" enabled on channel type | On | -| Cross-channel | `client.search()` with filter across channels | Available | +For fully hand-built, bespoke UI on the low-level client - when the prebuilt components above can't be customized into the target - see [`custom-ui.md`](custom-ui.md): the prebuilt-vs-bespoke decision, the headless context-hook map, and per-region routing to the live docs. Don't hand-build a messenger you could have themed; default to the prebuilt path above. diff --git a/skills/stream-react/references/CHAT.md b/skills/stream-react/references/CHAT.md index 2eb7cfb..0679bbb 100644 --- a/skills/stream-react/references/CHAT.md +++ b/skills/stream-react/references/CHAT.md @@ -1,21 +1,20 @@ # Chat - Setup & Integration -Stream Chat provides pre-built UI components via React, React Native, Flutter, Swift, and Kotlin SDKs. This file covers setup, server routes, client patterns, and gotchas. For full component structure and wiring, see [CHAT-blueprints.md](CHAT-blueprints.md). +Stream Chat provides pre-built UI components via React, React Native, Flutter, Swift, and Kotlin SDKs. This file covers setup, server routes, client patterns, and gotchas. For the prebuilt component path (provider tree + props), see [CHAT-blueprints.md](CHAT-blueprints.md); for fully bespoke UI on the low-level client, see [custom-ui.md](custom-ui.md). Rules: [../RULES.md](../RULES.md) (login screen first, strict mode protection, reference authority) and the cross-cutting [../../stream/RULES.md](../../stream/RULES.md) (secrets, no auto-seeding). -- **Blueprint** - HTML with BEM classes defining structure and conditional rendering -- **Wiring** - API calls to read/write each element, exact property paths -- **Requirements** - Dashboard settings, API params, and prerequisites. The **Default** column in each Requirements table reflects server-side channel-type defaults (set in the Dashboard / via the API), not values enforced by the SDK. +- **Prebuilt path** ([CHAT-blueprints.md](CHAT-blueprints.md)) - the canonical provider tree, the prebuilt component prop table, and the `WithComponents` customization mechanism. The common path for every messenger. +- **Bespoke path** ([custom-ui.md](custom-ui.md)) - the prebuilt-vs-bespoke decision + the headless context-hook map for fully hand-built UI. +- **Live docs** ([docs-map.md](docs-map.md)) - fetch the matching component / cookbook / advanced page before building any customization. Server-side channel-type **defaults** (permissions, features) are set in the Dashboard / via the API, not enforced by the SDK. ## Quick ref - **Packages:** `stream-chat`, `stream-chat-react`; import `stream-chat-react/css/index.css` (v14+ preferred alias; v13 used `dist/css/v2/index.css`). - **First:** **App Integration** -> **Setup** (CLI / channel types) before UI. -- **Per feature:** Jump to section (Channel List, Message List, ...) when implementing that screen. -- **Below the next rule:** full blueprints - **do not load past it** until you implement that component. +- **Per feature:** fetch the matching live page from [docs-map.md](docs-map.md) before implementing that screen; for fully hand-built UI on the low-level client, see [custom-ui.md](custom-ui.md). -Full component blueprints: [CHAT-blueprints.md](CHAT-blueprints.md) - load only the section you are implementing. +Prebuilt component path: [CHAT-blueprints.md](CHAT-blueprints.md) - the canonical provider tree + props. Bespoke UI on the low-level client: [custom-ui.md](custom-ui.md). --- diff --git a/skills/stream-react/references/FEEDS-blueprints.md b/skills/stream-react/references/FEEDS-blueprints.md index c818860..78b06a6 100644 --- a/skills/stream-react/references/FEEDS-blueprints.md +++ b/skills/stream-react/references/FEEDS-blueprints.md @@ -76,7 +76,7 @@ Individual activity card showing author, content, reactions, comments, and actio
- +
diff --git a/skills/stream-react/references/VIDEO-blueprints.md b/skills/stream-react/references/VIDEO-blueprints.md index cce2d29..1c09237 100644 --- a/skills/stream-react/references/VIDEO-blueprints.md +++ b/skills/stream-react/references/VIDEO-blueprints.md @@ -2,7 +2,7 @@ Setup, routes, and gotchas: [VIDEO.md](VIDEO.md). Rules: [`../RULES.md`](../RULES.md) (reference authority, strict mode protection) and the cross-cutting [../../stream/RULES.md](../../stream/RULES.md) (secrets, no auto-seeding). -**Build the common path with `@stream-io/video-react-sdk`'s prebuilt components and customize via `useCallStateHooks()` + `ParticipantView`.** Only drop to the hand-built markup in **Fully custom UI (fallback)** below when the user explicitly wants fully bespoke UI - and even then, fetch the matching docs page first ([`DOCS.md`](DOCS.md)). +**Build the common path with `@stream-io/video-react-sdk`'s prebuilt components and customize via `useCallStateHooks()` + `ParticipantView`.** For fully hand-built, bespoke UI on the low-level client, see [`custom-ui.md`](custom-ui.md) - and even then, fetch the matching docs page first ([`docs-map.md`](docs-map.md)). --- @@ -54,477 +54,10 @@ const [spotlight, ...others] = useParticipants(); **Customization hooks:** the umbrella is `useCallStateHooks()`, which returns sub-hooks you destructure: `useParticipants`, `useLocalParticipant`, `useRemoteParticipants`, `useCallCallingState`, `useCameraState`, `useMicrophoneState`, `useScreenShareState`, `useDominantSpeaker`, `useParticipantCount`, `useOwnCapabilities`, `useIsCallRecordingInProgress`, ... Plus `useCall()` and `useStreamVideoClient()`. Usage: `const { useCameraState } = useCallStateHooks(); const { camera, isMute } = useCameraState(); camera.toggle();` -**Docs-first:** for any customization (replacing call controls, custom layouts, lobby preview, PiP, network quality, livestream watching, ringing, ...) fetch the matching page from [`DOCS.md`](DOCS.md) first. Component reference pages live at `https://getstream.io/video/docs/react/ui-components/...`. +**Docs-first:** for any customization (replacing call controls, custom layouts, lobby preview, PiP, network quality, livestream watching, ringing, ...) fetch the matching page from [`docs-map.md`](docs-map.md) first. Component reference pages live at `https://getstream.io/video/docs/react/ui-components/...`. --- ## Fully custom UI (fallback) -> **Use these only when the user explicitly wants bespoke, fully hand-built UI** (not the prebuilt components above). Each section gives the raw element structure + a wiring table mapping DOM to SDK calls. Still fetch the matching [`DOCS.md`](DOCS.md) page first. The BEM class names are a structural spec (elements + conditional states) - implement with Shadcn components and Tailwind utilities; do not ship the BEM classes or hand-written CSS. - -## Lobby - -Pre-join screen where users preview their camera/mic and set preferences before entering a call. - -### Blueprint - -```html -
- -
- - - -
- - -
- -
-
-
-
- -
- - -
- - -
- - - - -
- -
-

- -
- - 3 others already in this call -
-
- -
- - -
- -
-``` - -### Wiring - -| Element | Read | Write | Property Path | -|---|---|---|---| -| `lobby__video` | `call.camera.state.mediaStream` | Assign stream to video element's `srcObject` | Local media stream | -| `lobby__toggle--camera` | `call.camera.state.status` | `call.camera.enable()` / `call.camera.disable()` | `'enabled'` or `'disabled'` | -| `lobby__toggle--mic` | `call.microphone.state.status` | `call.microphone.enable()` / `call.microphone.disable()` | `'enabled'` or `'disabled'` | -| `lobby__device-select--camera` | `call.camera.listDevices()` | `call.camera.select(deviceId)` | RxJS Observable of `MediaDeviceInfo[]` | -| `lobby__device-select--mic` | `call.microphone.listDevices()` | `call.microphone.select(deviceId)` | RxJS Observable of `MediaDeviceInfo[]` | -| `lobby__device-select--speaker` | `call.speaker.listDevices()` | `call.speaker.select(deviceId)` | RxJS Observable of `MediaDeviceInfo[]` | -| `lobby__call-title` | `call.state.custom.title` or `call.id` | - | Set during `call.getOrCreate({ data: { custom: { title } } })` | -| `lobby__participants-preview` | `call.state.participants` | - | Participants already joined | -| `lobby__join` | - | `call.join()` | Transitions to call layout | -| `lobby__cancel` | - | `call.leave()` | Navigates away | -| `lobby__audio-level` | `call.microphone.state.mediaStream` | - | Use `AudioContext` + `AnalyserNode` on the stream | - -> `call.{camera,microphone,speaker}.listDevices()` returns an **RxJS Observable** of `MediaDeviceInfo[]` - you must `.subscribe()` to it (it is not an array). Inside a `` context, prefer `useCameraState().devices` / `useMicrophoneState().devices` / `useSpeakerState().devices`, which are already-resolved arrays. - -### Requirements - -| Feature | Requirement | Default | -|---|---|---| -| Camera/mic access | Browser `getUserMedia` permission | Prompted on first access | -| Call reference | `call = client.call(callType, callId)` then `call.getOrCreate()` | Must create before lobby | -| Device enumeration | `navigator.mediaDevices.enumerateDevices()` | Available after permission grant | -| Participants preview | `call.getOrCreate()` returns current participants | Available | - ---- - -## Call Layout - -Container for the active call. Manages participant arrangement in different layout modes. - -### Blueprint - -```html -
- - - -
- - -
- - -
-
- -
-
- -
-
- - -
-
- -
-
- -
-
- - -
- -
- - is sharing their screen -
-
- - -
- -
- - -
- - wants to join - - -
- - -
- -
- -
-``` - -### Wiring - -| Element | Read | Write | Property Path | -|---|---|---|---| -| Participant list | `call.state.participants` | - | Array of `StreamVideoParticipant` objects | -| Dominant speaker | `call.state.dominantSpeaker` | - | Updates in real-time | -| Screen share track | `participant.screenShareStream` | - | Non-null when participant is screen sharing | -| `call-layout__screen-share-video` | Screen share participant's video track | Assign to `srcObject` | `participant.screenShareStream` | -| Layout mode | Client-side state | - | Auto-switch to spotlight when screen share starts | -| Self-view | `call.state.localParticipant` | - | Current user's participant object | -| Join request | `call.on('call.permission_request', cb)` | `call.grantPermissions(userId, ['send-audio','send-video'])` / `call.revokePermissions(userId, [...])` | `permissions` (string[]) is **required** - the second arg lists the capabilities to grant/revoke | - -### Requirements - -| Feature | Requirement | Default | -|---|---|---| -| Call joined | `call.join()` completed | - | -| Dominant speaker | Automatic | Available - determined server-side from audio levels | -| Screen sharing | `call.screenShare.enable()` | Available - browser `getDisplayMedia` | -| Layout modes | Client-side | No config - implement layout logic based on participant count and screen share state | -| Join requests | Call type configured with `join_ahead_time_seconds` or backstage mode | Off | - ---- - -## Participant Tile - -Individual participant's video/audio in the call. Used inside call layouts. - -### Blueprint - -```html -
- - - - - -
- -
- - -
-
- - - -
- - -
- - -
- - -
- - -
- - - - - -
-
- -
-``` - -### Wiring - -| Element | Read | Write | Property Path | -|---|---|---|---| -| `participant-tile__video` | Participant's video track | Assign to `srcObject` | `participant.videoStream` | -| `participant-tile__avatar` | Participant data | - | `participant.image` | -| `participant-tile__name` | Participant data | - | `participant.name` or `participant.userId` | -| `--speaking` modifier | Participant audio state | - | `participant.isSpeaking` (boolean) | -| `--muted` modifier | Participant audio state | - | `participant.audioStream` is null or `!hasAudio(participant)` (import `hasAudio` from `@stream-io/video-client`) | -| `--video-off` modifier | Participant video state | - | `participant.videoStream` is null or `!hasVideo(participant)` (import `hasVideo` from `@stream-io/video-client`) | -| `--dominant` modifier | `call.state.dominantSpeaker` | - | `participant.isDominantSpeaker` | -| Network quality | Participant stats | - | `participant.connectionQuality` - `ConnectionQuality.EXCELLENT`, `.GOOD`, `.POOR`, `.UNSPECIFIED` | -| Pin | - | Client-side state | Layout prioritizes pinned participant | -| Mute participant | - | `call.muteUser(userId, 'audio')` | Host/admin only | -| Remove participant | - | `call.kickUser({ user_id: userId })` | Host/admin only. Removes from the call; add `block: true` to also ban from rejoining. `call.blockUser(userId)` *bans* without removing - not the same as "remove" | - -### Requirements - -| Feature | Requirement | Default | -|---|---|---| -| Video rendering | Participant has granted camera permission and is publishing | - | -| Audio rendering | Attach `participant.audioStream` to an `