stream-chat-react-native-core 9.0.0-beta.37 → 9.0.0-beta.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,148 +0,0 @@
1
- # WithComponents — Component Override System
2
-
3
- ## Design Principle
4
-
5
- **All components are read from `useComponentsContext()`. All other contexts only provide data + APIs — never components.**
6
-
7
- ## Current State (Completed)
8
-
9
- ### What was done
10
-
11
- 1. **Created `ComponentsContext`** — `WithComponents` provider, `useComponentsContext()` hook, `ComponentOverrides` type
12
- 2. **Created `defaultComponents.ts`** — centralized map of all ~130 default components
13
- 3. **Stripped component keys** from all existing context types: `MessagesContextValue`, `InputMessageInputContextValue`, `ChannelContextValue`, `ChannelsContextValue`, `AttachmentPickerContextValue`, `ThreadsContextValue`, `ImageGalleryContextValue`
14
- 4. **Simplified `useCreate*Context` hooks** — no longer receive or forward component params
15
- 5. **Simplified `Channel.tsx`** — removed ~90 component imports, prop defaults, forwarding lines
16
- 6. **Simplified `ChannelList.tsx`** — removed ~19 component props
17
- 7. **Updated ~80 consumer files** — switched from old context hooks to `useComponentsContext()`
18
- 8. **Removed component override props** from ALL individual components
19
- 9. **Updated all 3 example apps** (SampleApp, ExpoMessaging, TypeScriptMessaging)
20
- 10. **Updated ~45 documentation pages** across docs-content repo
21
- 11. **Merged with develop** and resolved conflicts
22
-
23
- ### Architecture
24
-
25
- ```
26
- User: <WithComponents overrides={{ Message: Custom }}>
27
-
28
- ComponentsContext (merges parent + overrides, inner wins)
29
-
30
- useComponentsContext() → { ...DEFAULT_COMPONENTS, ...overrides }
31
-
32
- Consumer: const { Message } = useComponentsContext()
33
- ```
34
-
35
- ### Key Files
36
-
37
- | File | Purpose |
38
- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
39
- | `ComponentsContext.tsx` | ~60 lines. `ComponentOverrides` type (derived from `typeof DEFAULT_COMPONENTS`), `WithComponents` provider, `useComponentsContext()` hook |
40
- | `defaultComponents.ts` | ~300 lines. Single source of truth for all default component mappings. Adding a new component here auto-extends `ComponentOverrides` |
41
-
42
- ### Type System
43
-
44
- `ComponentOverrides` is derived automatically:
45
-
46
- ```ts
47
- export type ComponentOverrides = Partial<(typeof import('./defaultComponents'))['DEFAULT_COMPONENTS']>;
48
- ```
49
-
50
- No manual type maintenance — add a component to `DEFAULT_COMPONENTS` and the type updates.
51
-
52
- ### Circular Dependency Handling
53
-
54
- `defaultComponents.ts` → imports components → components import `useComponentsContext` from `ComponentsContext.tsx`.
55
-
56
- Broken by lazy-loading defaults in the hook:
57
-
58
- ```ts
59
- let cachedDefaults: ComponentOverrides | undefined;
60
- const getDefaults = () => {
61
- if (!cachedDefaults) {
62
- cachedDefaults = require('./defaultComponents').DEFAULT_COMPONENTS;
63
- }
64
- return cachedDefaults;
65
- };
66
- ```
67
-
68
- ### Naming Conventions
69
-
70
- Some component keys differ from their default component names to avoid collisions:
71
-
72
- | Override Key | Default Component | Why renamed |
73
- | --------------------------------------- | --------------------------------------- | ---------------------------------------------------------- |
74
- | `FileAttachmentIcon` | `FileIcon` | Clarity |
75
- | `ChannelListLoadingIndicator` | `ChannelListLoadingIndicator` | Split from shared `LoadingIndicator` — renders skeleton UI |
76
- | `MessageListLoadingIndicator` | `LoadingIndicator` | Split from shared `LoadingIndicator` — renders text |
77
- | `ChatLoadingIndicator` | `undefined` | Optional, no default |
78
- | `ThreadMessageComposer` | `MessageComposer` | Avoid collision with `MessageComposer` component name |
79
- | `ThreadListComponent` | `DefaultThreadListComponent` | Avoid collision with exported `ThreadList` |
80
- | `StartAudioRecordingButton` | `AudioRecordingButton` | Historical naming |
81
- | `ChannelPreview` | `ChannelPreviewView` | ChannelList preview item |
82
- | `ChannelPreviewAvatar` | `ChannelAvatar` | ChannelList preview avatar |
83
- | `ChannelListFooterLoadingIndicator` | `ChannelListFooterLoadingIndicator` | ChannelList footer |
84
- | `ChannelListHeaderErrorIndicator` | `ChannelListHeaderErrorIndicator` | ChannelList header |
85
- | `ChannelListHeaderNetworkDownIndicator` | `ChannelListHeaderNetworkDownIndicator` | ChannelList header |
86
-
87
- ### Optional Components (no default)
88
-
89
- These exist in `DEFAULT_COMPONENTS` as `undefined` with `React.ComponentType<any> | undefined` type assertions:
90
-
91
- `AttachmentPickerIOSSelectMorePhotos`, `ChatLoadingIndicator`, `CreatePollContent`, `ImageComponent`, `Input`, `ListHeaderComponent`, `MessageActions`, `MessageContentBottomView`, `MessageContentLeadingView`, `MessageContentTopView`, `MessageContentTrailingView`, `MessageLocation`, `MessageSpacer`, `MessageText`, `PollContent`
92
-
93
- ### Shared Component Keys (audited)
94
-
95
- Some keys were used in multiple contexts before the refactor. Audit results:
96
-
97
- | Key | Used By | Same Default? | Resolution |
98
- | ----------------------- | --------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------- |
99
- | `EmptyStateIndicator` | Channel + ChannelList | Yes (differentiates via `listType` prop) | Single key ✅ |
100
- | `LoadingErrorIndicator` | Channel + ChannelList | Yes (differentiates via `listType` prop) | Single key ✅ |
101
- | `LoadingIndicator` | Channel + ChannelList | **No** — Channel used text-based, ChannelList used skeleton | Split into `MessageListLoadingIndicator` + `ChannelListLoadingIndicator` ✅ |
102
-
103
- ### API Alignment with stream-chat-react
104
-
105
- | Aspect | React Native | React Web |
106
- | --------- | ----------------------------------- | -------------------------------------- |
107
- | Provider | `WithComponents` | `WithComponents` |
108
- | Prop name | `overrides` | `overrides` |
109
- | Hook | `useComponentsContext()` | `useComponentContext()` |
110
- | Type | `ComponentOverrides` (auto-derived) | `ComponentContextValue` (hand-written) |
111
- | Defaults | Lazy-loaded via `require()` | Set at `Channel` level |
112
- | Merge | `useMemo` | Plain spread (no memo) |
113
-
114
- ## Known Issues / Future Work
115
-
116
- ### Pre-existing Test Failures (not caused by this work)
117
-
118
- These test suites fail on `develop` too:
119
-
120
- - `offline-support/index.test.ts` — timeout
121
- - `ChannelList.test.js` — filter race condition (`channel.countUnread` mock missing)
122
- - `isAttachmentEqualHandler.test.js`, `MessageContent.test.js`, `MessageTextContainer.test.tsx`, `MessageUserReactions.test.tsx`, `ChannelPreview.test.tsx` — various pre-existing issues
123
-
124
- ### Linter Interaction
125
-
126
- `@typescript-eslint/no-unused-vars` (warn, max-warnings 0) aggressively strips unused type keys. When adding new keys to `ComponentOverrides`, the type and its consumer must land in the same edit — otherwise the linter removes the key between saves.
127
-
128
- Since `ComponentOverrides` is now auto-derived from `DEFAULT_COMPONENTS`, this is no longer an issue for the type itself. But be aware when adding optional components (`undefined as React.ComponentType<any> | undefined`).
129
-
130
- ### `contexts/index.ts` Barrel Export
131
-
132
- The `export * from './componentsContext/ComponentsContext'` line in `contexts/index.ts` was stripped by the linter multiple times during development. If `WithComponents` becomes unexportable from the package, check this barrel file first.
133
-
134
- ### Documentation
135
-
136
- Docs PR: https://github.com/GetStream/docs-content/pull/1169
137
-
138
- Updated ~45 pages across:
139
-
140
- - Core teaching pages (custom_components, message-customization, etc.)
141
- - Component reference pages (channel-list, message-list, message-composer, etc.)
142
- - Context docs (stripped component keys from 7 context pages)
143
- - Migration guide (upgrading-from-v8.md — comprehensive WithComponents section)
144
- - Advanced guides (audio, AI, image-picker, etc.)
145
-
146
- ### SDK PR
147
-
148
- https://github.com/GetStream/stream-chat-react-native/pull/3542
@@ -1,45 +0,0 @@
1
- import { DEFAULT_COMPONENTS } from '../defaultComponents';
2
-
3
- // Optional component keys that are intentionally undefined (no default implementation)
4
- const OPTIONAL_KEYS = new Set([
5
- 'AttachmentPickerIOSSelectMorePhotos',
6
- 'ChatLoadingIndicator',
7
- 'CreatePollContent',
8
- 'MessageActions',
9
- 'Input',
10
- 'ListHeaderComponent',
11
- 'MessageContentBottomView',
12
- 'MessageContentLeadingView',
13
- 'MessageContentTopView',
14
- 'MessageContentTrailingView',
15
- 'MessageLocation',
16
- 'MessageSpacer',
17
- 'MessageText',
18
- 'PollContent',
19
- ]);
20
-
21
- describe('DEFAULT_COMPONENTS', () => {
22
- it('should have all required values defined', () => {
23
- const entries = Object.entries(DEFAULT_COMPONENTS);
24
- expect(entries.length).toBeGreaterThan(50);
25
-
26
- const unexpectedUndefined = entries.filter(
27
- ([key, value]) => value === undefined && !OPTIONAL_KEYS.has(key),
28
- );
29
- if (unexpectedUndefined.length > 0) {
30
- console.log(
31
- 'Unexpectedly undefined keys:',
32
- unexpectedUndefined.map(([k]) => k),
33
- );
34
- }
35
- expect(unexpectedUndefined).toEqual([]);
36
- });
37
-
38
- it('optional keys should be explicitly listed', () => {
39
- const entries = Object.entries(DEFAULT_COMPONENTS);
40
- const actualUndefined = new Set(
41
- entries.filter(([, v]) => v === undefined || v === null).map(([k]) => k),
42
- );
43
- expect(actualUndefined).toEqual(OPTIONAL_KEYS);
44
- });
45
- });