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.
- package/lib/commonjs/contexts/componentsContext/ComponentsContext.js.map +1 -1
- package/lib/commonjs/contexts/componentsContext/defaultComponents.js +3 -16
- package/lib/commonjs/contexts/componentsContext/defaultComponents.js.map +1 -1
- package/lib/commonjs/version.json +1 -1
- package/lib/module/contexts/componentsContext/ComponentsContext.js.map +1 -1
- package/lib/module/contexts/componentsContext/defaultComponents.js +3 -16
- package/lib/module/contexts/componentsContext/defaultComponents.js.map +1 -1
- package/lib/module/version.json +1 -1
- package/lib/typescript/contexts/componentsContext/ComponentsContext.d.ts +2 -292
- package/lib/typescript/contexts/componentsContext/ComponentsContext.d.ts.map +1 -1
- package/lib/typescript/contexts/componentsContext/defaultComponents.d.ts +46 -18
- package/lib/typescript/contexts/componentsContext/defaultComponents.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/contexts/componentsContext/ComponentsContext.tsx +2 -1
- package/src/contexts/componentsContext/defaultComponents.ts +47 -35
- package/src/version.json +1 -1
- package/lib/commonjs/contexts/componentsContext/PLAN.md +0 -148
- package/lib/module/contexts/componentsContext/PLAN.md +0 -148
- package/src/contexts/componentsContext/PLAN.md +0 -148
- package/src/contexts/componentsContext/__tests__/defaultComponents.test.ts +0 -45
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { ImageProps, TextInputProps } from 'react-native';
|
|
3
|
+
import type { LocalMessage, UserResponse } from 'stream-chat';
|
|
4
|
+
import type { MessageTextProps } from '../../components/Message/MessageItemView/MessageTextContainer';
|
|
2
5
|
import type { MessageActionsProps } from '../../contexts/overlayContext/MessageOverlayHostLayer';
|
|
3
6
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
7
|
+
* Normalizes each component entry to React.ComponentType<P>, stripping
|
|
8
|
+
* extra inferred properties (like `displayName: string` from runtime
|
|
9
|
+
* assignments) that would otherwise leak into the override types and
|
|
10
|
+
* force integrators to match them.
|
|
6
11
|
*/
|
|
7
|
-
|
|
12
|
+
type NormalizeComponents<T> = {
|
|
13
|
+
[K in keyof T]: T[K] extends React.ComponentType<infer P> ? React.ComponentType<P> : T[K];
|
|
14
|
+
};
|
|
15
|
+
declare const components: {
|
|
8
16
|
Attachment: (props: import("../../components/Attachment/Attachment").AttachmentProps) => React.JSX.Element | null;
|
|
9
17
|
AttachButton: {
|
|
10
18
|
(props: import("../../components/MessageInput/components/InputButtons/AttachButton").AttachButtonProps): React.JSX.Element;
|
|
@@ -279,20 +287,40 @@ export declare const DEFAULT_COMPONENTS: {
|
|
|
279
287
|
};
|
|
280
288
|
ImageGalleryVideoControls: React.MemoExoticComponent<(props: import("../..").ImageGalleryVideoControlProps) => React.JSX.Element>;
|
|
281
289
|
MessageOverlayBackground: () => React.JSX.Element;
|
|
282
|
-
ImageComponent: React.ComponentType<
|
|
283
|
-
AttachmentPickerIOSSelectMorePhotos: React.ComponentType<any> | undefined;
|
|
284
|
-
ChatLoadingIndicator: React.ComponentType<any> | null | undefined;
|
|
285
|
-
CreatePollContent: React.ComponentType<any> | undefined;
|
|
286
|
-
MessageActions: React.ComponentType<MessageActionsProps> | undefined;
|
|
287
|
-
Input: React.ComponentType<any> | undefined;
|
|
288
|
-
ListHeaderComponent: React.ComponentType<any> | undefined;
|
|
289
|
-
MessageContentBottomView: React.ComponentType<any> | undefined;
|
|
290
|
-
MessageContentLeadingView: React.ComponentType<any> | undefined;
|
|
291
|
-
MessageContentTopView: React.ComponentType<any> | undefined;
|
|
292
|
-
MessageContentTrailingView: React.ComponentType<any> | undefined;
|
|
293
|
-
MessageLocation: React.ComponentType<any> | undefined;
|
|
294
|
-
MessageSpacer: React.ComponentType<any> | undefined;
|
|
295
|
-
MessageText: React.ComponentType<any> | undefined;
|
|
296
|
-
PollContent: React.ComponentType<any> | undefined;
|
|
290
|
+
ImageComponent: React.ComponentType<ImageProps>;
|
|
297
291
|
};
|
|
292
|
+
/**
|
|
293
|
+
* Optional component slots that have no default implementation.
|
|
294
|
+
* These are `undefined` unless the integrator provides them via WithComponents.
|
|
295
|
+
*/
|
|
296
|
+
export interface OptionalComponentOverrides {
|
|
297
|
+
AttachmentPickerIOSSelectMorePhotos?: React.ComponentType;
|
|
298
|
+
ChatLoadingIndicator?: React.ComponentType | null;
|
|
299
|
+
CreatePollContent?: React.ComponentType;
|
|
300
|
+
Input?: React.ComponentType<{
|
|
301
|
+
additionalTextInputProps?: TextInputProps;
|
|
302
|
+
getUsers: () => UserResponse[];
|
|
303
|
+
}>;
|
|
304
|
+
ListHeaderComponent?: React.ComponentType;
|
|
305
|
+
MessageActions?: React.ComponentType<MessageActionsProps>;
|
|
306
|
+
MessageContentBottomView?: React.ComponentType;
|
|
307
|
+
MessageContentLeadingView?: React.ComponentType;
|
|
308
|
+
MessageContentTopView?: React.ComponentType;
|
|
309
|
+
MessageContentTrailingView?: React.ComponentType;
|
|
310
|
+
MessageLocation?: React.ComponentType<{
|
|
311
|
+
message: LocalMessage;
|
|
312
|
+
}>;
|
|
313
|
+
MessageSpacer?: React.ComponentType;
|
|
314
|
+
MessageText?: React.ComponentType<MessageTextProps>;
|
|
315
|
+
PollContent?: React.ComponentType;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* All default component implementations used across the SDK.
|
|
319
|
+
* These are the components used when no overrides are provided via WithComponents.
|
|
320
|
+
*
|
|
321
|
+
* The `NormalizeComponents` cast ensures that internal details like
|
|
322
|
+
* `displayName: string` don't leak into the public override types.
|
|
323
|
+
*/
|
|
324
|
+
export declare const DEFAULT_COMPONENTS: NormalizeComponents<typeof components>;
|
|
325
|
+
export {};
|
|
298
326
|
//# sourceMappingURL=defaultComponents.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaultComponents.d.ts","sourceRoot":"","sources":["../../../../src/contexts/componentsContext/defaultComponents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"defaultComponents.d.ts","sourceRoot":"","sources":["../../../../src/contexts/componentsContext/defaultComponents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAS,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEjE,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAiE9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+DAA+D,CAAC;AAiFtG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uDAAuD,CAAC;AAEjG;;;;;GAKG;AACH,KAAK,mBAAmB,CAAC,CAAC,IAAI;KAC3B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAC1F,CAAC;AAEF,QAAA,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAsJW,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC;CACzD,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,0BAA0B;IACzC,mCAAmC,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC1D,oBAAoB,CAAC,EAAE,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC;IAClD,iBAAiB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IACxC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAC1B,wBAAwB,CAAC,EAAE,cAAc,CAAC;QAC1C,QAAQ,EAAE,MAAM,YAAY,EAAE,CAAC;KAChC,CAAC,CAAC;IACH,mBAAmB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC1C,cAAc,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,mBAAmB,CAAC,CAAC;IAC1D,wBAAwB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC/C,yBAAyB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAChD,qBAAqB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5C,0BAA0B,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IACjD,eAAe,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAAE,OAAO,EAAE,YAAY,CAAA;KAAE,CAAC,CAAC;IACjE,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IACpC,WAAW,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACpD,WAAW,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CACnC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,mBAAmB,CAAC,OAAO,UAAU,CAAc,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stream-chat-react-native-core",
|
|
3
3
|
"description": "The official React Native and Expo components for Stream Chat, a service for building chat applications",
|
|
4
|
-
"version": "9.0.0-beta.
|
|
4
|
+
"version": "9.0.0-beta.38",
|
|
5
5
|
"author": {
|
|
6
6
|
"company": "Stream.io Inc",
|
|
7
7
|
"name": "Stream.io Inc"
|
|
@@ -9,7 +9,8 @@ import React, { PropsWithChildren, useContext, useMemo } from 'react';
|
|
|
9
9
|
*/
|
|
10
10
|
export type ComponentOverrides = Partial<
|
|
11
11
|
(typeof import('./defaultComponents'))['DEFAULT_COMPONENTS']
|
|
12
|
-
|
|
12
|
+
> &
|
|
13
|
+
import('./defaultComponents').OptionalComponentOverrides;
|
|
13
14
|
|
|
14
15
|
const ComponentsContext = React.createContext<ComponentOverrides>({});
|
|
15
16
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Image } from 'react-native';
|
|
2
|
+
import { Image, ImageProps, TextInputProps } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import type { LocalMessage, UserResponse } from 'stream-chat';
|
|
3
5
|
|
|
4
6
|
import { Attachment } from '../../components/Attachment/Attachment';
|
|
5
7
|
import { AudioAttachment } from '../../components/Attachment/Audio';
|
|
@@ -64,6 +66,7 @@ import { MessageReplies } from '../../components/Message/MessageItemView/Message
|
|
|
64
66
|
import { MessageRepliesAvatars } from '../../components/Message/MessageItemView/MessageRepliesAvatars';
|
|
65
67
|
import { MessageStatus } from '../../components/Message/MessageItemView/MessageStatus';
|
|
66
68
|
import { MessageSwipeContent } from '../../components/Message/MessageItemView/MessageSwipeContent';
|
|
69
|
+
import type { MessageTextProps } from '../../components/Message/MessageItemView/MessageTextContainer';
|
|
67
70
|
import { MessageTimestamp } from '../../components/Message/MessageItemView/MessageTimestamp';
|
|
68
71
|
import { ReactionListBottom } from '../../components/Message/MessageItemView/ReactionList/ReactionListBottom';
|
|
69
72
|
import { ReactionListClustered } from '../../components/Message/MessageItemView/ReactionList/ReactionListClustered';
|
|
@@ -147,10 +150,16 @@ import { DefaultMessageOverlayBackground } from '../../contexts/overlayContext/M
|
|
|
147
150
|
import type { MessageActionsProps } from '../../contexts/overlayContext/MessageOverlayHostLayer';
|
|
148
151
|
|
|
149
152
|
/**
|
|
150
|
-
*
|
|
151
|
-
*
|
|
153
|
+
* Normalizes each component entry to React.ComponentType<P>, stripping
|
|
154
|
+
* extra inferred properties (like `displayName: string` from runtime
|
|
155
|
+
* assignments) that would otherwise leak into the override types and
|
|
156
|
+
* force integrators to match them.
|
|
152
157
|
*/
|
|
153
|
-
|
|
158
|
+
type NormalizeComponents<T> = {
|
|
159
|
+
[K in keyof T]: T[K] extends React.ComponentType<infer P> ? React.ComponentType<P> : T[K];
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const components = {
|
|
154
163
|
Attachment,
|
|
155
164
|
AttachButton,
|
|
156
165
|
AttachmentPickerContent,
|
|
@@ -300,35 +309,38 @@ export const DEFAULT_COMPONENTS = {
|
|
|
300
309
|
MessageOverlayBackground: DefaultMessageOverlayBackground,
|
|
301
310
|
|
|
302
311
|
// Image
|
|
303
|
-
|
|
304
|
-
ImageComponent: Image as React.ComponentType<any>,
|
|
305
|
-
|
|
306
|
-
// Optional overrides (no defaults — undefined unless user provides via WithComponents)
|
|
307
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
308
|
-
AttachmentPickerIOSSelectMorePhotos: undefined as React.ComponentType<any> | undefined,
|
|
309
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
310
|
-
ChatLoadingIndicator: undefined as React.ComponentType<any> | null | undefined,
|
|
311
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
312
|
-
CreatePollContent: undefined as React.ComponentType<any> | undefined,
|
|
313
|
-
MessageActions: undefined as React.ComponentType<MessageActionsProps> | undefined,
|
|
314
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
315
|
-
Input: undefined as React.ComponentType<any> | undefined,
|
|
316
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
317
|
-
ListHeaderComponent: undefined as React.ComponentType<any> | undefined,
|
|
318
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
319
|
-
MessageContentBottomView: undefined as React.ComponentType<any> | undefined,
|
|
320
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
321
|
-
MessageContentLeadingView: undefined as React.ComponentType<any> | undefined,
|
|
322
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
323
|
-
MessageContentTopView: undefined as React.ComponentType<any> | undefined,
|
|
324
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
325
|
-
MessageContentTrailingView: undefined as React.ComponentType<any> | undefined,
|
|
326
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
327
|
-
MessageLocation: undefined as React.ComponentType<any> | undefined,
|
|
328
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
329
|
-
MessageSpacer: undefined as React.ComponentType<any> | undefined,
|
|
330
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
331
|
-
MessageText: undefined as React.ComponentType<any> | undefined,
|
|
332
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
333
|
-
PollContent: undefined as React.ComponentType<any> | undefined,
|
|
312
|
+
ImageComponent: Image as React.ComponentType<ImageProps>,
|
|
334
313
|
};
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Optional component slots that have no default implementation.
|
|
317
|
+
* These are `undefined` unless the integrator provides them via WithComponents.
|
|
318
|
+
*/
|
|
319
|
+
export interface OptionalComponentOverrides {
|
|
320
|
+
AttachmentPickerIOSSelectMorePhotos?: React.ComponentType;
|
|
321
|
+
ChatLoadingIndicator?: React.ComponentType | null;
|
|
322
|
+
CreatePollContent?: React.ComponentType;
|
|
323
|
+
Input?: React.ComponentType<{
|
|
324
|
+
additionalTextInputProps?: TextInputProps;
|
|
325
|
+
getUsers: () => UserResponse[];
|
|
326
|
+
}>;
|
|
327
|
+
ListHeaderComponent?: React.ComponentType;
|
|
328
|
+
MessageActions?: React.ComponentType<MessageActionsProps>;
|
|
329
|
+
MessageContentBottomView?: React.ComponentType;
|
|
330
|
+
MessageContentLeadingView?: React.ComponentType;
|
|
331
|
+
MessageContentTopView?: React.ComponentType;
|
|
332
|
+
MessageContentTrailingView?: React.ComponentType;
|
|
333
|
+
MessageLocation?: React.ComponentType<{ message: LocalMessage }>;
|
|
334
|
+
MessageSpacer?: React.ComponentType;
|
|
335
|
+
MessageText?: React.ComponentType<MessageTextProps>;
|
|
336
|
+
PollContent?: React.ComponentType;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* All default component implementations used across the SDK.
|
|
341
|
+
* These are the components used when no overrides are provided via WithComponents.
|
|
342
|
+
*
|
|
343
|
+
* The `NormalizeComponents` cast ensures that internal details like
|
|
344
|
+
* `displayName: string` don't leak into the public override types.
|
|
345
|
+
*/
|
|
346
|
+
export const DEFAULT_COMPONENTS: NormalizeComponents<typeof components> = components;
|
package/src/version.json
CHANGED
|
@@ -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,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
|