stream-chat 9.42.3 → 9.43.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.js +1451 -1169
- package/dist/cjs/index.browser.js.map +3 -3
- package/dist/cjs/index.node.js +1452 -1171
- package/dist/cjs/index.node.js.map +3 -3
- package/dist/esm/index.mjs +1451 -1169
- package/dist/esm/index.mjs.map +3 -3
- package/dist/types/messageComposer/CustomDataManager.d.ts +3 -0
- package/dist/types/messageComposer/LocationComposer.d.ts +3 -0
- package/dist/types/messageComposer/MessageComposerEffectHandlers.d.ts +17 -0
- package/dist/types/messageComposer/attachmentManager.d.ts +7 -0
- package/dist/types/messageComposer/linkPreviewsManager.d.ts +4 -1
- package/dist/types/messageComposer/messageComposer.d.ts +39 -1
- package/dist/types/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.d.ts +2 -1
- package/dist/types/messageComposer/middleware/textComposer/commandEffects.d.ts +5 -0
- package/dist/types/messageComposer/middleware/textComposer/commandUtils.d.ts +7 -0
- package/dist/types/messageComposer/middleware/textComposer/commands.d.ts +2 -0
- package/dist/types/messageComposer/middleware/textComposer/index.d.ts +1 -0
- package/dist/types/messageComposer/middleware/textComposer/textMiddlewareUtils.d.ts +0 -34
- package/dist/types/messageComposer/middleware/textComposer/types.d.ts +13 -0
- package/dist/types/messageComposer/pollComposer.d.ts +3 -0
- package/dist/types/messageComposer/textComposer.d.ts +5 -1
- package/package.json +1 -1
- package/src/messageComposer/CustomDataManager.ts +8 -0
- package/src/messageComposer/LocationComposer.ts +8 -0
- package/src/messageComposer/MessageComposerEffectHandlers.ts +87 -0
- package/src/messageComposer/attachmentManager.ts +55 -0
- package/src/messageComposer/linkPreviewsManager.ts +12 -3
- package/src/messageComposer/messageComposer.ts +107 -0
- package/src/messageComposer/middleware/messageComposer/compositionValidation.ts +58 -18
- package/src/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.ts +7 -1
- package/src/messageComposer/middleware/textComposer/commandEffects.ts +51 -0
- package/src/messageComposer/middleware/textComposer/commandStringExtraction.ts +1 -4
- package/src/messageComposer/middleware/textComposer/commandUtils.ts +48 -0
- package/src/messageComposer/middleware/textComposer/commands.ts +15 -7
- package/src/messageComposer/middleware/textComposer/index.ts +1 -0
- package/src/messageComposer/middleware/textComposer/textMiddlewareUtils.ts +3 -46
- package/src/messageComposer/middleware/textComposer/types.ts +20 -0
- package/src/messageComposer/pollComposer.ts +8 -0
- package/src/messageComposer/textComposer.ts +54 -6
|
@@ -6,6 +6,7 @@ export type CustomDataManagerState = {
|
|
|
6
6
|
message: CustomMessageData;
|
|
7
7
|
custom: CustomMessageComposerData;
|
|
8
8
|
};
|
|
9
|
+
export type CustomDataManagerSnapshot = CustomDataManagerState;
|
|
9
10
|
export type CustomDataManagerOptions = {
|
|
10
11
|
composer: MessageComposer;
|
|
11
12
|
message?: DraftMessage | LocalMessage;
|
|
@@ -20,6 +21,8 @@ export declare class CustomDataManager {
|
|
|
20
21
|
initState: ({ message }?: {
|
|
21
22
|
message?: DraftMessage | LocalMessage;
|
|
22
23
|
}) => void;
|
|
24
|
+
getSnapshot: () => CustomDataManagerSnapshot;
|
|
25
|
+
restoreSnapshot: (snapshot: CustomDataManagerSnapshot) => void;
|
|
23
26
|
setMessageData(data: DeepPartial<CustomMessageData>): void;
|
|
24
27
|
setCustomData(data: DeepPartial<CustomMessageComposerData>): void;
|
|
25
28
|
}
|
|
@@ -16,6 +16,7 @@ export type LiveLocationPreview = Omit<LiveLocationPayload, 'end_at'> & {
|
|
|
16
16
|
export type LocationComposerState = {
|
|
17
17
|
location: StaticLocationPreview | LiveLocationPreview | null;
|
|
18
18
|
};
|
|
19
|
+
export type LocationComposerSnapshot = LocationComposerState;
|
|
19
20
|
export declare class LocationComposer {
|
|
20
21
|
readonly state: StateStore<LocationComposerState>;
|
|
21
22
|
readonly composer: MessageComposer;
|
|
@@ -28,6 +29,8 @@ export declare class LocationComposer {
|
|
|
28
29
|
initState: ({ message }?: {
|
|
29
30
|
message?: DraftMessage | LocalMessage;
|
|
30
31
|
}) => void;
|
|
32
|
+
getSnapshot: () => LocationComposerSnapshot;
|
|
33
|
+
restoreSnapshot: (snapshot: LocationComposerSnapshot) => void;
|
|
31
34
|
setData: (data: {
|
|
32
35
|
durationMs?: number;
|
|
33
36
|
} & Coords) => void;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { MessageComposer, MessageComposerEffectHandler } from './messageComposer';
|
|
2
|
+
export type MessageComposerEffectHandlersOptions = {
|
|
3
|
+
composer: MessageComposer;
|
|
4
|
+
};
|
|
5
|
+
export declare class MessageComposerEffectHandlers {
|
|
6
|
+
private options;
|
|
7
|
+
private handlers;
|
|
8
|
+
constructor(options: MessageComposerEffectHandlersOptions);
|
|
9
|
+
private registerDefaultHandlers;
|
|
10
|
+
registerEffectHandler: <T extends {
|
|
11
|
+
type: string;
|
|
12
|
+
}>(type: T["type"], handler: MessageComposerEffectHandler<T>) => void;
|
|
13
|
+
applyEffects: <T extends {
|
|
14
|
+
type: string;
|
|
15
|
+
}>(effects?: T[]) => void;
|
|
16
|
+
private applyEffect;
|
|
17
|
+
}
|
|
@@ -8,6 +8,7 @@ export type FileUploadFilter = (file: Partial<LocalUploadAttachment>) => boolean
|
|
|
8
8
|
export type AttachmentManagerState = {
|
|
9
9
|
attachments: LocalAttachment[];
|
|
10
10
|
};
|
|
11
|
+
export type AttachmentManagerSnapshot = AttachmentManagerState;
|
|
11
12
|
export type AttachmentManagerOptions = {
|
|
12
13
|
composer: MessageComposer;
|
|
13
14
|
message?: DraftMessage | LocalMessage;
|
|
@@ -41,9 +42,15 @@ export declare class AttachmentManager {
|
|
|
41
42
|
get pendingUploadsCount(): number;
|
|
42
43
|
get availableUploadSlots(): number;
|
|
43
44
|
getUploadsByState(state: AttachmentLoadingState): LocalAttachment[];
|
|
45
|
+
private cancelAttachmentUploads;
|
|
46
|
+
private normalizeSnapshotAttachment;
|
|
44
47
|
initState: ({ message }?: {
|
|
45
48
|
message?: DraftMessage | LocalMessage;
|
|
46
49
|
}) => void;
|
|
50
|
+
getSnapshot: () => AttachmentManagerSnapshot;
|
|
51
|
+
restoreSnapshot: (snapshot: AttachmentManagerSnapshot) => void;
|
|
52
|
+
setAttachments: (attachments: LocalAttachment[]) => void;
|
|
53
|
+
clearAttachments: () => void;
|
|
47
54
|
getAttachmentIndex: (localId: string) => number;
|
|
48
55
|
private prepareAttachmentUpdate;
|
|
49
56
|
updateAttachment: (attachmentToUpdate: LocalAttachment) => void;
|
|
@@ -7,7 +7,7 @@ export type LinkPreview = OGAttachment & {
|
|
|
7
7
|
status: LinkPreviewStatus;
|
|
8
8
|
};
|
|
9
9
|
export interface ILinkPreviewsManager {
|
|
10
|
-
/** Function cancels all
|
|
10
|
+
/** Function cancels all scheduled or in-progress URL enrichment queries. */
|
|
11
11
|
cancelURLEnrichment: () => void;
|
|
12
12
|
/** Function that triggers the search for URLs and their enrichment. */
|
|
13
13
|
findAndEnrichUrls?: DebouncedFunc<(text: string) => void>;
|
|
@@ -29,6 +29,7 @@ export type LinkPreviewMap = Map<LinkURL, LinkPreview>;
|
|
|
29
29
|
export type LinkPreviewsManagerState = {
|
|
30
30
|
previews: LinkPreviewMap;
|
|
31
31
|
};
|
|
32
|
+
export type LinkPreviewsManagerSnapshot = LinkPreviewsManagerState;
|
|
32
33
|
export type LinkPreviewsManagerOptions = {
|
|
33
34
|
composer: MessageComposer;
|
|
34
35
|
message?: DraftMessage | LocalMessage;
|
|
@@ -59,6 +60,8 @@ export declare class LinkPreviewsManager implements ILinkPreviewsManager {
|
|
|
59
60
|
initState: ({ message }?: {
|
|
60
61
|
message?: DraftMessage | LocalMessage;
|
|
61
62
|
}) => void;
|
|
63
|
+
getSnapshot: () => LinkPreviewsManagerSnapshot;
|
|
64
|
+
restoreSnapshot: (snapshot: LinkPreviewsManagerSnapshot) => void;
|
|
62
65
|
private _findAndEnrichUrls;
|
|
63
66
|
cancelURLEnrichment: () => void;
|
|
64
67
|
/**
|
|
@@ -11,10 +11,17 @@ import { StateStore } from '../store';
|
|
|
11
11
|
import { generateUUIDv4 } from '../utils';
|
|
12
12
|
import { Channel } from '../channel';
|
|
13
13
|
import { Thread } from '../thread';
|
|
14
|
-
import type { ChannelAPIResponse, DraftResponse, LocalMessage, LocalMessageBase, MessageResponse } from '../types';
|
|
14
|
+
import type { ChannelAPIResponse, CommandResponse, DraftResponse, LocalMessage, LocalMessageBase, MessageResponse } from '../types';
|
|
15
15
|
import { WithSubscriptions } from '../utils/WithSubscriptions';
|
|
16
16
|
import type { StreamChat } from '../client';
|
|
17
17
|
import type { MessageComposerConfig } from './configuration/types';
|
|
18
|
+
import type { CommandSuggestionDisabledReason, TextComposerCommandActivationEffect, TextComposerCommandClearEffect } from './middleware/textComposer/types';
|
|
19
|
+
import type { AttachmentManagerSnapshot } from './attachmentManager';
|
|
20
|
+
import type { CustomDataManagerSnapshot } from './CustomDataManager';
|
|
21
|
+
import type { LinkPreviewsManagerSnapshot } from './linkPreviewsManager';
|
|
22
|
+
import type { LocationComposerSnapshot } from './LocationComposer';
|
|
23
|
+
import type { PollComposerSnapshot } from './pollComposer';
|
|
24
|
+
import type { TextComposerSnapshot } from './textComposer';
|
|
18
25
|
import type { DeepPartial } from '../types.utility';
|
|
19
26
|
type UnregisterSubscriptions = Unsubscribe;
|
|
20
27
|
export type LastComposerChange = {
|
|
@@ -24,6 +31,22 @@ export type LastComposerChange = {
|
|
|
24
31
|
export type EditingAuditState = {
|
|
25
32
|
lastChange: LastComposerChange;
|
|
26
33
|
};
|
|
34
|
+
export type BuiltInMessageComposerEffect = TextComposerCommandActivationEffect | TextComposerCommandClearEffect;
|
|
35
|
+
export type CustomMessageComposerEffect = {
|
|
36
|
+
type: string & {};
|
|
37
|
+
} & Record<string, unknown>;
|
|
38
|
+
export type MessageComposerEffect = BuiltInMessageComposerEffect | CustomMessageComposerEffect;
|
|
39
|
+
export type MessageComposerEffectHandler<T extends {
|
|
40
|
+
type: string;
|
|
41
|
+
} = MessageComposerEffect> = (effect: T, composer: MessageComposer) => void;
|
|
42
|
+
export type MessageComposerSnapshot = {
|
|
43
|
+
attachmentManager: AttachmentManagerSnapshot;
|
|
44
|
+
customDataManager: CustomDataManagerSnapshot;
|
|
45
|
+
linkPreviewsManager: LinkPreviewsManagerSnapshot;
|
|
46
|
+
locationComposer: LocationComposerSnapshot;
|
|
47
|
+
pollComposer: PollComposerSnapshot;
|
|
48
|
+
textComposer: TextComposerSnapshot;
|
|
49
|
+
};
|
|
27
50
|
export type LocalMessageWithLegacyThreadId = LocalMessage & {
|
|
28
51
|
legacyThreadId?: string;
|
|
29
52
|
};
|
|
@@ -60,6 +83,8 @@ export declare class MessageComposer extends WithSubscriptions {
|
|
|
60
83
|
pollComposer: PollComposer;
|
|
61
84
|
locationComposer: LocationComposer;
|
|
62
85
|
customDataManager: CustomDataManager;
|
|
86
|
+
private snapshots;
|
|
87
|
+
private effectHandlers;
|
|
63
88
|
constructor({ composition, config, compositionContext, client, }: MessageComposerOptions);
|
|
64
89
|
static evaluateContextType(compositionContext: CompositionContext): "message" | "channel" | "thread" | "legacy_thread";
|
|
65
90
|
static constructTag(compositionContext: CompositionContext): `${ReturnType<typeof MessageComposer.evaluateContextType>}_${string}`;
|
|
@@ -76,6 +101,8 @@ export declare class MessageComposer extends WithSubscriptions {
|
|
|
76
101
|
get draftId(): string | null;
|
|
77
102
|
get lastChange(): LastComposerChange;
|
|
78
103
|
get quotedMessage(): LocalMessageBase | null;
|
|
104
|
+
getCommandDisabledReason: (command: CommandResponse) => CommandSuggestionDisabledReason | undefined;
|
|
105
|
+
isCommandDisabled: (command: CommandResponse) => boolean;
|
|
79
106
|
get pollId(): string | null;
|
|
80
107
|
get showReplyInChannel(): boolean;
|
|
81
108
|
get hasSendableData(): boolean;
|
|
@@ -89,6 +116,17 @@ export declare class MessageComposer extends WithSubscriptions {
|
|
|
89
116
|
}) => void;
|
|
90
117
|
initStateFromChannelResponse: (channelApiResponse: ChannelAPIResponse) => void;
|
|
91
118
|
initEditingAuditState: (composition?: DraftResponse | MessageResponse | LocalMessage) => EditingAuditState;
|
|
119
|
+
clearSnapshots: () => void;
|
|
120
|
+
getSnapshot: () => MessageComposerSnapshot;
|
|
121
|
+
restoreSnapshot: (snapshot: MessageComposerSnapshot) => void;
|
|
122
|
+
captureSnapshot: (snapshot?: MessageComposerSnapshot) => void;
|
|
123
|
+
popSnapshot: () => MessageComposerSnapshot | undefined;
|
|
124
|
+
registerEffectHandler: <T extends {
|
|
125
|
+
type: string;
|
|
126
|
+
}>(type: T["type"], handler: MessageComposerEffectHandler<T>) => void;
|
|
127
|
+
applyEffects: <T extends {
|
|
128
|
+
type: string;
|
|
129
|
+
}>(effects?: T[]) => void;
|
|
92
130
|
private logStateUpdateTimestamp;
|
|
93
131
|
private logDraftUpdateTimestamp;
|
|
94
132
|
registerDraftEventSubscriptions: () => () => void;
|
package/dist/types/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { MiddlewareExecutor } from '../../../middleware';
|
|
2
2
|
import type { ExecuteParams, MiddlewareExecutionResult, MiddlewareHandler } from '../../../middleware';
|
|
3
|
-
import type { Suggestion, TextComposerMiddlewareExecutorOptions, TextComposerState } from './types';
|
|
3
|
+
import type { Suggestion, TextComposerEffect, TextComposerMiddlewareExecutorOptions, TextComposerState } from './types';
|
|
4
4
|
export type TextComposerMiddlewareExecutorState<T extends Suggestion = Suggestion> = TextComposerState<T> & {
|
|
5
5
|
change?: {
|
|
6
6
|
selectedSuggestion?: T;
|
|
7
7
|
};
|
|
8
|
+
effects?: TextComposerEffect[];
|
|
8
9
|
};
|
|
9
10
|
export type TextComposerHandlerNames = 'onChange' | 'onSuggestionItemSelect';
|
|
10
11
|
export type TextComposerMiddleware<T extends Suggestion = Suggestion> = {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Middleware } from '../../../middleware';
|
|
2
|
+
import type { CommandSuggestion } from './types';
|
|
3
|
+
import type { TextComposerMiddlewareExecutorState } from './TextComposerMiddlewareExecutor';
|
|
4
|
+
export type CommandEffectsMiddleware = Middleware<TextComposerMiddlewareExecutorState<CommandSuggestion>, 'onChange' | 'onSuggestionItemSelect'>;
|
|
5
|
+
export declare const createCommandEffectsMiddleware: () => CommandEffectsMiddleware;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { MessageComposer } from '../../messageComposer';
|
|
2
|
+
import type { CommandResponse } from '../../../types';
|
|
3
|
+
export declare function escapeCommandRegExp(text: string): string;
|
|
4
|
+
export declare const getRawCommandName: (text?: string) => string | undefined;
|
|
5
|
+
export declare const getCompleteCommandInString: (text: string) => string | null;
|
|
6
|
+
export declare const stripCommandFromText: (text: string, commandName: string) => string;
|
|
7
|
+
export declare const notifyCommandDisabled: (composer: MessageComposer, command: CommandResponse) => true | undefined;
|
|
@@ -2,6 +2,7 @@ import type { Channel } from '../../../channel';
|
|
|
2
2
|
import type { Middleware } from '../../../middleware';
|
|
3
3
|
import type { SearchSourceOptions } from '../../../search';
|
|
4
4
|
import { BaseSearchSourceSync } from '../../../search';
|
|
5
|
+
import type { MessageComposer } from '../../messageComposer';
|
|
5
6
|
import type { CommandSuggestion, TextComposerMiddlewareOptions } from './types';
|
|
6
7
|
import type { TextComposerMiddlewareExecutorState } from './TextComposerMiddlewareExecutor';
|
|
7
8
|
export declare class CommandSearchSource extends BaseSearchSourceSync<CommandSuggestion> {
|
|
@@ -35,5 +36,6 @@ export declare class CommandSearchSource extends BaseSearchSourceSync<CommandSug
|
|
|
35
36
|
}
|
|
36
37
|
export type CommandsMiddleware = Middleware<TextComposerMiddlewareExecutorState<CommandSuggestion>, 'onChange' | 'onSuggestionItemSelect'>;
|
|
37
38
|
export declare const createCommandsMiddleware: (channel: Channel, options?: Partial<TextComposerMiddlewareOptions> & {
|
|
39
|
+
composer?: MessageComposer;
|
|
38
40
|
searchSource?: CommandSearchSource;
|
|
39
41
|
}) => CommandsMiddleware;
|
|
@@ -10,7 +10,6 @@ export declare const getTriggerCharWithToken: ({ trigger, text, isCommand, accep
|
|
|
10
10
|
isCommand?: boolean;
|
|
11
11
|
acceptTrailingSpaces?: boolean;
|
|
12
12
|
}) => string | null;
|
|
13
|
-
export declare const getCompleteCommandInString: (text: string) => string | null;
|
|
14
13
|
export declare const insertItemWithTrigger: ({ insertText, selection, text, trigger, }: {
|
|
15
14
|
insertText: string;
|
|
16
15
|
selection: TextSelection;
|
|
@@ -28,39 +27,6 @@ export declare const replaceWordWithEntity: ({ caretPosition, getEntityString, t
|
|
|
28
27
|
getEntityString: (word: string) => Promise<string | null> | string | null;
|
|
29
28
|
text: string;
|
|
30
29
|
}) => Promise<string>;
|
|
31
|
-
/**
|
|
32
|
-
* Escapes a string for use in a regular expression
|
|
33
|
-
* @param text - The string to escape
|
|
34
|
-
* @returns The escaped string
|
|
35
|
-
* What does this regex do?
|
|
36
|
-
|
|
37
|
-
The regex escapes special regex characters by adding a backslash before them. Here's what it matches:
|
|
38
|
-
- dash
|
|
39
|
-
[ ] square brackets
|
|
40
|
-
{ } curly braces
|
|
41
|
-
( ) parentheses
|
|
42
|
-
* asterisk
|
|
43
|
-
+ plus
|
|
44
|
-
? question mark
|
|
45
|
-
. period
|
|
46
|
-
, comma
|
|
47
|
-
/ forward slash
|
|
48
|
-
\ backslash
|
|
49
|
-
^ caret
|
|
50
|
-
$ dollar sign
|
|
51
|
-
| pipe
|
|
52
|
-
# hash
|
|
53
|
-
|
|
54
|
-
The \\$& replacement adds a backslash before any matched character.
|
|
55
|
-
This is needed when you want to use these characters literally
|
|
56
|
-
in a regex pattern instead of their special regex meanings.
|
|
57
|
-
For example:
|
|
58
|
-
escapeRegExp("hello.world") // Returns: "hello\.world"
|
|
59
|
-
escapeRegExp("[test]") // Returns: "\[test\]"
|
|
60
|
-
|
|
61
|
-
This is commonly used when building dynamic regex patterns from user input to prevent special characters from being interpreted as regex syntax.
|
|
62
|
-
*/
|
|
63
|
-
export declare function escapeRegExp(text: string): string;
|
|
64
30
|
export type TokenizationPayload = {
|
|
65
31
|
tokenizedDisplayName: {
|
|
66
32
|
token: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { MessageComposer } from '../../messageComposer';
|
|
2
|
+
import type { MessageComposerEffect } from '../../messageComposer';
|
|
2
3
|
import type { CommandResponse, UserResponse } from '../../../types';
|
|
3
4
|
import type { TokenizationPayload } from './textMiddlewareUtils';
|
|
4
5
|
import type { SearchSource, SearchSourceSync } from '../../../search';
|
|
@@ -9,10 +10,22 @@ export type TextComposerSuggestion<T = unknown> = T & {
|
|
|
9
10
|
export type BaseSuggestion = {
|
|
10
11
|
id: string;
|
|
11
12
|
};
|
|
13
|
+
export type CommandSuggestionDisabledReason = 'editing' | 'quoted_message';
|
|
12
14
|
export type CommandSuggestion = BaseSuggestion & CommandResponse;
|
|
13
15
|
export type UserSuggestion = BaseSuggestion & UserResponse & TokenizationPayload;
|
|
14
16
|
export type CustomValidSuggestion = BaseSuggestion & CustomTextComposerSuggestion;
|
|
15
17
|
export type Suggestion = CommandSuggestion | UserSuggestion | CustomValidSuggestion;
|
|
18
|
+
export type TextComposerStateSnapshot = TextComposerState;
|
|
19
|
+
export type TextComposerCommandActivationStateToRestore = Partial<TextComposerStateSnapshot>;
|
|
20
|
+
export type TextComposerCommandActivationEffect = {
|
|
21
|
+
command: CommandResponse;
|
|
22
|
+
stateToRestore?: TextComposerCommandActivationStateToRestore;
|
|
23
|
+
type: 'command.activate';
|
|
24
|
+
};
|
|
25
|
+
export type TextComposerCommandClearEffect = {
|
|
26
|
+
type: 'command.clear';
|
|
27
|
+
};
|
|
28
|
+
export type TextComposerEffect = MessageComposerEffect;
|
|
16
29
|
export type TextComposerMiddlewareOptions = {
|
|
17
30
|
minChars: number;
|
|
18
31
|
trigger: string;
|
|
@@ -3,6 +3,7 @@ import { StateStore } from '../store';
|
|
|
3
3
|
import { VotingVisibility } from '../types';
|
|
4
4
|
import type { MessageComposer } from './messageComposer';
|
|
5
5
|
import type { PollComposerFieldErrors, PollComposerState, UpdateFieldsData } from './middleware/pollComposer';
|
|
6
|
+
export type PollComposerSnapshot = PollComposerState;
|
|
6
7
|
export type PollComposerOptions = {
|
|
7
8
|
composer: MessageComposer;
|
|
8
9
|
};
|
|
@@ -25,6 +26,8 @@ export declare class PollComposer {
|
|
|
25
26
|
get voting_visibility(): VotingVisibility | undefined;
|
|
26
27
|
get canCreatePoll(): boolean;
|
|
27
28
|
initState: () => void;
|
|
29
|
+
getSnapshot: () => PollComposerSnapshot;
|
|
30
|
+
restoreSnapshot: (snapshot: PollComposerSnapshot) => void;
|
|
28
31
|
/**
|
|
29
32
|
* Updates specified fields and generates relevant errors
|
|
30
33
|
* @param data
|
|
@@ -2,7 +2,7 @@ import { TextComposerMiddlewareExecutor } from './middleware';
|
|
|
2
2
|
import { StateStore } from '../store';
|
|
3
3
|
import type { TextComposerSuggestion } from './middleware/textComposer/types';
|
|
4
4
|
import type { TextSelection } from './middleware/textComposer/types';
|
|
5
|
-
import type { TextComposerState } from './middleware/textComposer/types';
|
|
5
|
+
import type { TextComposerState, TextComposerStateSnapshot } from './middleware/textComposer/types';
|
|
6
6
|
import type { Suggestions } from './middleware/textComposer/types';
|
|
7
7
|
import type { MessageComposer } from './messageComposer';
|
|
8
8
|
import type { CommandResponse, DraftMessage, LocalMessage, UserResponse } from '../types';
|
|
@@ -10,6 +10,7 @@ export type TextComposerOptions = {
|
|
|
10
10
|
composer: MessageComposer;
|
|
11
11
|
message?: DraftMessage | LocalMessage;
|
|
12
12
|
};
|
|
13
|
+
export type TextComposerSnapshot = TextComposerStateSnapshot;
|
|
13
14
|
export declare const textIsEmpty: (text: string) => boolean;
|
|
14
15
|
export declare class TextComposer {
|
|
15
16
|
readonly composer: MessageComposer;
|
|
@@ -37,6 +38,8 @@ export declare class TextComposer {
|
|
|
37
38
|
initState: ({ message }?: {
|
|
38
39
|
message?: DraftMessage | LocalMessage;
|
|
39
40
|
}) => void;
|
|
41
|
+
getSnapshot: (state?: TextComposerState) => TextComposerSnapshot;
|
|
42
|
+
restoreSnapshot: (snapshot: TextComposerSnapshot) => void;
|
|
40
43
|
setMentionedUsers(users: UserResponse[]): void;
|
|
41
44
|
clearCommand(): void;
|
|
42
45
|
upsertMentionedUser: (user: UserResponse) => void;
|
|
@@ -56,6 +59,7 @@ export declare class TextComposer {
|
|
|
56
59
|
}) => void;
|
|
57
60
|
setSuggestions: (suggestions: Suggestions) => void;
|
|
58
61
|
closeSuggestions: () => void;
|
|
62
|
+
private commitState;
|
|
59
63
|
handleChange: ({ text, selection, }: {
|
|
60
64
|
selection: TextSelection;
|
|
61
65
|
text: string;
|
package/package.json
CHANGED
|
@@ -13,6 +13,8 @@ export type CustomDataManagerState = {
|
|
|
13
13
|
custom: CustomMessageComposerData;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
+
export type CustomDataManagerSnapshot = CustomDataManagerState;
|
|
17
|
+
|
|
16
18
|
export type CustomDataManagerOptions = {
|
|
17
19
|
composer: MessageComposer;
|
|
18
20
|
message?: DraftMessage | LocalMessage;
|
|
@@ -50,6 +52,12 @@ export class CustomDataManager {
|
|
|
50
52
|
this.state.next(initState({ composer: this.composer, message }));
|
|
51
53
|
};
|
|
52
54
|
|
|
55
|
+
getSnapshot = (): CustomDataManagerSnapshot => this.state.getLatestValue();
|
|
56
|
+
|
|
57
|
+
restoreSnapshot = (snapshot: CustomDataManagerSnapshot) => {
|
|
58
|
+
this.state.next(snapshot);
|
|
59
|
+
};
|
|
60
|
+
|
|
53
61
|
setMessageData(data: DeepPartial<CustomMessageData>) {
|
|
54
62
|
this.state.partialNext({
|
|
55
63
|
message: {
|
|
@@ -24,6 +24,8 @@ export type LocationComposerState = {
|
|
|
24
24
|
location: StaticLocationPreview | LiveLocationPreview | null;
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
export type LocationComposerSnapshot = LocationComposerState;
|
|
28
|
+
|
|
27
29
|
const MIN_LIVE_LOCATION_SHARE_DURATION = 60 * 1000; // 1 minute;
|
|
28
30
|
|
|
29
31
|
const initState = ({
|
|
@@ -79,6 +81,12 @@ export class LocationComposer {
|
|
|
79
81
|
this.state.next(initState({ message }));
|
|
80
82
|
};
|
|
81
83
|
|
|
84
|
+
getSnapshot = (): LocationComposerSnapshot => this.state.getLatestValue();
|
|
85
|
+
|
|
86
|
+
restoreSnapshot = (snapshot: LocationComposerSnapshot) => {
|
|
87
|
+
this.state.next(snapshot);
|
|
88
|
+
};
|
|
89
|
+
|
|
82
90
|
setData = (data: { durationMs?: number } & Coords) => {
|
|
83
91
|
if (!this.config.enabled) return;
|
|
84
92
|
if (!data.latitude || !data.longitude) return;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { MessageComposer, MessageComposerEffectHandler } from './messageComposer';
|
|
2
|
+
import type {
|
|
3
|
+
TextComposerCommandActivationEffect,
|
|
4
|
+
TextComposerCommandClearEffect,
|
|
5
|
+
} from './middleware/textComposer/types';
|
|
6
|
+
|
|
7
|
+
type RegisteredMessageComposerEffectHandler = (
|
|
8
|
+
effect: { type: string },
|
|
9
|
+
composer: MessageComposer,
|
|
10
|
+
) => void;
|
|
11
|
+
|
|
12
|
+
export type MessageComposerEffectHandlersOptions = {
|
|
13
|
+
composer: MessageComposer;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const applyCommandActivationEffect: MessageComposerEffectHandler<
|
|
17
|
+
TextComposerCommandActivationEffect
|
|
18
|
+
> = (effect, composer) => {
|
|
19
|
+
const snapshot = composer.getSnapshot();
|
|
20
|
+
if (effect.stateToRestore) {
|
|
21
|
+
snapshot.textComposer = {
|
|
22
|
+
...snapshot.textComposer,
|
|
23
|
+
...effect.stateToRestore,
|
|
24
|
+
command: null,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
composer.captureSnapshot(snapshot);
|
|
28
|
+
|
|
29
|
+
// we manually clear because we want the command to still persist
|
|
30
|
+
composer.textComposer.state.next({
|
|
31
|
+
command: effect.command,
|
|
32
|
+
mentionedUsers: [],
|
|
33
|
+
suggestions: undefined,
|
|
34
|
+
selection: { start: 0, end: 0 },
|
|
35
|
+
text: '',
|
|
36
|
+
});
|
|
37
|
+
composer.attachmentManager.initState();
|
|
38
|
+
composer.linkPreviewsManager.initState();
|
|
39
|
+
composer.locationComposer.initState();
|
|
40
|
+
composer.pollComposer.initState();
|
|
41
|
+
composer.customDataManager.initState();
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const applyCommandClearEffect: MessageComposerEffectHandler<
|
|
45
|
+
TextComposerCommandClearEffect
|
|
46
|
+
> = (_, composer) => {
|
|
47
|
+
const snapshot = composer.popSnapshot();
|
|
48
|
+
|
|
49
|
+
if (!snapshot) return;
|
|
50
|
+
|
|
51
|
+
composer.restoreSnapshot(snapshot);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export class MessageComposerEffectHandlers {
|
|
55
|
+
private handlers = new Map<string, RegisteredMessageComposerEffectHandler>();
|
|
56
|
+
|
|
57
|
+
constructor(private options: MessageComposerEffectHandlersOptions) {
|
|
58
|
+
this.registerDefaultHandlers();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private registerDefaultHandlers = () => {
|
|
62
|
+
this.registerEffectHandler<TextComposerCommandActivationEffect>(
|
|
63
|
+
'command.activate',
|
|
64
|
+
applyCommandActivationEffect,
|
|
65
|
+
);
|
|
66
|
+
this.registerEffectHandler<TextComposerCommandClearEffect>(
|
|
67
|
+
'command.clear',
|
|
68
|
+
applyCommandClearEffect,
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
registerEffectHandler = <T extends { type: string }>(
|
|
73
|
+
type: T['type'],
|
|
74
|
+
handler: MessageComposerEffectHandler<T>,
|
|
75
|
+
): void => {
|
|
76
|
+
this.handlers.set(type, handler as RegisteredMessageComposerEffectHandler);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
applyEffects = <T extends { type: string }>(effects: T[] = []) => {
|
|
80
|
+
effects.forEach((effect) => this.applyEffect(effect));
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
private applyEffect = (effect: { type: string }) => {
|
|
84
|
+
const handler = this.handlers.get(effect.type);
|
|
85
|
+
handler?.(effect, this.options.composer);
|
|
86
|
+
};
|
|
87
|
+
}
|
|
@@ -41,6 +41,8 @@ export type AttachmentManagerState = {
|
|
|
41
41
|
attachments: LocalAttachment[];
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
+
export type AttachmentManagerSnapshot = AttachmentManagerState;
|
|
45
|
+
|
|
44
46
|
export type AttachmentManagerOptions = {
|
|
45
47
|
composer: MessageComposer;
|
|
46
48
|
message?: DraftMessage | LocalMessage;
|
|
@@ -208,10 +210,63 @@ export class AttachmentManager {
|
|
|
208
210
|
);
|
|
209
211
|
}
|
|
210
212
|
|
|
213
|
+
private cancelAttachmentUploads = (attachments: LocalAttachment[]) => {
|
|
214
|
+
for (const { localMetadata } of attachments) {
|
|
215
|
+
this.client.uploadManager.deleteUploadRecord(localMetadata.id);
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
private normalizeSnapshotAttachment = (attachment: LocalAttachment) => {
|
|
220
|
+
if (attachment.localMetadata.uploadState !== 'uploading') return attachment;
|
|
221
|
+
|
|
222
|
+
this.client.uploadManager.deleteUploadRecord(attachment.localMetadata.id);
|
|
223
|
+
|
|
224
|
+
return {
|
|
225
|
+
...attachment,
|
|
226
|
+
localMetadata: {
|
|
227
|
+
...attachment.localMetadata,
|
|
228
|
+
uploadProgress: undefined,
|
|
229
|
+
uploadState: 'failed',
|
|
230
|
+
},
|
|
231
|
+
} as LocalAttachment;
|
|
232
|
+
};
|
|
233
|
+
|
|
211
234
|
initState = ({ message }: { message?: DraftMessage | LocalMessage } = {}) => {
|
|
235
|
+
this.cancelAttachmentUploads(this.attachments);
|
|
212
236
|
this.state.next(initState({ message }));
|
|
213
237
|
};
|
|
214
238
|
|
|
239
|
+
getSnapshot = (): AttachmentManagerSnapshot => {
|
|
240
|
+
const state = this.state.getLatestValue();
|
|
241
|
+
let hasUpdates = false;
|
|
242
|
+
const attachments = state.attachments.map(this.normalizeSnapshotAttachment);
|
|
243
|
+
|
|
244
|
+
for (let i = 0; i < attachments.length; i++) {
|
|
245
|
+
if (attachments[i] !== state.attachments[i]) {
|
|
246
|
+
hasUpdates = true;
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return hasUpdates ? { ...state, attachments } : state;
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
restoreSnapshot = (snapshot: AttachmentManagerSnapshot) => {
|
|
255
|
+
this.cancelAttachmentUploads(this.attachments);
|
|
256
|
+
this.state.next(snapshot);
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
setAttachments = (attachments: LocalAttachment[]) => {
|
|
260
|
+
this.state.partialNext({ attachments });
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
clearAttachments = () => {
|
|
264
|
+
if (!this.attachments.length) return;
|
|
265
|
+
this.removeAttachments(
|
|
266
|
+
this.attachments.map((attachment) => attachment.localMetadata.id),
|
|
267
|
+
);
|
|
268
|
+
};
|
|
269
|
+
|
|
215
270
|
getAttachmentIndex = (localId: string) => {
|
|
216
271
|
const attachmentsById = this.attachmentsById;
|
|
217
272
|
|
|
@@ -11,7 +11,7 @@ export type LinkPreview = OGAttachment & {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
export interface ILinkPreviewsManager {
|
|
14
|
-
/** Function cancels all
|
|
14
|
+
/** Function cancels all scheduled or in-progress URL enrichment queries. */
|
|
15
15
|
cancelURLEnrichment: () => void;
|
|
16
16
|
/** Function that triggers the search for URLs and their enrichment. */
|
|
17
17
|
findAndEnrichUrls?: DebouncedFunc<(text: string) => void>;
|
|
@@ -38,6 +38,8 @@ export type LinkPreviewsManagerState = {
|
|
|
38
38
|
previews: LinkPreviewMap;
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
+
export type LinkPreviewsManagerSnapshot = LinkPreviewsManagerState;
|
|
42
|
+
|
|
41
43
|
export type LinkPreviewsManagerOptions = {
|
|
42
44
|
composer: MessageComposer;
|
|
43
45
|
message?: DraftMessage | LocalMessage;
|
|
@@ -186,9 +188,16 @@ export class LinkPreviewsManager implements ILinkPreviewsManager {
|
|
|
186
188
|
}
|
|
187
189
|
|
|
188
190
|
initState = ({ message }: { message?: DraftMessage | LocalMessage } = {}) => {
|
|
191
|
+
this.cancelURLEnrichment();
|
|
189
192
|
this.state.next(initState({ message: this.enabled ? message : undefined }));
|
|
190
193
|
};
|
|
191
194
|
|
|
195
|
+
getSnapshot = (): LinkPreviewsManagerSnapshot => this.state.getLatestValue();
|
|
196
|
+
|
|
197
|
+
restoreSnapshot = (snapshot: LinkPreviewsManagerSnapshot) => {
|
|
198
|
+
this.state.next(snapshot);
|
|
199
|
+
};
|
|
200
|
+
|
|
192
201
|
private _findAndEnrichUrls = async (text: string) => {
|
|
193
202
|
if (!this.enabled) return;
|
|
194
203
|
const urls = this.config.findURLFn(text);
|
|
@@ -254,8 +263,8 @@ export class LinkPreviewsManager implements ILinkPreviewsManager {
|
|
|
254
263
|
};
|
|
255
264
|
|
|
256
265
|
cancelURLEnrichment = () => {
|
|
257
|
-
this.findAndEnrichUrls.cancel();
|
|
258
|
-
this.findAndEnrichUrls.flush();
|
|
266
|
+
this.findAndEnrichUrls.cancel?.();
|
|
267
|
+
this.findAndEnrichUrls.flush?.();
|
|
259
268
|
};
|
|
260
269
|
|
|
261
270
|
/**
|