-
-
Notifications
You must be signed in to change notification settings - Fork 40
feat: add radio and checkbox group components for modals #754
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
Merged
+434
−4
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
58a38df
feat: add radio and checkbox group components for modals
Lulalaby 6f464a0
Initial plan
Copilot 5221ce2
fix: address review comments - grammar, formatting, and validation
Copilot 9a5a8cf
fix: correct XML documentation formatting for SubComponentType
Copilot f3d6ff5
fix: remove Checkbox from modal-only component types
Copilot e11778c
docs: clarify modal-only component types documentation
Copilot cb607f4
Merge pull request #755 from Aiko-IT-Systems/copilot/sub-pr-754
Lulalaby 4b90bc1
fix: wrong impl
Lulalaby a4b4739
Apply suggestions from code review
Lulalaby 7a1480c
Apply suggestion from @Lulalaby
Lulalaby 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
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
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
61 changes: 61 additions & 0 deletions
61
DisCatSharp/Entities/Components/V2Components/DiscordCheckboxComponent.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,61 @@ | ||
| using System; | ||
|
|
||
| using DisCatSharp.Enums; | ||
|
|
||
| using Newtonsoft.Json; | ||
|
|
||
| namespace DisCatSharp.Entities; | ||
|
|
||
| /// <summary> | ||
| /// Represents a single checkbox component. Modal-only. | ||
| /// </summary> | ||
| public sealed class DiscordCheckboxComponent : DiscordComponent, ILabelComponent | ||
| { | ||
| /// <summary> | ||
| /// Creates a new empty checkbox component. | ||
| /// </summary> | ||
| internal DiscordCheckboxComponent() | ||
| { | ||
| this.Type = ComponentType.Checkbox; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Creates a new checkbox component with the provided options. | ||
| /// </summary> | ||
| /// <param name="customId">The custom id for this component.</param> | ||
| /// <param name="isDefault">Whether the checkbox is checked by default.</param> | ||
| public DiscordCheckboxComponent(string? customId = null, bool? isDefault = null) | ||
| : this() | ||
| { | ||
| this.CustomId = customId ?? Guid.NewGuid().ToString(); | ||
| this.Default = isDefault; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// The custom id for this component. | ||
| /// </summary> | ||
| [JsonProperty("custom_id", NullValueHandling = NullValueHandling.Ignore)] | ||
| public override string? CustomId { get; internal set; } = Guid.NewGuid().ToString(); | ||
|
|
||
| /// <summary> | ||
| /// Whether the checkbox is checked by default. | ||
| /// </summary> | ||
| [JsonProperty("default", NullValueHandling = NullValueHandling.Ignore)] | ||
| public bool? Default { get; internal set; } | ||
|
|
||
| /// <summary> | ||
| /// The submitted value. Present on modal submit interactions. | ||
| /// </summary> | ||
| [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] | ||
| public bool? Value { get; internal set; } | ||
|
|
||
| /// <summary> | ||
| /// Assigns a unique id to this component. | ||
| /// </summary> | ||
| /// <param name="id">The id to assign.</param> | ||
| public DiscordCheckboxComponent WithId(int id) | ||
| { | ||
| this.Id = id; | ||
| return this; | ||
| } | ||
| } |
104 changes: 104 additions & 0 deletions
104
DisCatSharp/Entities/Components/V2Components/DiscordCheckboxGroupComponent.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,104 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
|
|
||
| using DisCatSharp.Enums; | ||
|
|
||
| using Newtonsoft.Json; | ||
|
|
||
| namespace DisCatSharp.Entities; | ||
|
|
||
| /// <summary> | ||
| /// Represents a checkbox group component. Modal-only. | ||
| /// </summary> | ||
| public sealed class DiscordCheckboxGroupComponent : DiscordComponent, ILabelComponent | ||
| { | ||
| /// <summary> | ||
| /// Creates a new empty checkbox group component. | ||
| /// </summary> | ||
| internal DiscordCheckboxGroupComponent() | ||
| { | ||
| this.Type = ComponentType.CheckboxGroup; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Creates a new checkbox group component with the provided options. | ||
| /// </summary> | ||
| /// <param name="options">The selectable options. Must contain between 1 and 10 entries.</param> | ||
| /// <param name="customId">The custom id for this component.</param> | ||
| /// <param name="minValues">The minimum number of selections. Defaults to 1.</param> | ||
| /// <param name="maxValues">The maximum number of selections. Defaults to the number of options.</param> | ||
| /// <param name="required">Whether a selection is required.</param> | ||
| public DiscordCheckboxGroupComponent(IEnumerable<DiscordCheckboxGroupComponentOption> options, string? customId = null, int? minValues = null, int? maxValues = null, bool? required = null) | ||
| : this() | ||
| { | ||
| ArgumentNullException.ThrowIfNull(options); | ||
| var optionList = options.ToList(); | ||
| if (optionList.Count is < 1 or > 10) | ||
| throw new ArgumentException("Checkbox groups must include between 1 and 10 options."); | ||
|
|
||
| var minimum = minValues ?? 1; | ||
| var maximum = maxValues ?? optionList.Count; | ||
|
|
||
| if (minimum is < 0 or > 10) | ||
| throw new ArgumentException("Minimum values must be between 0 and 10.", nameof(minValues)); | ||
| if (maximum is < 1 or > 10) | ||
| throw new ArgumentException("Maximum values must be between 1 and 10.", nameof(maxValues)); | ||
| if (minimum > maximum) | ||
| throw new ArgumentException("Minimum values cannot exceed maximum values."); | ||
| if (maximum > optionList.Count) | ||
| throw new ArgumentException("Maximum values cannot exceed the number of options."); | ||
|
|
||
| this.CustomId = customId ?? Guid.NewGuid().ToString(); | ||
| this.Options = optionList; | ||
| this.MinimumValues = minimum; | ||
| this.MaximumValues = maximum; | ||
| this.Required = required; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// The custom id for this component. | ||
| /// </summary> | ||
| [JsonProperty("custom_id", NullValueHandling = NullValueHandling.Ignore)] | ||
| public override string? CustomId { get; internal set; } = Guid.NewGuid().ToString(); | ||
|
|
||
| /// <summary> | ||
| /// The available options. | ||
| /// </summary> | ||
| [JsonProperty("options", NullValueHandling = NullValueHandling.Ignore)] | ||
| public IReadOnlyList<DiscordCheckboxGroupComponentOption> Options { get; internal set; } = Array.Empty<DiscordCheckboxGroupComponentOption>(); | ||
|
|
||
| /// <summary> | ||
| /// The minimum number of selections. | ||
| /// </summary> | ||
| [JsonProperty("min_values", NullValueHandling = NullValueHandling.Ignore)] | ||
| public int? MinimumValues { get; internal set; } = 0; | ||
|
|
||
| /// <summary> | ||
| /// The maximum number of selections. | ||
| /// </summary> | ||
| [JsonProperty("max_values", NullValueHandling = NullValueHandling.Ignore)] | ||
| public int? MaximumValues { get; internal set; } | ||
|
|
||
| /// <summary> | ||
| /// Whether the component requires a selection. | ||
| /// </summary> | ||
| [JsonProperty("required", NullValueHandling = NullValueHandling.Ignore)] | ||
| public bool? Required { get; internal set; } | ||
|
|
||
| /// <summary> | ||
| /// The submitted values. Present on modal submit interactions. | ||
| /// </summary> | ||
| [JsonProperty("values", NullValueHandling = NullValueHandling.Ignore)] | ||
| public string[]? Values { get; internal set; } | ||
|
|
||
| /// <summary> | ||
| /// Assigns a unique id to this component. | ||
| /// </summary> | ||
| /// <param name="id">The id to assign.</param> | ||
| public DiscordCheckboxGroupComponent WithId(int id) | ||
| { | ||
| this.Id = id; | ||
| return this; | ||
| } | ||
| } |
61 changes: 61 additions & 0 deletions
61
DisCatSharp/Entities/Components/V2Components/DiscordCheckboxGroupComponentOption.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,61 @@ | ||
| using System; | ||
|
|
||
| using Newtonsoft.Json; | ||
|
|
||
| namespace DisCatSharp.Entities; | ||
|
|
||
| /// <summary> | ||
| /// Represents an option within a checkbox group component. | ||
| /// </summary> | ||
| public sealed class DiscordCheckboxGroupComponentOption : ObservableApiObject | ||
| { | ||
| /// <summary> | ||
| /// Creates a new checkbox group option. | ||
| /// </summary> | ||
| /// <param name="label">The display label. Max 100 characters.</param> | ||
| /// <param name="value">The option value. Max 100 characters.</param> | ||
| /// <param name="description">An optional description. Max 100 characters.</param> | ||
| /// <param name="isDefault">Whether this option should be selected by default.</param> | ||
| public DiscordCheckboxGroupComponentOption(string label, string value, string? description = null, bool isDefault = false) | ||
| { | ||
| if (string.IsNullOrWhiteSpace(label)) | ||
| throw new ArgumentException("Label must be provided.", nameof(label)); | ||
| if (string.IsNullOrWhiteSpace(value)) | ||
| throw new ArgumentException("Value must be provided.", nameof(value)); | ||
| if (label.Length > 100) | ||
| throw new ArgumentException("Option label cannot exceed 100 characters.", nameof(label)); | ||
| if (value.Length > 100) | ||
| throw new ArgumentException("Option value cannot exceed 100 characters.", nameof(value)); | ||
| if (description is { Length: > 100 }) | ||
| throw new ArgumentException("Option description cannot exceed 100 characters.", nameof(description)); | ||
|
|
||
| this.Label = label; | ||
| this.Value = value; | ||
| this.Description = description; | ||
| this.Default = isDefault; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// The display label. | ||
| /// </summary> | ||
| [JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)] | ||
| public string Label { get; internal set; } | ||
|
|
||
| /// <summary> | ||
| /// The underlying value returned on submit. | ||
| /// </summary> | ||
| [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] | ||
| public string Value { get; internal set; } | ||
|
|
||
| /// <summary> | ||
| /// Optional helper text. | ||
| /// </summary> | ||
| [JsonProperty("description", NullValueHandling = NullValueHandling.Ignore)] | ||
| public string? Description { get; internal set; } | ||
|
|
||
| /// <summary> | ||
| /// Whether this option is pre-selected. | ||
| /// </summary> | ||
| [JsonProperty("default", NullValueHandling = NullValueHandling.Ignore)] | ||
| public bool Default { get; internal set; } | ||
| } |
78 changes: 78 additions & 0 deletions
78
DisCatSharp/Entities/Components/V2Components/DiscordRadioGroupComponent.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,78 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
|
|
||
| using DisCatSharp.Enums; | ||
|
|
||
| using Newtonsoft.Json; | ||
|
|
||
| namespace DisCatSharp.Entities; | ||
|
|
||
| /// <summary> | ||
| /// Represents a radio group component. Modal-only. | ||
| /// </summary> | ||
| public sealed class DiscordRadioGroupComponent : DiscordComponent, ILabelComponent | ||
| { | ||
| /// <summary> | ||
| /// Creates a new empty radio group component. | ||
| /// </summary> | ||
| internal DiscordRadioGroupComponent() | ||
| { | ||
| this.Type = ComponentType.RadioGroup; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Creates a new radio group component with the provided options. | ||
| /// </summary> | ||
| /// <param name="options">The selectable options. Must contain between 2 and 10 entries.</param> | ||
| /// <param name="customId">The custom id for this component.</param> | ||
| /// <param name="required">Whether a selection is required.</param> | ||
| public DiscordRadioGroupComponent(IEnumerable<DiscordRadioGroupComponentOption> options, string? customId = null, bool? required = null) | ||
| : this() | ||
| { | ||
| ArgumentNullException.ThrowIfNull(options); | ||
| var optionList = options.ToList(); | ||
| if (optionList.Count is < 2 or > 10) | ||
| throw new ArgumentException("Radio groups must include between 2 and 10 options."); | ||
| if (optionList.Count(x => x.Default) > 1) | ||
| throw new ArgumentException("Only one radio option can be marked as default."); | ||
|
|
||
| this.CustomId = customId ?? Guid.NewGuid().ToString(); | ||
| this.Options = optionList; | ||
| this.Required = required; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// The custom id for this component. | ||
| /// </summary> | ||
| [JsonProperty("custom_id", NullValueHandling = NullValueHandling.Ignore)] | ||
| public override string? CustomId { get; internal set; } = Guid.NewGuid().ToString(); | ||
|
|
||
| /// <summary> | ||
| /// The available options. | ||
| /// </summary> | ||
| [JsonProperty("options", NullValueHandling = NullValueHandling.Ignore)] | ||
| public IReadOnlyList<DiscordRadioGroupComponentOption> Options { get; internal set; } = Array.Empty<DiscordRadioGroupComponentOption>(); | ||
|
|
||
| /// <summary> | ||
| /// Whether the component requires a selection. | ||
| /// </summary> | ||
| [JsonProperty("required", NullValueHandling = NullValueHandling.Ignore)] | ||
| public bool? Required { get; internal set; } | ||
|
|
||
| /// <summary> | ||
| /// The submitted value. Present on modal submit interactions. | ||
| /// </summary> | ||
| [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] | ||
| public string? SelectedValue { get; internal set; } | ||
|
|
||
| /// <summary> | ||
| /// Assigns a unique id to this component. | ||
| /// </summary> | ||
| /// <param name="id">The id to assign.</param> | ||
| public DiscordRadioGroupComponent WithId(int id) | ||
| { | ||
| this.Id = id; | ||
| return this; | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
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.