Skip to content

Commit fc8346e

Browse files
committed
feat: components v2 jsx
1 parent eaa5ee1 commit fc8346e

30 files changed

+383
-92
lines changed

apps/test-bot/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
"@commandkit/devtools": "workspace:*",
1515
"@commandkit/i18n": "workspace:*",
1616
"@commandkit/legacy": "workspace:*",
17-
"discord.js": "^14.17.3",
17+
"discord.js": "^14.19.1",
1818
"dotenv": "^16.4.7"
1919
},
2020
"devDependencies": {
2121
"tsx": "^4.7.0"
2222
}
23-
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import CommandKit, {
2+
Button,
3+
ChatInputCommand,
4+
CommandData,
5+
Container,
6+
File,
7+
MediaGallery,
8+
MediaGalleryItem,
9+
Section,
10+
Separator,
11+
TextDisplay,
12+
} from 'commandkit';
13+
import {
14+
AttachmentBuilder,
15+
ButtonStyle,
16+
MessageFlags,
17+
SeparatorSpacingSize,
18+
} from 'discord.js';
19+
20+
export const command: CommandData = {
21+
name: 'components',
22+
description: 'Test components v2',
23+
};
24+
25+
const fileContent = '# This is a test file\nHello world!';
26+
const mediaItems: string[] = Array.from(
27+
{
28+
length: 6,
29+
},
30+
(_, i) => `https://cdn.discordapp.com/embed/avatars/${i}.png`,
31+
);
32+
33+
export const chatInput: ChatInputCommand = async (ctx) => {
34+
const container = (
35+
<Container>
36+
<TextDisplay content="# CommandKit Components v2 test" />
37+
<Section>
38+
<TextDisplay content="This is a section" />
39+
<Button url="https://commandkit.dev" style={ButtonStyle.Link}>
40+
Website
41+
</Button>
42+
</Section>
43+
<Separator spacing={SeparatorSpacingSize.Large} />
44+
<TextDisplay content="This is after separator" />
45+
<File url="attachment://components-v2-are-awesome.md" />
46+
<Separator spacing={SeparatorSpacingSize.Large} dividier />
47+
<TextDisplay content="Discord's default avatars" />
48+
<MediaGallery>
49+
{mediaItems.map((item) => (
50+
<MediaGalleryItem description="Gallery item description" url={item} />
51+
))}
52+
</MediaGallery>
53+
</Container>
54+
);
55+
56+
await ctx.interaction.reply({
57+
components: [container],
58+
files: [
59+
new AttachmentBuilder(Buffer.from(fileContent), {
60+
name: 'components-v2-are-awesome.md',
61+
}),
62+
],
63+
flags: MessageFlags.IsComponentsV2,
64+
});
65+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import CommandKit, {
2+
ChatInputCommand,
3+
CommandData,
4+
MediaGallery,
5+
MediaGalleryItem,
6+
TextDisplay,
7+
} from 'commandkit';
8+
import { MessageFlags } from 'discord.js';
9+
10+
export const command: CommandData = {
11+
name: 'gallery',
12+
description: 'Test components v2 gallery',
13+
};
14+
15+
const mediaItems: string[] = Array.from(
16+
{
17+
length: 6,
18+
},
19+
(_, i) => `https://cdn.discordapp.com/embed/avatars/${i}.png`,
20+
);
21+
22+
export const chatInput: ChatInputCommand = async (ctx) => {
23+
const components = (
24+
<>
25+
<TextDisplay content="Discord avatars" />
26+
<MediaGallery>
27+
{mediaItems.map((item) => (
28+
<MediaGalleryItem description="Gallery item description" url={item} />
29+
))}
30+
</MediaGallery>
31+
</>
32+
);
33+
34+
await ctx.interaction.reply({
35+
components,
36+
flags: MessageFlags.IsComponentsV2,
37+
});
38+
};

packages/commandkit/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"@types/ms": "^0.7.34",
4747
"@types/node": "^22.10.2",
4848
"@types/yargs": "^17.0.32",
49-
"discord.js": "^14.17.3",
49+
"discord.js": "^14.19.1",
5050
"tsconfig": "workspace:*",
5151
"tsx": "^4.19.2",
5252
"typescript": "^5.7.3",
@@ -58,4 +58,4 @@
5858
"engines": {
5959
"node": ">=22"
6060
}
61-
}
61+
}

packages/commandkit/src/components/common/element.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ActionRowBuilder, TextInputBuilder } from 'discord.js';
2-
import type { ButtonKit } from '../button/ButtonKit';
2+
import type { ButtonKit } from '../v1/button/ButtonKit';
33
import { warnUnstable } from '../../utils/warn-unstable';
4-
import { ModalKit } from '../modal/ModalKit';
4+
import { ModalKit } from '../v1/modal/ModalKit';
55

66
export const ElementType = {
77
ActionRow: 'action-row',

packages/commandkit/src/components/index.ts

+15-12
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
11
// action row
2-
export * from './action-row/ActionRow';
2+
export * from './v1/action-row/ActionRow';
33

44
// buttons
5-
export * from './button/ButtonKit';
6-
export * from './button/Button';
5+
export * from './v1/button/ButtonKit';
6+
export * from './v1/button/Button';
77

88
// modals
9-
export * from './modal/ModalKit';
10-
export * from './modal/Modal';
9+
export * from './v1/modal/ModalKit';
10+
export * from './v1/modal/Modal';
1111

1212
// select menus
13-
export * from './select-menu/StringSelectMenuKit';
14-
export * from './select-menu/ChannelSelectMenuKit';
15-
export * from './select-menu/MentionableSelectMenuKit';
16-
export * from './select-menu/UserSelectMenuKit';
17-
export * from './select-menu/RoleSelectMenuKit';
18-
export * from './select-menu/SelectMenu';
19-
export * from './select-menu/common';
13+
export * from './v1/select-menu/StringSelectMenuKit';
14+
export * from './v1/select-menu/ChannelSelectMenuKit';
15+
export * from './v1/select-menu/MentionableSelectMenuKit';
16+
export * from './v1/select-menu/UserSelectMenuKit';
17+
export * from './v1/select-menu/RoleSelectMenuKit';
18+
export * from './v1/select-menu/SelectMenu';
19+
export * from './v1/select-menu/common';
20+
21+
// v2
22+
export * from './v2/index';
2023

2124
// common
2225
export * from './common/element';

packages/commandkit/src/components/action-row/ActionRow.ts renamed to packages/commandkit/src/components/v1/action-row/ActionRow.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ActionRowBuilder } from 'discord.js';
2-
import { AnyCommandKitElement, CommandKitElement } from '../common/element';
2+
import { AnyCommandKitElement, CommandKitElement } from '../../common/element';
33

44
export interface ActionRowProps {
55
children?: AnyCommandKitElement[] | AnyCommandKitElement;

packages/commandkit/src/components/button/Button.ts renamed to packages/commandkit/src/components/v1/button/Button.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import {
55
type CommandKitButtonBuilderInteractionCollectorDispatch,
66
type CommandKitButtonBuilderInteractionCollectorDispatchContextData,
77
} from './ButtonKit';
8-
import { CommandKitElement } from '../common/element';
9-
import { MaybeArray } from '../common/types';
10-
import { EventInterceptorErrorHandler } from '../common/EventInterceptor';
8+
import { CommandKitElement } from '../../common/element';
9+
import { MaybeArray } from '../../common/types';
10+
import { EventInterceptorErrorHandler } from '../../common/EventInterceptor';
1111

1212
export type ButtonChildrenLike = string | number | boolean;
1313

packages/commandkit/src/components/button/ButtonKit.ts renamed to packages/commandkit/src/components/v1/button/ButtonKit.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ import {
99
exitContext,
1010
getCommandKit,
1111
getContext,
12-
} from '../../context/async-context';
12+
} from '../../../context/async-context';
1313
import {
1414
EventInterceptorContextData,
1515
EventInterceptorErrorHandler,
16-
} from '../common/EventInterceptor';
16+
} from '../../common/EventInterceptor';
1717

1818
export type ButtonKitPredicate = (
1919
interaction: ButtonInteraction,

packages/commandkit/src/components/modal/Modal.ts renamed to packages/commandkit/src/components/v1/modal/Modal.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { ActionRowBuilder, TextInputBuilder, TextInputStyle } from 'discord.js';
2-
import { MaybeArray } from '../common/types';
3-
import { CommandKitElement } from '../common/element';
2+
import { MaybeArray } from '../../common/types';
3+
import { CommandKitElement } from '../../common/element';
44
import {
55
CommandKitModalBuilderInteractionCollectorDispatchContextData,
66
ModalKit,
77
OnModalKitEnd,
88
OnModalKitSubmit,
99
} from './ModalKit';
10-
import { EventInterceptorErrorHandler } from '../common/EventInterceptor';
10+
import { EventInterceptorErrorHandler } from '../../common/EventInterceptor';
1111

1212
export interface ModalProps {
1313
customId?: string;

packages/commandkit/src/components/modal/ModalKit.ts renamed to packages/commandkit/src/components/v1/modal/ModalKit.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import {
88
exitContext,
99
getCommandKit,
1010
getContext,
11-
} from '../../context/async-context';
11+
} from '../../../context/async-context';
1212
import {
1313
EventInterceptorContextData,
1414
EventInterceptorErrorHandler,
15-
} from '../common/EventInterceptor';
15+
} from '../../common/EventInterceptor';
1616

1717
export type ModalKitPredicate = (
1818
interaction: ModalSubmitInteraction,

packages/commandkit/src/components/select-menu/ChannelSelectMenuKit.ts renamed to packages/commandkit/src/components/v1/select-menu/ChannelSelectMenuKit.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import {
77
exitContext,
88
getCommandKit,
99
getContext,
10-
} from '../../context/async-context';
11-
import { EventInterceptorErrorHandler } from '../common/EventInterceptor';
10+
} from '../../../context/async-context';
11+
import { EventInterceptorErrorHandler } from '../../common/EventInterceptor';
1212
import {
1313
CommandKitSelectMenuBuilderInteractionCollectorDispatch,
1414
CommandKitSelectMenuBuilderInteractionCollectorDispatchContextData,

packages/commandkit/src/components/select-menu/MentionableSelectMenuKit.ts renamed to packages/commandkit/src/components/v1/select-menu/MentionableSelectMenuKit.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import {
77
exitContext,
88
getCommandKit,
99
getContext,
10-
} from '../../context/async-context';
11-
import { EventInterceptorErrorHandler } from '../common/EventInterceptor';
10+
} from '../../../context/async-context';
11+
import { EventInterceptorErrorHandler } from '../../common/EventInterceptor';
1212
import {
1313
CommandKitSelectMenuBuilderInteractionCollectorDispatch,
1414
CommandKitSelectMenuBuilderInteractionCollectorDispatchContextData,

packages/commandkit/src/components/select-menu/RoleSelectMenuKit.ts renamed to packages/commandkit/src/components/v1/select-menu/RoleSelectMenuKit.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import {
77
exitContext,
88
getCommandKit,
99
getContext,
10-
} from '../../context/async-context';
11-
import { EventInterceptorErrorHandler } from '../common/EventInterceptor';
10+
} from '../../../context/async-context';
11+
import { EventInterceptorErrorHandler } from '../../common/EventInterceptor';
1212
import {
1313
CommandKitSelectMenuBuilderInteractionCollectorDispatch,
1414
CommandKitSelectMenuBuilderInteractionCollectorDispatchContextData,

packages/commandkit/src/components/select-menu/SelectMenu.ts renamed to packages/commandkit/src/components/v1/select-menu/SelectMenu.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { MentionableSelectMenuKit } from './MentionableSelectMenuKit';
1818
import { RoleSelectMenuKit } from './RoleSelectMenuKit';
1919
import { StringSelectMenuKit } from './StringSelectMenuKit';
2020
import { UserSelectMenuKit } from './UserSelectMenuKit';
21-
import { MaybeArray } from '../common/types';
21+
import { MaybeArray } from '../../common/types';
2222
import {
2323
CommandKitSelectMenuBuilderInteractionCollectorDispatch,
2424
CommandKitSelectMenuBuilderInteractionCollectorDispatchContextData,

packages/commandkit/src/components/select-menu/StringSelectMenuKit.ts renamed to packages/commandkit/src/components/v1/select-menu/StringSelectMenuKit.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import {
77
exitContext,
88
getCommandKit,
99
getContext,
10-
} from '../../context/async-context';
11-
import { EventInterceptorErrorHandler } from '../common/EventInterceptor';
10+
} from '../../../context/async-context';
11+
import { EventInterceptorErrorHandler } from '../../common/EventInterceptor';
1212
import {
1313
CommandKitSelectMenuBuilderInteractionCollectorDispatch,
1414
CommandKitSelectMenuBuilderInteractionCollectorDispatchContextData,

packages/commandkit/src/components/select-menu/UserSelectMenuKit.ts renamed to packages/commandkit/src/components/v1/select-menu/UserSelectMenuKit.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import {
77
exitContext,
88
getCommandKit,
99
getContext,
10-
} from '../../context/async-context';
11-
import { EventInterceptorErrorHandler } from '../common/EventInterceptor';
10+
} from '../../../context/async-context';
11+
import { EventInterceptorErrorHandler } from '../../common/EventInterceptor';
1212
import {
1313
CommandKitSelectMenuBuilderInteractionCollectorDispatch,
1414
CommandKitSelectMenuBuilderInteractionCollectorDispatchContextData,

packages/commandkit/src/components/select-menu/common.ts renamed to packages/commandkit/src/components/v1/select-menu/common.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Awaitable, Events } from 'discord.js';
2-
import { EventInterceptorContextData } from '../common/EventInterceptor';
2+
import { EventInterceptorContextData } from '../../common/EventInterceptor';
33

44
export type SelectMenuKitPredicate<T> = (interaction: T) => Awaitable<boolean>;
55

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { ComponentBuilder } from 'discord.js';
2+
3+
export function applyId(props: { id?: number }, component: ComponentBuilder) {
4+
if (props.id != null) {
5+
component.setId(props.id);
6+
}
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import {
2+
ActionRowBuilder,
3+
ComponentBuilder,
4+
ContainerBuilder,
5+
ContainerComponentData,
6+
FileBuilder,
7+
MediaGalleryBuilder,
8+
SectionBuilder,
9+
SeparatorBuilder,
10+
TextDisplayBuilder,
11+
} from 'discord.js';
12+
import { applyId } from './common';
13+
14+
export interface ContainerProps
15+
extends Omit<ContainerComponentData, 'type' | 'components'> {
16+
children?: ComponentBuilder[];
17+
}
18+
19+
export function Container(props: ContainerProps): ContainerBuilder {
20+
const container = new ContainerBuilder();
21+
22+
applyId(props, container);
23+
24+
if (typeof props.accentColor != null) {
25+
container.setAccentColor(props.accentColor);
26+
}
27+
28+
if (props.spoiler != null) {
29+
container.setSpoiler(props.spoiler);
30+
}
31+
32+
if (props.children?.length) {
33+
for (const child of props.children.flat()) {
34+
if (child instanceof TextDisplayBuilder) {
35+
container.addTextDisplayComponents(child);
36+
}
37+
38+
if (child instanceof FileBuilder) {
39+
container.addFileComponents(child);
40+
}
41+
42+
if (child instanceof ActionRowBuilder) {
43+
container.addActionRowComponents(child);
44+
}
45+
46+
if (child instanceof SeparatorBuilder) {
47+
container.addSeparatorComponents(child);
48+
}
49+
50+
if (child instanceof SectionBuilder) {
51+
container.addSectionComponents(child);
52+
}
53+
54+
if (child instanceof MediaGalleryBuilder) {
55+
container.addMediaGalleryComponents(child);
56+
}
57+
}
58+
}
59+
60+
return container;
61+
}

0 commit comments

Comments
 (0)