Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
211ade1
add channel types to channel select builder and info
Cenngo Jan 3, 2026
0d5b167
add channelTypes to select builder from IModal
Cenngo Jan 3, 2026
d6401d6
remove public setter requirement from modal component definition and …
Cenngo Jan 3, 2026
49d1106
refactor modal building to run typeConverter writes even without moda…
Cenngo Jan 3, 2026
fc0c643
add inline docs to channelTypes props and method
Cenngo Jan 3, 2026
ae8dd3b
add property as a target for ChannelTypesAttribute
Cenngo Jan 5, 2026
e917861
move enum option building logic out of enum typeConverter
Cenngo Jan 5, 2026
a49fb5b
add channel type constraint mapping to channel single-select typeConv…
Cenngo Jan 5, 2026
a59db13
move SelectMenuOptionAttribute to its own file
Cenngo Jan 5, 2026
00cb8dc
add null forgiving operator to channel type mapping
Cenngo Jan 5, 2026
704ba8b
remove list initialization from enum modal typeConverter
Cenngo Jan 5, 2026
fe14bd8
disallow channel default value assignment to mentionable selects
Cenngo Jan 5, 2026
d22baa9
add id property to modal components
Cenngo Jan 15, 2026
9527060
add component id assignment from attributes
Cenngo Jan 18, 2026
1695390
update component attribute ctor signatures and inline docs
Cenngo Jan 18, 2026
a50db7b
Update src/Discord.Net.Interactions/TypeConverters/ModalComponents/En…
Cenngo Jan 18, 2026
3b3cc1c
replace default values of component ids with 0
Cenngo Jan 22, 2026
f794c99
Merge remote-tracking branch 'origin/fix/modal-write-invocation' into…
Cenngo Jan 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Discord.Interactions
/// <summary>
/// Specify the target channel types for a <see cref="ApplicationCommandOptionType.Channel"/> option.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class ChannelTypesAttribute : Attribute
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,9 @@ public class ModalChannelSelectAttribute : ModalSelectComponentAttribute
/// Create a new <see cref="ModalChannelSelectAttribute"/>.
/// </summary>
/// <param name="customId">Custom ID of the channel select component.</param>
public ModalChannelSelectAttribute(string customId, int minValues = 1, int maxValues = 1) : base(customId, minValues, maxValues) { }
/// <param name="minValues">The minimum number of values that can be selected.</param>
/// <param name="maxValues">The maximum number of values that can be selected.</param>
/// <param name="id">Optional identifier for the component.</param>
public ModalChannelSelectAttribute(string customId, int minValues = 1, int maxValues = 1, int id = 0)
: base(customId, minValues, maxValues, id) { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,16 @@ public abstract class ModalComponentAttribute : Attribute
/// </summary>
public abstract ComponentType ComponentType { get; }

internal ModalComponentAttribute() { }
/// <summary>
/// Gets the optional identifier for component.
/// </summary>
/// <remarks>
/// Sending components with an id of 0 is allowed but will be treated as empty and replaced by the API.
/// </remarks>
public int Id { get; set; }

internal ModalComponentAttribute(int id = 0)
{
Id = id;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ public class ModalFileUploadAttribute : ModalInputAttribute
/// <param name="customId">Custom ID of the file upload component.</param>
/// <param name="minValues">Minimum number of files that can be uploaded.</param>
/// <param name="maxValues">Maximum number of files that can be uploaded.</param>
public ModalFileUploadAttribute(string customId, int minValues = 1, int maxValues = 1) : base(customId)
/// <param name="id">The optional identifier for the component.</param>
public ModalFileUploadAttribute(string customId, int minValues = 1, int maxValues = 1, int id = 0)
: base(customId, id)
{
MinValues = minValues;
MaxValues = maxValues;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ public abstract class ModalInputAttribute : ModalComponentAttribute
/// Create a new <see cref="ModalInputAttribute"/>.
/// </summary>
/// <param name="customId">The custom id of the input.</param>
internal ModalInputAttribute(string customId)
/// <param name="id">Optional identifier for component.</param>
internal ModalInputAttribute(string customId, int id) : base(id)
{
CustomId = customId;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ public class ModalMentionableSelectAttribute : ModalSelectComponentAttribute
/// <param name="customId">Custom ID of the mentionable select component.</param>
/// <param name="minValues">Minimum number of values that can be selected.</param>
/// <param name="maxValues">Maximum number of values that can be selected</param>
public ModalMentionableSelectAttribute(string customId, int minValues = 1, int maxValues = 1) : base(customId, minValues, maxValues) { }
/// <param name="id">The optional identifier for the component.</param>
public ModalMentionableSelectAttribute(string customId, int minValues = 1, int maxValues = 1, int id = 0)
: base(customId, minValues, maxValues, id) { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ public class ModalRoleSelectAttribute : ModalSelectComponentAttribute
/// <param name="customId">Custom ID of the role select component.</param>
/// <param name="minValues">Minimum number of values that can be selected.</param>
/// <param name="maxValues">Maximum number of values that can be selected.</param>
public ModalRoleSelectAttribute(string customId, int minValues = 1, int maxValues = 1) : base(customId, minValues, maxValues) { }
/// <param name="id">The optional identifier for the component.</param>
public ModalRoleSelectAttribute(string customId, int minValues = 1, int maxValues = 1, int id = 0)
: base(customId, minValues, maxValues, id) { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public abstract class ModalSelectComponentAttribute : ModalInputAttribute
/// </summary>
public string Placeholder { get; set; }

internal ModalSelectComponentAttribute(string customId, int minValues = 1, int maxValues = 1) : base(customId)
internal ModalSelectComponentAttribute(string customId, int minValues = 1, int maxValues = 1, int id = 0)
: base(customId, id)
{
MinValues = minValues;
MaxValues = maxValues;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ public sealed class ModalSelectMenuAttribute : ModalSelectComponentAttribute
/// <param name="customId">Custom ID of the select menu component.</param>
/// <param name="minValues">Minimum number of values that can be selected.</param>
/// <param name="maxValues">Maximum number of values that can be selected.</param>
public ModalSelectMenuAttribute(string customId, int minValues = 1, int maxValues = 1) : base(customId, minValues, maxValues) { }
/// <param name="id">The optional identifier for the component.</param>
public ModalSelectMenuAttribute(string customId, int minValues = 1, int maxValues = 1, int id = 0)
: base(customId, minValues, maxValues, id) { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ public class ModalTextDisplayAttribute : ModalComponentAttribute
/// Create a new <see cref="ModalTextInputAttribute"/>.
/// </summary>
/// <param name="content">Content of the text display.</param>
public ModalTextDisplayAttribute(string content = null)
/// <param name="id">Optional identifier for component.</param>
public ModalTextDisplayAttribute(string content = null, int id = 0)
: base(id)
{
Content = content;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,27 @@ public sealed class ModalTextInputAttribute : ModalInputAttribute
/// <summary>
/// Gets the style of the text input.
/// </summary>
public TextInputStyle Style { get; }
public TextInputStyle Style { get; set; }

/// <summary>
/// Gets the placeholder of the text input.
/// </summary>
public string Placeholder { get; }
public string Placeholder { get; set; }

/// <summary>
/// Gets the minimum length of the text input.
/// </summary>
public int MinLength { get; }
public int MinLength { get; set; }

/// <summary>
/// Gets the maximum length of the text input.
/// </summary>
public int MaxLength { get; }
public int MaxLength { get; set; }

/// <summary>
/// Gets the initial value to be displayed by this input.
/// </summary>
public string InitialValue { get; }
public string InitialValue { get; set; }

/// <summary>
/// Create a new <see cref="ModalTextInputAttribute"/>.
Expand All @@ -42,8 +42,9 @@ public sealed class ModalTextInputAttribute : ModalInputAttribute
/// <param name="minLength">The minimum length of the text input's content.</param>
/// <param name="maxLength">The maximum length of the text input's content.</param>
/// <param name="initValue">The initial value to be displayed by this input.</param>
public ModalTextInputAttribute(string customId, TextInputStyle style = TextInputStyle.Short, string placeholder = null, int minLength = 1, int maxLength = 4000, string initValue = null)
: base(customId)
/// <param name="id">The optional identifier for the component.</param>
public ModalTextInputAttribute(string customId, TextInputStyle style = TextInputStyle.Short, string placeholder = null, int minLength = 1, int maxLength = 4000, string initValue = null, int id = 0)
: base(customId, id)
{
Style = style;
Placeholder = placeholder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ public class ModalUserSelectAttribute : ModalSelectComponentAttribute
/// <param name="customId">Custom ID of the user select component.</param>
/// <param name="minValues">Minimum number of values that can be selected.</param>
/// <param name="maxValues">Maximum number of values that can be selected.</param>
public ModalUserSelectAttribute(string customId, int minValues = 1, int maxValues = 1) : base(customId, minValues, maxValues) { }
/// <param name="id">The optional identifier for the component.</param>
public ModalUserSelectAttribute(string customId, int minValues = 1, int maxValues = 1, int id = 0)
: base(customId, minValues, maxValues, id) { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;

namespace Discord.Interactions;

/// <summary>
/// Adds additional metadata to enum fields that are used for select-menus.
/// </summary>
/// <remarks>
/// To manually add select menu options to modal components, use <see cref="ModalSelectMenuOptionAttribute"/> instead.
/// </remarks>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public class SelectMenuOptionAttribute : Attribute
{
/// <summary>
/// Gets or sets the desription of the option.
/// </summary>
public string Description { get; set; }

/// <summary>
/// Gets or sets whether the option is selected by default.
/// </summary>
public bool IsDefault { get; set; }

/// <summary>
/// Gets or sets the emote of the option.
/// </summary>
/// <remarks>
/// Can be either an <see cref="Emoji"/> or an <see cref="Discord.Emote"/>
/// </remarks>
public string Emote { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@ namespace Discord.Interactions.Builders;
/// </summary>
public class ChannelSelectComponentBuilder : SnowflakeSelectComponentBuilder<ChannelSelectComponentInfo, ChannelSelectComponentBuilder>
{
private readonly List<ChannelType> _channelTypes = new();

protected override ChannelSelectComponentBuilder Instance => this;

/// <summary>
/// Gets the presented channel types for this Channel Select.
/// </summary>
public IReadOnlyCollection<ChannelType> ChannelTypes => _channelTypes.AsReadOnly();

/// <summary>
/// Initializes a new <see cref="ChannelSelectComponentBuilder"/>.
/// </summary>
Expand Down Expand Up @@ -42,6 +49,19 @@ public ChannelSelectComponentBuilder AddDefaultValues(params IEnumerable<IChanne
return this;
}

/// <summary>
/// Sets the value of <see cref="ChannelTypes"/>.
/// </summary>
/// <param name="channelTypes">the new value of <see cref="ChannelTypes"/>.</param>
/// <returns>
/// The builder instance.
/// </returns>
public ChannelSelectComponentBuilder WithChannelTypes(params IEnumerable<ChannelType> channelTypes)
{
_channelTypes.AddRange(channelTypes);
return this;
}

internal override ChannelSelectComponentInfo Build(ModalInfo modal)
=> new(this, modal);
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ public interface IModalComponentBuilder
/// </summary>
object DefaultValue { get; }

/// <summary>
/// Gets the optional identifier for component.
/// </summary>
/// <remarks>
/// Sending components with an id of 0 is allowed but will be treated as empty and replaced by the API.
/// </remarks>
int Id { get; }

/// <summary>
/// Gets a collection of the attributes of this component.
/// </summary>
Expand Down Expand Up @@ -62,4 +70,13 @@ public interface IModalComponentBuilder
/// The builder instance.
/// </returns>
IModalComponentBuilder WithAttributes(params Attribute[] attributes);

/// <summary>
/// Sets <see cref="Id"/>.
/// </summary>
/// <param name="id">New value of the <see cref="Id"/>.</param>
/// <returns>
/// The builder instance.
/// </returns>
IModalComponentBuilder WithId(int id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public abstract class ModalComponentBuilder<TInfo, TBuilder> : IModalComponentBu
/// <inheritdoc/>
public object DefaultValue { get; set; }

/// <inheritdoc/>
public int Id { get; set; }

/// <inheritdoc/>
public IReadOnlyCollection<Attribute> Attributes => _attributes;

Expand Down Expand Up @@ -87,6 +90,19 @@ public virtual TBuilder WithAttributes(params Attribute[] attributes)
return Instance;
}

/// <summary>
/// Sets <see cref="Id"/>.
/// </summary>
/// <param name="id">New value of the <see cref="Id"/>.</param>
/// <returns>
/// The builder instance.
/// </returns>
public virtual TBuilder WithId(int id)
{
Id = id;
return Instance;
}

internal abstract TInfo Build(ModalInfo modal);

/// <inheritdoc/>
Expand All @@ -97,4 +113,7 @@ public virtual TBuilder WithAttributes(params Attribute[] attributes)

/// <inheritdoc/>
IModalComponentBuilder IModalComponentBuilder.WithAttributes(params Attribute[] attributes) => WithAttributes(attributes);

/// <inheritdoc/>
IModalComponentBuilder IModalComponentBuilder.WithId(int id) => WithId(id);
}
Loading