Skip to content

fix(EmojiPicker): drop @emoji-mart/react peer dependency - #3255

Merged
oliverlaz merged 1 commit into
masterfrom
fix/drop-emoji-mart-react-peer-dep
Aug 5, 2026
Merged

fix(EmojiPicker): drop @emoji-mart/react peer dependency#3255
oliverlaz merged 1 commit into
masterfrom
fix/drop-emoji-mart-react-peer-dep

Conversation

@oliverlaz

@oliverlaz oliverlaz commented Aug 4, 2026

Copy link
Copy Markdown
Member

🎯 Goal

@emoji-mart/react declares react as ^16.8 || ^17 || ^18 in its peerDependencies β€” React 19 is missing. Integrators on React 19 therefore hit peer-dependency resolution errors on install and have to add package.json overrides to get past them, even though the package works fine on React 19 in practice.

The wrapper that package provides is ~20 lines of glue around the emoji-mart Picker custom element. Rather than asking every React 19 integrator to carry an override, we vendor it and drop the dependency.

πŸ›  Implementation details

Vendored the wrapper - new src/plugins/Emojis/Picker.tsx, taken from @emoji-mart/react (MIT, Copyright (c) Missive). Behaviour is identical to upstream;

@emoji-mart/react declares react as ^16.8 || ^17 || ^18, omitting React
19, so integrators on React 19 hit peer-dependency errors and have to add
package.json overrides even though the package works fine there.

Vendor its ~20-line wrapper around the emoji-mart Picker custom element
instead (MIT, from missive/emoji-mart) and remove the dependency from
peerDependencies, peerDependenciesMeta and devDependencies. emoji-mart
and @emoji-mart/data remain optional peer dependencies.

This also lets us drop the CJS default-unwrapping workaround from #3199,
which existed because @emoji-mart/react ships CJS with the component on
exports.default and broke under strict ESM interop.

Not a breaking change: @emoji-mart/react was an optional peer dependency
and nothing in the SDK imports it any more.
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

πŸ“ Walkthrough

Walkthrough

Changes

The PR adds a local React Picker wrapper for the emoji-mart custom element. EmojiPicker uses the wrapper and its props type. Tests cover mounting, updates, StrictMode, and cleanup. The @emoji-mart/react dependency entries are removed.

Emoji picker integration

Layer / File(s) Summary
Picker wrapper and lifecycle validation
src/plugins/Emojis/Picker.tsx, src/plugins/Emojis/__tests__/Picker.test.tsx
Adds the Picker component with prop forwarding, rerender updates, mount initialization, and unmount cleanup. Tests cover rendering, StrictMode, theme updates, and removal.
EmojiPicker wiring and dependency removal
src/plugins/Emojis/EmojiPicker.tsx, package.json
Updates EmojiPicker to use the local Picker and PickerProps. Removes @emoji-mart/react from peer, optional peer, and development dependencies.

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

Suggested reviewers: martincupela, arnautov-anton

πŸš₯ Pre-merge checks | βœ… 5
βœ… Passed checks (5 passed)
Check name Status Explanation
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.
Title check βœ… Passed The title clearly and concisely describes removal of the @emoji-mart/react peer dependency.
Description check βœ… Passed The description provides the goal and implementation details, and the stated absence of UI changes makes the missing UI Changes section non-critical.
✨ 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 fix/drop-emoji-mart-react-peer-dep

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

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Size Change: +154 B (+0.02%)

Total Size: 884 kB

πŸ“¦ View Changed
Filename Size Change
dist/cjs/emojis.js 2.65 kB +72 B (+2.79%)
dist/es/emojis.mjs 2.59 kB +82 B (+3.27%)
ℹ️ View Unchanged
Filename Size
dist/cjs/audioProcessing.js 1.74 kB
dist/cjs/channel-detail.js 23.3 kB
dist/cjs/index.js 293 kB
dist/cjs/mp3-encoder.js 814 B
dist/cjs/ReactPlayerWrapper.js 546 B
dist/cjs/useChannelHeaderOnlineStatus.js 41.2 kB
dist/cjs/useMessageComposerController.js 1.01 kB
dist/cjs/useNotificationApi.js 57.9 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/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 937 B
dist/es/useNotificationApi.mjs 56.7 kB

compressed-size-action

@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.

🧹 Nitpick comments (1)
src/plugins/Emojis/Picker.tsx (1)

28-29: πŸ“ Maintainability & Code Quality | πŸ”΅ Trivial | ⚑ Quick win

Document the ESLint exception.

Add a reason before the suppression. The effect must create the picker once. Prop changes use instance.current.update(props).

Proposed change
+    // Create the picker once. Prop changes use instance.current.update(props) above.
     // eslint-disable-next-line react-hooks/exhaustive-deps
     }, []);

As per coding guidelines, β€œDo not suppress ESLint/Prettier rules broadly; justify and scope exceptions when necessary.”

πŸ€– Prompt for 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.

In `@src/plugins/Emojis/Picker.tsx` around lines 28 - 29, Add a concise
justification for the react-hooks/exhaustive-deps suppression next to the
disable directive in the effect that creates the picker, stating that it
intentionally runs once and subsequent prop changes are handled through
instance.current.update(props).

Source: Coding guidelines

πŸ€– 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.

Nitpick comments:
In `@src/plugins/Emojis/Picker.tsx`:
- Around line 28-29: Add a concise justification for the
react-hooks/exhaustive-deps suppression next to the disable directive in the
effect that creates the picker, stating that it intentionally runs once and
subsequent prop changes are handled through instance.current.update(props).

ℹ️ Review info
βš™οΈ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 029e94ed-44e4-4386-ad63-81f110204be5

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 972b68c and 85bb342.

β›” Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
πŸ“’ Files selected for processing (4)
  • package.json
  • src/plugins/Emojis/EmojiPicker.tsx
  • src/plugins/Emojis/Picker.tsx
  • src/plugins/Emojis/__tests__/Picker.test.tsx
πŸ’€ Files with no reviewable changes (1)
  • package.json

@codecov

codecov Bot commented Aug 4, 2026

Copy link
Copy Markdown

Codecov Report

βœ… All modified and coverable lines are covered by tests.
βœ… Project coverage is 85.19%. Comparing base (972b68c) to head (85bb342).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3255      +/-   ##
==========================================
+ Coverage   85.18%   85.19%   +0.01%     
==========================================
  Files         507      508       +1     
  Lines       15949    15958       +9     
  Branches     5025     5025              
==========================================
+ Hits        13586    13596      +10     
+ Misses       2363     2362       -1     

β˜” 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.

@oliverlaz
oliverlaz merged commit 0820e4c into master Aug 5, 2026
16 checks passed
@oliverlaz
oliverlaz deleted the fix/drop-emoji-mart-react-peer-dep branch August 5, 2026 08:28
oliverlaz added a commit that referenced this pull request Aug 5, 2026
### 🎯 Goal

Agent-facing documentation in this repo was spread across three files
that nothing verified, and all three had drifted.

**`AI.md`** was a hand-maintained integration guide for AI assistants,
shipped in the npm tarball. It duplicates what the official docs and
tutorial already cover. Every item below is wrong on `master` today:

| Claim in `AI.md` | Reality |
| --- | --- |
| `import 'stream-chat-react/dist/css/v2/index.css'` β€” **6 occurrences**
| `build-styling` emits `dist/css/index.css`; there is no
`dist/css/v2/`, so this import cannot resolve |
| `examples/tutorial/src/4-custom-ui-components/` |
`6-custom-ui-components` |
| `examples/tutorial/src/7-livestream/` | `optional-livestream` |
| `examples/tutorial/src/6-emoji-picker/` | `7-emoji-picker` |
| `examples/vite/src/stream-imports-theme.scss` | does not exist
(`examples/vite/src/index.scss`) |
| `stream-chat`: `^9.27.2` | `^9.50.2` |
| install `@emoji-mart/react`, add React 19 overrides | no longer a
dependency (#3255) |

An AI-facing guide that hands out a CSS import path which doesn't exist
is worse than no guide β€” it produces confidently broken integrations. We
now publish maintained [agent
skills](https://getstream.io/agent-skills/docs/installation/) that cover
integration properly and stay in sync across SDKs.

**`CLAUDE.md` and `AGENTS.md`** covered overlapping ground with no
shared source, so each drifted independently β€” `CLAUDE.md` still
documented Jest, a Playwright e2e suite, and a `MessageInput` component,
none of which exist. Two files describing one repo is the reason they
were both wrong.

**`yarn types`** silently checked nothing (details below), so the type
errors a contributor expected it to catch went unreported.

### πŸ›  Implementation details

#### 1. Deleted `AI.md`

423 lines, and removed from the `files` array in `package.json` β€” it was
being published to npm, so this drops a file from the package tarball,
not just from the repo.

**Added a `Build with AI Agents` section to `README.md`**, directly
after *React Chat Tutorial*. The tutorial is presented as the best way
to get started, so the agent-driven path belongs beside it rather than
buried further down. It documents the install (`curl -fsSL
https://getstream.io/cli.sh | bash` + `getstream init`), links
[`/stream-react`](https://getstream.io/agent-skills/docs/skills/stream-react/),
and shows example invocations. Three entry points, so it's discoverable
however someone scans the README: a `Quick Links` bullet at the top, the
section itself, and a cross-reference from the existing "Using AI
assistants" block at the bottom β€” that block points at `AGENTS.md`,
which is about *contributing to this repo*, a different audience from
someone integrating the SDK.

Content came from the live docs pages rather than memory, so the install
command, the four skill capabilities (scaffold / enhance / audit /
migrate, including Sendbird β†’ Stream Chat) and the supported-agent list
match what the docs actually say.

#### 2. `AGENTS.md` is now the single source; `CLAUDE.md` imports it

`CLAUDE.md` is reduced to a pointer ending in `@AGENTS.md`, which Claude
Code expands inline. `AGENTS.md` absorbed the architecture content and
keeps its own contribution rules, so there is one file to maintain for
every agent that reads this repo β€” and `AGENTS.md` is already the
filename Copilot, Cursor, Codex and Aider read.

An import rather than a symlink: git symlinks degrade to a plain text
file on Windows checkouts with `core.symlinks=false`, which would leave
Claude Code with no guidance at all.

Every claim in the merged file was re-derived from source rather than
carried over. Corrections:

| Was documented | Reality in `src` |
| --- | --- |
| "Run Jest tests", `yarn e2e`, `yarn e2e-fixtures` | Vitest only; no
Jest, no Playwright suite in this repo |
| `<MessageInput>` + `MessageInput/hooks/` | Directory no longer exists
β€” it's `MessageComposer`, backed by `stream-chat`'s `MessageComposer`
class |
| `<Channel Message={CustomMessage} />` | `ChannelProps` carries no
component slots; overrides go through `<WithComponents overrides={{ …
}}>` |
| `useStateStore(chatClient.state.channelsArray)` | A selector is
required; shallow-compares selected keys |
| 3 bundle entry points | 4 β€” `channel-detail` was added;
`build-styling` emits 4 stylesheets |
| `css-reset β†’ stream-new β†’ …` layers | `modern-normalize, stream-new,
stream-new-plugins, stream-overrides, stream-app-overrides` |
| `_global-theme-variables.scss` | `variable-tokens.scss` +
`light.scss`/`dark.scss` |
| Yarn binary pinned to `yarn-4.14.1.cjs` | Now unpinned by filename
(it's 4.15.0 and moves) |
| "Never commit directly to `main`" | Default branch is `master` |
| Styling / Build / i18n sections duplicated verbatim | Deduplicated |

Added, because it isn't discoverable without reading several files:
composer state ownership and the `client.messageComposerCache`
resolution order; the Vite 8 / Rolldown constraints in `vite.config.ts`
and why they must not be "simplified" (hardcoded `es`/`cjs` output dirs,
regex externals for subpath imports); the `npmMinimalAgeGate: 1d` /
`enableScripts: false` dependency gates; the Vitest setup contract and
`mock-builders` inventory; `src/a11y` primitives; i18n `keySeparator:
false` (keys legitimately contain `/`); and the CI job list.

The architectural sections that still held were each re-verified against
source before being kept: the 500ms/200ms/500ms-leading/2000ms throttles
in `Channel.tsx`, `PREPEND_OFFSET = 10 ** 7`, the `processMessages`
ordering, the string-serialization memoization FIXME in
`useCreateChannelStateContext`, `areMessageUIPropsEqual`'s cheap-prop
ordering, and the `react-compat` ESLint block.

#### 3. `yarn types` now type-checks `src`

```diff
-    "types": "tsc --emitDeclarationOnly false --noEmit",
+    "types": "tsc --project tsconfig.lib.json --noEmit",
```

Without `--project`, `tsc` resolves the root `tsconfig.json` β€” a
solution-style config with `"files": []` and project references only. It
therefore checked **no files**, exited in under a second and always
passed. `--emitDeclarationOnly false` is dropped: it only existed to
dodge the old TS5053 error when `--noEmit` met `emitDeclarationOnly`,
and under this repo's TypeScript 6 the output is byte-identical without
it (diffed both forms).

`yarn types:tests` is left alone but is now documented honestly: it is
**not run by CI** and is currently red repo-wide (~1300 errors), so
`AGENTS.md` frames it as advisory against a baseline rather than a green
gate. Worth a follow-up; out of scope here.

### βœ… Verification

- `yarn lint` β€” exit 0 (prettier covers Markdown in this repo)
- **`yarn types` was verified to actually check, not merely to run**:
injected `const __typecheck_probe: number = "not a number"` into
`src/utils/getChannel.ts`, confirmed it was reported as `TS2322`, then
reverted. Before this change the same probe produced no output.
- Nothing in CI invokes `yarn types`, so enabling it cannot turn CI red.
The same `tsconfig.lib.json` is already compiled by `yarn build` in CI
with `noEmitOnError`, so `src` type errors were failing CI before this
change too β€” this only makes the check runnable locally under a
memorable name.
- `require()` of `package.json` to confirm the earlier `files` edit kept
it valid; no remaining references to `AI.md` anywhere in the repo.

### 🎨 UI Changes

None β€” documentation and one script definition.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Documentation**
* Added an β€œAI Agent Skills” quick link and guidance for building,
upgrading, integrating, auditing, and migrating Stream Chat React
applications with AI agents.
* Replaced outdated repository guidance with expanded documentation
covering development workflows, architecture, testing, accessibility,
styling, troubleshooting, and contribution practices.
  * Removed the obsolete AI integration guide and related references.
* Updated published package contents to reflect the documentation
changes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
github-actions Bot pushed a commit that referenced this pull request Aug 7, 2026
## [14.11.0](v14.10.0...v14.11.0) (2026-08-07)

### Bug Fixes

* **Channel:** guard render-phase channel.getConfig() against disconnected channels ([#3257](#3257)) ([f60273f](f60273f)), closes [#3254](#3254) [#2393](#2393) [#3249](#3249)
* **EmojiPicker:** drop @emoji-mart/react peer dependency ([#3255](#3255)) ([0820e4c](0820e4c))

### Features

* add icons to ComponentContext ([#3246](#3246)) ([972b68c](972b68c))
* localized unread count ([#3250](#3250)) ([1b8fa34](1b8fa34)), closes [GetStream/stream-chat-react-native#3679](GetStream/stream-chat-react-native#3679)
* **MessageComposer:** introduce context for custom composers ([#3249](#3249)) ([5776c16](5776c16)), closes [#3248](#3248)
@stream-ci-bot

Copy link
Copy Markdown

πŸŽ‰ This PR is included in version 14.11.0 πŸŽ‰

The release is available on:

Your semantic-release bot πŸ“¦πŸš€

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants