deact-modal
Create or use Discord modals with Deact. Use when implementing form inputs and text submissions.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Create or use Discord modals with Deact. Use when implementing form inputs and text submissions.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Add new moves to the battle system. Use when implementing attack, status, or support moves for Pokemon.
Add a Pokemon (real or fake) to src/config/pokemonConfig.js with its moves, abilities, rarity, and evolution data. Use when the user asks to add, register, implement, or create a new Pokemon, Pokemon form, or fake/custom Pokemon in the battle system.
Find a Pokemon's Discord emoji string — canonical (e.g. `<:25:1100282072003772457>`) from `pokestar-pk-{n}`, form variants (e.g. `<:483origin:1404654211324448848>`) from `pokestar-forms-1`, or fakemon (e.g. `<:ashpikachu:1109522092283658250>`) from `pokestar-pk-extra` — via Playwright CLI. Use when the user asks for a Pokemon's emoji, emoji ID, form emoji, fakemon emoji, or needs an `<:name:snowflake>` string.
Create an implementation plan before adding one or more Pokemon via the `add-pokemon` skill. Builds Pokemon, moves, and abilities tables with all required inputs, flags unimplemented moves/abilities, and produces step-by-step implementation instructions. Use when the user asks to plan adding a Pokemon, plan a Pokemon batch, or invokes this skill before `add-pokemon`.
Verify Discord bot changes by running the bot and testing commands in Discord via Playwright CLI. Use when the user asks to test, verify, or check bot commands in Discord.
Verify a Pokemon's configuration in pokemonConfig.js by testing its moves and abilities in Discord via Playwright CLI. Use when validating a Pokemon's battle behavior after configuration changes.
| name | deact-modal |
| description | Create or use Discord modals with Deact. Use when implementing form inputs and text submissions. |
Modals in Deact require two parts:
src/modals/)Modal builder location: src/modals/<category>Modals.js
Text input component: src/modals/components/textInputRow.js
// src/modals/myModals.js
const { buildGenericTextInputModal } = require("./genericModals");
/**
* @param {object} param0
* @param {string} param0.id - Component ID (provided by Deact)
* @param {string=} param0.title
* @param {string=} param0.value - Pre-fill value
* @param {boolean=} param0.required
*/
const buildMySearchModal = ({ id, title = "Search", value, required = true }) =>
buildGenericTextInputModal({
id,
textInputId: "searchInput", // Used to retrieve value
title,
label: "Enter search term",
placeholder: "Type here...",
value,
required,
});
module.exports = { buildMySearchModal };
const {
ModalBuilder,
TextInputBuilder,
TextInputStyle,
ActionRowBuilder,
} = require("discord.js");
const buildCustomModal = ({ id, title = "Custom Form" }) => {
const modal = new ModalBuilder().setCustomId(id).setTitle(title);
const nameInput = new TextInputBuilder()
.setCustomId("nameInput")
.setLabel("Name")
.setStyle(TextInputStyle.Short)
.setRequired(true);
const descInput = new TextInputBuilder()
.setCustomId("descriptionInput")
.setLabel("Description")
.setStyle(TextInputStyle.Paragraph)
.setRequired(false);
modal.addComponents(
new ActionRowBuilder().addComponents(nameInput),
new ActionRowBuilder().addComponents(descInput),
);
return modal;
};
module.exports = { buildCustomModal };
const {
useState,
useCallbackBinding,
useModalSubmitCallbackBinding,
createModal,
createElement,
} = require("../../deact/deact");
const { ButtonStyle } = require("discord.js");
const Button = require("../../deact/elements/Button");
const { buildMySearchModal } = require("../../modals/myModals");
module.exports = async (ref, { initialValue }) => {
const [searchTerm, setSearchTerm] = useState(initialValue, ref);
// 1. Handle modal submission
const onSubmitKey = useModalSubmitCallbackBinding((interaction) => {
const value = interaction.fields.getTextInputValue("searchInput");
setSearchTerm(value);
}, ref);
// 2. Open modal (MUST use defer: false)
const openModalKey = useCallbackBinding(
(interaction) => {
return createModal(
buildMySearchModal,
{ title: "Search", value: searchTerm },
onSubmitKey,
interaction,
ref,
);
},
ref,
{ defer: false }, // Required for modals!
);
return {
contents: [searchTerm ? `Searching: ${searchTerm}` : "Click to search"],
components: [
[
createElement(Button, {
emoji: "🔎",
label: "Search",
callbackBindingKey: openModalKey,
style: searchTerm ? ButtonStyle.Primary : ButtonStyle.Secondary,
}),
],
],
};
};
createModal(
modalBuilderFunction, // Function that returns ModalBuilder
props, // Props passed to builder (without id)
submitCallbackKey, // From useModalSubmitCallbackBinding
interaction, // Current interaction
ref, // DeactElement ref
data, // Optional extra data (available in submit callback)
);
In the submit callback, use interaction.fields.getTextInputValue(inputId):
const onSubmitKey = useModalSubmitCallbackBinding((interaction, data) => {
const name = interaction.fields.getTextInputValue("nameInput");
const description = interaction.fields.getTextInputValue("descriptionInput");
// data contains any extra data passed to createModal
console.log(data.extraInfo);
setFormData({ name, description });
}, ref);
const {
useState,
useCallbackBinding,
useModalSubmitCallbackBinding,
createModal,
createElement,
} = require("../../deact/deact");
const { ButtonStyle } = require("discord.js");
const Button = require("../../deact/elements/Button");
const { buildGenericTextInputModal } = require("../../modals/genericModals");
const buildSearchModal = ({ id, value }) =>
buildGenericTextInputModal({
id,
textInputId: "query",
title: "Search",
label: "Search Query",
placeholder: "Enter search term...",
value,
required: false,
});
module.exports = async (ref, {}) => {
const [query, setQuery] = useState("", ref);
const submitKey = useModalSubmitCallbackBinding((interaction) => {
setQuery(interaction.fields.getTextInputValue("query"));
}, ref);
const openKey = useCallbackBinding(
(interaction) =>
createModal(
buildSearchModal,
{ value: query },
submitKey,
interaction,
ref,
),
ref,
{ defer: false },
);
const clearKey = useCallbackBinding(() => setQuery(""), ref);
return {
contents: [query ? `Results for: "${query}"` : "No search active"],
components: [
[
createElement(Button, {
emoji: "🔎",
callbackBindingKey: openKey,
style: query ? ButtonStyle.Primary : ButtonStyle.Secondary,
}),
createElement(Button, {
emoji: "❌",
label: "Clear",
callbackBindingKey: clearKey,
disabled: !query,
}),
],
],
};
};
defer: false is required for the button that opens the modalid from Deact - don't set it manuallyuseModalSubmitCallbackBinding for submit handlerscreateModal() from the open callbacktextInputId must match between builder and getTextInputValue()