Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
a7cf032
feat(flags): add new message flag
shiftinv Jan 9, 2025
9becf08
feat(enums): add new component types
shiftinv Jan 9, 2025
215f37f
feat(types): add `id` field to all component types
shiftinv Jan 9, 2025
91325ed
feat(types): add typeddicts for new components
shiftinv Jan 9, 2025
c5084d8
chore: add some comments from testing
shiftinv Jan 9, 2025
cf74701
fix: thumbnail media field has been renamed now
shiftinv Jan 25, 2025
bd96624
chore: update comment now that sections allow buttons too
shiftinv Feb 4, 2025
e06c077
fix: make `SectionComponent.components` typing more permissive
shiftinv Feb 20, 2025
f2f2817
feat: add `SeparatorSpacingSize` enum
shiftinv Feb 20, 2025
93902f5
feat(components): implement new component classes roughly
shiftinv Feb 20, 2025
7765c46
fix(components): rename `components.File` -> `components.FileComponen…
shiftinv Feb 20, 2025
0222377
feat: add new components to factory function
shiftinv Feb 20, 2025
9bb4013
fix: improve `Container` repr
shiftinv Feb 20, 2025
928033c
refactor: rename existing action row component type aliases
shiftinv Feb 21, 2025
b37c87c
perf: use mapping for `_component_factory`
shiftinv Feb 21, 2025
ff6c20d
refactor: make child component typehints more specific
shiftinv Feb 21, 2025
2522af4
chore: move some TODOs
shiftinv Feb 21, 2025
103c1c2
docs: add docstrings for new components
shiftinv Feb 21, 2025
a363451
feat(types): make child component types for `ActionRow` and `SectionC…
shiftinv Feb 21, 2025
3cfcdd0
fix(typing): resolve pyright complaints related to `Message.components`
shiftinv Feb 21, 2025
7cd06f0
refactor(typing): expand `Message.components` type beyond just `Actio…
shiftinv Feb 21, 2025
82eb456
fix: update relevant methods to account for new `Message.components` …
shiftinv Feb 22, 2025
a7c2648
feat: add `id` field to message/modal interaction data
shiftinv Mar 6, 2025
891ca40
refactor: introduce yet another ui base type, for non-actionrow-child…
shiftinv Mar 8, 2025
bd2865a
feat(ui): add new ui components, still partially broken
shiftinv Mar 15, 2025
222f513
refactor(ui): rework section and container to actually be usable
shiftinv Mar 15, 2025
962c5d7
docs: add ui components to docs, fix references
shiftinv Mar 15, 2025
a95e1b2
fix(ui): fix `MediaGallery` parameter type
shiftinv Mar 15, 2025
6198aa6
refactor(types): move action row types to `ui._types`, add some short…
shiftinv Mar 15, 2025
0ded39d
feat(types): add new components to `MessageComponentInput` union
shiftinv Mar 15, 2025
2ad9e10
feat: support v2 components in `normalize_components`/`components_to_…
shiftinv Apr 18, 2025
58b6045
docs: add changelog entry
shiftinv Apr 18, 2025
69591bf
fix: make `ActionRow` subclass `UIComponent`
shiftinv Jun 9, 2025
a8fb923
chore: rename `(Message|Modal)ComponentInput` utility type to `(Messa…
shiftinv Jun 9, 2025
95ac094
chore(typing): declare `__repr_attributes__` in components as classvars
shiftinv Jun 9, 2025
3dd1aa7
chore: clarify name of action row child type tuple
shiftinv Jun 9, 2025
61cb394
refactor: try/catch component_factory
shiftinv Jun 9, 2025
567a685
fix(types): `typing.TypeAlias` is 3.10+
shiftinv Jun 9, 2025
23ac2e1
perf: reduce `_message_component_factory` call overhead
shiftinv Jun 11, 2025
7bee2ce
fix: support reused components in `_walk_all_components`
shiftinv Jun 11, 2025
3f5dbf2
Merge remote-tracking branch 'upstream/master' into feature/component…
shiftinv Jul 16, 2025
b400868
chore: update comment re PEP 705 in component types
shiftinv Jul 16, 2025
dfa793e
docs: update SeparatorSpacingSize member docstrings
shiftinv Jul 16, 2025
8f442fa
fix: remove undocumented `MessageInteractionData.id`
shiftinv Jul 16, 2025
a524626
feat: strip leading underscores in `ui.Item` repr keys
shiftinv Jul 16, 2025
c108dd3
fix: it's not a bug, it's a feature (empty action rows are now meant …
shiftinv Jul 16, 2025
b3a4894
fix(typing): add missing `[Any]` to buttons in sections
shiftinv Jul 16, 2025
a308569
chore(docs): copy -> proxy
shiftinv Jul 16, 2025
a362a74
docs: finish list of `Component` subclasses
shiftinv Jul 16, 2025
12da63d
refactor: make primary `ui.Thumbnail` parameters positional
shiftinv Aug 7, 2025
9978a04
feat: implement `UnfurledMediaItem`
shiftinv Aug 7, 2025
b744af8
feat: support `Attachment` and `AssetMixin` for component media items
shiftinv Aug 8, 2025
a01e35b
docs: clarify `attachment://` urls
shiftinv Aug 8, 2025
6c4dccc
feat: implement `Component.id`
shiftinv Aug 8, 2025
137db4c
feat: implement `.id` in ui component types
shiftinv Aug 9, 2025
97b1b64
fix: add missing `id` param to decorators + `ActionRow.add_*`
shiftinv Aug 9, 2025
035e036
test: fix broken `components_to_dict` test
shiftinv Aug 9, 2025
4958265
docs: note that `id` must be unique per message
shiftinv Aug 9, 2025
41cc252
fix(types): add `id` to `ModalInteractionActionRow` typeddict
shiftinv Aug 9, 2025
932982c
chore(docs): rephrase `id` default note
shiftinv Aug 9, 2025
3edad5c
fix(docs): add AssetMixin + Attachment to supported media input types
shiftinv Aug 9, 2025
81801a3
fix(docs): `AssetMixin` isn't documented, `Asset` is fine for now.
shiftinv Aug 9, 2025
465feca
refactor: move `handle_media_item_input` to .components
shiftinv Aug 10, 2025
c6a7804
feat: make `MediaGalleryItem` user-instantiable
shiftinv Aug 10, 2025
8d3fe20
docs: clarify `Separator.spacing` description
shiftinv Aug 11, 2025
ae8e4c9
fix: raise if `ui.File` media url is not an `attachment://`
shiftinv Aug 11, 2025
2dc64f0
fix: raise TypeError in `handle_media_item_input` for invalid inputs
shiftinv Aug 11, 2025
ea3c67a
feat: remove `Section./Container.components` attribute proxy
shiftinv Aug 11, 2025
f1e86d3
feat: add `str()` cast to `TextDisplay.content`, matching embed behavior
shiftinv Aug 11, 2025
9b812f9
chore: remove + update TODOs
shiftinv Aug 11, 2025
44bc2a9
test: expand `normalize_components` test for v2
shiftinv Aug 13, 2025
e3d66c9
fix: duplicate call in `File.file` setter, oops
shiftinv Aug 13, 2025
79b0ef8
chore: move `MediaItemInput` type alias out of type-checking-only block
shiftinv Aug 13, 2025
9b0d216
fix: clarify `ui.File` error regarding local files
shiftinv Aug 13, 2025
ee83dc9
fix(docs): add missing media attribute descriptions in `Thumbnail` + …
shiftinv Aug 13, 2025
bf3f2ce
feat: add `File.name/.size`, provided by api
shiftinv Aug 13, 2025
4e66b18
feat: add `ui.walk_components`
shiftinv Aug 19, 2025
2107734
fix: include name+size in `FileComponent._raw_construct` call
shiftinv Aug 19, 2025
4d3bc25
feat: add public `components_from_message` method, and `from_componen…
shiftinv Aug 19, 2025
3fca8c2
docs: add links to v2 versions of `ActionRow.rows_from_message/.walk_…
shiftinv Aug 19, 2025
159a09f
fix: retain other media fields in `ui.File.from_component`
shiftinv Aug 19, 2025
c83465d
fix: attach state to `UnfurledMediaItem`s when creating components fr…
shiftinv Aug 19, 2025
a385833
sec: don't pass `state` for the time being
shiftinv Aug 19, 2025
56d495f
fix: attach state to media again, fetch from `proxy_url` instead
shiftinv Aug 19, 2025
568809d
revert: remove all `AssetMixin` stuff from `UnfurledMediaItem`
shiftinv Aug 19, 2025
79b58bb
feat: add `ui.Container.accent_color` alias
shiftinv Aug 20, 2025
530f3f9
chore: remove resolved/unnecessary `TODO`s
shiftinv Aug 20, 2025
69d03bd
docs: add `id` attribute description to core components
shiftinv Aug 20, 2025
6634885
docs: document limits of Section and MediaGallery items
shiftinv Aug 20, 2025
ef63a6c
refactor: rename `SeparatorSpacingSize` -> `SeparatorSpacing`
shiftinv Aug 20, 2025
e906012
refactor!: rename `Section./Container.components` to `children` to ma…
shiftinv Aug 20, 2025
b95ed4c
feat: add `Component.is_v2` attribute
shiftinv Aug 20, 2025
f705ef6
feat: automatically set `is_components_v2` flag when sending v2 compo…
shiftinv Aug 20, 2025
ee9816b
Merge remote-tracking branch 'upstream/master' into feature/component…
shiftinv Aug 22, 2025
31925f1
fix: handle `flags` in `InteractionResponse.edit_message` properly
shiftinv Aug 22, 2025
1de2a54
docs: update `components` parameter descriptions re cv2
shiftinv Aug 22, 2025
8fc2087
docs: add `is_components_v2` flag to `flags` parameter description
shiftinv Aug 22, 2025
479f438
docs: remove module prefix from `|components_type|` shortcut
shiftinv Aug 22, 2025
9a566f9
fix: keep previous flags when editing message with v2 components
shiftinv Aug 23, 2025
538fefb
feat: set `?with_components=1` on webhook requests by default
shiftinv Aug 23, 2025
90d6c2b
chore: remove more obsolete TODOs
shiftinv Aug 23, 2025
3ab6961
chore(docs): copy over missing component descriptions
shiftinv Aug 23, 2025
7f4a8e2
feat: add `ui.Section(str)` qol shortcut
shiftinv Aug 23, 2025
3afe3fc
docs: add examples/components_v2.py
shiftinv Aug 23, 2025
830343e
docs: finish changelog
shiftinv Aug 23, 2025
50c8d55
chore(docs): fix reference in changelog
shiftinv Aug 23, 2025
2250cae
Merge remote-tracking branch 'upstream/master' into feature/component…
shiftinv Aug 23, 2025
25a1ad3
Merge branch 'master' into feature/components-v2
shiftinv Aug 24, 2025
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
14 changes: 14 additions & 0 deletions changelog/1294.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Add support for :ddocs:`components v2 <components/reference>` (`example <https://github.com/DisnakeDev/disnake/blob/master/examples/components_v2.py>`_):
- These components allow you to have more control over the layout of your messages, and are used instead of the classic ``content`` and ``embeds`` fields.
- New top-level components:
- :class:`ui.Section`: Displays an accessory (:class:`ui.Thumbnail` or :class:`ui.Button`) alongside some text.
- :class:`ui.TextDisplay`: Text component, similar to the ``content`` field of messages.
- :class:`ui.MediaGallery`: A gallery/mosaic of up to 10 :class:`MediaGalleryItem`\s.
- :class:`ui.File`: Display an uploaded file as an attachment.
- :class:`ui.Separator`: A spacer/separator adding vertical padding.
- :class:`ui.Container`: Contains other components, visually similar to :class:`Embed`\s.
- Each component has a corresponding new :class:`ComponentType`.
- New :attr:`MessageFlags.is_components_v2` flag. This is set automatically when sending v2 components, and cannot be reverted once set.
- New :func:`ui.walk_components` and :func:`ui.components_from_message` utility functions.
- All ``ui.*`` components now inherit from a common :class:`ui.UIComponent` base class.
- Components now have an :attr:`~ui.UIComponent.id` attribute, which is a unique (per-message) optional numeric identifier.
45 changes: 30 additions & 15 deletions disnake/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
PermissionOverwrite as PermissionOverwritePayload,
)
from .types.threads import PartialForumTag as PartialForumTagPayload
from .ui.action_row import Components, MessageUIComponent
from .ui._types import MessageComponents
from .ui.view import View
from .user import ClientUser
from .voice_region import VoiceRegion
Expand Down Expand Up @@ -1442,7 +1442,7 @@ async def send(
reference: Union[Message, MessageReference, PartialMessage] = ...,
mention_author: bool = ...,
view: View = ...,
components: Components[MessageUIComponent] = ...,
components: MessageComponents = ...,
poll: Poll = ...,
) -> Message: ...

Expand All @@ -1463,7 +1463,7 @@ async def send(
reference: Union[Message, MessageReference, PartialMessage] = ...,
mention_author: bool = ...,
view: View = ...,
components: Components[MessageUIComponent] = ...,
components: MessageComponents = ...,
poll: Poll = ...,
) -> Message: ...

Expand All @@ -1484,7 +1484,7 @@ async def send(
reference: Union[Message, MessageReference, PartialMessage] = ...,
mention_author: bool = ...,
view: View = ...,
components: Components[MessageUIComponent] = ...,
components: MessageComponents = ...,
poll: Poll = ...,
) -> Message: ...

Expand All @@ -1505,7 +1505,7 @@ async def send(
reference: Union[Message, MessageReference, PartialMessage] = ...,
mention_author: bool = ...,
view: View = ...,
components: Components[MessageUIComponent] = ...,
components: MessageComponents = ...,
poll: Poll = ...,
) -> Message: ...

Expand All @@ -1527,7 +1527,7 @@ async def send(
reference: Optional[Union[Message, MessageReference, PartialMessage]] = None,
mention_author: Optional[bool] = None,
view: Optional[View] = None,
components: Optional[Components[MessageUIComponent]] = None,
components: Optional[MessageComponents] = None,
poll: Optional[Poll] = None,
):
"""|coro|
Expand All @@ -1540,8 +1540,8 @@ async def send(
``stickers``, ``components``, ``poll`` or ``view`` must be provided.

To upload a single file, the ``file`` parameter should be used with a
single :class:`.File` object. To upload multiple files, the ``files``
parameter should be used with a :class:`list` of :class:`.File` objects.
single :class:`~disnake.File` object. To upload multiple files, the ``files``
parameter should be used with a :class:`list` of :class:`~disnake.File` objects.
**Specifying both parameters will lead to an exception**.

To upload a single embed, the ``embed`` parameter should be used with a
Expand All @@ -1567,9 +1567,9 @@ async def send(

.. versionadded:: 2.0

file: :class:`.File`
file: :class:`~disnake.File`
The file to upload. This cannot be mixed with the ``files`` parameter.
files: List[:class:`.File`]
files: List[:class:`~disnake.File`]
A list of files to upload. Must be a maximum of 10.
This cannot be mixed with the ``file`` parameter.
stickers: Sequence[Union[:class:`.GuildSticker`, :class:`.StandardSticker`, :class:`.StickerItem`]]
Expand Down Expand Up @@ -1623,6 +1623,11 @@ async def send(

.. versionadded:: 2.4

.. note::
Passing v2 components here automatically sets the :attr:`~.MessageFlags.is_components_v2` flag.
Setting this flag cannot be reverted. Note that this also disables the
``content``, ``embeds``, ``stickers``, and ``poll`` fields.

suppress_embeds: :class:`bool`
Whether to suppress embeds for the message. This hides
all the embeds from the UI if set to ``True``.
Expand All @@ -1631,8 +1636,8 @@ async def send(

flags: :class:`.MessageFlags`
The flags to set for this message.
Only :attr:`~.MessageFlags.suppress_embeds` and :attr:`~.MessageFlags.suppress_notifications`
are supported.
Only :attr:`~.MessageFlags.suppress_embeds`, :attr:`~.MessageFlags.suppress_notifications`,
and :attr:`~.MessageFlags.is_components_v2` are supported.

If parameter ``suppress_embeds`` is provided,
that will override the setting of :attr:`.MessageFlags.suppress_embeds`.
Expand All @@ -1657,7 +1662,8 @@ async def send(
or the ``reference`` object is not a :class:`.Message`,
:class:`.MessageReference` or :class:`.PartialMessage`.
ValueError
The ``files`` or ``embeds`` list is too large.
The ``files`` or ``embeds`` list is too large, or
you tried to send v2 components together with ``content``, ``embeds``, ``stickers``, or ``poll``.

Returns
-------
Expand Down Expand Up @@ -1721,19 +1727,28 @@ async def send(
"reference parameter must be Message, MessageReference, or PartialMessage"
) from None

is_v2 = False
if view is not None and components is not None:
raise TypeError("cannot pass both view and components parameter to send()")
elif view:
if not hasattr(view, "__discord_ui_view__"):
raise TypeError(f"view parameter must be View not {view.__class__!r}")
components_payload = view.to_components()
elif components:
from .ui.action_row import components_to_dict
from .ui.action_row import normalize_components_to_dict

components_payload = components_to_dict(components)
components_payload, is_v2 = normalize_components_to_dict(components)
else:
components_payload = None

# set cv2 flag automatically
if is_v2:
flags = MessageFlags._from_value(0 if flags is None else flags.value)
flags.is_components_v2 = True
# components v2 cannot be used with other content fields
if flags and flags.is_components_v2 and (content or embeds or stickers or poll):
raise ValueError("Cannot use v2 components with content, embeds, stickers, or polls")

flags_payload = None
if suppress_embeds is not None:
flags = MessageFlags._from_value(0 if flags is None else flags.value)
Expand Down
31 changes: 19 additions & 12 deletions disnake/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
from .types.soundboard import PartialSoundboardSound as PartialSoundboardSoundPayload
from .types.threads import ThreadArchiveDurationLiteral
from .types.voice import VoiceChannelEffect as VoiceChannelEffectPayload
from .ui.action_row import Components, MessageUIComponent
from .ui._types import MessageComponents
from .ui.view import View
from .user import BaseUser, ClientUser, User
from .voice_region import VoiceRegion
Expand Down Expand Up @@ -3522,7 +3522,7 @@ async def create_thread(
stickers: Sequence[Union[GuildSticker, StandardSticker, StickerItem]] = ...,
allowed_mentions: AllowedMentions = ...,
view: View = ...,
components: Components = ...,
components: MessageComponents = ...,
reason: Optional[str] = None,
) -> ThreadWithMessage: ...

Expand All @@ -3542,7 +3542,7 @@ async def create_thread(
stickers: Sequence[Union[GuildSticker, StandardSticker, StickerItem]] = ...,
allowed_mentions: AllowedMentions = ...,
view: View = ...,
components: Components = ...,
components: MessageComponents = ...,
reason: Optional[str] = None,
) -> ThreadWithMessage: ...

Expand All @@ -3562,7 +3562,7 @@ async def create_thread(
stickers: Sequence[Union[GuildSticker, StandardSticker, StickerItem]] = ...,
allowed_mentions: AllowedMentions = ...,
view: View = ...,
components: Components = ...,
components: MessageComponents = ...,
reason: Optional[str] = None,
) -> ThreadWithMessage: ...

Expand All @@ -3582,7 +3582,7 @@ async def create_thread(
stickers: Sequence[Union[GuildSticker, StandardSticker, StickerItem]] = ...,
allowed_mentions: AllowedMentions = ...,
view: View = ...,
components: Components = ...,
components: MessageComponents = ...,
reason: Optional[str] = None,
) -> ThreadWithMessage: ...

Expand All @@ -3603,7 +3603,7 @@ async def create_thread(
stickers: Sequence[Union[GuildSticker, StandardSticker, StickerItem]] = MISSING,
allowed_mentions: AllowedMentions = MISSING,
view: View = MISSING,
components: Components[MessageUIComponent] = MISSING,
components: MessageComponents = MISSING,
reason: Optional[str] = None,
) -> ThreadWithMessage:
"""|coro|
Expand Down Expand Up @@ -3656,16 +3656,17 @@ async def create_thread(
all the embeds from the UI if set to ``True``.
flags: :class:`MessageFlags`
The flags to set for this message.
Only :attr:`~MessageFlags.suppress_embeds` is supported.
Only :attr:`~MessageFlags.suppress_embeds` and :attr:`~MessageFlags.is_components_v2`
are supported.

If parameter ``suppress_embeds`` is provided,
that will override the setting of :attr:`MessageFlags.suppress_embeds`.

.. versionadded:: 2.9

file: :class:`.File`
file: :class:`~disnake.File`
The file to upload. This cannot be mixed with the ``files`` parameter.
files: List[:class:`.File`]
files: List[:class:`~disnake.File`]
A list of files to upload. Must be a maximum of 10.
This cannot be mixed with the ``file`` parameter.
stickers: Sequence[Union[:class:`.GuildSticker`, :class:`.StandardSticker`, :class:`.StickerItem`]]
Expand All @@ -3681,6 +3682,12 @@ async def create_thread(
A Discord UI View to add to the message. This cannot be mixed with ``components``.
components: |components_type|
A list of components to include in the message. This cannot be mixed with ``view``.

.. note::
Passing v2 components here automatically sets the :attr:`~MessageFlags.is_components_v2` flag.
Setting this flag cannot be reverted. Note that this also disables the
``content``, ``embeds``, and ``stickers`` fields.

reason: Optional[:class:`str`]
The reason for creating the thread. Shows up on the audit log.

Expand All @@ -3693,11 +3700,11 @@ async def create_thread(
TypeError
Specified both ``file`` and ``files``,
or you specified both ``embed`` and ``embeds``,
or you specified both ``view`` and ``components``.
or you specified both ``view`` and ``components``,
or you have passed an object that is not :class:`File` to ``file`` or ``files``.
ValueError
Specified more than 10 embeds,
or more than 10 files.
Specified more than 10 embeds, or more than 10 files, or
you tried to send v2 components together with ``content``, ``embeds``, or ``stickers``.

Returns
-------
Expand Down
Loading
Loading