Skip to content

chore(tutorial): align the example app with the rewritten React chat tutorial - #3251

Merged
oliverlaz merged 4 commits into
masterfrom
tutorial-app-align-with-docs
Jul 28, 2026
Merged

chore(tutorial): align the example app with the rewritten React chat tutorial#3251
oliverlaz merged 4 commits into
masterfrom
tutorial-app-align-with-docs

Conversation

@oliverlaz

@oliverlaz oliverlaz commented Jul 28, 2026

Copy link
Copy Markdown
Member

🎯 Goal

examples/tutorial had drifted out of sync with the published React chat tutorial, which was restructured in GetStream/getstream.io#345 into numbered steps 0-7 plus two optional recipes. Folder numbering no longer lined up with the tutorial's step numbers, and there was no runnable counterpart for the theming step at all.

Two things also made the example unusable as it stood:

  • It did not boot on a clean install. Two React instances, Invalid hook call on first render. Reproduces on master.
  • The preview panel clipped the chat UI at the edges and pushed the composer below the fold.

The point of this example is that a reader can run the exact code the tutorial gave them, so a folder here needs to map 1:1 to a heading there.

🛠 Implementation details

Three commits, each independently revertable.

1. Step alignment (244f77697)

Folders renumbered to match the tutorial, and the two non-linear steps renamed to optional-*:

Folder Tutorial section
2-client-setup Step 2 - Connect the client
3-core-component-setup Step 3 - Get a working chat UI
4-channel-list Step 4 - Add a channel list
5-theming Step 5 - Theme it (new)
6-custom-ui-components Step 6 - Replace an SDK component
7-emoji-picker Step 7 - Enable the emoji picker and autocomplete
optional-custom-attachment-type Optional - add a custom attachment type
optional-livestream Optional - a livestream-style chat app

The tutorial's Step 0 (environment) and Step 1 (project + credentials) have no runnable counterpart, so numbering starts at 2.

Also in this commit:

  • Preview panel layout fix. The chrome panes are sized in viewport units and padded, so under the default content-box the padding was added on top of 100vh — 1312px of content in a 1272px viewport. Fixed with border-box on the six named chrome classes only, deliberately not .tutorial-browser *, so the SDK's own box-sizing is untouched.
  • Entry cleanup. Removed the 16 per-step main.tsx / index.html files. They date to chore: add tutorial to examples #2697, when the step browser did not exist and booting a step's own HTML was the only way to run it. Since the browser landed they have been dead weight: vite build only ever emitted dist/index.html, nothing referenced them, and all eight main.tsx were byte-identical. Each step folder now holds exactly the files the tutorial tells you to create.

2. React dedupe (4b865aabc)

stream-chat-react is consumed as a workspace dependency, so Vite serves its built output from outside the app's root and resolves that copy's react import separately from the app's. The SDK and the app end up on two React instances and the first hook call throws. resolve.dedupe: ['react', 'react-dom'] forces both onto a single copy.

Split out on its own because it is the one change that is not tutorial content — it can be cherry-picked or reverted independently.

3. Step stylesheet cleanup (6a67e4447) — no rendering change

The step browser renders every step in one document, so all seven stylesheets are live at once. Steps 3 and 4 import the SDK stylesheet unlayered (as the tutorial has them, since Step 5 is where you are taught to move it into a layer), and unlayered CSS outranks every @layer regardless of specificity — so the tutorial's @layer stream-overrides { .custom-theme { ... } } silently does nothing here.

The themed steps declare the tokens unlayered on .str-chat.custom-theme instead. Channel.tsx:163 and ChannelList.tsx:342 both do clsx('str-chat', theme, ...), so the theme class lands on the same element as str-chat; at 0,2,0 this beats the SDK's own .str-chat (0,1,0) regardless of source order, and it only matches steps that actually pass theme="custom-theme", so it cannot leak into the unthemed ones. README flags this as the one deliberate deviation, with a pointer to keep the tokens in the layer in your own app.

That leaves layout.css with exactly two distinct versions, mirroring the tutorial's two, byte-identical within each group so drift shows up in a diff.

Also: html / body / #root were previously declared only in the step stylesheets, so the chrome silently depended on a step's CSS for body { margin: 0 } and would pick up the UA margin if steps were ever loaded lazily or in isolation (2-client-setup has no layout.css at all). tutorial-main.css now declares them itself.

Parts of each layout.css copy are inert inside the step browser and stay that way on purpose, since the file has to remain a faithful copy of what the tutorial has readers write. README documents each case:

  • the custom-theme tokens do nothing in 7-emoji-picker and optional-livestream, which do not pass theme="custom-theme" — matching the tutorial, where the reader's single layout.css holds the tokens and leaves them unused for those same two examples
  • the .str-chat__* widths lose to .tutorial-browser__step-shell .str-chat__* in tutorial-main.css (0,2,0 against 0,1,0); the tutorial's widths assume the app owns the whole page, here it is sized to fit a preview card

No bundle cost either way — Vite collapses the identical copies, so the built CSS contains one width: 30% and one @layer stream.

🎨 UI Changes

No change to the SDK itself, and no change to any tutorial code block. The visual deltas are all in the example app:

  • New 5-theming step, so the tutorial's theming milestone is now runnable.
  • Preview panel no longer clips. Before, the chat UI was cut off at the card's edges and the composer sat below the fold. Now every step reports overflowX/Y: 0 with the preview card fully within the viewport.
  • Step 2 corner padding. 2-client-setup renders bare text with no chat chrome, so it landed inside the card's 28px corner arc and the first glyph was clipped. Padded via the step-client-setup class.

Verified across all eight steps by reading computed styles after switching:

Step Theme class on .str-chat --str-chat__accent-primary
3, 4 messaging light #005fff
5, 6, optional-custom-attachment-type custom-theme #0d47a1
7 messaging light #005fff
optional-livestream str-chat__theme-dark #4586ff

Step 7 intentionally shows the default accent — the tutorial's emoji block renders <Chat> without the theme prop, and notes so explicitly.

tsc -b, vite build, and gated prettier all pass. No console errors on any step.

To see it: yarn start:tutorial from the repo root.


Opened without a reviewer since I am not sure who owns this area — happy to add whoever should look at it.

Companion PR: GetStream/getstream.io#345

Summary by CodeRabbit

  • New Features
    • Expanded the tutorial browser with updated step structure, channel list, theming, custom UI components, emoji picker, and livestream (including optional milestones).
  • Documentation
    • Refreshed the tutorial README with current folder/step mapping and step-browser rendering notes.
  • Bug Fixes
    • Improved tutorial preview/layout sizing to avoid viewport clipping/overflow.
    • Prevented issues from multiple React instances during development.
  • Refactor
    • Reworked step mounting and applied consistent theme overrides across steps.
  • Chores
    • Updated the example environment key name to VITE_STREAM_API_KEY (with legacy fallback).

…rial

The published tutorial was restructured (GetStream/getstream.io#345) into
numbered steps 0-7 plus two optional recipes. This aligns the example app so a
folder here maps 1:1 to a heading there.

- Renumber the step folders to match the tutorial (2-client-setup through
  7-emoji-picker), and rename the two non-linear steps to optional-*.
- Add the missing 5-theming step. The tutorial teaches theming before the
  component overrides, but the app had no counterpart for it.
- Scope every themed step's overrides under a `step-<id>` class, applied by the
  browser in src/App.tsx. The step browser renders all steps in one document, so
  all eight stylesheets are live at once; steps 3 and 4 import the SDK stylesheet
  unlayered (as the tutorial has them), and unlayered CSS outranks every @layer
  regardless of specificity. Without the scope, a layered override does nothing
  and an unscoped one restyles the earlier steps. README documents this as the
  one deliberate deviation from the tutorial.
- Fix the preview panel clipping the chat UI. The chrome panes are sized in
  viewport units and padded, so under the default content-box the padding was
  added on top of 100vh and pushed the composer below the fold. Sets border-box
  on the six named chrome classes only, so the SDK's own box-sizing is untouched.
- Drop the 16 per-step main.tsx and index.html files. They predate the step
  browser, were never part of any build (vite build only ever emitted
  dist/index.html), and had become a maintenance coupling for the scope class.
  Each step folder now holds exactly the files the tutorial tells you to create.
`stream-chat-react` is consumed as a workspace dependency, so Vite serves its
built output from outside the app's root and resolves that copy's `react` import
separately from the app's. The SDK and the app end up on two React instances and
the first hook call throws "Invalid hook call", which made the tutorial app fail
to boot on a clean install regardless of how it was started.

`resolve.dedupe` forces both onto a single copy.
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2b81a953-6d20-4f7b-8064-6daa94db44c6

📥 Commits

Reviewing files that changed from the base of the PR and between 6a67e44 and b52229a.

📒 Files selected for processing (1)
  • examples/tutorial/src/6-custom-ui-components/App.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • examples/tutorial/src/6-custom-ui-components/App.tsx

📝 Walkthrough

Walkthrough

The tutorial browser and step examples were reorganized around shared client setup, updated step metadata, scoped styling, new chat examples, credential fallback support, documentation, and Vite React deduplication. Obsolete per-step HTML/bootstrap files were removed.

Changes

Tutorial browser and examples

Layer / File(s) Summary
Step registry, documentation, and browser layout
examples/tutorial/README.md, examples/tutorial/.env.example, examples/tutorial/src/App.tsx, examples/tutorial/src/tutorial-main.css, examples/tutorial/vite.config.ts
Tutorial steps, documentation, environment guidance, preview scoping, browser sizing, and React resolution settings were updated.
Shared client setup
examples/tutorial/src/2-client-setup/*, examples/tutorial/src/{3-core-component-setup,5-theming,6-custom-ui-components,7-emoji-picker}/*.tsx, examples/tutorial/src/optional-*/App.tsx
A shared Chat client setup was added, API key lookup now prefers VITE_STREAM_API_KEY with a legacy fallback, and example imports use the shared credentials module.
Core chat and attachment examples
examples/tutorial/src/3-core-component-setup/*, examples/tutorial/src/4-channel-list/*, examples/tutorial/src/optional-custom-attachment-type/*
Core chat layouts, channel-list rendering, channel data augmentation, custom attachment types, and product-attachment detection were added or updated.
Themed and optional step styling
examples/tutorial/src/{5-theming,6-custom-ui-components,7-emoji-picker}/*.css, examples/tutorial/src/optional-*/layout.css
Themed examples import SDK styles into a layer, apply unlayered theme variables, and define chat panel layout sizing.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested labels: released on @latest``

Suggested reviewers: martincupela, arnautov-anton

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and clearly summarizes the main tutorial alignment change.
Description check ✅ Passed It includes the required Goal, Implementation details, and UI Changes sections, though no screenshots are attached.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tutorial-app-align-with-docs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

Size Change: 0 B

Total Size: 881 kB

ℹ️ View Unchanged
Filename Size
dist/cjs/audioProcessing.js 1.74 kB
dist/cjs/channel-detail.js 23.1 kB
dist/cjs/emojis.js 2.56 kB
dist/cjs/index.js 293 kB
dist/cjs/mp3-encoder.js 814 B
dist/cjs/ReactPlayerWrapper.js 547 B
dist/cjs/useChannelHeaderOnlineStatus.js 41.1 kB
dist/cjs/useMessageComposerController.js 1.01 kB
dist/cjs/useNotificationApi.js 57.5 kB
dist/css/channel-detail.css 2.84 kB
dist/css/emoji-picker.css 178 B
dist/css/emoji-replacement.css 456 B
dist/css/index.css 41.4 kB
dist/es/audioProcessing.mjs 1.65 kB
dist/es/channel-detail.mjs 22.7 kB
dist/es/emojis.mjs 2.48 kB
dist/es/index.mjs 290 kB
dist/es/mp3-encoder.mjs 768 B
dist/es/ReactPlayerWrapper.mjs 485 B
dist/es/useChannelHeaderOnlineStatus.mjs 40.6 kB
dist/es/useMessageComposerController.mjs 935 B
dist/es/useNotificationApi.mjs 56.1 kB

compressed-size-action

@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.24%. Comparing base (1068e79) to head (b52229a).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3251      +/-   ##
==========================================
+ Coverage   85.22%   85.24%   +0.01%     
==========================================
  Files         506      506              
  Lines       15795    15795              
  Branches     5023     5023              
==========================================
+ Hits        13462    13465       +3     
+ Misses       2333     2330       -3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/tutorial/src/7-emoji-picker/layout.css`:
- Around line 11-36: Match each scoped token override to the theme actually
rendered by its Chat component: in
examples/tutorial/src/7-emoji-picker/layout.css lines 11-36, either make the
step’s Chat use theme="custom-theme" or scope the overrides to its rendered
theme class; in examples/tutorial/src/optional-livestream/layout.css lines
11-36, target .str-chat__theme-dark or change the component to use custom-theme.
Ensure both override blocks apply to their corresponding rendered themes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 744a4c03-67e4-4cda-8d9c-05f10ed38e0c

📥 Commits

Reviewing files that changed from the base of the PR and between 0d1c643 and 4b865aa.

📒 Files selected for processing (42)
  • examples/tutorial/.env.example
  • examples/tutorial/README.md
  • examples/tutorial/src/1-client-setup/index.html
  • examples/tutorial/src/1-client-setup/main.tsx
  • examples/tutorial/src/2-client-setup/App.tsx
  • examples/tutorial/src/2-client-setup/credentials.ts
  • examples/tutorial/src/2-core-component-setup/index.html
  • examples/tutorial/src/2-core-component-setup/main.tsx
  • examples/tutorial/src/3-channel-list/index.html
  • examples/tutorial/src/3-channel-list/layout.css
  • examples/tutorial/src/3-channel-list/main.tsx
  • examples/tutorial/src/3-core-component-setup/App.tsx
  • examples/tutorial/src/3-core-component-setup/layout.css
  • examples/tutorial/src/3-core-component-setup/stream-chat.d.ts
  • examples/tutorial/src/4-channel-list/App.tsx
  • examples/tutorial/src/4-channel-list/layout.css
  • examples/tutorial/src/4-custom-ui-components/index.html
  • examples/tutorial/src/4-custom-ui-components/layout.css
  • examples/tutorial/src/4-custom-ui-components/main.tsx
  • examples/tutorial/src/5-custom-attachment-type/index.html
  • examples/tutorial/src/5-custom-attachment-type/layout.css
  • examples/tutorial/src/5-custom-attachment-type/main.tsx
  • examples/tutorial/src/5-theming/App.tsx
  • examples/tutorial/src/5-theming/layout.css
  • examples/tutorial/src/6-custom-ui-components/App.tsx
  • examples/tutorial/src/6-custom-ui-components/layout.css
  • examples/tutorial/src/6-emoji-picker/index.html
  • examples/tutorial/src/6-emoji-picker/layout.css
  • examples/tutorial/src/6-emoji-picker/main.tsx
  • examples/tutorial/src/7-emoji-picker/App.tsx
  • examples/tutorial/src/7-emoji-picker/layout.css
  • examples/tutorial/src/7-livestream/index.html
  • examples/tutorial/src/7-livestream/layout.css
  • examples/tutorial/src/7-livestream/main.tsx
  • examples/tutorial/src/App.tsx
  • examples/tutorial/src/optional-custom-attachment-type/App.tsx
  • examples/tutorial/src/optional-custom-attachment-type/layout.css
  • examples/tutorial/src/optional-custom-attachment-type/stream-chat.d.ts
  • examples/tutorial/src/optional-livestream/App.tsx
  • examples/tutorial/src/optional-livestream/layout.css
  • examples/tutorial/src/tutorial-main.css
  • examples/tutorial/vite.config.ts
💤 Files with no reviewable changes (19)
  • examples/tutorial/src/7-livestream/index.html
  • examples/tutorial/src/7-livestream/main.tsx
  • examples/tutorial/src/5-custom-attachment-type/index.html
  • examples/tutorial/src/1-client-setup/index.html
  • examples/tutorial/src/5-custom-attachment-type/layout.css
  • examples/tutorial/src/3-channel-list/index.html
  • examples/tutorial/src/3-channel-list/main.tsx
  • examples/tutorial/src/1-client-setup/main.tsx
  • examples/tutorial/src/2-core-component-setup/index.html
  • examples/tutorial/src/4-custom-ui-components/main.tsx
  • examples/tutorial/src/6-emoji-picker/index.html
  • examples/tutorial/src/3-channel-list/layout.css
  • examples/tutorial/src/4-custom-ui-components/index.html
  • examples/tutorial/src/6-emoji-picker/layout.css
  • examples/tutorial/src/2-core-component-setup/main.tsx
  • examples/tutorial/src/4-custom-ui-components/layout.css
  • examples/tutorial/src/5-custom-attachment-type/main.tsx
  • examples/tutorial/src/6-emoji-picker/main.tsx
  • examples/tutorial/src/7-livestream/layout.css

Comment thread examples/tutorial/src/7-emoji-picker/layout.css Outdated
Follow-up cleanup on the step CSS. No rendering change.

- Drop the per-step `.step-<id> .custom-theme` prefix for `.str-chat.custom-theme`.
  Channel.tsx and ChannelList.tsx both do `clsx('str-chat', theme, ...)`, so the
  theme class lands on the same element as `str-chat`; at 0,2,0 this beats the
  SDK's own `.str-chat` (0,1,0) regardless of source order, and it only matches
  the steps that actually pass `theme="custom-theme"`, so it still cannot leak
  into the unthemed steps. The layout.css copies are now byte-identical within
  each group - two distinct versions, matching the tutorial's two - so drift
  shows up in a diff. The CSS no longer depends on the browser's wrapper class.
- Declare the html/body/#root rules in tutorial-main.css. They were coming only
  from the step stylesheets, so the chrome silently relied on a step's CSS for
  `body { margin: 0 }` and would pick up the UA margin if steps were ever loaded
  lazily or in isolation (2-client-setup has no layout.css at all).
- Normalize steps 3 and 4 to the tutorial's 2-space indentation.
- README documents which parts of each copy are inert inside the step browser
  (the custom-theme tokens in the two steps that don't opt in, and the
  .str-chat__* widths, which lose to tutorial-main.css) and why they stay anyway:
  the file has to remain a faithful copy of what the tutorial has readers write.
@oliverlaz
oliverlaz merged commit 9704393 into master Jul 28, 2026
14 checks passed
@oliverlaz
oliverlaz deleted the tutorial-app-align-with-docs branch July 28, 2026 13:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant