-
-
Notifications
You must be signed in to change notification settings - Fork 749
[Docs] Document new modal components #3219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
Misha-133
wants to merge
3
commits into
dev
Choose a base branch
from
docs/modal-select-menus
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+157
−1
Draft
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| --- | ||
| uid: Guides.IntFw.Modals | ||
| title: Modals in Interaction Service | ||
| --- | ||
|
|
||
| # Modals | ||
| The interaction service provides a set of tools which can be used to create and handle modals. Modals are a type of interactive component that can be used to gather input from users in a structured way. | ||
|
|
||
| In the Interaction Framework modals can be defined using a class that inherits `IModal`. `ModalBuilder` can be still used to create modals programmatically, but using `IModal` is the recommended way. | ||
|
|
||
| The title of the modal is set by implementing the `Title` property of the `IModal` interface. | ||
|
|
||
| [!code-csharp[Example modal](samples/modals/modal-class.cs)] | ||
|
|
||
| > [!NOTE] | ||
| > If you are using Modals in the interaction service it is **highly | ||
| > recommended** that you enable `PreCompiledLambdas` in your config | ||
| > to prevent performance issues. | ||
|
|
||
| ## Responding with a modal | ||
| To respond to an interaction with a modal, you can use the `RespondWithModalAsync<TModal>` method provided by the interaction context. This method takes a generic parameter `TModal`, which should be a class that implements the `IModal` interface. | ||
| Additionally, the method can take an instance of `TModal` to pre-fill the modal with data (or alter the title). | ||
|
|
||
| ```csharp | ||
| await RespondWithModalAsync<ExampleModal>("example-modal-custom-id"); | ||
| ``` | ||
|
|
||
|
|
||
| ## Handling modal submissions | ||
| To handle a modal you need to create a method in your interaction module and annotate it with the `ModalInteraction` attribute. The method's last parameter must be of type `TModal`, where `TModal` is the class that implements the `IModal` interface. Simitar to `ComponentInteraction` methods, parts of the custom ID can be defined with a wildcard character and extracted using method parameters. | ||
|
|
||
| ```csharp | ||
| [ModalInteraction("example-modal-custom-id")] | ||
| public async Task HandleExampleModal(ExampleModal modal) | ||
| { | ||
| // Handle the modal submission | ||
| } | ||
| ``` | ||
|
|
||
|
|
||
| ## Input names | ||
|
|
||
| Modal components can be annotated with a description using the `InputLabel` attribute. If no label is provided, the property name will be used as the label. | ||
|
|
||
| ```csharp | ||
| [InputLabel("Component label", "Some description")] | ||
| ``` | ||
|
|
||
|  | ||
|
|
||
|
|
||
| ## Required inputs | ||
| Modal components are required by default. To make a component optional, you can use the `RequiredInput` attribute with the boolean parameter set to `false`. | ||
|
|
||
| ```csharp | ||
| [RequiredInput(false)] | ||
| ``` | ||
|
|
||
|
|
||
|
|
||
| ## Supported components | ||
|
|
||
| Modals currently support the following components: | ||
| - [Text Input](#text-input) | ||
| - Select Menus (Dropdowns) | ||
| - [Text selects](#text-selects) | ||
| - [User selects](#user--role--mentionable-and-channel-selects) | ||
| - [Role selects](#user--role--mentionable-and-channel-selects) | ||
| - [Mentionable selects](#user--role--mentionable-and-channel-selects) | ||
| - [Channel selects](#user--role--mentionable-and-channel-selects) | ||
| - [File Uploads](#file-uploads) | ||
| - [Text Display](#text-display | ||
|
|
||
| ## Text Input | ||
| Text inputs allow users to input text data into a modal. They can be configured with various options such as placeholder text, minimum and maximum length, and whether the input is required. Text inputs can be single-line or paragraph style. | ||
|
|
||
|  | ||
|
|
||
| ## Select Menus | ||
| Select menus allow users to select one or more options from a dropdown list. | ||
|
|
||
| ### Text Selects | ||
| Text selects allow users to select one or more options from a predefined list of text options. | ||
| The select menu is defined using the `ModalSelectMenu` attribute. The attribute can be used on a property of type `string`, `string[]` or an `enum` (annotated with `[Flags]` for multi-selects). | ||
| In string selects, the default Modal TypeConverter discovers the most suitable TypeReader registered in the active `InteractionService` instance and converts `string` values to the underlying CLR type of the array property using that TypeReader. Out of the box, you can use any `IConvertible` array as the backing field of a Text Select component. | ||
| In the case of `string`, `string[]` or any other array, the options must be provided using the `ModalSelectMenuOption` attribute. | ||
|
|
||
| ```csharp | ||
| [ModalSelectMenu("custom-id")] | ||
| [ModalSelectMenuOption("label1", "Value1", "Some description 1")] | ||
| [ModalSelectMenuOption("label2", "Value2", "Some description 2")] | ||
| public string[] TextSelectMenu { get; set; } | ||
| ``` | ||
|
|
||
|  | ||
| In case of `enum`, the enum values are automatically converted into options. `Hide` attribute can be used to declaratively remove options from the select menu. Custom attributes can be created by inheriting the `Hide` attribute and overriding the `Predicate` method to apply the attribute selectively during runtime. | ||
|
|
||
| Option properties (like description, isDefault, and emote) can be configured by adding a `SelectMenuOption` attribute to the enum fields. Emote property accepts identifier strings for both unicode emojis and discord emotes. | ||
|
|
||
| Enum selects are the recommended way of implementing select menus in modals. It provides a reusable and type-safe way of accepting user inputs, as it is also possible to create generic modal classes and swap select menus in-and-out by simply changing the generic parameter on instantiation. | ||
| ### User, Role, Mentionable and Channel Selects | ||
| User, Role, Mentionable and Channel selects allow users to select one or more entities of a specific type from a prefilled select menu. | ||
| `ModalUserSelect`, `ModalRoleSelect`, `ModalMentionableSelect` and `ModalChannelSelect` attributes can be used on properties of type `IUser`, `IRole`, `IMentionable`, `IChannel`, or any other implementation of the aforementioned interfaces(as long as the received entity type can be up-cast into it) for single-selects, or arrays of respective types for multi-selects. | ||
|
|
||
| [!code-csharp[Example modal](samples/modals/prefilled-selects.cs)] | ||
|  | ||
| For Channel selects in particular, the property type (if single entity), or the underlying type of the array can be used to restrict the type of channels available to the user. Implementations like `IStageChannel`, `IVoiceChannel`, `IDMChannel`, `IGroupChannel`, `ICategoryChannel`, `INewsChannel`, `IThreadChannel`, `ITextChannel`, `IMediaChannel`, or `IForumChannel` can be used. | ||
Misha-133 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| Additionally for Channel Select components, channel type constraints can be defined by annotating the property with a `ChannelTypes` attribute. | ||
| ## File Uploads | ||
| File upload components allow users to upload files as part of their modal submission. A single file upload can take up to 10 attachments. The size limit for the uploaded files is determined by Discord's limits for the current context (e.g., server boost level, user's nitro status). | ||
| The file upload component is defined using the `ModalFileUpload` attribute. The attribute can be used on a property of type `IAttachment` or `IAttachment[]`. | ||
|
|
||
| ```csharp | ||
| [ModalFileUpload("file-upload-id", maxValues: 5)] | ||
| public IAttachment[] FileUploads { get; set; } | ||
| ``` | ||
|  | ||
|
|
||
| ## Text Display | ||
| Text display components allow you to display read-only text within a modal. This can be useful for providing instructions or additional information to users. The text can be formatted using Markdown syntax. | ||
|
|
||
| The text display component is defined using the `ModalTextDisplay` attribute. The attribute can be used on a property of type `string`. The value of the property will be displayed as read-only text in the modal. In the case the property is `null`, the value provided in the attribute's optional `content` parameter will be used as a fallback. | ||
|
|
||
| ```csharp | ||
| [ModalTextDisplay(content: "Fallback content")] | ||
| public string? TextDisplay { get; set; } = """ | ||
| # Text display! | ||
| Hello there! | ||
| -# wires | ||
| """; | ||
| ``` | ||
|  | ||
|
|
||
| ## Modal TypeConverters | ||
| Modal TypeConverters use the same principle as Slash Command TypeConverters and Component TypeConverters to convert CLR type values to and from API entities and values. They are assigned to modal component properties by their respective CLR types (with the exception being Text Display components). Every default behaviour mentioned in this document regarding value conversions and property values can be overridden by implementing custom generic or concrete Modal TypeConverters by inheriting `ModalComponentTypeConverter` class and registering the TypeConveter to the `InteractionService` instance in use. `WriteAsync` method is invoked after the regular the component building flow is done executing with the component builder instance being used. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| public class ExampleModal : IModal | ||
| { | ||
| public string Title = "Example Modal"; | ||
|
|
||
| // other modal components | ||
| } |
11 changes: 11 additions & 0 deletions
11
docs/guides/int_framework/samples/modals/prefilled-selects.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| [ModalUserSelect("user-select-id")] | ||
| public IUser[] SelectedUsers { get; set; } | ||
|
|
||
| [ModalChannelSelect("channel-select-id")] | ||
| public IChannel[] SelectedChannels { get; set; } | ||
|
|
||
| [ModalRoleSelect("role-select-id")] | ||
| public IRole[] SelectedRoles { get; set; } | ||
|
|
||
| [ModalMentionableSelect("mentionable-select-id")] | ||
| public IMentionable[] SelectedMentionables { get; set; } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.