From b1550eda69a93f1364c6e5fc0ab9f870a416875f Mon Sep 17 00:00:00 2001 From: martincupela Date: Thu, 5 Nov 2026 15:51:13 +0100 Subject: [PATCH 1/2] fix!: ship the CustomChannelData typing and remove dead exports and the transliterate dependency - Move the stream-chat Custom*Data augmentation into src/types/defaultDataInterfaces.ts so tsc emits it; apps that import stream-chat-react get channel.data.custom.name and .image typed. - DefaultChannelData holds only name and image, the fields the SDK renders a channel from. - Stop exporting Alert's Root and Header from the package root; use Alert.Root and Alert.Header. - Remove the unused icons UploadIcon, BinIcon, PauseIcon, PlayIcon, DownloadIcon and CloseIconRound, and the translation key only UploadIcon used. - Drop the unused optional dependency @stream-io/transliterate. BREAKING CHANGE: Root, Header, UploadIcon, BinIcon, PauseIcon and PlayIcon are no longer exported, @stream-io/transliterate is no longer installed with the package, and DefaultChannelData no longer has subtitle or team. See BC-101 in ai-docs/v15-breaking-changes.md. --- ai-docs/ai-migration-v14-v15.md | 41 +++++++--- ai-docs/i18n-v15-key-map.json | 6 +- ai-docs/i18n-v15-migration.md | 4 +- ai-docs/v15-breaking-changes.md | 76 ++++++++++++++++++- .../3-core-component-setup/stream-chat.d.ts | 7 -- .../stream-chat.d.ts | 6 +- examples/vite/src/i18n/de.ts | 1 - examples/vite/src/i18n/it.ts | 1 - package.json | 3 - src/@types/stream-chat-custom-data.d.ts | 39 ---------- src/components/Attachment/icons.tsx | 18 ----- .../Channel/__tests__/Channel.test.tsx | 1 - src/components/Dialog/components/Alert.tsx | 4 +- src/components/MessageComposer/icons.tsx | 57 -------------- src/components/Modal/icons.tsx | 21 ----- src/i18n/__tests__/catalog.fixture.json | 1 - src/i18n/keys.ts | 1 - src/types/defaultDataInterfaces.ts | 30 +++++++- yarn.lock | 27 ------- 19 files changed, 138 insertions(+), 206 deletions(-) delete mode 100644 examples/tutorial/src/3-core-component-setup/stream-chat.d.ts delete mode 100644 src/@types/stream-chat-custom-data.d.ts delete mode 100644 src/components/Modal/icons.tsx diff --git a/ai-docs/ai-migration-v14-v15.md b/ai-docs/ai-migration-v14-v15.md index 87150e7a5a..b1cab8a2aa 100644 --- a/ai-docs/ai-migration-v14-v15.md +++ b/ai-docs/ai-migration-v14-v15.md @@ -2,7 +2,7 @@ Execution-only guide for a coding agent migrating a third-party app from `stream-chat-react` v14 to v15. It covers the root package and its subpath entry points (`stream-chat-react/slot-layout`, `/slot-geometry`, `/channel-detail`, `/emojis`, `/ai-components`, `/mp3-encoder` and the `css/*` stylesheets). v15 requires `stream-chat` v10, itself a breaking client release, so upgrade both together; this guide covers the `stream-chat` changes a React app usually hits, and the [stream-chat guide](#companion-documents) covers the rest. The i18n runtime now comes from `@stream-io/i18n` and the state store from `@stream-io/state-store`, both installed as dependencies of this package. -Every breaking change in [`v15-breaking-changes.md`](https://github.com/GetStream/stream-chat-react/blob/master/ai-docs/v15-breaking-changes.md) (`BC-001` to `BC-095`) is covered here. The [index at the end](#index-of-breaking-changes) maps each `BC` entry to its section. +Every breaking change in [`v15-breaking-changes.md`](https://github.com/GetStream/stream-chat-react/blob/master/ai-docs/v15-breaking-changes.md) (`BC-001` to `BC-095`, and `BC-101`) is covered here. The [index at the end](#index-of-breaking-changes) maps each `BC` entry to its section. Verified against `master` @ `1c02ba07f` (`stream-chat-react@0.0.0-development`, after the `v15.0.0-rc.3` tag; `stream-chat` peer `^10.0.0-rc.29`, checked against stream-chat-js `release-v10` @ `fdfcb296`), 2026-11-03. @@ -128,6 +128,9 @@ styles() { rg -n --hidden -g '*.{css,scss,sass,less}' -g '!**/node_modules/**' - rg -n --hidden -g 'package.json' -g '!**/node_modules/**' -e '"(stream-chat|stream-chat-react|dayjs|i18next|@stream-io/[a-z-]+)"\s*:' . rg -n --hidden -g '.nvmrc' -g '.node-version' -g '*.{yml,yaml}' -g 'Dockerfile*' -g '!**/node_modules/**' -g '!.git' -e 'node-version|FROM node|^v?[0-9]+(\.[0-9]+)*$' . code '\b(ChatView|ChatViewContext|useChatViewContext|useActiveThread|ChatViewSelector\w*|ChatView\w*SelectorButton|defaultChatViewSelectorItemSet|AIStates|getAttachmentPreviewUrl|isUploadConfirmationPending|hasPendingUploadState|StateStore)\b' +# §1 removed exports: unused icons, @stream-io/transliterate imports, Alert parts imported as Root / Header +code '\b(UploadIcon|BinIcon|PauseIcon|PlayIcon)\b|@stream-io/transliterate' +rg -n -U --hidden -t ts -t js -g '!**/node_modules/**' -g '!**/dist/**' -g '!**/build/**' -e "import\s+(type\s+)?\{[^}]*\b(Root|Header)\b[^}]*\}\s*from\s*['\"]stream-chat-react['\"]" . # §2 client and code '\b(useCreateChatClient|useChat|defaultLanguage|channelsQueryState|latestMessageDatesByChannels|recoverStateOnReconnect|enableWSFallback|wsUrlParams|isLocalUnreadCountEnabled|StreamChatOptions)\b|connection\.changed' # §3 layout: Window, ChatView @@ -327,6 +330,7 @@ These compile cleanly, or are ignored in plain JS, and change behavior at runtim - **Node `>=22.18.0`.** `stream-chat@10` declares `engines.node >=22.18.0`, and Yarn 1 refuses to install on older Node. Move `.nvmrc` and every CI `node-version` (GitHub Actions `setup-node`, Docker base images, deploy workflows) to Node 22 before anything else: CI is usually the first thing to break. - **`dayjs` and `i18next` are no longer dependencies of this package.** It depends on `@stream-io/i18n`, which brings both (`dayjs ^1.11.23`, `i18next ^26`). `stream-chat` v10 depends on neither. If the app declared them only because of this SDK, remove them. If it keeps `dayjs`, its version must dedupe with `@stream-io/i18n`'s, or `import 'dayjs/locale/xx'` registers the locale on a different instance and dates stay English. - **`@stream-io/state-store` must resolve to exactly one copy.** `stream-chat`, `@stream-io/i18n` and this package hand each other store instances. `StateStore` has `protected` members, so stores from two copies are not assignable to `useStateStore`'s parameter. Check with `yarn why @stream-io/state-store` / `npm ls @stream-io/state-store`. A linked `stream-chat` checkout needs bundler dedupe. +- **`@stream-io/transliterate` is no longer installed with this package.** It was an optional dependency that no SDK code imported. If the app imports it, add it to the app's own dependencies. - **New subpath exports:** `stream-chat-react/slot-layout` (`ChatView` and its slot system) and `stream-chat-react/slot-geometry`. `stream-chat-react/ai-components`, `/channel-detail`, `/emojis` and `/mp3-encoder` already existed. ```bash @@ -375,10 +379,31 @@ Each import below is now a compile error (`TS2305` / `TS2724`) and `undefined` i | `MESSAGE_ACTIONS`, `OPTIONAL_MESSAGE_ACTIONS`, `getMessageActions`, `MessageActionsArray`, `Capabilities` | [Section 10](#messageactions-and-message_actions-are-removed) | | `useUserRole` | [Section 12](#useuserrole-is-renamed-to-usemessagepermissions) | | `deTranslations` ... `trTranslations`, `enTranslations`, `isLanguageSupported`, `SupportedTranslations`, `DateFormatterOptions` | [Section 18](#18-i18n) | +| `Root`, `Header` | [Section 1](#alert-parts-and-unused-icons) | +| `UploadIcon`, `BinIcon`, `PauseIcon`, `PlayIcon` | [Section 1](#alert-parts-and-unused-icons) | | `DefaultCommandData` | [Section 17](#17-other-stream-chat-v10-data-shapes) | New root exports: `useMessagePaginator()` returns the active list's paginator (the thread's inside a thread, the channel's otherwise), `useIsCooldownActive()` tells whether slow mode is counting down, and `messageHasMentions(message)` tells whether a message mentions anyone (a user, `@channel`, `@here`, a role or a user group). +### `Alert` parts and unused icons + +`Root` and `Header` were the parts of `Alert`, exported from the package root under generic names. Use `Alert.Root` and `Alert.Header`, the same components (`Alert.Actions` is unchanged): + +```tsx +// v14 +import { Header, Root } from 'stream-chat-react'; +// v15 +import { Alert } from 'stream-chat-react'; + +export const DeleteWarning = () => ( + + + +); +``` + +`UploadIcon`, `BinIcon`, `PauseIcon` and `PlayIcon` are removed; no SDK component rendered them. Copy the SVG into the app, or use the v15 icon set: `IconPlus` or `IconAttachment` for `UploadIcon`, `IconDelete` for `BinIcon`, `IconPauseFill` for `PauseIcon`, `IconPlayFill` for `PlayIcon`. They follow the v15 design and take `BaseIconProps`. + --- ## 2. Client and `` @@ -1054,13 +1079,7 @@ These keep the same signature and change behavior: import type { ChannelStateData } from 'stream-chat'; import { useChannel, useStateStore } from 'stream-chat-react'; - // `name` is custom data in stream-chat v10; declare it once, app-wide (section 17). - declare module 'stream-chat' { - interface CustomChannelData { - name?: string; - } - } - + // `name` is custom data in stream-chat v10, typed by stream-chat-react (section 17). const dataSelector = ({ data }: ChannelStateData) => ({ data }); export const ChannelNameInput = () => { @@ -3164,15 +3183,14 @@ React props typed with `stream-chat` types change with them. The React APIs are **Channel, chat context and search:** -- **Channel `name` and `image` are custom data.** A `stream-chat` v10 channel response carries them under `custom`, with no top-level `name`, so `channel.data?.name` (the most common read, in every channel header and preview) is `undefined`. Read `channel.data?.custom?.name` / `.image`. To type them, augment `CustomChannelData`. `name` is still a top-level **filter** key (`{ name: { $autocomplete: q } }`); other custom fields filter as `'custom.'`. Writes go under `data.custom`, and `channel.update({ data: { custom } })` replaces the whole custom object, so spread the existing `custom` (or use `channel.updatePartial`) to keep the other fields. The full mapping is in [`v10-breaking-changes.md`](https://github.com/GetStream/stream-chat-js/blob/release-v10/ai-docs/v10-breaking-changes.md) in stream-chat-js. +- **Channel `name` and `image` are custom data.** A `stream-chat` v10 channel response carries them under `custom`, with no top-level `name`, so `channel.data?.name` (the most common read, in every channel header and preview) is `undefined`. Read `channel.data?.custom?.name` / `.image`. Importing `stream-chat-react` types them: it merges `DefaultChannelData` (`image` and `name`, each `string | undefined`) into `CustomChannelData`. Augment `CustomChannelData` only for the app's other fields, and delete an app's own `name` / `image` declarations. Declaring `name` or `image` with another type does not fail with `skipLibCheck` (the app's type wins) and fails inside `stream-chat`'s `custom_types.d.ts` (`TS2430`) without it, so rename such a field. `DefaultChannelData` no longer has `subtitle` or `team`: declare them yourself if the app stores them under `custom`, and read the channel's team from the top-level `channel.data.team`. `name` is still a top-level **filter** key (`{ name: { $autocomplete: q } }`); other custom fields filter as `'custom.'`. Writes go under `data.custom`, and `channel.update({ data: { custom } })` replaces the whole custom object, so spread the existing `custom` (or use `channel.updatePartial`) to keep the other fields. The full mapping is in [`v10-breaking-changes.md`](https://github.com/GetStream/stream-chat-js/blob/release-v10/ai-docs/v10-breaking-changes.md) in stream-chat-js. ```tsx import type { Channel, ChannelFilters } from 'stream-chat'; declare module 'stream-chat' { interface CustomChannelData { - image?: string; - name?: string; + demo?: string; } } @@ -3518,3 +3536,4 @@ Run after every section is applied. | BC-093 | Mention handlers in the message context and from `useMentionsHandler` can be `undefined` | [12](#onmentionsclickmessage-and-onmentionshovermessage-are-undefined-without-a-handler) | | BC-094 | `mentionsMarkdownPlugin` takes mention entities only | [12](#mentionsmarkdownplugin-takes-mention-entities-only) | | BC-095 | `disableQuotedMessages` removed | [12](#the-disablequotedmessages-prop-is-removed) | +| BC-101 | `Root`, `Header`, composer icons, `@stream-io/transliterate`; `CustomChannelData` typed | [1](#packages), [1](#alert-parts-and-unused-icons), [17](#17-other-stream-chat-v10-data-shapes) | diff --git a/ai-docs/i18n-v15-key-map.json b/ai-docs/i18n-v15-key-map.json index 9bdc03eed5..6a4bff017a 100644 --- a/ai-docs/i18n-v15-key-map.json +++ b/ai-docs/i18n-v15-key-map.json @@ -1,6 +1,6 @@ { "$comment": "Migration table: natural-language translation key (v14) -> namespaced key (v15). Hand-reviewed; nothing regenerates it. Integrators who passed translationsForLanguage/registerTranslation dictionaries keyed on the old strings should use this to rename their keys. Where one v14 key became several v15 keys, `key` is the first and `also` lists the rest: copy the translation to each. See ai-docs/i18n-v15-migration.md.", - "count": 661, + "count": 660, "keys": { "aria/Active": { "key": "a11y.accessibleLabel.active.ariaLabel", @@ -2019,10 +2019,6 @@ "key": "messageComposer.geolocationPreview.sharedLocation.title", "prose": true }, - "Attach files": { - "key": "messageComposer.icons.attachFiles.text", - "prose": true - }, "aria/Cancel Reply": { "key": "messageComposer.quotedMessagePreview.cancelReply.ariaLabel", "prose": true diff --git a/ai-docs/i18n-v15-migration.md b/ai-docs/i18n-v15-migration.md index a2face459c..4bd4cde9ea 100644 --- a/ai-docs/i18n-v15-migration.md +++ b/ai-docs/i18n-v15-migration.md @@ -36,7 +36,7 @@ imported and copied into `Streami18n` at construction, so they shipped even if y ## Renaming your keys -Every old key that v15 still has maps to a new key ([some were removed](#keys-removed-without-a-replacement)). A few now feed two: their entry lists the second under `also`, and the translation goes on both. The full table (661 rows, covering the `aiComponents.*` keys of `stream-chat-react/ai-components` except the attachment's `Image`, which the plugin README maps) is +Every old key that v15 still has maps to a new key ([some were removed](#keys-removed-without-a-replacement)). A few now feed two: their entry lists the second under `also`, and the translation goes on both. The full table (660 rows, covering the `aiComponents.*` keys of `stream-chat-react/ai-components` except the attachment's `Image`, which the plugin README maps) is [`i18n-v15-key-map.json`](https://github.com/GetStream/stream-chat-react/blob/master/ai-docs/i18n-v15-key-map.json): ```json @@ -107,7 +107,7 @@ nothing catches a stale one there. The extra plural categories some languages us These v14 keys (from `src/i18n/en.json` at `v14.10.0`, plural suffixes folded) have no entry in the key map. A `t()` call on one of them no longer compiles (`TS2769`), and a dictionary entry for one never matches. Copy you still need is app-owned now: give it a key of your own through `asDynamicKey`, with the English inline, and keep its translations in your dictionaries ([Calling `t` in your own components](#calling-t-in-your-own-components)). ```text -{{ imageCount }} more | {{ user }} is typing... | {{ users }} and {{ user }} are typing... | {{ users }} and more are typing... | +{{ imageCount }} | Allow comments | Allow option suggestion | aria/Collapse sidebar | aria/Expand sidebar | aria/Unblock User | Attachment | Channel members | Close emoji picker | Commands matching | Connection failure, reconnecting now... | Create | Delete for me | Download attachment {{ name }} | Drag your files here to add to your post | Emoji matching | End | End vote | Error connecting to chat, refresh the page to try again. | Error removing members | Error uploading file | Error uploading image | Failed to delete the message | Failed to load channels | Failed to load more channels | Failed to mark channel as read | File is too large: {{ size }}, maximum upload size is {{ limit }} | Image | Link | live | Manage members | Maximum number of votes (from 2 to 10) | mention/Channel | mention/Here | Menu | Messages have been marked unread. | Missing permissions to upload the attachment | network error | New | No chats here yet… | Nobody will be able to vote in this poll anymore. | Ok | Open emoji picker | People matching | Remove | Remove {{ count }} members | Remove channel members | Removed {{ count }} members | Reply to Message | Searching... | searchResultsCount | Select a thread to continue the conversation | Shared live location | Slow Mode ON | Submit | Thread reply | Upload type: "{{ type }}" is not allowed | You've reached the maximum number of files +{{ imageCount }} more | {{ user }} is typing... | {{ users }} and {{ user }} are typing... | {{ users }} and more are typing... | +{{ imageCount }} | Allow comments | Allow option suggestion | aria/Collapse sidebar | aria/Expand sidebar | aria/Unblock User | Attach files | Attachment | Channel members | Close emoji picker | Commands matching | Connection failure, reconnecting now... | Create | Delete for me | Download attachment {{ name }} | Drag your files here to add to your post | Emoji matching | End | End vote | Error connecting to chat, refresh the page to try again. | Error removing members | Error uploading file | Error uploading image | Failed to delete the message | Failed to load channels | Failed to load more channels | Failed to mark channel as read | File is too large: {{ size }}, maximum upload size is {{ limit }} | Image | Link | live | Manage members | Maximum number of votes (from 2 to 10) | mention/Channel | mention/Here | Menu | Messages have been marked unread. | Missing permissions to upload the attachment | network error | New | No chats here yet… | Nobody will be able to vote in this poll anymore. | Ok | Open emoji picker | People matching | Remove | Remove {{ count }} members | Remove channel members | Removed {{ count }} members | Reply to Message | Searching... | searchResultsCount | Select a thread to continue the conversation | Shared live location | Slow Mode ON | Submit | Thread reply | Upload type: "{{ type }}" is not allowed | You've reached the maximum number of files ``` ```tsx diff --git a/ai-docs/v15-breaking-changes.md b/ai-docs/v15-breaking-changes.md index fb0146a72c..712c28cf6b 100644 --- a/ai-docs/v15-breaking-changes.md +++ b/ai-docs/v15-breaking-changes.md @@ -1,6 +1,6 @@ # React v15 Breaking Changes -Last updated: 2026-11-03 +Last updated: 2026-11-05 ## Scope @@ -64,7 +64,7 @@ yarn api-surface check --doc ai-docs/v15-breaking-changes.md --diff diff.json ## Index -95 entries. +96 entries. | ID | Title | Group | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | @@ -163,6 +163,7 @@ yarn api-surface check --doc ai-docs/v15-breaking-changes.md --diff diff.json | [BC-093](#bc-093) | `MessageContextValue.onMentionsClickMessage` / `onMentionsHoverMessage` and `useMentionsHandler`'s handlers are `undefined` without a handler | Messages and message lists | | [BC-094](#bc-094) | `mentionsMarkdownPlugin` and `createMentionPluginAndDisplayTextSet` take mention entities only | Messages and message lists | | [BC-095](#bc-095) | `disableQuotedMessages` is removed from `MessageProps`, `MessageListProps` and `useMessagePermissions` | Messages and message lists | +| [BC-101](#bc-101) | `Root`, `Header`, `UploadIcon`, `BinIcon`, `PauseIcon`, `PlayIcon` unexported; `@stream-io/transliterate` dropped; `CustomChannelData` typed for apps; `DefaultChannelData` holds only `name` and `image` | Package and runtime | ## Package and runtime @@ -245,6 +246,77 @@ export const DayDivider = ({ message }: { message: LocalMessage }) => { }; ``` + + +### BC-101: `Root`, `Header`, `UploadIcon`, `BinIcon`, `PauseIcon` and `PlayIcon` are no longer exported; `@stream-io/transliterate` is no longer a dependency; `CustomChannelData` is typed for apps and `DefaultChannelData` holds only `name` and `image` + +- Status: confirmed +- Area: package / exports / types +- User impact: + - compile error (`TS2305`) on importing `Root` or `Header` from `stream-chat-react`, and `undefined` in plain JS. They are the parts of `Alert`, exported under generic names; `Alert.Root`, `Alert.Header` and `Alert.Actions` are unchanged. + - compile error (`TS2305`) on importing `UploadIcon`, `BinIcon`, `PauseIcon` or `PlayIcon`. No SDK component rendered them in v14 or v15. + - install: `@stream-io/transliterate` is no longer installed with this package. No SDK code imported it in v14 or v15; an app that imports it without declaring it gets a module-not-found error. + - types: `channel.data.custom.name` and `.image` are typed `string | undefined` in every app that imports `stream-chat-react`. v14 and earlier v15 release candidates declared the merge of `DefaultChannelData` into `CustomChannelData` in a file `tsc` did not emit, so apps saw `CustomChannelData` without those fields. An app that augments `CustomChannelData` with `name` or `image` under another type gets no error with `skipLibCheck: true` (its own type wins), and `TS2430` inside `stream-chat`'s `custom_types.d.ts` without it. + - types: `DefaultChannelData` loses `subtitle` and `team`. No SDK code read them; `team` is a top-level channel field in `stream-chat` v10 (`channel.data.team`), not custom data. Code that reads `DefaultChannelData['team']`, or relies on `extends DefaultChannelData` to type `custom.subtitle` / `custom.team`, gets `TS2339`. +- Old API: + - `Root`, `Header` (`src/components/Dialog/components/Alert.tsx`), re-exported from the package root through `Dialog/components/index.ts` + - `UploadIcon`, `BinIcon`, `PauseIcon`, `PlayIcon` (`src/components/MessageComposer/icons.tsx`), re-exported through `MessageComposer/index.ts` + - `optionalDependencies['@stream-io/transliterate']: ^1.5.5` + - `DefaultChannelData`: `image`, `name`, `subtitle`, `team` (all `string | undefined`) + - `src/@types/stream-chat-custom-data.d.ts`, a declaration-only file that `tsc` never copies to `dist/types` +- Replacement: + - `Root` / `Header`: `Alert.Root` / `Alert.Header`, the same components. + - The icons: copy the SVG into the app, or use the v15 icon set: `IconPlus` or `IconAttachment` for `UploadIcon`, `IconDelete` for `BinIcon`, `IconPauseFill` for `PauseIcon`, `IconPlayFill` for `PlayIcon`. They follow the v15 design, not the v14 shapes, and take `BaseIconProps`. + - `@stream-io/transliterate`: add it to the app's own dependencies if the app imports it. Mention search in `stream-chat` takes a `transliterate` function on its mentions middleware. + - `CustomChannelData`: delete an app's own `name?: string` / `image?: string` declarations, which are now redundant, and keep the augmentation for the app's other fields. Rename a field the app declares as `name` or `image` with another type. Declare `subtitle?: string` / `team?: string` on `CustomChannelData` if the app stores them under `custom`; read the channel's team from `channel.data.team`. +- Evidence: + - `release-v14:src/components/Dialog/components/Alert.tsx:6`, `:25` `export const Root` / `export const Header`; `master:src/components/Dialog/components/Alert.tsx` declares both without `export` and exports them as `Alert.Root` / `Alert.Header`, like `Prompt` and `Viewer` + - `release-v14:src/components/MessageComposer/icons.tsx:3`, `:30`, `:36`, `:47`; `release-v14:src/components/MessageComposer/index.ts:19` `export * from './icons'`; no other reference in `src` or `examples` on either branch + - `release-v14:package.json:122` `"@stream-io/transliterate": "^1.5.5"`; no import in `src` on either branch + - `release-v14:src/@types/stream-chat-custom-data.d.ts:19` `interface CustomChannelData extends DefaultChannelData {}`; `release-v14:tsconfig.lib.json` emits declarations from `.ts` sources only, so `dist/types/@types` does not exist. `master:src/types/defaultDataInterfaces.ts` declares `DefaultChannelData` with `image` and `name` only, declares the merge and ships as `dist/types/types/defaultDataInterfaces.d.ts`, re-exported from `dist/types/index.d.ts` + - commit: REACT-1306 +- Docs impact: + - `02-state/01-state-and-entities/06-data-conventions.md` (the `CustomChannelData` augmentation sample), `08-release-guides/01-upgrade-to-v15.md` +- Example needed: yes + +Before (v14): + +```tsx +import { Header, Root } from 'stream-chat-react'; + +declare module 'stream-chat' { + interface CustomChannelData { + image?: string; + name?: string; + priority?: number; + } +} + +export const DeleteWarning = () => ( + +
+ +); +``` + +After (v15): + +```tsx +import { Alert } from 'stream-chat-react'; + +declare module 'stream-chat' { + interface CustomChannelData { + priority?: number; + } +} + +export const DeleteWarning = () => ( + + + +); +``` + ## Contexts and customization diff --git a/examples/tutorial/src/3-core-component-setup/stream-chat.d.ts b/examples/tutorial/src/3-core-component-setup/stream-chat.d.ts deleted file mode 100644 index d19d0e61e1..0000000000 --- a/examples/tutorial/src/3-core-component-setup/stream-chat.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { DefaultChannelData } from 'stream-chat-react'; - -declare module 'stream-chat' { - interface CustomChannelData extends DefaultChannelData { - image?: string; - } -} diff --git a/examples/tutorial/src/optional-custom-attachment-type/stream-chat.d.ts b/examples/tutorial/src/optional-custom-attachment-type/stream-chat.d.ts index 391ba909f6..febc4041b7 100644 --- a/examples/tutorial/src/optional-custom-attachment-type/stream-chat.d.ts +++ b/examples/tutorial/src/optional-custom-attachment-type/stream-chat.d.ts @@ -1,4 +1,4 @@ -import type { DefaultAttachmentData, DefaultChannelData } from 'stream-chat-react'; +import type { DefaultAttachmentData } from 'stream-chat-react'; declare module 'stream-chat' { interface CustomAttachmentData extends DefaultAttachmentData { @@ -6,8 +6,4 @@ declare module 'stream-chat' { name?: string; url?: string; } - - interface CustomChannelData extends DefaultChannelData { - image?: string; - } } diff --git a/examples/vite/src/i18n/de.ts b/examples/vite/src/i18n/de.ts index c49ee917e8..f6c347c99c 100644 --- a/examples/vite/src/i18n/de.ts +++ b/examples/vite/src/i18n/de.ts @@ -612,7 +612,6 @@ export const deTranslations = { 'messageComposer.geolocationPreview.removeLocationAttachment.ariaLabel': 'Standortanhang entfernen', 'messageComposer.geolocationPreview.sharedLocation.title': 'Geteilter Standort', - 'messageComposer.icons.attachFiles.text': 'Dateien anhängen', 'messageComposer.quotedMessagePreview.cancelReply.ariaLabel': 'Antwort abbrechen', 'messageComposer.quotedMessagePreview.files.label_one': '{{ count }} Datei', 'messageComposer.quotedMessagePreview.files.label_other': '{{ count }} Dateien', diff --git a/examples/vite/src/i18n/it.ts b/examples/vite/src/i18n/it.ts index daf6513531..cd718a1ca4 100644 --- a/examples/vite/src/i18n/it.ts +++ b/examples/vite/src/i18n/it.ts @@ -606,7 +606,6 @@ export const itTranslations = { 'messageComposer.geolocationPreview.removeLocationAttachment.ariaLabel': 'Rimuovi l’allegato di posizione', 'messageComposer.geolocationPreview.sharedLocation.title': 'Posizione condivisa', - 'messageComposer.icons.attachFiles.text': 'Allega file', 'messageComposer.quotedMessagePreview.cancelReply.ariaLabel': 'Annulla risposta', 'messageComposer.quotedMessagePreview.files.label_one': '{{ count }} file', 'messageComposer.quotedMessagePreview.files.label_other': '{{ count }} file', diff --git a/package.json b/package.json index eda513b73f..dfd5beed0b 100644 --- a/package.json +++ b/package.json @@ -134,9 +134,6 @@ "use-sync-external-store": "^1.7.0", "zod": "^4.1.12" }, - "optionalDependencies": { - "@stream-io/transliterate": "^1.5.5" - }, "peerDependencies": { "@breezystack/lamejs": "^1.2.7", "@emoji-mart/data": "^1.1.0", diff --git a/src/@types/stream-chat-custom-data.d.ts b/src/@types/stream-chat-custom-data.d.ts deleted file mode 100644 index a899fb23ef..0000000000 --- a/src/@types/stream-chat-custom-data.d.ts +++ /dev/null @@ -1,39 +0,0 @@ -import 'stream-chat'; - -import { - DefaultAttachmentData, - DefaultChannelData, - DefaultEventData, - DefaultMemberData, - DefaultMessageComposerData, - DefaultMessageData, - DefaultPollData, - DefaultPollOptionData, - DefaultReactionData, - DefaultThreadData, - DefaultUserData, -} from '../types/defaultDataInterfaces'; - -declare module 'stream-chat' { - interface CustomChannelData extends DefaultChannelData {} - - interface CustomAttachmentData extends DefaultAttachmentData {} - - interface CustomEventData extends DefaultEventData {} - - interface CustomMemberData extends DefaultMemberData {} - - interface CustomMessageData extends DefaultMessageData {} - - interface CustomPollOptionData extends DefaultPollOptionData {} - - interface CustomPollData extends DefaultPollData {} - - interface CustomReactionData extends DefaultReactionData {} - - interface CustomUserData extends DefaultUserData {} - - interface CustomThreadData extends DefaultThreadData {} - - interface CustomMessageComposerData extends DefaultMessageComposerData {} -} diff --git a/src/components/Attachment/icons.tsx b/src/components/Attachment/icons.tsx index 034e42eb1a..1d1380db72 100644 --- a/src/components/Attachment/icons.tsx +++ b/src/components/Attachment/icons.tsx @@ -1,22 +1,4 @@ import React from 'react'; -import type { IconProps } from '../../types/types'; - -export const DownloadIcon = ({ className }: IconProps) => ( - - - -); export const ExternalLinkIcon = () => ( diff --git a/src/components/Channel/__tests__/Channel.test.tsx b/src/components/Channel/__tests__/Channel.test.tsx index 60e43a9a75..33191aa0be 100644 --- a/src/components/Channel/__tests__/Channel.test.tsx +++ b/src/components/Channel/__tests__/Channel.test.tsx @@ -44,7 +44,6 @@ import type { ChannelProps } from '../Channel'; import { convertDateToTimestamp } from '../../../mock-builders'; vi.mock('../../Loading', () => ({ - LoadingChannel: vi.fn(() =>
Loading channel
), LoadingErrorIndicator: vi.fn(() =>
), LoadingIndicator: vi.fn(() =>
loading
), })); diff --git a/src/components/Dialog/components/Alert.tsx b/src/components/Dialog/components/Alert.tsx index f882fecdb3..a1523f885b 100644 --- a/src/components/Dialog/components/Alert.tsx +++ b/src/components/Dialog/components/Alert.tsx @@ -3,7 +3,7 @@ import clsx from 'clsx'; import { useModalContext } from '../../../context'; import { useAriaIdentifiers } from '../../../a11y/hooks/useAriaIdentifiers'; -export const Root = forwardRef>(function AlertRoot( +const Root = forwardRef>(function AlertRoot( { children, className, ...props }: ComponentProps<'div'>, ref, ) { @@ -22,7 +22,7 @@ export type AlertHeaderProps = ComponentProps<'div'> & { titleId?: string; }; -export const Header = forwardRef(function AlertHeader( +const Header = forwardRef(function AlertHeader( { children, className, description, descriptionId, Icon, title, titleId, ...props }, ref, ) { diff --git a/src/components/MessageComposer/icons.tsx b/src/components/MessageComposer/icons.tsx index 211013b1ba..7e506861ac 100644 --- a/src/components/MessageComposer/icons.tsx +++ b/src/components/MessageComposer/icons.tsx @@ -1,60 +1,3 @@ -import { useTranslationContext } from '../../context/TranslationContext'; - -export const UploadIcon = () => { - const { t } = useTranslationContext(); - return ( - - {t('messageComposer.icons.attachFiles.text', 'Attach files')} - - - - - - - - - - ); -}; - -export const BinIcon = () => ( - - - -); - -export const PauseIcon = () => ( - - - -); - -export const PlayIcon = () => ( - - - -); - export const CheckSignIcon = () => ( diff --git a/src/components/Modal/icons.tsx b/src/components/Modal/icons.tsx deleted file mode 100644 index ba55f4df98..0000000000 --- a/src/components/Modal/icons.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; - -export const CloseIconRound = () => ( - - - - - -); diff --git a/src/i18n/__tests__/catalog.fixture.json b/src/i18n/__tests__/catalog.fixture.json index 61f0fee9df..3860bd3e42 100644 --- a/src/i18n/__tests__/catalog.fixture.json +++ b/src/i18n/__tests__/catalog.fixture.json @@ -448,7 +448,6 @@ "messageComposer.geolocationPreview.location.text": "Location: {{ coordinates }}", "messageComposer.geolocationPreview.removeLocationAttachment.ariaLabel": "Remove location attachment", "messageComposer.geolocationPreview.sharedLocation.title": "Shared location", - "messageComposer.icons.attachFiles.text": "Attach files", "messageComposer.quotedMessagePreview.cancelReply.ariaLabel": "Cancel Reply", "messageComposer.quotedMessagePreview.files.label_one": "{{ count }} file", "messageComposer.quotedMessagePreview.files.label_other": "{{ count }} files", diff --git a/src/i18n/keys.ts b/src/i18n/keys.ts index 85d4502458..ef21587f76 100644 --- a/src/i18n/keys.ts +++ b/src/i18n/keys.ts @@ -459,7 +459,6 @@ export type TranslationCatalog = { 'messageComposer.geolocationPreview.location.text': 'Location: {{ coordinates }}'; 'messageComposer.geolocationPreview.removeLocationAttachment.ariaLabel': 'Remove location attachment'; 'messageComposer.geolocationPreview.sharedLocation.title': 'Shared location'; - 'messageComposer.icons.attachFiles.text': 'Attach files'; 'messageComposer.quotedMessagePreview.cancelReply.ariaLabel': 'Cancel Reply'; 'messageComposer.quotedMessagePreview.files.label_one': '{{ count }} file'; 'messageComposer.quotedMessagePreview.files.label_other': '{{ count }} files'; diff --git a/src/types/defaultDataInterfaces.ts b/src/types/defaultDataInterfaces.ts index 6255335444..08b21ca90c 100644 --- a/src/types/defaultDataInterfaces.ts +++ b/src/types/defaultDataInterfaces.ts @@ -1,9 +1,8 @@ /* eslint-disable @typescript-eslint/no-empty-object-type */ +/** The fields of `channel.data.custom` that the SDK renders a channel's name and image from. */ export interface DefaultChannelData { image?: string; name?: string; - subtitle?: string; - team?: string; } export interface DefaultAttachmentData {} @@ -25,3 +24,30 @@ export interface DefaultUserData {} export interface DefaultThreadData {} export interface DefaultMessageComposerData {} + +// Merges the Default*Data interfaces into stream-chat's custom-data interfaces. This module ships +// as a declaration file reachable from the package entry, so the merge reaches every app that +// imports stream-chat-react; an app's own augmentation of the same interfaces adds to it. +declare module 'stream-chat' { + interface CustomChannelData extends DefaultChannelData {} + + interface CustomAttachmentData extends DefaultAttachmentData {} + + interface CustomEventData extends DefaultEventData {} + + interface CustomMemberData extends DefaultMemberData {} + + interface CustomMessageData extends DefaultMessageData {} + + interface CustomPollOptionData extends DefaultPollOptionData {} + + interface CustomPollData extends DefaultPollData {} + + interface CustomReactionData extends DefaultReactionData {} + + interface CustomUserData extends DefaultUserData {} + + interface CustomThreadData extends DefaultThreadData {} + + interface CustomMessageComposerData extends DefaultMessageComposerData {} +} diff --git a/yarn.lock b/yarn.lock index 9fdbfd6b92..5523e0dbd7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2136,13 +2136,6 @@ __metadata: languageName: node linkType: hard -"@stream-io/escape-string-regexp@npm:^5.0.1": - version: 5.0.1 - resolution: "@stream-io/escape-string-regexp@npm:5.0.1" - checksum: 10c0/86901c6f6e13ee72598ff5d19625cc5247bceba26e808da868f6ede85cdd91a08fb3caae4745ee77a5aa49f318cebd4d6412b7208f820ec2bf1a9a27f431b115 - languageName: node - linkType: hard - "@stream-io/i18n@npm:^1.1.0": version: 1.1.0 resolution: "@stream-io/i18n@npm:1.1.0" @@ -2273,16 +2266,6 @@ __metadata: languageName: unknown linkType: soft -"@stream-io/transliterate@npm:^1.5.5": - version: 1.5.5 - resolution: "@stream-io/transliterate@npm:1.5.5" - dependencies: - "@stream-io/escape-string-regexp": "npm:^5.0.1" - lodash.deburr: "npm:^4.1.0" - checksum: 10c0/1afe6b85da18346be35dd92ad602cbd7a566d549e51547e4a25a3d3ebf614839c6651ab8f61f349c498db621a93d5f64918e4aeec4a2981cac0d18392fc89c12 - languageName: node - linkType: hard - "@swc/core-darwin-arm64@npm:1.15.33": version: 1.15.33 resolution: "@swc/core-darwin-arm64@npm:1.15.33" @@ -7041,13 +7024,6 @@ __metadata: languageName: node linkType: hard -"lodash.deburr@npm:^4.1.0": - version: 4.1.0 - resolution: "lodash.deburr@npm:4.1.0" - checksum: 10c0/30c068e9c3b21d65d260887a8849fa7b94692f868adcc4527136c296b4e71ced7149f58e0f37154d3c56d7950cc605ad3e10b2ee0baedf5638af0befc5013ebc - languageName: node - linkType: hard - "lodash.escaperegexp@npm:^4.1.2": version: 4.1.2 resolution: "lodash.escaperegexp@npm:4.1.2" @@ -10281,7 +10257,6 @@ __metadata: "@semantic-release/github": "npm:^12.0.8" "@stream-io/i18n": "npm:^1.1.0" "@stream-io/state-store": "npm:^1.2.0" - "@stream-io/transliterate": "npm:^1.5.5" "@testing-library/dom": "npm:^10.4.1" "@testing-library/jest-dom": "npm:^6.9.1" "@testing-library/react": "npm:^16.3.2" @@ -10362,8 +10337,6 @@ __metadata: dependenciesMeta: "@parcel/watcher": built: true - "@stream-io/transliterate": - optional: true "@swc/core": built: true esbuild: From 0992212b9125a465a45a2a3c1d8c1fb506e40b31 Mon Sep 17 00:00:00 2001 From: martincupela Date: Thu, 5 Nov 2026 16:14:33 +0100 Subject: [PATCH 2/2] docs(ai-docs): detect required/namespaced Root and Header; load SDK typing in the sample --- ai-docs/ai-migration-v14-v15.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ai-docs/ai-migration-v14-v15.md b/ai-docs/ai-migration-v14-v15.md index be3bac67e3..ed5b6fb7f4 100644 --- a/ai-docs/ai-migration-v14-v15.md +++ b/ai-docs/ai-migration-v14-v15.md @@ -128,9 +128,11 @@ styles() { rg -n --hidden -g '*.{css,scss,sass,less}' -g '!**/node_modules/**' - rg -n --hidden -g 'package.json' -g '!**/node_modules/**' -e '"(stream-chat|stream-chat-react|dayjs|i18next|@stream-io/[a-z-]+)"\s*:' . rg -n --hidden -g '.nvmrc' -g '.node-version' -g '*.{yml,yaml}' -g 'Dockerfile*' -g '!**/node_modules/**' -g '!.git' -e 'node-version|FROM node|^v?[0-9]+(\.[0-9]+)*$' . code '\b(ChatView|ChatViewContext|useChatViewContext|useActiveThread|ChatViewSelector\w*|ChatView\w*SelectorButton|defaultChatViewSelectorItemSet|AIStates|getAttachmentPreviewUrl|isUploadConfirmationPending|hasPendingUploadState|StateStore)\b' -# §1 removed exports: unused icons, @stream-io/transliterate imports, Alert parts imported as Root / Header +# §1 removed exports: unused icons, @stream-io/transliterate imports, Alert parts imported or required as Root / Header code '\b(UploadIcon|BinIcon|PauseIcon|PlayIcon)\b|@stream-io/transliterate' -rg -n -U --hidden -t ts -t js -g '!**/node_modules/**' -g '!**/dist/**' -g '!**/build/**' -e "import\s+(type\s+)?\{[^}]*\b(Root|Header)\b[^}]*\}\s*from\s*['\"]stream-chat-react['\"]" . +rg -n -U --hidden -t ts -t js -g '!**/node_modules/**' -g '!**/dist/**' -g '!**/build/**' -e "(import\s+(type\s+)?\{[^}]*\b(Root|Header)\b[^}]*\}\s*from\s*|\{[^}]*\b(Root|Header)\b[^}]*\}\s*=\s*require\(\s*)['\"]stream-chat-react['\"]" . +# §1 the package used as a namespace (import * as X / X = require): in each hit file, check X.Root, X.Header and the icon names above +rg -n --hidden -t ts -t js -g '!**/node_modules/**' -g '!**/dist/**' -g '!**/build/**' -e "import\s+\*\s+as\s+\w+\s+from\s*['\"]stream-chat-react['\"]|\b\w+\s*=\s*require\(\s*['\"]stream-chat-react['\"]\s*\)" . # §2 client and code '\b(useCreateChatClient|useChat|defaultLanguage|channelsQueryState|latestMessageDatesByChannels|recoverStateOnReconnect|enableWSFallback|wsUrlParams|isLocalUnreadCountEnabled|StreamChatOptions)\b|connection\.changed' # §3 layout: Window, ChatView @@ -3230,6 +3232,8 @@ React props typed with `stream-chat` types change with them. The React APIs are ```tsx import type { Channel, ChannelFilters } from 'stream-chat'; + // Loads the SDK's typing of `custom.name` / `custom.image`; any import from the package does. + import type {} from 'stream-chat-react'; declare module 'stream-chat' { interface CustomChannelData { @@ -3455,10 +3459,12 @@ Run after every section is applied. 2. **Leftover identifiers.** Every v14 name below was removed or renamed. In a plain-JS app this grep is the only thing that finds them. It must print nothing outside comments, changelogs and app identifiers that only share the name (record those in the report). Uses the `code` / `styles` helpers from [Detection](#detection). ```bash - code '\b(WindowProps|ChannelStateContext|ChannelStateContextValue|ChannelStateProvider|useChannelStateContext|ChannelActionContext|ChannelActionContextValue|ChannelActionProvider|useChannelActionContext|ChannelNotifications|MarkReadWrapperOptions|RetrySendMessage|TypingContext|TypingContextValue|TypingProvider|useTypingContext|ChannelUnreadUiState|channelUnreadUiState|setChannelUnreadUiState|updateChannelUiUnreadState|useThreadsViewContext|ThreadsViewContextValue|ThreadAdapter|activeChatView|setActiveChatView|setActiveChannel|setActiveChannelOnMount|customActiveChannel|channelsQueryState|latestMessageDatesByChannels|useChannelEditMessageHandler|useChannelMentionsHandler|ChannelListUI|ChannelListUIProps|usePaginatedChannels|useConnectionRecoveredListener|CustomQueryChannelParams|CustomQueryChannelsFn|EffectiveQueryParams|moveChannelUpwards|findLastPinnedChannelIndex|extractSortValue|isChannelPinned|isChannelArchived|shouldConsiderPinnedChannels|shouldConsiderArchivedChannels|allowNewMessagesFromUnfilteredChannels|lockChannelOrder|showChannelSearch|sendChannelsToList|renderChannels|channelRenderFilterFn|customQueryChannels|recoveryThrottleIntervalMs|onMessageNewHandler|channelUpdateCount|useLegacyThreadContext|additionalMessageComposerProps|additionalMessageListProps|additionalVirtualizedMessageListProps|additionalParentMessageProps|enableDateSeparator|disableDateSeparator|HeaderStartContent|MESSAGE_ACTIONS|OPTIONAL_MESSAGE_ACTIONS|getMessageActions|MessageActionsArray|actionsEnabled|messageIsUnread|initializeOnMount|channelQueryOptions|markReadOnMount|activeUnreadHandler|skipMessageDataMemoization|allowConcurrentAudioPlayback|allowConcurrentPlayback|doSendMessageRequest|doUpdateMessageRequest|doDeleteMessageRequest|doMarkReadRequest|overrideSubmitHandler|preventClearingOnUnmount|loadMoreNewer|loadMoreThread|loadingMoreNewer|jumpToLatestMessage|jumpToFirstUnreadMessage|highlightedMessageId|threadSuppressAutoscroll|loadingMoreForJumpToChannelMessage|messageLimit|hasPendingUploadState|recoverStateOnReconnect|wsUrlParams|isLocalUnreadCountEnabled|StreamChatOptions|isLanguageSupported|SupportedTranslations|DateFormatterOptions|getTranslators|registerSetLanguageCallback|getAvailableLanguages|geti18Instance|deTranslations|enTranslations|esTranslations|frTranslations|hiTranslations|itTranslations|jaTranslations|koTranslations|nlTranslations|ptTranslations|ruTranslations|trTranslations|ChannelSort|UserSort|ReactionSort|WatcherState|unBlockUser|ReminderResponse|CommandResponse|DefaultCommandData|CustomCommandData|chatContainer|useUserRole|disableQuotedMessages|MentionedUserEventHandler|mentionedUser|noGroupByUser|shouldGroupByUser|defaultItemHeight|scrollSeekPlaceHolder|endOfGroup|firstOfGroup|groupedByUser)\b|` / `pnpm why `) shows a single version of each, and `stream-chat` satisfies `peerDependencies['stream-chat']` of the installed `stream-chat-react`.