@linktr.ee/messaging-react 3.29.1-rc-1785477229 → 3.29.1

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/dist/index.d.ts CHANGED
@@ -404,9 +404,9 @@ export declare interface ChannelViewProps {
404
404
  */
405
405
  onBroadcastClick?: BroadcastClickHandler;
406
406
  /**
407
- * Resolves the current campaign name for a broadcast label. The host may
408
- * keep this resolver stable when its backing cache changes; ChannelView
409
- * re-invokes it on render and publishes changed names to memoized rows. The
407
+ * Resolves the current campaign name for a broadcast label. The host must
408
+ * provide a new resolver reference when a returned name changes so
409
+ * ChannelView re-renders and publishes the new value to memoized rows. The
410
410
  * stamped message name remains the fallback until this returns a name.
411
411
  */
412
412
  resolveBroadcastName?: BroadcastNameResolver;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linktr.ee/messaging-react",
3
- "version": "3.29.1-rc-1785477229",
3
+ "version": "3.29.1",
4
4
  "description": "React messaging components built on messaging-core for web applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "@linktr.ee/component-library": "11.8.6",
53
- "@linktr.ee/messaging-core": "2.3.0-rc-1785477229",
53
+ "@linktr.ee/messaging-core": "^2.2.0",
54
54
  "@linktr.ee/messaging-taxonomy": "^0.5.0",
55
55
  "@phosphor-icons/react": "^2.1.10",
56
56
  "culori": "^4.0.2"
@@ -113,69 +113,4 @@ describe('ChannelView broadcast-name resolution', () => {
113
113
  expect(mounts).toHaveBeenCalledOnce()
114
114
  expect(unmounts).not.toHaveBeenCalled()
115
115
  })
116
-
117
- it('re-reads a stable resolver when ChannelView re-renders after the cache fills', async () => {
118
- const { channel, client } = createChannel()
119
- const resolvedName: { current?: string } = {}
120
- const resolveBroadcastName = () => resolvedName.current
121
- const mounts = vi.fn()
122
- const unmounts = vi.fn()
123
-
124
- const RowProbe = ({ children }: { children: React.ReactNode }) => {
125
- useEffect(() => {
126
- mounts()
127
- return unmounts
128
- }, [])
129
- return <>{children}</>
130
- }
131
- const renderMessage = (messageNode: React.ReactElement) => (
132
- <RowProbe>{messageNode}</RowProbe>
133
- )
134
-
135
- let rerender!: ReturnType<typeof render>['rerender']
136
- await act(async () => {
137
- rerender = render(
138
- <Chat client={client}>
139
- <Channel channel={channel as StreamChannel}>
140
- <ChannelView
141
- channel={channel as StreamChannel}
142
- resolveBroadcastName={resolveBroadcastName}
143
- renderMessage={renderMessage}
144
- showStarButton={false}
145
- />
146
- </Channel>
147
- </Chat>
148
- ).rerender
149
- })
150
-
151
- expect(
152
- screen.getByTestId('sent-message-broadcast-status')
153
- ).toHaveTextContent('July 9th Class attendees')
154
- expect(mounts).toHaveBeenCalledOnce()
155
-
156
- resolvedName.current = 'July 9th Class absentee'
157
-
158
- // ChannelView is memoized on props; flip an unrelated prop so the tree
159
- // re-renders and re-invokes the same stable resolver against the live ref.
160
- act(() => {
161
- rerender(
162
- <Chat client={client}>
163
- <Channel channel={channel as StreamChannel}>
164
- <ChannelView
165
- channel={channel as StreamChannel}
166
- resolveBroadcastName={resolveBroadcastName}
167
- renderMessage={renderMessage}
168
- showStarButton={true}
169
- />
170
- </Channel>
171
- </Chat>
172
- )
173
- })
174
-
175
- expect(
176
- screen.getByTestId('sent-message-broadcast-status')
177
- ).toHaveTextContent('July 9th Class absentee')
178
- expect(mounts).toHaveBeenCalledOnce()
179
- expect(unmounts).not.toHaveBeenCalled()
180
- })
181
116
  })
@@ -16,7 +16,10 @@ import type { ChannelViewProps } from '../types'
16
16
  import { ChannelHeaderRedesign } from './ChannelHeaderRedesign'
17
17
  import { CustomDateSeparator } from './CustomDateSeparator'
18
18
  import { CustomMessage } from './CustomMessage'
19
- import { BroadcastNameContext, useBroadcastNamesById } from './CustomMessage/BroadcastNameContext'
19
+ import {
20
+ BroadcastNameContext,
21
+ useBroadcastNamesById,
22
+ } from './CustomMessage/BroadcastNameContext'
20
23
  import { CustomMessageActions } from './CustomMessage/CustomMessageActions'
21
24
  import { CustomMessageInput } from './CustomMessageInput'
22
25
  import { CustomSystemMessage } from './CustomSystemMessage'
@@ -102,8 +105,8 @@ const ChannelViewInner: React.FC<{
102
105
  const messageBroadcastClick = onBroadcastClick
103
106
  ? stableOnBroadcastClick
104
107
  : undefined
105
- // Resolve outside memoized Stream rows so a stable host resolver backed by a
106
- // live cache still publishes new campaign names when this tree re-renders.
108
+ // Resolve outside memoized Stream rows so new campaign names publish without
109
+ // remounting the rows.
107
110
  const broadcastNamesById = useBroadcastNamesById(
108
111
  messages,
109
112
  resolveBroadcastName
@@ -19,9 +19,8 @@ const broadcastIdFromMessage = (message: {
19
19
  /**
20
20
  * Resolve campaign names for the messages currently in view.
21
21
  *
22
- * Built outside memoized Stream rows so a host can keep `resolveBroadcastName`
23
- * referentially stable (ref/cache-backed) and still publish new strings when
24
- * ChannelView re-renders after the cache fills in.
22
+ * Built outside memoized Stream rows so a new resolver reference can publish
23
+ * new campaign names without remounting the Stream message rows.
25
24
  */
26
25
  export const buildBroadcastNamesById = (
27
26
  messages: readonly { metadata?: { broadcast_id?: unknown } }[] | undefined,
@@ -74,18 +73,18 @@ const areBroadcastNamesEqual = (
74
73
  }
75
74
 
76
75
  /**
77
- * Re-invokes a (possibly stable) resolver on every render, but only returns a
78
- * new object when the resolved strings actually change — so context consumers
79
- * update for late-arriving campaign names without thrashing on unrelated
80
- * ChannelViewInner renders.
76
+ * Re-invokes the resolver on every render, but only returns a new object when
77
+ * the resolved strings actually change — so context consumers update for
78
+ * late-arriving campaign names without thrashing on unrelated renders.
81
79
  */
82
80
  export const useBroadcastNamesById = (
83
81
  messages: readonly { metadata?: { broadcast_id?: unknown } }[] | undefined,
84
82
  resolveBroadcastName: BroadcastNameResolver | undefined
85
83
  ): BroadcastNamesById | undefined => {
86
84
  const names = buildBroadcastNamesById(messages, resolveBroadcastName)
87
- const [publishedNames, setPublishedNames] =
88
- useState<BroadcastNamesById | undefined>(names)
85
+ const [publishedNames, setPublishedNames] = useState<
86
+ BroadcastNamesById | undefined
87
+ >(names)
89
88
 
90
89
  if (!areBroadcastNamesEqual(publishedNames, names)) {
91
90
  setPublishedNames(names)
package/src/types.ts CHANGED
@@ -376,9 +376,9 @@ export interface ChannelViewProps {
376
376
  onBroadcastClick?: BroadcastClickHandler
377
377
 
378
378
  /**
379
- * Resolves the current campaign name for a broadcast label. The host may
380
- * keep this resolver stable when its backing cache changes; ChannelView
381
- * re-invokes it on render and publishes changed names to memoized rows. The
379
+ * Resolves the current campaign name for a broadcast label. The host must
380
+ * provide a new resolver reference when a returned name changes so
381
+ * ChannelView re-renders and publishes the new value to memoized rows. The
382
382
  * stamped message name remains the fallback until this returns a name.
383
383
  */
384
384
  resolveBroadcastName?: BroadcastNameResolver