diff --git a/ai-docs/ai-migration-v14-v15.md b/ai-docs/ai-migration-v14-v15.md index c34c07f20..b22278f3e 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-097`) 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-097`, `BC-101` and `BC-102`) 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,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 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*|\{[^}]*\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 @@ -330,6 +335,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 @@ -378,10 +384,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 `` @@ -1057,13 +1084,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 = () => { @@ -3231,15 +3252,16 @@ 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'; + // 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 { - image?: string; - name?: string; + demo?: string; } } @@ -3461,10 +3483,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|initialMessage|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`. @@ -3586,4 +3610,5 @@ Run after every section is applied. | BC-094 | `mentionsMarkdownPlugin` takes mention entities only | [12](#mentionsmarkdownplugin-takes-mention-entities-only) | | BC-095 | `disableQuotedMessages` removed | [12](#the-disablequotedmessages-prop-is-removed) | | BC-097 | Channel detail close buttons need `onClose` outside a modal; `onLayoutChange` is called | [10](#channeldetail-takes-onclose-outside-a-modal-it-shows-no-close-button-without-it) | +| 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) | | BC-102 | `initialMessage` removed; `useIsRenderedAsThreadParent()` | [12](#initialmessage-is-removed-use-useisrenderedasthreadparent) | diff --git a/ai-docs/i18n-v15-key-map.json b/ai-docs/i18n-v15-key-map.json index 1299c50ab..a89c85e29 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", @@ -2020,10 +2020,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 a2face459..4bd4cde9e 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 bf7e553a7..23cae16e5 100644 --- a/ai-docs/v15-breaking-changes.md +++ b/ai-docs/v15-breaking-changes.md @@ -64,7 +64,7 @@ yarn api-surface check --doc ai-docs/v15-breaking-changes.md --diff diff.json ## Index -96 entries. +98 entries. | ID | Title | Group | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | @@ -163,6 +163,8 @@ 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-097](#bc-097) | channel detail views render no close button outside a modal without `onClose`; `ChannelDetail` calls `onLayoutChange` | Chat, ChatView and layout | +| [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 | | [BC-102](#bc-102) | `initialMessage` is removed from `MessageProps` and `MessageContextValue`; `useIsRenderedAsThreadParent()` tells the thread's parent message apart | Messages and message lists | ## Package and runtime @@ -246,6 +248,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 d19d0e61e..000000000 --- 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 391ba909f..febc4041b 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 11661bc8f..c25efdb93 100644 --- a/examples/vite/src/i18n/de.ts +++ b/examples/vite/src/i18n/de.ts @@ -613,7 +613,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 3b8042729..037203235 100644 --- a/examples/vite/src/i18n/it.ts +++ b/examples/vite/src/i18n/it.ts @@ -607,7 +607,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 fa5b941ba..b953a9baf 100644 --- a/package.json +++ b/package.json @@ -152,9 +152,6 @@ "use-sync-external-store": "^1.7.0", "zod": "^4.2.0" }, - "optionalDependencies": { - "@stream-io/transliterate": "^1.5.5" - }, "peerDependencies": { "@a2ui/react": "~0.15.0", "@a2ui/web_core": "~0.15.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 a899fb23e..000000000 --- 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 034e42eb1..1d1380db7 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 60e43a9a7..33191aa0b 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 f882fecdb..a1523f885 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 211013b1b..7e506861a 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 ba55f4df9..000000000 --- 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 6781a811a..6e365491c 100644 --- a/src/i18n/__tests__/catalog.fixture.json +++ b/src/i18n/__tests__/catalog.fixture.json @@ -449,7 +449,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 a4610fdd7..322411ebb 100644 --- a/src/i18n/keys.ts +++ b/src/i18n/keys.ts @@ -460,7 +460,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 625533544..08b21ca90 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 68360d13b..d861326d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3234,13 +3234,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" @@ -3371,16 +3364,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" @@ -8453,13 +8436,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" @@ -12002,7 +11978,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" @@ -12088,8 +12063,6 @@ __metadata: dependenciesMeta: "@parcel/watcher": built: true - "@stream-io/transliterate": - optional: true "@swc/core": built: true esbuild: