stream-chat 9.0.1 → 9.1.0
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/cjs/index.browser.cjs +65 -33
- package/dist/cjs/index.browser.cjs.map +3 -3
- package/dist/cjs/index.node.cjs +65 -33
- package/dist/cjs/index.node.cjs.map +3 -3
- package/dist/esm/index.js +65 -33
- package/dist/esm/index.js.map +3 -3
- package/dist/types/messageComposer/middleware/messageComposer/pollOnly.d.ts +3 -0
- package/dist/types/messageComposer/middleware/pollComposer/types.d.ts +1 -0
- package/dist/types/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.d.ts +1 -1
- package/dist/types/messageComposer/pollComposer.d.ts +7 -2
- package/package.json +1 -1
- package/src/messageComposer/messageComposer.ts +5 -6
- package/src/messageComposer/middleware/messageComposer/MessageComposerMiddlewareExecutor.ts +2 -0
- package/src/messageComposer/middleware/messageComposer/pollOnly.ts +49 -0
- package/src/messageComposer/middleware/pollComposer/state.ts +11 -3
- package/src/messageComposer/middleware/pollComposer/types.ts +1 -0
- package/src/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.ts +10 -24
- package/src/messageComposer/pollComposer.ts +16 -2
|
@@ -43,6 +43,7 @@ export type PollComposerStateChangeMiddlewareValue = {
|
|
|
43
43
|
targetFields: Partial<{
|
|
44
44
|
[K in keyof PollComposerState['data']]: K extends 'options' ? PollComposerOptionUpdate : PollComposerState['data'][K];
|
|
45
45
|
}>;
|
|
46
|
+
injectedFieldErrors?: PollComposerFieldErrors;
|
|
46
47
|
};
|
|
47
48
|
export type PollComposerStateMiddlewareValue = MiddlewareExecutionResult<PollComposerStateChangeMiddlewareValue>;
|
|
48
49
|
export {};
|
package/dist/types/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ExecuteParams, MiddlewareExecutionResult, MiddlewareHandler } from '../../../middleware';
|
|
2
1
|
import { MiddlewareExecutor } from '../../../middleware';
|
|
2
|
+
import type { ExecuteParams, MiddlewareExecutionResult, MiddlewareHandler } from '../../../middleware';
|
|
3
3
|
import type { Suggestion, TextComposerMiddlewareExecutorOptions, TextComposerState } from './types';
|
|
4
4
|
export type TextComposerMiddlewareExecutorState<T extends Suggestion = Suggestion> = TextComposerState<T> & {
|
|
5
5
|
change?: {
|
|
@@ -2,7 +2,7 @@ import { PollComposerCompositionMiddlewareExecutor, PollComposerStateMiddlewareE
|
|
|
2
2
|
import { StateStore } from '../store';
|
|
3
3
|
import { VotingVisibility } from '../types';
|
|
4
4
|
import type { MessageComposer } from './messageComposer';
|
|
5
|
-
import type { PollComposerState, UpdateFieldsData } from './middleware/pollComposer';
|
|
5
|
+
import type { PollComposerFieldErrors, PollComposerState, UpdateFieldsData } from './middleware/pollComposer';
|
|
6
6
|
export type PollComposerOptions = {
|
|
7
7
|
composer: MessageComposer;
|
|
8
8
|
};
|
|
@@ -25,7 +25,12 @@ export declare class PollComposer {
|
|
|
25
25
|
get voting_visibility(): VotingVisibility | undefined;
|
|
26
26
|
get canCreatePoll(): boolean;
|
|
27
27
|
initState: () => void;
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Updates specified fields and generates relevant errors
|
|
30
|
+
* @param data
|
|
31
|
+
* @param injectedFieldErrors - errors produced externally that will take precedence over the errors generated in the middleware chaing
|
|
32
|
+
*/
|
|
33
|
+
updateFields: (data: UpdateFieldsData, injectedFieldErrors?: PollComposerFieldErrors) => Promise<void>;
|
|
29
34
|
handleFieldBlur: (field: keyof PollComposerState["data"]) => Promise<void>;
|
|
30
35
|
compose: () => Promise<import("..").PollComposerCompositionMiddlewareValueState | undefined>;
|
|
31
36
|
}
|
package/package.json
CHANGED
|
@@ -88,16 +88,18 @@ const initState = (
|
|
|
88
88
|
const quotedMessage = composition.quoted_message;
|
|
89
89
|
let message;
|
|
90
90
|
let draftId = null;
|
|
91
|
+
let id = MessageComposer.generateId(); // do not use draft id for messsage id
|
|
91
92
|
if (compositionIsDraftResponse(composition)) {
|
|
92
93
|
message = composition.message;
|
|
93
94
|
draftId = composition.message.id;
|
|
94
95
|
} else {
|
|
95
96
|
message = composition;
|
|
97
|
+
id = composition.id;
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
return {
|
|
99
101
|
draftId,
|
|
100
|
-
id
|
|
102
|
+
id,
|
|
101
103
|
quotedMessage: quotedMessage
|
|
102
104
|
? formatMessage(quotedMessage as MessageResponseBase)
|
|
103
105
|
: null,
|
|
@@ -318,6 +320,7 @@ export class MessageComposer {
|
|
|
318
320
|
this.attachmentManager.initState({ message });
|
|
319
321
|
this.linkPreviewsManager.initState({ message });
|
|
320
322
|
this.textComposer.initState({ message });
|
|
323
|
+
this.pollComposer.initState();
|
|
321
324
|
this.customDataManager.initState({ message });
|
|
322
325
|
this.state.next(initState(composition));
|
|
323
326
|
if (
|
|
@@ -543,11 +546,6 @@ export class MessageComposer {
|
|
|
543
546
|
};
|
|
544
547
|
|
|
545
548
|
clear = () => {
|
|
546
|
-
this.attachmentManager.initState();
|
|
547
|
-
this.linkPreviewsManager.initState();
|
|
548
|
-
this.textComposer.initState();
|
|
549
|
-
this.pollComposer.initState();
|
|
550
|
-
this.customDataManager.initState();
|
|
551
549
|
this.initState();
|
|
552
550
|
};
|
|
553
551
|
|
|
@@ -630,6 +628,7 @@ export class MessageComposer {
|
|
|
630
628
|
try {
|
|
631
629
|
const { poll } = await this.client.createPoll(composition.data);
|
|
632
630
|
this.state.partialNext({ pollId: poll.id });
|
|
631
|
+
this.pollComposer.initState();
|
|
633
632
|
} catch (error) {
|
|
634
633
|
this.client.notifications.add({
|
|
635
634
|
message: 'Failed to create the poll',
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
createCustomDataCompositionMiddleware,
|
|
31
31
|
createDraftCustomDataCompositionMiddleware,
|
|
32
32
|
} from './customData';
|
|
33
|
+
import { createPollOnlyCompositionMiddleware } from './pollOnly';
|
|
33
34
|
|
|
34
35
|
export class MessageComposerMiddlewareExecutor extends MiddlewareExecutor<
|
|
35
36
|
MessageComposerMiddlewareState,
|
|
@@ -40,6 +41,7 @@ export class MessageComposerMiddlewareExecutor extends MiddlewareExecutor<
|
|
|
40
41
|
// todo: document how to add custom data to a composed message using middleware
|
|
41
42
|
// or adding custom composer components (apart from AttachmentsManager, TextComposer etc.)
|
|
42
43
|
this.use([
|
|
44
|
+
createPollOnlyCompositionMiddleware(composer),
|
|
43
45
|
createTextComposerCompositionMiddleware(composer),
|
|
44
46
|
createAttachmentsCompositionMiddleware(composer),
|
|
45
47
|
createLinkPreviewsCompositionMiddleware(composer),
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
MessageComposerMiddlewareState,
|
|
3
|
+
MessageCompositionMiddleware,
|
|
4
|
+
} from './types';
|
|
5
|
+
import type { MessageComposer } from '../../messageComposer';
|
|
6
|
+
import type { MiddlewareHandlerParams } from '../../../middleware';
|
|
7
|
+
import type { LocalMessage } from '../../../types';
|
|
8
|
+
|
|
9
|
+
const pollLocalMessageNullifiedFields: Pick<
|
|
10
|
+
LocalMessage,
|
|
11
|
+
'attachments' | 'mentioned_users' | 'parent_id' | 'quoted_message' | 'text'
|
|
12
|
+
> = {
|
|
13
|
+
attachments: [],
|
|
14
|
+
mentioned_users: [],
|
|
15
|
+
parent_id: undefined,
|
|
16
|
+
quoted_message: undefined,
|
|
17
|
+
text: '',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const createPollOnlyCompositionMiddleware = (
|
|
21
|
+
composer: MessageComposer,
|
|
22
|
+
): MessageCompositionMiddleware => ({
|
|
23
|
+
id: 'stream-io/message-composer-middleware/poll-only',
|
|
24
|
+
handlers: {
|
|
25
|
+
compose: ({
|
|
26
|
+
state,
|
|
27
|
+
complete,
|
|
28
|
+
forward,
|
|
29
|
+
}: MiddlewareHandlerParams<MessageComposerMiddlewareState>) => {
|
|
30
|
+
const pollId = composer.pollId;
|
|
31
|
+
const isEditingMessage = !!composer.editedMessage;
|
|
32
|
+
const isComposingThreadReply = !!composer.threadId;
|
|
33
|
+
if (!pollId || isComposingThreadReply || isEditingMessage) return forward();
|
|
34
|
+
|
|
35
|
+
return complete({
|
|
36
|
+
...state,
|
|
37
|
+
localMessage: {
|
|
38
|
+
...state.localMessage,
|
|
39
|
+
...pollLocalMessageNullifiedFields,
|
|
40
|
+
poll_id: pollId,
|
|
41
|
+
},
|
|
42
|
+
message: {
|
|
43
|
+
id: state.localMessage.id,
|
|
44
|
+
poll_id: pollId,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
});
|
|
@@ -31,6 +31,10 @@ export const pollStateChangeValidators: Partial<
|
|
|
31
31
|
max_votes_allowed: ({ data, value }) => {
|
|
32
32
|
if (data.enforce_unique_vote && value)
|
|
33
33
|
return { max_votes_allowed: 'Enforce unique vote is enabled' };
|
|
34
|
+
const numericMatch = value.match(/^[0-9]+$/);
|
|
35
|
+
if (!numericMatch && value) {
|
|
36
|
+
return { max_votes_allowed: 'Only numbers are allowed' };
|
|
37
|
+
}
|
|
34
38
|
if (value?.length > 1 && !value.match(VALID_MAX_VOTES_VALUE_REGEX))
|
|
35
39
|
return { max_votes_allowed: 'Type a number from 2 to 10' };
|
|
36
40
|
return { max_votes_allowed: undefined };
|
|
@@ -225,7 +229,7 @@ export const createPollComposerStateMiddleware = ({
|
|
|
225
229
|
forward,
|
|
226
230
|
}: MiddlewareHandlerParams<PollComposerStateChangeMiddlewareValue>) => {
|
|
227
231
|
if (!state.targetFields) return forward();
|
|
228
|
-
const { previousState } = state;
|
|
232
|
+
const { previousState, injectedFieldErrors } = state;
|
|
229
233
|
const finalValidators = {
|
|
230
234
|
...pollStateChangeValidators,
|
|
231
235
|
...defaultPollFieldChangeEventValidators,
|
|
@@ -247,7 +251,7 @@ export const createPollComposerStateMiddleware = ({
|
|
|
247
251
|
nextState: {
|
|
248
252
|
...previousState,
|
|
249
253
|
data: { ...previousState.data, ...newData },
|
|
250
|
-
errors: { ...previousState.errors, ...newErrors },
|
|
254
|
+
errors: { ...previousState.errors, ...newErrors, ...injectedFieldErrors },
|
|
251
255
|
},
|
|
252
256
|
});
|
|
253
257
|
},
|
|
@@ -275,7 +279,11 @@ export const createPollComposerStateMiddleware = ({
|
|
|
275
279
|
nextState: {
|
|
276
280
|
...previousState,
|
|
277
281
|
data: { ...previousState.data, ...newData },
|
|
278
|
-
errors: {
|
|
282
|
+
errors: {
|
|
283
|
+
...previousState.errors,
|
|
284
|
+
...newErrors,
|
|
285
|
+
...state.injectedFieldErrors,
|
|
286
|
+
},
|
|
279
287
|
},
|
|
280
288
|
});
|
|
281
289
|
},
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { createCommandsMiddleware } from './commands';
|
|
2
2
|
import { createMentionsMiddleware } from './mentions';
|
|
3
3
|
import { createTextComposerPreValidationMiddleware } from './validation';
|
|
4
|
+
import { MiddlewareExecutor } from '../../../middleware';
|
|
4
5
|
import type {
|
|
5
6
|
ExecuteParams,
|
|
6
7
|
MiddlewareExecutionResult,
|
|
7
8
|
MiddlewareHandler,
|
|
8
9
|
} from '../../../middleware';
|
|
9
|
-
import { MiddlewareExecutor } from '../../../middleware';
|
|
10
|
-
import { withCancellation } from '../../../utils/concurrency';
|
|
11
10
|
import type {
|
|
12
11
|
Suggestion,
|
|
12
|
+
Suggestions,
|
|
13
13
|
TextComposerMiddlewareExecutorOptions,
|
|
14
14
|
TextComposerState,
|
|
15
15
|
} from './types';
|
|
@@ -58,28 +58,14 @@ export class TextComposerMiddlewareExecutor<
|
|
|
58
58
|
initialValue: initialState,
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
},
|
|
70
|
-
);
|
|
71
|
-
if (searchResult === 'canceled') return { ...result, status: 'discard' };
|
|
72
|
-
} catch (error) {
|
|
73
|
-
// Clear suggestions on search error
|
|
74
|
-
return {
|
|
75
|
-
...result,
|
|
76
|
-
state: {
|
|
77
|
-
...result.state,
|
|
78
|
-
suggestions: undefined,
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
}
|
|
61
|
+
const { query, searchSource } = result.state.suggestions ?? ({} as Suggestions);
|
|
62
|
+
/**
|
|
63
|
+
* Catching error just for sanity purposes.
|
|
64
|
+
* The BaseSearchSource.search() method returns debounced result.
|
|
65
|
+
* That means the result of the previous search call as the debounced call result is unknown at the moment.
|
|
66
|
+
* Custom search source implementation should handle errors meaningfully internally.
|
|
67
|
+
*/
|
|
68
|
+
searchSource?.search(query)?.catch(console.error);
|
|
83
69
|
|
|
84
70
|
return result;
|
|
85
71
|
}
|
|
@@ -7,7 +7,11 @@ import { StateStore } from '../store';
|
|
|
7
7
|
import { VotingVisibility } from '../types';
|
|
8
8
|
import { generateUUIDv4 } from '../utils';
|
|
9
9
|
import type { MessageComposer } from './messageComposer';
|
|
10
|
-
import type {
|
|
10
|
+
import type {
|
|
11
|
+
PollComposerFieldErrors,
|
|
12
|
+
PollComposerState,
|
|
13
|
+
UpdateFieldsData,
|
|
14
|
+
} from './middleware/pollComposer';
|
|
11
15
|
|
|
12
16
|
export type PollComposerOptions = {
|
|
13
17
|
composer: MessageComposer;
|
|
@@ -102,13 +106,23 @@ export class PollComposer {
|
|
|
102
106
|
this.state.next(this.initialState);
|
|
103
107
|
};
|
|
104
108
|
|
|
105
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Updates specified fields and generates relevant errors
|
|
111
|
+
* @param data
|
|
112
|
+
* @param injectedFieldErrors - errors produced externally that will take precedence over the errors generated in the middleware chaing
|
|
113
|
+
*/
|
|
114
|
+
// FIXME: change method params to a single object with the next major release
|
|
115
|
+
updateFields = async (
|
|
116
|
+
data: UpdateFieldsData,
|
|
117
|
+
injectedFieldErrors?: PollComposerFieldErrors,
|
|
118
|
+
) => {
|
|
106
119
|
const { state, status } = await this.stateMiddlewareExecutor.execute({
|
|
107
120
|
eventName: 'handleFieldChange',
|
|
108
121
|
initialValue: {
|
|
109
122
|
nextState: { ...this.state.getLatestValue() },
|
|
110
123
|
previousState: { ...this.state.getLatestValue() },
|
|
111
124
|
targetFields: data,
|
|
125
|
+
injectedFieldErrors,
|
|
112
126
|
},
|
|
113
127
|
});
|
|
114
128
|
|