diff --git a/README.md b/README.md index 8072cda7..9ba9190d 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,13 @@ Check out our current openings and apply via [Stream's website](https://getstrea ### Install with NPM +Run this command if you are using **Angular 19**: + +```shell +# Some SDK depedencies doesn't yet have official support for Angular 19, so we need to add --force flag until then +npm install stream-chat-angular stream-chat @ngx-translate/core@15 ngx-float-ui@18 --force +``` + Supported Angular versions: **Angular 15-18** Run this command if you are using **Angular 18**: diff --git a/copy-generated-component-docs.ts b/copy-generated-component-docs.ts index 2bbb62c4..b6c537ce 100644 --- a/copy-generated-component-docs.ts +++ b/copy-generated-component-docs.ts @@ -62,19 +62,19 @@ fs.readdir(generatedDocsPath, (err: any, files: string[]) => { const propertiesContent = extractProperties(generatedFileContent); fs.readFile( - `${componentDocsPath}/${file}x`, + `${componentDocsPath}/${file}`, 'utf8', (err: any, docFile: any) => { if (err) throw new Error( - `${componentDocsPath}/${file}x couldn't be opened, error: ${err}, make sure that this file exists` + `${componentDocsPath}/${file} couldn't be opened, error: ${err}, make sure that this file exists` ); if (file !== '_category_.json') { const result = insertGeneratedParts(docFile, propertiesContent); fs.writeFile( - `${componentDocsPath}/${file}x`, + `${componentDocsPath}/${file}`, result, 'utf8', (err: any) => { diff --git a/copy-generated-service-docs.ts b/copy-generated-service-docs.ts index f3a14a94..51154d34 100644 --- a/copy-generated-service-docs.ts +++ b/copy-generated-service-docs.ts @@ -31,10 +31,23 @@ fs.readdir(sourcePath, (err: any, files: string[]) => { } // Remove the thre prefix from the title - const result = data - .replace(/# Class:/g, '#') - .replace('', '') - .replace('\\', ''); + const result = + `---` + + `\n` + + `title: ${file.replace('.md', '')}` + + `\n` + + `slug: /chat/docs/sdk/angular/services/${file.replace('.md', '')}/` + + `\n` + + `---` + + '\n\n' + + data + .replace(`# Class: ${file.replace('.md', '')}`, '') + .replace( + /\b(?!README)(\w+)\.md\b/g, + '/chat/docs/sdk/angular/services/$1' + ) + .replace('', '') + .replace('\\', ''); fs.writeFile(`${sourcePath}/${file}`, result, 'utf8', (err: any) => { if (err) { @@ -42,7 +55,7 @@ fs.readdir(sourcePath, (err: any, files: string[]) => { } fs.copyFile( `${sourcePath}/${file}`, - `${serviceDocsTargetPath}/${file}x`, + `${serviceDocsTargetPath}/${file}`, (err: any) => { if (err) { throw err; diff --git a/package.json b/package.json index e1b4e6a4..949227fb 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,11 @@ "build:sample-app": "npm run config:prod && ng build --stats-json --project sample-app", "preanalyze:sample-app": "npm run build:sample-app", "analyze:sample-app": "webpack-bundle-analyzer dist/sample-app/stats.json", - "copy-css": "rm -rf projects/stream-chat-angular/src/assets/styles && copyfiles --up 5 \"node_modules/@stream-io/stream-chat-css/dist/v2/**/*\" projects/stream-chat-angular/src/assets/styles && copyfiles --up 5 \"node_modules/@stream-io/stream-chat-css/dist/assets/**/*\" projects/stream-chat-angular/src/assets/assets" + "copy-css": "rm -rf projects/stream-chat-angular/src/assets/styles && copyfiles --up 5 \"node_modules/@stream-io/stream-chat-css/dist/v2/**/*\" projects/stream-chat-angular/src/assets/styles && copyfiles --up 5 \"node_modules/@stream-io/stream-chat-css/dist/assets/**/*\" projects/stream-chat-angular/src/assets/assets", + "generate-docs": "npm run typedoc:services && npm run typedoc:components && npm run copy-docs:v5", + "typedoc:services": "typedoc --plugin typedoc-plugin-markdown --plugin typedoc-plugin-reference-excluder --cleanOutputDir true --excludeConstructors true --hideBreadcrumbs true --hideInPageTOC true --excludePrivate true --out temp-service-docs --exclude '!**/*service.ts' --excludeNotDocumented --tsconfig projects/stream-chat-angular/tsconfig.lib.json projects/stream-chat-angular/src/public-api.ts", + "typedoc:components": "typedoc --plugin typedoc-plugin-markdown --plugin typedoc-plugin-reference-excluder --cleanOutputDir true --excludeConstructors true --sort source-order --hideBreadcrumbs true --hideInPageTOC true --excludePrivate true --excludeNotDocumented --out temp-component-docs --exclude '!**/*component.ts' --tsconfig projects/stream-chat-angular/tsconfig.lib.json projects/stream-chat-angular/src/public-api.ts", + "copy-docs:v5": "ts-node copy-generated-service-docs.ts ../docs/data/docs/chat-sdk/angular/v5-latest/06-services & (ts-node remove-generated-component-docs-content ../docs/data/docs/chat-sdk/angular/v5-latest/05-components && ts-node copy-generated-component-docs.ts ../docs/data/docs/chat-sdk/angular/v5-latest/05-components)" }, "lint-staged": { "**/*": [ diff --git a/projects/stream-chat-angular/src/lib/attachment.service.ts b/projects/stream-chat-angular/src/lib/attachment.service.ts index fd0c7caa..98d7f2ec 100644 --- a/projects/stream-chat-angular/src/lib/attachment.service.ts +++ b/projects/stream-chat-angular/src/lib/attachment.service.ts @@ -40,13 +40,13 @@ export class AttachmentService< */ attachmentUploadInProgressCounter$ = new BehaviorSubject(0); /** - * Emits the state of the uploads ([`AttachmentUpload[]`](https://github.com/GetStream/stream-chat-angular/blob/master/projects/stream-chat-angular/src/lib/types.ts)), it adds a state (`success`, `error` or `uploading`) to each file the user selects for upload. It is used by the [`AttachmentPreviewList`](../components/AttachmentPreviewListComponent.mdx) to display the attachment previews. + * Emits the state of the uploads ([`AttachmentUpload[]`](https://github.com/GetStream/stream-chat-angular/blob/master/projects/stream-chat-angular/src/lib/types.ts)), it adds a state (`success`, `error` or `uploading`) to each file the user selects for upload. It is used by the [`AttachmentPreviewList`](/chat/docs/sdk/angular/components/AttachmentPreviewListComponent/) to display the attachment previews. */ attachmentUploads$: Observable; /** * You can get and set the list if uploaded custom attachments * - * By default the SDK components won't display these, but you can provide your own `customAttachmentPreviewListTemplate$` and `customAttachmentListTemplate$` for the [`CustomTemplatesService`](../../services/CustomTemplatesService). + * By default the SDK components won't display these, but you can provide your own `customAttachmentPreviewListTemplate$` and `customAttachmentListTemplate$` for the [`CustomTemplatesService`](/chat/docs/sdk/angular/services/CustomTemplatesService/). */ customAttachments$ = new BehaviorSubject[]>([]); /** @@ -210,7 +210,7 @@ export class AttachmentService< /** * You can add custom `image`, `video` and `file` attachments using this method. * - * Note: If you just want to use your own CDN for file uploads, you don't necessary need this method, you can just specify you own upload function in the [`ChannelService`](./ChannelService.mdx) + * Note: If you just want to use your own CDN for file uploads, you don't necessary need this method, you can just specify you own upload function in the [`ChannelService`](/chat/docs/sdk/angular/services/ChannelService/) * @param attachment */ addAttachment(attachment: Attachment) { diff --git a/projects/stream-chat-angular/src/lib/avatar-placeholder/avatar-placeholder.component.ts b/projects/stream-chat-angular/src/lib/avatar-placeholder/avatar-placeholder.component.ts index 4341d432..43a0df6a 100644 --- a/projects/stream-chat-angular/src/lib/avatar-placeholder/avatar-placeholder.component.ts +++ b/projects/stream-chat-angular/src/lib/avatar-placeholder/avatar-placeholder.component.ts @@ -9,7 +9,7 @@ import { } from '../types'; /** - * The `AvatarPlaceholder` component displays the [default avatar](./AvatarComponent.mdx) unless a [custom template](../services/CustomTemplatesService.mdx) is provided. This component is used by the SDK internally, you likely won't need to use it. + * The `AvatarPlaceholder` component displays the [default avatar](/chat/docs/sdk/angular/components/AvatarComponent/) unless a [custom template](/chat/docs/sdk/angular/services/CustomTemplatesService/) is provided. This component is used by the SDK internally, you likely won't need to use it. */ @Component({ selector: 'stream-avatar-placeholder', diff --git a/projects/stream-chat-angular/src/lib/channel.service.ts b/projects/stream-chat-angular/src/lib/channel.service.ts index 5fcd4ab9..2b7cf181 100644 --- a/projects/stream-chat-angular/src/lib/channel.service.ts +++ b/projects/stream-chat-angular/src/lib/channel.service.ts @@ -60,7 +60,7 @@ export class ChannelService< * Emits the currently loaded and [watched](https://getstream.io/chat/docs/javascript/watch_channel/?language=javascript) channel list. * * :::important - * If you want to subscribe to channel events, you need to manually reenter Angular's change detection zone, our [Change detection guide](../concepts/change-detection.mdx) explains this in detail. + * If you want to subscribe to channel events, you need to manually reenter Angular's change detection zone, our [Change detection guide](/chat/docs/sdk/angular/concepts/change-detection/) explains this in detail. * ::: */ channels$: Observable[] | undefined>; @@ -72,7 +72,7 @@ export class ChannelService< * Emits the currently active channel. * * :::important - * If you want to subscribe to channel events, you need to manually reenter Angular's change detection zone, our [Change detection guide](../concepts/change-detection.mdx) explains this in detail. + * If you want to subscribe to channel events, you need to manually reenter Angular's change detection zone, our [Change detection guide](/chat/docs/sdk/angular/concepts/change-detection/) explains this in detail. * ::: * * The active channel will always be marked as read when a new message is received @@ -121,7 +121,7 @@ export class ChannelService< /** * If you're using [semantic filters for moderation](https://getstream.io/automated-moderation/docs/automod_configuration/?q=semantic%20filters) you can set up rules for bouncing messages. * - * If a message is bounced, it will be emitted via this `Observable`. The built-in [`MessageBouncePrompt` component](../../components/MessageBouncePromptComponent) will display the bounce option to the user if a bounced message is clicked. + * If a message is bounced, it will be emitted via this `Observable`. The built-in [`MessageBouncePrompt` component](/chat/docs/sdk/angular/components/MessageBouncePromptComponent/) will display the bounce option to the user if a bounced message is clicked. */ bouncedMessage$: BehaviorSubject | undefined>; /** @@ -137,7 +137,7 @@ export class ChannelService< */ activeChannelUnreadCount?: number; /** - * Custom event handler to call if a new message received from a channel that is not being watched, provide an event handler if you want to override the [default channel list ordering](./ChannelService.mdx/#channels) + * Custom event handler to call if a new message received from a channel that is not being watched, provide an event handler if you want to override the [default channel list ordering](/chat/docs/sdk/angular/services/ChannelService/#channels/) * * If you're adding a new channel, make sure that it's a [watched](https://getstream.io/chat/docs/javascript/watch_channel/?language=javascript) channel. */ @@ -149,7 +149,7 @@ export class ChannelService< ) => void ) => void; /** - * Custom event handler to call when the user is added to a channel, provide an event handler if you want to override the [default channel list ordering](./ChannelService.mdx/#channels). + * Custom event handler to call when the user is added to a channel, provide an event handler if you want to override the [default channel list ordering](/chat/docs/sdk/angular/services/ChannelService/#channels/). * * If you're adding a new channel, make sure that it's a [watched](https://getstream.io/chat/docs/javascript/watch_channel/?language=javascript) channel. */ @@ -161,7 +161,7 @@ export class ChannelService< ) => void ) => void; /** - * Custom event handler to call when the user is removed from a channel, provide an event handler if you want to override the [default channel list ordering](./ChannelService.mdx/#channels). + * Custom event handler to call when the user is removed from a channel, provide an event handler if you want to override the [default channel list ordering](/chat/docs/sdk/angular/services/ChannelService/#channels/). * * If you're adding a new channel, make sure that it's a [watched](https://getstream.io/chat/docs/javascript/watch_channel/?language=javascript) channel. */ @@ -173,7 +173,7 @@ export class ChannelService< ) => void ) => void; /** - * Custom event handler to call when a channel is deleted, provide an event handler if you want to override the [default channel list ordering](./ChannelService.mdx/#channels). + * Custom event handler to call when a channel is deleted, provide an event handler if you want to override the [default channel list ordering](/chat/docs/sdk/angular/services/ChannelService/#channels/). * * If you're adding a new channel, make sure that it's a [watched](https://getstream.io/chat/docs/javascript/watch_channel/?language=javascript) channel. */ @@ -189,7 +189,7 @@ export class ChannelService< parentMessageSetter: (message: StreamMessage | undefined) => void ) => void; /** - * Custom event handler to call when a channel is updated, provide an event handler if you want to override the [default channel list ordering](./ChannelService.mdx/#channels). + * Custom event handler to call when a channel is updated, provide an event handler if you want to override the [default channel list ordering](/chat/docs/sdk/angular/services/ChannelService/#channels/). * * If you're adding a new channel, make sure that it's a [watched](https://getstream.io/chat/docs/javascript/watch_channel/?language=javascript) channel. */ @@ -205,7 +205,7 @@ export class ChannelService< parentMessageSetter: (message: StreamMessage | undefined) => void ) => void; /** - * Custom event handler to call when a channel is truncated, provide an event handler if you want to override the [default channel list ordering](./ChannelService.mdx/#channels). + * Custom event handler to call when a channel is truncated, provide an event handler if you want to override the [default channel list ordering](/chat/docs/sdk/angular/services/ChannelService/#channels/). * * If you're adding a new channel, make sure that it's a [watched](https://getstream.io/chat/docs/javascript/watch_channel/?language=javascript) channel. */ @@ -221,7 +221,7 @@ export class ChannelService< parentMessageSetter: (message: StreamMessage | undefined) => void ) => void; /** - * Custom event handler to call when a channel becomes hidden, provide an event handler if you want to override the [default channel list ordering](./ChannelService.mdx/#channels). + * Custom event handler to call when a channel becomes hidden, provide an event handler if you want to override the [default channel list ordering](/chat/docs/sdk/angular/services/ChannelService/#channels/). * * If you're adding a new channel, make sure that it's a [watched](https://getstream.io/chat/docs/javascript/watch_channel/?language=javascript) channel. */ @@ -237,7 +237,7 @@ export class ChannelService< parentMessageSetter: (message: StreamMessage | undefined) => void ) => void; /** - * Custom event handler to call when a channel becomes visible, provide an event handler if you want to override the [default channel list ordering](./ChannelService.mdx/#channels). + * Custom event handler to call when a channel becomes visible, provide an event handler if you want to override the [default channel list ordering](/chat/docs/sdk/angular/services/ChannelService/#channels/). * * If you're adding a new channel, make sure that it's a [watched](https://getstream.io/chat/docs/javascript/watch_channel/?language=javascript) channel. */ @@ -253,7 +253,7 @@ export class ChannelService< parentMessageSetter: (message: StreamMessage | undefined) => void ) => void; /** - * Custom event handler to call if a new message received from a channel that is being watched, provide an event handler if you want to override the [default channel list ordering](./ChannelService.mdx/#channels). + * Custom event handler to call if a new message received from a channel that is being watched, provide an event handler if you want to override the [default channel list ordering](/chat/docs/sdk/angular/services/ChannelService/#channels/). * * If you're adding a new channel, make sure that it's a [watched](https://getstream.io/chat/docs/javascript/watch_channel/?language=javascript) channel. */ @@ -775,7 +775,7 @@ export class ChannelService< } /** - * Resets the `activeChannel$`, `channels$` and `activeChannelMessages$` Observables. Useful when disconnecting a chat user, use in combination with [`disconnectUser`](./ChatClientService.mdx/#disconnectuser). + * Resets the `activeChannel$`, `channels$` and `activeChannelMessages$` Observables. Useful when disconnecting a chat user, use in combination with [`disconnectUser`](/chat/docs/sdk/angular/services/ChatClientService/#disconnectuser/). */ reset() { this.deselectActiveChannel(); @@ -961,7 +961,7 @@ export class ChannelService< /** * Uploads files to the channel. If you want to know more about [file uploads](https://getstream.io/chat/docs/javascript/file_uploads/?language=javascript) check out the platform documentation. - * @param uploads the attachments to upload (output of the [`AttachmentService`](./AttachmentService.mdx)) + * @param uploads the attachments to upload (output of the [`AttachmentService`](/chat/docs/sdk/angular/services/AttachmentService/)) * @returns the result of file upload requests */ async uploadAttachments( @@ -1042,7 +1042,7 @@ export class ChannelService< /** * Deletes an uploaded file by URL. If you want to know more about [file uploads](https://getstream.io/chat/docs/javascript/file_uploads/?language=javascript) check out the platform documentation - * @param attachmentUpload Attachment to be deleted (output of the [`AttachmentService`](./AttachmentService.mdx)) + * @param attachmentUpload Attachment to be deleted (output of the [`AttachmentService`](/chat/docs/sdk/angular/services/AttachmentService/)) */ async deleteAttachment(attachmentUpload: AttachmentUpload) { const channel = this.activeChannelSubject.getValue()!; diff --git a/projects/stream-chat-angular/src/lib/channel/channel.component.ts b/projects/stream-chat-angular/src/lib/channel/channel.component.ts index 2ae855c3..2a266846 100644 --- a/projects/stream-chat-angular/src/lib/channel/channel.component.ts +++ b/projects/stream-chat-angular/src/lib/channel/channel.component.ts @@ -6,7 +6,7 @@ import { ThemeService } from '../theme.service'; import { CustomTemplatesService } from '../custom-templates.service'; /** - * The `Channel` component is a container component that displays the [`ChannelHeader`](./ChannelHeaderComponent.mdx), [`MessageList`](./MessageListComponent.mdx), [`NotificationList`](./NotificationListComponent.mdx) and [`MessageInput`](./MessageInputComponent.mdx) components. You can also provide the [`Thread`](./ThreadComponent.mdx) component to use message [threads](https://getstream.io/chat/docs/javascript/threads/?language=javascript). + * The `Channel` component is a container component that displays the [`ChannelHeader`](/chat/docs/sdk/angular/components/ChannelHeaderComponent/), [`MessageList`](/chat/docs/sdk/angular/components/MessageListComponent), [`NotificationList`](/chat/docs/sdk/angular/components/NotificationListComponent/) and [`MessageInput`](/chat/docs/sdk/angular/components/MessageInputComponent/) components. You can also provide the [`Thread`](/chat/docs/sdk/angular/components/ThreadComponent/) component to use message [threads](https://getstream.io/chat/docs/javascript/threads/?language=javascript). */ @Component({ selector: 'stream-channel', diff --git a/projects/stream-chat-angular/src/lib/chat-client.service.ts b/projects/stream-chat-angular/src/lib/chat-client.service.ts index 2a535cda..d9d62f61 100644 --- a/projects/stream-chat-angular/src/lib/chat-client.service.ts +++ b/projects/stream-chat-angular/src/lib/chat-client.service.ts @@ -39,7 +39,7 @@ export class ChatClientService< /** * Emits [`ClientEvent`](https://github.com/GetStream/stream-chat-angular/blob/master/projects/stream-chat-angular/src/lib/chat-client.service.ts) events. The platform documentation covers [the list of client, user presence and notification events](https://getstream.io/chat/docs/javascript/event_object/?language=javascript). * :::important - * For performance reasons this Observable operates outside of the Angular change detection zone. If you subscribe to it, you need to manually reenter Angular's change detection zone, our [Change detection guide](../concepts/change-detection.mdx) explains this in detail. + * For performance reasons this Observable operates outside of the Angular change detection zone. If you subscribe to it, you need to manually reenter Angular's change detection zone, our [Change detection guide](/chat/docs/sdk/angular/concepts/change-detection/) explains this in detail. * ::: */ events$: Observable>; @@ -52,7 +52,7 @@ export class ChatClientService< */ connectionState$: Observable<'offline' | 'online'>; /** - * Emits the list of pending invites of the user. It emits every pending invitation during initialization and then extends the list when a new invite is received. More information can be found in the [channel invitations](../code-examples/channel-invites.mdx) guide. + * Emits the list of pending invites of the user. It emits every pending invitation during initialization and then extends the list when a new invite is received. More information can be found in the [channel invitations](/chat/docs/sdk/angular/code-examples/channel-invites/) guide. */ pendingInvites$: Observable[]>; /** @@ -183,7 +183,7 @@ export class ChatClientService< } /** - * Disconnects the current user, and closes the WebSocket connection. Useful when disconnecting a chat user, use in combination with [`reset`](./ChannelService.mdx/#reset). + * Disconnects the current user, and closes the WebSocket connection. Useful when disconnecting a chat user, use in combination with [`reset`](/chat/docs/sdk/angular/services/ChannelService/#reset/). */ async disconnectUser() { this.pendingInvitesSubject.next([]); diff --git a/projects/stream-chat-angular/src/lib/custom-templates.service.ts b/projects/stream-chat-angular/src/lib/custom-templates.service.ts index 92fc19e5..64af6e67 100644 --- a/projects/stream-chat-angular/src/lib/custom-templates.service.ts +++ b/projects/stream-chat-angular/src/lib/custom-templates.service.ts @@ -52,145 +52,145 @@ export class CustomTemplatesService< T extends DefaultStreamChatGenerics = DefaultStreamChatGenerics > { /** - * The autocomplete list item template for mentioning users (used in the [`AutocompleteTextareaComponent`](../components/AutocompleteTextareaComponent.mdx)) + * The autocomplete list item template for mentioning users (used in the [`AutocompleteTextareaComponent`](/chat/docs/sdk/angular/components/AutocompleteTextareaComponent/)) */ mentionAutocompleteItemTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The autocomplete list item template for commands (used in the [`AutocompleteTextareaComponent`](../components/AutocompleteTextareaComponent.mdx)) + * The autocomplete list item template for commands (used in the [`AutocompleteTextareaComponent`](/chat/docs/sdk/angular/components/AutocompleteTextareaComponent/)) */ commandAutocompleteItemTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * Template used to display an item in the [channel list](../components/ChannelListComponent.mdx) (instead of the default [channal list item](../components/ChannelPreviewComponent.mdx)) + * Template used to display an item in the [channel list](/chat/docs/sdk/angular/components/ChannelListComponent/) (instead of the default [channal list item](/chat/docs/sdk/angular/components/ChannelPreviewComponent/)) * */ channelPreviewTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used for displaying a [mention inside a message](../code-examples/mention-actions.mdx) + * The template used for displaying a [mention inside a message](/chat/docs/sdk/angular/code-examples/mention-actions/) * */ mentionTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template for [emoji picker](../code-examples/emoji-picker.mdx) + * The template for [emoji picker](/chat/docs/sdk/angular/code-examples/emoji-picker) * */ emojiPickerTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The typing indicator template used in the [message list](../components/MessageListComponent.mdx) + * The typing indicator template used in the [message list](/chat/docs/sdk/angular/components/MessageListComponent/) * */ typingIndicatorTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used to display a message in the [message list](../components/MessageListComponent.mdx) (instead of the [default message component](../components/MessageComponent.mdx)) + * The template used to display a message in the [message list](/chat/docs/sdk/angular/components/MessageListComponent/) (instead of the [default message component](/chat/docs/sdk/angular/components/MessageComponent/)) * */ messageTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template for channel actions displayed in the [channel header](../components/ChannelHeaderComponent.mdx) (by default no channel action is displayed) + * The template for channel actions displayed in the [channel header](/chat/docs/sdk/angular/components/ChannelHeaderComponent/) (by default no channel action is displayed) * */ channelActionsTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used to display attachments of a [message](../components/MessageComponent.mdx) (instead of the [default attachment list](../components/AttachmentListComponent.mdx)) + * The template used to display attachments of a [message](/chat/docs/sdk/angular/components/MessageComponent/) (instead of the [default attachment list](/chat/docs/sdk/angular/components/AttachmentListComponent/)) * */ attachmentListTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used to display attachments in the [message input](../components/MessageInputComponent.mdx) component (instead of the [default attachment preview](../components/AttachmentPreviewListComponent.mdx)) + * The template used to display attachments in the [message input](/chat/docs/sdk/angular/components/MessageInputComponent) component (instead of the [default attachment preview](/chat/docs/sdk/angular/components/AttachmentPreviewListComponent)) * */ attachmentPreviewListTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used to display avatars for channels and users (instead of the [default avatar](../components/AvatarComponent.mdx)) + * The template used to display avatars for channels and users (instead of the [default avatar](/chat/docs/sdk/angular/components/AvatarComponent/)) * */ avatarTemplate$ = new BehaviorSubject | undefined>( undefined ); /** - * Template for displaying icons (instead of the [default icon component](../components/IconComponent.mdx)) + * Template for displaying icons (instead of the [default icon component](/chat/docs/sdk/angular/components/IconComponent/)) * */ iconTemplate$ = new BehaviorSubject | undefined>( undefined ); /** - * Template for displaying the loading indicator (instead of the [default loading indicator](../components/LoadingIndicatorComponent.mdx)) + * Template for displaying the loading indicator (instead of the [default loading indicator](/chat/docs/sdk/angular/components/LoadingIndicatorComponent/)) * */ loadingIndicatorTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * Template for displaying the message actions box (instead of the [default message actions box](../components/MessageActionsBoxComponent.mdx)) + * Template for displaying the message actions box (instead of the [default message actions box](/chat/docs/sdk/angular/components/MessageActionsBoxComponent/)) * */ messageActionsBoxTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used for displaying an item in the [message actions box](../components/MessageActionsBoxComponent.mdx) + * The template used for displaying an item in the [message actions box](/chat/docs/sdk/angular/components/MessageActionsBoxComponent/) * */ messageActionsBoxItemTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used to display the reactions of a [message](../components/MessageComponent.mdx), and the selector to add a reaction to a message (instead of the [default message reactions component](../components/MessageReactionsComponent.mdx)) + * The template used to display the reactions of a [message](/chat/docs/sdk/angular/components/MessageComponent/), and the selector to add a reaction to a message (instead of the [default message reactions component](/chat/docs/sdk/angular/components/MessageReactionsComponent/)) * */ messageReactionsTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used to display the reactions of a [message](../components/MessageComponent.mdx), and the selector to add a reaction to a message (instead of the [default message reactions component](../components/MessageReactionsComponent.mdx)) + * The template used to display the reactions of a [message](/chat/docs/sdk/angular/components/MessageComponent/), and the selector to add a reaction to a message (instead of the [default message reactions component](/chat/docs/sdk/angular/components/MessageReactionsComponent/)) * */ messageReactionsSelectorTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used to display a modal window (instead of the [default modal](../components/ModalComponent.mdx)) + * The template used to display a modal window (instead of the [default modal](/chat/docs/sdk/angular/components/ModalComponent/)) * */ modalTemplate$ = new BehaviorSubject | undefined>( undefined ); /** - * The template used to override the [default notification component](../components/NotificationComponent.mdx) + * The template used to override the [default notification component](/chat/docs/sdk/angular/components/NotificationComponent/) * */ notificationTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used for header of a [thread](../components/ThreadComponent.mdx) + * The template used for header of a [thread](/chat/docs/sdk/angular/components/ThreadComponent/) * */ threadHeaderTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used for displaying the delivered state of the message inside the [message component](../components/MessageComponent.mdx) + * The template used for displaying the delivered state of the message inside the [message component](/chat/docs/sdk/angular/components/MessageComponent/) * * Displayed for the last message sent by the current user, if the message isn't yet read by anyone * @@ -199,7 +199,7 @@ export class CustomTemplatesService< TemplateRef | undefined >(undefined); /** - * The template used for displaying the sending state of the message inside the [message component](../components/MessageComponent.mdx) + * The template used for displaying the sending state of the message inside the [message component](/chat/docs/sdk/angular/components/MessageComponent/) * * Displayed for the last message sent by the current user, if the message is currently being sent * @@ -208,7 +208,7 @@ export class CustomTemplatesService< TemplateRef | undefined >(undefined); /** - * The template used for displaying the sent state of the message inside the [message component](../components/MessageComponent.mdx) + * The template used for displaying the sent state of the message inside the [message component](/chat/docs/sdk/angular/components/MessageComponent/) * * Displayed for the last message sent by the current user, if the message is read at least by one user * @@ -217,82 +217,82 @@ export class CustomTemplatesService< TemplateRef | undefined >(undefined); /** - * Template to display custom metadata inside [message component](../components/MessageComponent.mdx) + * Template to display custom metadata inside [message component](/chat/docs/sdk/angular/components/MessageComponent/) * */ customMessageMetadataTemplate$ = new BehaviorSubject< TemplateRef> | undefined >(undefined); /** - * The template used to display additional information about a channel under the channel name inside the [channel header component](../components/ChannelHeaderComponent.mdx) + * The template used to display additional information about a channel under the channel name inside the [channel header component](/chat/docs/sdk/angular/components/ChannelHeaderComponent/) * */ channelHeaderInfoTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used for displaying file upload/attachment selector inside the [message input](../components/MessageInputComponent.mdx) + * The template used for displaying file upload/attachment selector inside the [message input](/chat/docs/sdk/angular/components/MessageInputComponent/) * */ customAttachmentUploadTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template that can be used to override how a single image attachment is displayed inside the [attachment list](../components/AttachmentListComponent.mdx) + * The template that can be used to override how a single image attachment is displayed inside the [attachment list](/chat/docs/sdk/angular/components/AttachmentListComponent/) */ imageAttachmentTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template that can be used to override how a voice recording attachment is displayed inside the [attachment list](../components/AttachmentListComponent.mdx), by default the [voice recording component](../components/VoiceRecordingComponent.mdx) is used + * The template that can be used to override how a voice recording attachment is displayed inside the [attachment list](/chat/docs/sdk/angular/components/AttachmentListComponent/), by default the [voice recording component](/chat/docs/sdk/angular/components/VoiceRecordingComponent/) is used */ voiceRecordingAttachmentTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template that can be used to override how a video attachment is displayed inside the [attachment list](../components/AttachmentListComponent.mdx) + * The template that can be used to override how a video attachment is displayed inside the [attachment list](/chat/docs/sdk/angular/components/AttachmentListComponent/) */ videoAttachmentTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template that can be used to override how image gallery is displayed inside the [attachment list](../components/AttachmentListComponent.mdx) + * The template that can be used to override how image gallery is displayed inside the [attachment list](/chat/docs/sdk/angular/components/AttachmentListComponent/) */ galleryAttachmentTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template that can be used to override how a file attachment is displayed inside the [attachment list](../components/AttachmentListComponent.mdx) + * The template that can be used to override how a file attachment is displayed inside the [attachment list](/chat/docs/sdk/angular/components/AttachmentListComponent/) */ fileAttachmentTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template that can be used to override how a card attachment is displayed inside the [attachment list](../components/AttachmentListComponent.mdx) + * The template that can be used to override how a card attachment is displayed inside the [attachment list](/chat/docs/sdk/angular/components/AttachmentListComponent/) */ cardAttachmentTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template that can be used to override how attachment actions are displayed inside the [attachment list](../components/AttachmentListComponent.mdx) + * The template that can be used to override how attachment actions are displayed inside the [attachment list](/chat/docs/sdk/angular/components/AttachmentListComponent/) */ attachmentActionsTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used to display [system messages](https://getstream.io/chat/docs/javascript/silent_messages/?language=javascript&q=system) indise the [message component](../components/MessageComponent.mdx) + * The template used to display [system messages](https://getstream.io/chat/docs/javascript/silent_messages/?language=javascript&q=system) indise the [message component](/chat/docs/sdk/angular/components/MessageComponent/) */ systemMessageTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used to display the date separator inside the [message list](../components/MessageListComponent.mdx) + * The template used to display the date separator inside the [message list](/chat/docs/sdk/angular/components/MessageListComponent/) */ dateSeparatorTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used to display unread messages indicator inside the [message list](../components/MessageListComponent.mdx) when the channel is opened + * The template used to display unread messages indicator inside the [message list](/chat/docs/sdk/angular/components/MessageListComponent/) when the channel is opened * * This UI element is used to separate unread messages from read messages */ @@ -300,7 +300,7 @@ export class CustomTemplatesService< TemplateRef | undefined >(undefined); /** - * The template used to display unread messages notification inside the [message list](../components/MessageListComponent.mdx) when the channel is opened + * The template used to display unread messages notification inside the [message list](/chat/docs/sdk/angular/components/MessageListComponent/) when the channel is opened * * Users can use this notification to jump to the first unread message when it's clicked */ @@ -320,38 +320,38 @@ export class CustomTemplatesService< TemplateRef | undefined >(undefined); /** - * The template used to display the [message bounce prompt](../components/MessageBouncePromptComponent.mdx) + * The template used to display the [message bounce prompt](/chat/docs/sdk/angular/components/MessageBouncePromptComponent/) */ messageBouncePromptTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * Template used to display the channel information inside the [channel list item](../components/ChannelPreviewComponent.mdx) + * Template used to display the channel information inside the [channel list item](/chat/docs/sdk/angular/components/ChannelPreviewComponent/) * */ channelPreviewInfoTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used to display custom attachment previews in the [message input component](../../components/MessageInputComponent.mdx) + * The template used to display custom attachment previews in the [message input component](/chat/docs/sdk/angular/components/MessageInputComponent/) */ customAttachmentPreviewListTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used to display custom attachments in the [message component](../../components/MessageComponent.mdx) + * The template used to display custom attachments in the [message component](/chat/docs/sdk/angular/components/MessageComponent/) */ customAttachmentListTemplate$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * The template used to display the number of thread replies inside the [message component](../../components/MessageComponent.mdx) + * The template used to display the number of thread replies inside the [message component](/chat/docs/sdk/angular/components/MessageComponent/) */ threadLinkButton$ = new BehaviorSubject< TemplateRef | undefined >(undefined); /** - * Template to display custom metadata inside the message bubble of the [message component](../components/MessageComponent.mdx) + * Template to display custom metadata inside the message bubble of the [message component](/chat/docs/sdk/angular/components/MessageComponent/) * * To properly position your template you should override the `grid-template-areas` of the `.str-chat__message-inner` selector */ diff --git a/projects/stream-chat-angular/src/lib/icon/icon-placeholder/icon-placeholder.component.ts b/projects/stream-chat-angular/src/lib/icon/icon-placeholder/icon-placeholder.component.ts index 0916e089..b3b5e18c 100644 --- a/projects/stream-chat-angular/src/lib/icon/icon-placeholder/icon-placeholder.component.ts +++ b/projects/stream-chat-angular/src/lib/icon/icon-placeholder/icon-placeholder.component.ts @@ -4,7 +4,7 @@ import { IconContext } from '../../types'; import { CustomTemplatesService } from '../../custom-templates.service'; /** - * The `IconPlaceholder` component displays the [default icons](./IconComponent.mdx) unless a [custom template](../services/CustomTemplatesService.mdx) is provided. This component is used by the SDK internally, you likely won't need to use it. + * The `IconPlaceholder` component displays the [default icons](/chat/docs/sdk/angular/components/IconComponent/) unless a [custom template](/chat/docs/sdk/angular/services/CustomTemplatesService/) is provided. This component is used by the SDK internally, you likely won't need to use it. */ @Component({ selector: 'stream-icon-placeholder', diff --git a/projects/stream-chat-angular/src/lib/icon/loading-indicator-placeholder/loading-indicator-placeholder.component.ts b/projects/stream-chat-angular/src/lib/icon/loading-indicator-placeholder/loading-indicator-placeholder.component.ts index dc2a5c59..ada73f00 100644 --- a/projects/stream-chat-angular/src/lib/icon/loading-indicator-placeholder/loading-indicator-placeholder.component.ts +++ b/projects/stream-chat-angular/src/lib/icon/loading-indicator-placeholder/loading-indicator-placeholder.component.ts @@ -2,7 +2,7 @@ import { Component } from '@angular/core'; import { CustomTemplatesService } from '../../custom-templates.service'; /** - * The `LoadingInficatorPlaceholder` component displays the [default loading indicator](./LoadingIndicatorComponent.mdx) unless a [custom template](../services/CustomTemplatesService.mdx) is provided. This component is used by the SDK internally, you likely won't need to use it. + * The `LoadingInficatorPlaceholder` component displays the [default loading indicator](/chat/docs/sdk/angular/components/LoadingIndicatorComponent/) unless a [custom template](/chat/docs/sdk/angular/services/CustomTemplatesService/) is provided. This component is used by the SDK internally, you likely won't need to use it. */ @Component({ selector: 'stream-loading-indicator-placeholder', diff --git a/projects/stream-chat-angular/src/lib/message-actions-box/message-actions-box.component.ts b/projects/stream-chat-angular/src/lib/message-actions-box/message-actions-box.component.ts index bdc92661..bc3dd31e 100644 --- a/projects/stream-chat-angular/src/lib/message-actions-box/message-actions-box.component.ts +++ b/projects/stream-chat-angular/src/lib/message-actions-box/message-actions-box.component.ts @@ -21,7 +21,7 @@ import { } from '../types'; import { MessageActionsService } from '../message-actions.service'; /** - * The `MessageActionsBox` component displays a list of message actions (i.e edit), that can be opened or closed. You can find the [list of the supported actions](../concepts/message-interactions.mdx) in the message interaction guide. + * The `MessageActionsBox` component displays a list of message actions (i.e edit), that can be opened or closed. You can find the [list of the supported actions](/chat/docs/sdk/angular/concepts/message-interactions/) in the message interaction guide. */ @Component({ selector: 'stream-message-actions-box', @@ -44,7 +44,7 @@ export class MessageActionsBoxComponent */ @Input() messageTextHtmlElement: HTMLElement | undefined; /** - * The list of [channel capabilities](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript) that are enabled for the current user, the list of [supported interactions](../concepts/message-interactions.mdx) can be found in our message interaction guide. Unathorized actions won't be displayed on the UI. + * The list of [channel capabilities](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript) that are enabled for the current user, the list of [supported interactions](/chat/docs/sdk/angular/concepts/message-interactions) can be found in our message interaction guide. Unathorized actions won't be displayed on the UI. */ @Input() enabledActions: string[] = []; messageActionItemTemplate: diff --git a/projects/stream-chat-angular/src/lib/message-actions.service.ts b/projects/stream-chat-angular/src/lib/message-actions.service.ts index 14a2bc35..3364601f 100644 --- a/projects/stream-chat-angular/src/lib/message-actions.service.ts +++ b/projects/stream-chat-angular/src/lib/message-actions.service.ts @@ -14,7 +14,7 @@ import { NotificationService } from './notification.service'; import { ChannelService } from './channel.service'; /** - * The message actions service provides customization options for the [message actions](../../components/MessageActionsBoxComponent) + * The message actions service provides customization options for the [message actions](/chat/docs/sdk/angular/components/MessageActionsBoxComponent) */ @Injectable({ providedIn: 'root', @@ -183,7 +183,7 @@ export class MessageActionsService< */ customActions$ = new BehaviorSubject([]); /** - * By default the [`MessageComponent`](../../components/MessageComponent) will display the [`MessageActionsBoxComponent`](../../components/MessageActionsBoxComponent). You can override that behavior by providing your own event handler. + * By default the [`MessageComponent`](/chat/docs/sdk/angular/components/MessageComponent/) will display the [`MessageActionsBoxComponent`](/chat/docs/sdk/angular/components/MessageActionsBoxComponent/). You can override that behavior by providing your own event handler. */ customActionClickHandler?: (details: MessageActionsClickDetails) => void; private hasDisplayedClipboardWarning = false; diff --git a/projects/stream-chat-angular/src/lib/message-bounce-prompt/message-bounce-prompt.component.ts b/projects/stream-chat-angular/src/lib/message-bounce-prompt/message-bounce-prompt.component.ts index 33f87a0f..0f73e40d 100644 --- a/projects/stream-chat-angular/src/lib/message-bounce-prompt/message-bounce-prompt.component.ts +++ b/projects/stream-chat-angular/src/lib/message-bounce-prompt/message-bounce-prompt.component.ts @@ -6,7 +6,7 @@ import { MessageActionsService } from '../message-actions.service'; import { StreamMessage } from '../types'; /** - * The component watches for the [`channelService.bouncedMessage$` stream](../../services/ChannelService/#bouncedmessage) and opens the bounce modal if a message is emitted. + * The component watches for the [`channelService.bouncedMessage$` stream](/chat/docs/sdk/angular/services/ChannelService/#bouncedmessage) and opens the bounce modal if a message is emitted. * * To bounce messages, you need to set up [semantic filters for moderation](https://getstream.io/automated-moderation/docs/automod_configuration/?q=semantic%20filters). */ diff --git a/projects/stream-chat-angular/src/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.html b/projects/stream-chat-angular/src/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.html index e56cde3b..8ec3c339 100644 --- a/projects/stream-chat-angular/src/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.html +++ b/projects/stream-chat-angular/src/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.html @@ -15,24 +15,34 @@ (paste)="pasteFromClipboard.emit($event)" > -
-
- + + + + +
+
+ +
+
+ +
-
- -
-
+ diff --git a/projects/stream-chat-angular/src/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.ts b/projects/stream-chat-angular/src/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.ts index c71e953d..a2fc51fe 100644 --- a/projects/stream-chat-angular/src/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.ts +++ b/projects/stream-chat-angular/src/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.ts @@ -24,13 +24,14 @@ import { UserResponse } from 'stream-chat'; import { ChannelService } from '../../channel.service'; import { TextareaInterface } from '../textarea.interface'; import { ChatClientService } from '../../chat-client.service'; -import { debounceTime } from 'rxjs/operators'; +import { debounceTime, filter } from 'rxjs/operators'; import { TransliterationService } from '../../transliteration.service'; import { EmojiInputService } from '../emoji-input.service'; import { CustomTemplatesService } from '../../custom-templates.service'; +import { MessageInputConfigService } from '../message-input-config.service'; /** - * The `AutocompleteTextarea` component is used by the [`MessageInput`](./MessageInputComponent.mdx) component to display the input HTML element where users can type their message. + * The `AutocompleteTextarea` component is used by the [`MessageInput`](/chat/docs/sdk/angular/components/MessageInputComponent/) component to display the input HTML element where users can type their message. */ @Component({ selector: 'stream-autocomplete-textarea', @@ -51,15 +52,15 @@ export class AutocompleteTextareaComponent */ @Input() placeholder = ''; /** - * If true, users can mention other users in messages. You can also set this input on the [`MessageInput`](./MessageInputComponent.mdx/#inputs-and-outputs) component. + * If true, users can mention other users in messages. You can also set this input on the [`MessageInput`](/chat/docs/sdk/angular/components/MessageInputComponent/#inputs-and-outputs/) component. */ @Input() areMentionsEnabled: boolean | undefined = true; /** - * See [`MessageInputConfigService`](../services/MessageInputConfigService.mdx) for more information + * See [`MessageInputConfigService`](/chat/docs/sdk/angular/services/MessageInputConfigService) for more information */ @Input() inputMode!: 'desktop' | 'mobile'; /** - * The scope for user mentions, either members of the current channel of members of the application. You can also set this input on the [`MessageInput`](./MessageInputComponent.mdx/#inputs-and-outputs) component. + * The scope for user mentions, either members of the current channel of members of the application. You can also set this input on the [`MessageInput`](/chat/docs/sdk/angular/components/MessageInputComponent/#inputs-and-outputs) component. */ @Input() mentionScope: 'channel' | 'application' = 'channel'; /** @@ -137,13 +138,21 @@ export class AutocompleteTextareaComponent private transliterationService: TransliterationService, private emojiInputService: EmojiInputService, private customTemplatesService: CustomTemplatesService, - private cdRef: ChangeDetectorRef + private cdRef: ChangeDetectorRef, + private messageInputConfigService: MessageInputConfigService ) { - this.searchTerm$.pipe(debounceTime(300)).subscribe((searchTerm) => { - if (searchTerm.startsWith(this.mentionTriggerChar)) { - void this.updateMentionOptions(searchTerm); - } - }); + this.searchTerm$ + .pipe( + filter((searchTerm) => searchTerm.length !== 1), + debounceTime(300) + ) + .subscribe((searchTerm) => { + if (searchTerm.startsWith(this.mentionTriggerChar)) { + void this.updateMentionOptions(searchTerm); + } else { + void this.updateCustomAutocompleteOptions(searchTerm); + } + }); this.subscriptions.push( this.channelService.activeChannel$.subscribe((channel) => { const commands = channel?.getConfig()?.commands || []; @@ -155,6 +164,7 @@ export class AutocompleteTextareaComponent this.mentionedUsers = []; this.userMentions.next([...this.mentionedUsers]); void this.updateMentionOptions(this.searchTerm$.getValue()); + void this.updateCustomAutocompleteOptions(this.searchTerm$.getValue()); }) ); this.subscriptions.push( @@ -183,20 +193,60 @@ export class AutocompleteTextareaComponent this.userMentionConfig, this.slashCommandConfig, ]; + this.subscriptions.push( + this.messageInputConfigService.customAutocompletes$.subscribe( + (customConfigs) => { + const builtInItems = + this.autocompleteConfig.mentions?.filter( + (m) => + m === this.userMentionConfig || m === this.slashCommandConfig + ) ?? []; + const transformedCustomConfigs = customConfigs.map((c) => { + const copy: Mentions = { + items: c.options.map((o) => ({ + ...o, + templateRef: c.templateRef, + })), + triggerChar: c.triggerCharacter, + dropUp: true, + labelKey: this.autocompleteKey, + returnTrigger: true, + allowSpace: c.allowSpace, + mentionFilter: ( + searchString: string, + items: { autocompleteLabel: string }[] + ) => this.filter(searchString, items), + mentionSelect: (item, triggerChar) => + this.itemSelectedFromAutocompleteList( + item as MentionAutcompleteListItem, + triggerChar + ), + }; + + return copy; + }); + + this.autocompleteConfig.mentions = [ + ...builtInItems, + ...transformedCustomConfigs, + ]; + this.autocompleteConfig = { ...this.autocompleteConfig }; + } + ) + ); } ngOnChanges(changes: SimpleChanges): void { if (changes.areMentionsEnabled) { - if (this.areMentionsEnabled) { - this.autocompleteConfig.mentions = [ - this.userMentionConfig, - this.slashCommandConfig, - ]; - this.autocompleteConfig = { ...this.autocompleteConfig }; - } else { - this.autocompleteConfig.mentions = [this.slashCommandConfig]; - this.autocompleteConfig = { ...this.autocompleteConfig }; - } + this.autocompleteConfig.mentions = + this.autocompleteConfig?.mentions?.filter((c) => { + if (c !== this.userMentionConfig) { + return true; + } else { + return this.areMentionsEnabled; + } + }) ?? []; + this.autocompleteConfig = { ...this.autocompleteConfig }; } if (changes.mentionScope) { void this.updateMentionOptions(this.searchTerm$.getValue()); @@ -258,11 +308,14 @@ export class AutocompleteTextareaComponent } autcompleteSearchTermChanged(searchTerm: string) { - if (searchTerm === this.mentionTriggerChar) { - void this.updateMentionOptions(); - } else { - this.searchTerm$.next(searchTerm); + if (searchTerm.length === 1) { + if (searchTerm === this.mentionTriggerChar) { + void this.updateMentionOptions(); + } else { + void this.updateCustomAutocompleteOptions(searchTerm); + } } + this.searchTerm$.next(searchTerm); } inputChanged() { @@ -326,8 +379,7 @@ export class AutocompleteTextareaComponent ); this.userMentionConfig.items = items; this.autocompleteConfig.mentions = [ - this.userMentionConfig, - this.slashCommandConfig, + ...(this.autocompleteConfig?.mentions ?? []), ]; this.autocompleteConfig = { ...this.autocompleteConfig }; this.cdRef.detectChanges(); @@ -346,4 +398,31 @@ export class AutocompleteTextareaComponent this.mentionedUsers = updatedMentionedUsers; } } + + private async updateCustomAutocompleteOptions(searchTerm: string) { + if ( + this.messageInputConfigService.customAutocompletes$.getValue().length === + 0 + ) { + return; + } + const customMentionConfig = this.autocompleteConfig.mentions?.find( + (c) => c.triggerChar && searchTerm.startsWith(c.triggerChar) + ); + const customAutocompleteConfig = customMentionConfig + ? this.messageInputConfigService.customAutocompletes$ + .getValue() + .find((c) => c.triggerCharacter === customMentionConfig?.triggerChar) + : undefined; + if (customMentionConfig && customAutocompleteConfig?.updateOptions) { + const newOptions = await customAutocompleteConfig.updateOptions( + searchTerm.replace(customMentionConfig.triggerChar || '', '') + ); + customMentionConfig.items = newOptions.map((o) => ({ + ...o, + templateRef: customAutocompleteConfig.templateRef, + })); + this.autocompleteConfig = { ...this.autocompleteConfig }; + } + } } diff --git a/projects/stream-chat-angular/src/lib/message-input/emoji-input.service.ts b/projects/stream-chat-angular/src/lib/message-input/emoji-input.service.ts index 7d055bf4..dd3ac0be 100644 --- a/projects/stream-chat-angular/src/lib/message-input/emoji-input.service.ts +++ b/projects/stream-chat-angular/src/lib/message-input/emoji-input.service.ts @@ -2,14 +2,14 @@ import { Injectable } from '@angular/core'; import { Subject } from 'rxjs'; /** - * If you have an emoji picker in your application, you can propagate the selected emoji to the textarea using this service, more info can be found in [custom emoji picker guide](../code-examples/emoji-picker.mdx) + * If you have an emoji picker in your application, you can propagate the selected emoji to the textarea using this service, more info can be found in [custom emoji picker guide](/chat/docs/sdk/angular/code-examples/emoji-picker/) */ @Injectable({ providedIn: 'root', }) export class EmojiInputService { /** - * If you have an emoji picker in your application, you can propagate the selected emoji to the textarea using this Subject, more info can be found in [custom emoji picker guide](../code-examples/emoji-picker.mdx) + * If you have an emoji picker in your application, you can propagate the selected emoji to the textarea using this Subject, more info can be found in [custom emoji picker guide](/chat/docs/sdk/angular/code-examples/emoji-picker/) */ emojiInput$ = new Subject(); diff --git a/projects/stream-chat-angular/src/lib/message-input/message-input-config.service.ts b/projects/stream-chat-angular/src/lib/message-input/message-input-config.service.ts index 9ae2f513..76c7c963 100644 --- a/projects/stream-chat-angular/src/lib/message-input/message-input-config.service.ts +++ b/projects/stream-chat-angular/src/lib/message-input/message-input-config.service.ts @@ -1,8 +1,10 @@ import { Injectable } from '@angular/core'; import { MessageInputComponent } from './message-input.component'; +import { BehaviorSubject } from 'rxjs'; +import { CustomAutocomplete } from '../types'; /** - * The `MessageInputConfigService` is used to keep a consistent configuration among the different [`MessageInput`](../components/MessageInputComponent.mdx) components if your UI has more than one input component. + * The `MessageInputConfigService` is used to keep a consistent configuration among the different [`MessageInput`](/chat/docs/sdk/angular/components/MessageInputComponent/) components if your UI has more than one input component. */ @Injectable({ providedIn: 'root', @@ -13,7 +15,7 @@ export class MessageInputConfigService { */ isFileUploadEnabled: boolean | undefined = true; /** - * If true, users can mention other users in messages. You also [need to use the `AutocompleteTextarea`](../concepts/opt-in-architecture.mdx) for this feature to work. + * If true, users can mention other users in messages. You also [need to use the `AutocompleteTextarea`](/chat/docs/sdk/angular/concepts/opt-in-architecture/) for this feature to work. */ areMentionsEnabled: boolean | undefined = true; /** @@ -36,7 +38,7 @@ export class MessageInputConfigService { /** * Override the message input's default event handler for [paste events](https://developer.mozilla.org/en-US/docs/Web/API/Element/paste_event) * - * The event handler will receive the event object, and the [message input component](../../components/MessageInputComponent). + * The event handler will receive the event object, and the [message input component](/chat/docs/sdk/angular/components/MessageInputComponent). * * You can use the public API of the message input component to update the composer. Typically you want to update the message text and/or attachments, this is how you can do these: * - Change message text: `inputComponent.textareaValue = ''` @@ -47,6 +49,12 @@ export class MessageInputConfigService { event: ClipboardEvent, inputComponent: MessageInputComponent ) => void; + /** + * Add custom autocomplete configurations to the message input + * + * Only works when using StreamAutocompleteTextareaModule + */ + customAutocompletes$ = new BehaviorSubject([]); constructor() {} } diff --git a/projects/stream-chat-angular/src/lib/message-input/message-input.component.ts b/projects/stream-chat-angular/src/lib/message-input/message-input.component.ts index 4be02cad..ec111f52 100644 --- a/projects/stream-chat-angular/src/lib/message-input/message-input.component.ts +++ b/projects/stream-chat-angular/src/lib/message-input/message-input.component.ts @@ -59,15 +59,15 @@ export class MessageInputComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit { /** - * If file upload is enabled, the user can open a file selector from the input. Please note that the user also needs to have the necessary [channel capability](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript). If no value is provided, it is set from the [`MessageInputConfigService`](../services/MessageInputConfigService.mdx). + * If file upload is enabled, the user can open a file selector from the input. Please note that the user also needs to have the necessary [channel capability](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript). If no value is provided, it is set from the [`MessageInputConfigService`](/chat/docs/sdk/angular/services/MessageInputConfigService/). */ @Input() isFileUploadEnabled: boolean | undefined; /** - * If true, users can mention other users in messages. You also [need to use the `AutocompleteTextarea`](../concepts/opt-in-architecture.mdx) for this feature to work. If no value is provided, it is set from the [`MessageInputConfigService`](../services/MessageInputConfigService.mdx). + * If true, users can mention other users in messages. You also [need to use the `AutocompleteTextarea`](/chat/docs/sdk/angular/concepts/opt-in-architecture/) for this feature to work. If no value is provided, it is set from the [`MessageInputConfigService`](/chat/docs/sdk/angular/services/MessageInputConfigService/). */ @Input() areMentionsEnabled: boolean | undefined; /** - * The scope for user mentions, either members of the current channel of members of the application. If no value is provided, it is set from the [`MessageInputConfigService`](../services/MessageInputConfigService.mdx). + * The scope for user mentions, either members of the current channel of members of the application. If no value is provided, it is set from the [`MessageInputConfigService`](/chat/docs/sdk/angular/services/MessageInputConfigService/). */ @Input() mentionScope: 'channel' | 'application' | undefined; /** @@ -75,7 +75,7 @@ export class MessageInputComponent */ @Input() mode: 'thread' | 'main' = 'main'; /** - * If true, users can select multiple files to upload. If no value is provided, it is set from the [`MessageInputConfigService`](../services/MessageInputConfigService.mdx). + * If true, users can select multiple files to upload. If no value is provided, it is set from the [`MessageInputConfigService`](/chat/docs/sdk/angular/services/MessageInputConfigService/). */ @Input() isMultipleFileUploadEnabled: boolean | undefined; /** @@ -87,7 +87,7 @@ export class MessageInputComponent */ @Input() sendMessage$: Observable | undefined; /** - * In `desktop` mode the `Enter` key will trigger message sending, in `mobile` mode the `Enter` key will insert a new line to the message input. If no value is provided, it is set from the [`MessageInputConfigService`](../services/MessageInputConfigService.mdx). + * In `desktop` mode the `Enter` key will trigger message sending, in `mobile` mode the `Enter` key will insert a new line to the message input. If no value is provided, it is set from the [`MessageInputConfigService`](/chat/docs/sdk/angular/services/MessageInputConfigService/). */ @Input() inputMode: 'desktop' | 'mobile'; /** @@ -95,7 +95,7 @@ export class MessageInputComponent */ @Input() autoFocus = true; /** - * By default the input will react to changes in `messageToEdit$` from [`MessageActionsService`](../services/MessageActionsService.mdx) and display the message to be edited (taking into account the current `mode`). + * By default the input will react to changes in `messageToEdit$` from [`MessageActionsService`](/chat/docs/sdk/angular/services/MessageActionsService/) and display the message to be edited (taking into account the current `mode`). * * If you don't need that behavior, you can turn this of with this flag. In that case you should create your own edit message UI. */ diff --git a/projects/stream-chat-angular/src/lib/message-input/textarea/textarea.component.ts b/projects/stream-chat-angular/src/lib/message-input/textarea/textarea.component.ts index c7927574..0794d1f7 100644 --- a/projects/stream-chat-angular/src/lib/message-input/textarea/textarea.component.ts +++ b/projects/stream-chat-angular/src/lib/message-input/textarea/textarea.component.ts @@ -17,7 +17,7 @@ import { TextareaInterface } from '../textarea.interface'; import { UserResponse } from 'stream-chat'; /** - * The `Textarea` component is used by the [`MessageInput`](./MessageInputComponent.mdx) component to display the input HTML element where users can type their message. + * The `Textarea` component is used by the [`MessageInput`](/chat/docs/sdk/angular/components/MessageInputComponent/) component to display the input HTML element where users can type their message. */ @Component({ selector: 'stream-textarea', @@ -38,7 +38,7 @@ export class TextareaComponent */ @Input() placeholder = ''; /** - * See [`MessageInputConfigService`](../services/MessageInputConfigService.mdx) for more information + * See [`MessageInputConfigService`](/chat/docs/sdk/angular/services/MessageInputConfigService) for more information */ @Input() inputMode!: 'desktop' | 'mobile'; /** diff --git a/projects/stream-chat-angular/src/lib/message-reactions-selector/message-reactions-selector.component.ts b/projects/stream-chat-angular/src/lib/message-reactions-selector/message-reactions-selector.component.ts index ac29af31..d607d407 100644 --- a/projects/stream-chat-angular/src/lib/message-reactions-selector/message-reactions-selector.component.ts +++ b/projects/stream-chat-angular/src/lib/message-reactions-selector/message-reactions-selector.component.ts @@ -13,7 +13,7 @@ import { MessageReactionsService } from '../message-reactions.service'; import { Subscription } from 'rxjs'; /** - * The `MessageReactionsSelectorComponent` makes it possible for users to react to a message, the reaction options can be set using the [`MessageReactionsService`](../../services/MessageReactionsService). You can read more about [message reactions](https://getstream.io/chat/docs/javascript/send_reaction/?language=javascript) in the platform documentation. + * The `MessageReactionsSelectorComponent` makes it possible for users to react to a message, the reaction options can be set using the [`MessageReactionsService`](/chat/docs/sdk/angular/services/MessageReactionsService/). You can read more about [message reactions](https://getstream.io/chat/docs/javascript/send_reaction/?language=javascript) in the platform documentation. */ @Component({ selector: 'stream-message-reactions-selector', @@ -24,7 +24,7 @@ export class MessageReactionsSelectorComponent implements OnInit, OnDestroy, AfterViewInit { /** - * List of the user's own reactions of a [message](../types/stream-message.mdx), used to display the users of a reaction type. + * List of the user's own reactions of a [message](/chat/docs/sdk/angular/types/stream-message/), used to display the users of a reaction type. */ @Input() ownReactions: ReactionResponse[] = []; /** diff --git a/projects/stream-chat-angular/src/lib/message-reactions.service.ts b/projects/stream-chat-angular/src/lib/message-reactions.service.ts index 7732c9ec..752d9df4 100644 --- a/projects/stream-chat-angular/src/lib/message-reactions.service.ts +++ b/projects/stream-chat-angular/src/lib/message-reactions.service.ts @@ -15,7 +15,7 @@ export class MessageReactionsService { /** * The enabled [reactions](https://getstream.io/chat/docs/javascript/send_reaction/?language=javascript) and the associated emoji * - * You can provide any string as a reaction. The emoji can be provided as a string, if you want to use custom images for reactions you have to provide a [custom reactions UI](../../services/CustomTemplatesService/#messagereactionstemplate) + * You can provide any string as a reaction. The emoji can be provided as a string, if you want to use custom images for reactions you have to provide a [custom reactions UI](/chat/docs/sdk/angular/services/CustomTemplatesService/#messagereactionstemplate/) */ reactions$ = new BehaviorSubject<{ [key in MessageReactionType]: string }>({ haha: '😂', @@ -25,7 +25,7 @@ export class MessageReactionsService { wow: '😮', }); /** - * By default the [`MessageReactionsComponent`](../../components/MessageReactionsComponent) will display the reacting users when a reaction is clicked. You can override this with your own UI by providing a custom event handler. + * By default the [`MessageReactionsComponent`](/chat/docs/sdk/angular/components/MessageReactionsComponent/) will display the reacting users when a reaction is clicked. You can override this with your own UI by providing a custom event handler. * * The event handler can retrieve all reactions of a message using the [`messageReactionsService.queryReactions()`](https://getstream.io/chat/docs/sdk/angular/services/MessageReactionsService/#queryreactions) */ diff --git a/projects/stream-chat-angular/src/lib/message-reactions/message-reactions.component.ts b/projects/stream-chat-angular/src/lib/message-reactions/message-reactions.component.ts index 73f3d037..73a5c1e2 100644 --- a/projects/stream-chat-angular/src/lib/message-reactions/message-reactions.component.ts +++ b/projects/stream-chat-angular/src/lib/message-reactions/message-reactions.component.ts @@ -47,12 +47,12 @@ export class MessageReactionsComponent @Input() messageReactionCounts: { [key in MessageReactionType]?: number } = {}; /** - * List of reactions of a [message](../types/stream-message.mdx), used to display the users of a reaction type. + * List of reactions of a [message](/chat/docs/sdk/angular/types/stream-message/), used to display the users of a reaction type. * @deprecated you can fetch the reactions using [`messageReactionsService.queryReactions()`](https://getstream.io/chat/docs/sdk/angular/services/MessageReactionsService/#queryreactions) */ @Input() latestReactions: ReactionResponse[] = []; /** - * List of the user's own reactions of a [message](../types/stream-message.mdx), used to display the users of a reaction type. + * List of the user's own reactions of a [message](/chat/docs/sdk/angular/types/stream-message/), used to display the users of a reaction type. */ @Input() ownReactions: ReactionResponse[] = []; @ViewChild('selectorContainer') private selectorContainer: diff --git a/projects/stream-chat-angular/src/lib/message/message.component.ts b/projects/stream-chat-angular/src/lib/message/message.component.ts index 38ff98f5..65015cc1 100644 --- a/projects/stream-chat-angular/src/lib/message/message.component.ts +++ b/projects/stream-chat-angular/src/lib/message/message.component.ts @@ -48,7 +48,7 @@ type MessagePart = { }; /** - * The `Message` component displays a message with additional information such as sender and date, and enables [interaction with the message (i.e. edit or react)](../concepts/message-interactions.mdx). + * The `Message` component displays a message with additional information such as sender and date, and enables [interaction with the message (i.e. edit or react)](/chat/docs/sdk/angular/concepts/message-interactions/). */ @Component({ selector: 'stream-message', @@ -64,7 +64,7 @@ export class MessageComponent */ @Input() message: StreamMessage | undefined; /** - * The list of [channel capabilities](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript) that are enabled for the current user, the list of [supported interactions](../concepts/message-interactions.mdx) can be found in our message interaction guide. Unathorized actions won't be displayed on the UI. The [`MessageList`](./MessageListComponent.mdx) component automatically sets this based on [channel capabilities](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript). + * The list of [channel capabilities](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript) that are enabled for the current user, the list of [supported interactions](/chat/docs/sdk/angular/concepts/message-interactions/) can be found in our message interaction guide. Unathorized actions won't be displayed on the UI. The [`MessageList`](/chat/docs/sdk/angular/components/MessageListComponent/) component automatically sets this based on [channel capabilities](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript). */ @Input() enabledMessageActions: string[] = []; /** diff --git a/projects/stream-chat-angular/src/lib/notification.service.ts b/projects/stream-chat-angular/src/lib/notification.service.ts index c7baeb79..14b1562f 100644 --- a/projects/stream-chat-angular/src/lib/notification.service.ts +++ b/projects/stream-chat-angular/src/lib/notification.service.ts @@ -3,7 +3,7 @@ import { BehaviorSubject, Observable } from 'rxjs'; import { NotificationPayload, NotificationType } from './types'; /** - * The `NotificationService` can be used to add or remove notifications. By default the [`NotificationList`](../components/NotificationListComponent.mdx) component displays the currently active notifications. + * The `NotificationService` can be used to add or remove notifications. By default the [`NotificationList`](/chat/docs/sdk/angular/components/NotificationListComponent/) component displays the currently active notifications. */ @Injectable({ providedIn: 'root', diff --git a/projects/stream-chat-angular/src/lib/notification/notification.component.ts b/projects/stream-chat-angular/src/lib/notification/notification.component.ts index 3d86bfe1..1bb9f94a 100644 --- a/projects/stream-chat-angular/src/lib/notification/notification.component.ts +++ b/projects/stream-chat-angular/src/lib/notification/notification.component.ts @@ -2,7 +2,7 @@ import { Component, Input, TemplateRef } from '@angular/core'; import { NotificationType } from '../types'; /** - * The `Notification` component displays a notification within the [`NotificationList`](./NotificationListComponent.mdx) + * The `Notification` component displays a notification within the [`NotificationList`](/chat/docs/sdk/angular/components/NotificationListComponent/) */ @Component({ selector: 'stream-notification', diff --git a/projects/stream-chat-angular/src/lib/stream-i18n.service.ts b/projects/stream-chat-angular/src/lib/stream-i18n.service.ts index 90dd5872..348cbc8b 100644 --- a/projects/stream-chat-angular/src/lib/stream-i18n.service.ts +++ b/projects/stream-chat-angular/src/lib/stream-i18n.service.ts @@ -3,7 +3,7 @@ import { TranslateService } from '@ngx-translate/core'; import { en } from '../assets/i18n/en'; /** - * The `StreamI18nService` can be used to customize the labels of the chat UI. Our [translation guide](../concepts/translation.mdx) covers this topic in detail. + * The `StreamI18nService` can be used to customize the labels of the chat UI. Our [translation guide](/chat/docs/sdk/angular/concepts/translation/) covers this topic in detail. */ @Injectable({ providedIn: 'root', diff --git a/projects/stream-chat-angular/src/lib/theme.service.ts b/projects/stream-chat-angular/src/lib/theme.service.ts index 0652ca5a..e0862070 100644 --- a/projects/stream-chat-angular/src/lib/theme.service.ts +++ b/projects/stream-chat-angular/src/lib/theme.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; /** - * The `ThemeService` can be used to change the theme of the chat UI and to customize the theme. Our [theming guide](../theming/introduction.mdx) gives a complete overview about the topic. + * The `ThemeService` can be used to change the theme of the chat UI and to customize the theme. Our [theming guide](/chat/docs/sdk/angular/theming/themingv2/) gives a complete overview about the topic. */ @Injectable({ providedIn: 'root', diff --git a/projects/stream-chat-angular/src/lib/thread/thread.component.ts b/projects/stream-chat-angular/src/lib/thread/thread.component.ts index e4ccc8aa..c9f71564 100644 --- a/projects/stream-chat-angular/src/lib/thread/thread.component.ts +++ b/projects/stream-chat-angular/src/lib/thread/thread.component.ts @@ -12,7 +12,7 @@ import { } from '../types'; /** - * The `Thread` component represents a [message thread](https://getstream.io/chat/docs/javascript/threads/?language=javascript), it is a container component that displays a thread with a header, [`MessageList`](./MessageListComponent.mdx) and [`MessageInput`](./MessageInputComponent.mdx) components. + * The `Thread` component represents a [message thread](https://getstream.io/chat/docs/javascript/threads/?language=javascript), it is a container component that displays a thread with a header, [`MessageList`](/chat/docs/sdk/angular/components/MessageListComponent) and [`MessageInput`](/chat/docs/sdk/angular/components/MessageInputComponent/) components. */ @Component({ selector: 'stream-thread', diff --git a/projects/stream-chat-angular/src/lib/types.ts b/projects/stream-chat-angular/src/lib/types.ts index 935680f6..89ff5126 100644 --- a/projects/stream-chat-angular/src/lib/types.ts +++ b/projects/stream-chat-angular/src/lib/types.ts @@ -500,3 +500,43 @@ export type ThreadReplyButtonContext< > = { message: StreamMessage; }; + +export type CustomAutocompleteItemContext = { + item: CustomAutocompleteItem; +}; + +export type CustomAutocompleteItem = { + /** + * This is the text that will be inserted into the message input once a user selects an option (appended after the trigger character) + */ + autocompleteLabel: string; +}; + +export type CustomAutocomplete = { + /** + * The character that will trigger the autocomplete (for example #) + * + * The SDK supports @ and / by default, so you can't use those + */ + triggerCharacter: string; + /** + * The HTML template to display an item in the autocomplete list + */ + templateRef: TemplateRef<{ item: CustomAutocompleteItem }>; + /** + * Set to `true` if space characters can be part of the `autocompleteLabel` + */ + allowSpace: boolean; + /** + * The options to choose from + * + * In case you want to use dynamic/server-side filtering, use `updateOptions` instead + */ + options: CustomAutocompleteItem[]; + /** + * If you want to have dynamic/server-side filtering provide a method that will be called any time the autocomplete options should be filtered + * @param searchTerm the text to filter by (without the trigger character), can be an empty string + * @returns a promise that will resolve to the options, you should take care of error handling + */ + updateOptions?: (searchTerm: string) => Promise; +};