diff --git a/.claude/settings.local.json b/.claude/settings.local.json
index 1909644..b8d38dd 100644
--- a/.claude/settings.local.json
+++ b/.claude/settings.local.json
@@ -14,7 +14,8 @@
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(bun tsc:*)",
- "Bash(ls:*)"
+ "Bash(ls:*)",
+ "Bash(bun x tsc:*)"
],
"deny": []
}
diff --git a/src/examples/input-autodelete-demo.tsx b/src/examples/input-autodelete-demo.tsx
new file mode 100644
index 0000000..d0effcd
--- /dev/null
+++ b/src/examples/input-autodelete-demo.tsx
@@ -0,0 +1,88 @@
+///
+import React, { useState } from 'react';
+import { MtcuteAdapter } from '../mtcute-adapter';
+
+const AutoDeleteDemo: React.FC = () => {
+ const [mode, setMode] = useState<'normal' | 'secret'>('normal');
+ const [messages, setMessages] = useState([]);
+
+ const handleNormalInput = (text: string) => {
+ setMessages(prev => [...prev, `Normal message: ${text}`]);
+ };
+
+ const handleSecretInput = (text: string) => {
+ setMessages(prev => [...prev, `Secret received (message deleted): ***`]);
+ };
+
+ const toggleMode = () => {
+ setMode(mode === 'normal' ? 'secret' : 'normal');
+ setMessages([]);
+ };
+
+ return (
+ <>
+ Input Auto-Delete Demo
+ {'\n\n'}
+
+ Current mode: {mode === 'normal' ? '📝 Normal Mode' : '🤫 Secret Mode'}
+ {'\n\n'}
+
+ {mode === 'normal' ? (
+ <>
+ Send any message - it will stay in the chat.
+ {'\n'}
+
+ >
+ ) : (
+ <>
+ Send a secret message - it will be deleted automatically!
+ {'\n'}
+
+ >
+ )}
+
+ {'\n\n'}
+
+ {messages.length > 0 && (
+ <>
+ Received Messages:
+ {'\n'}
+ {messages.map((msg, idx) => (
+
+ • {msg}
+ {'\n'}
+
+ ))}
+ {'\n'}
+ >
+ )}
+
+
+
+ {messages.length > 0 && (
+
+ )}
+
+ >
+ );
+};
+
+// Set up the bot
+async function main() {
+ const adapter = new MtcuteAdapter({
+ apiId: parseInt(process.env.API_ID!),
+ apiHash: process.env.API_HASH!,
+ botToken: process.env.BOT_TOKEN!
+ });
+
+ // Register the demo command
+ adapter.onCommand('autodelete', () => );
+
+ // Start the bot
+ await adapter.start(process.env.BOT_TOKEN!);
+ console.log('Auto-delete demo bot is running! Send /autodelete to start.');
+}
+
+main().catch(console.error);
\ No newline at end of file
diff --git a/src/examples/quiz-bot.tsx b/src/examples/quiz-bot.tsx
index 84c16cb..ca94772 100644
--- a/src/examples/quiz-bot.tsx
+++ b/src/examples/quiz-bot.tsx
@@ -103,8 +103,8 @@ const QuizBot: React.FC = () => {
>
)}
- {/* Input handler for answers */}
- {waitingForAnswer && }
+ {/* Input handler for answers - auto-delete for cleaner chat */}
+ {waitingForAnswer && }
>
);
};
diff --git a/src/input-example.tsx b/src/input-example.tsx
index 202205f..5f629eb 100644
--- a/src/input-example.tsx
+++ b/src/input-example.tsx
@@ -43,7 +43,7 @@ const InputExample: React.FC = () => {
{'\n\n'}
{/* Input handler - will process any reply to this message */}
- {waitingForInput && }
+ {waitingForInput && }
{/* Button to clear history */}
{messages.length > 0 && (
diff --git a/src/jsx.d.ts b/src/jsx.d.ts
index 2fc386b..450290e 100644
--- a/src/jsx.d.ts
+++ b/src/jsx.d.ts
@@ -58,6 +58,7 @@ declare module 'react' {
input: {
onSubmit?: (text: string) => void;
+ autoDelete?: boolean;
};
}
}
@@ -122,6 +123,7 @@ export interface TelegramRowNode {
export interface TelegramInputNode {
type: 'input';
onSubmit?: (text: string) => void;
+ autoDelete?: boolean;
}
export interface TelegramRootNode {
diff --git a/src/mtcute-adapter.ts b/src/mtcute-adapter.ts
index 1d47d06..190b298 100644
--- a/src/mtcute-adapter.ts
+++ b/src/mtcute-adapter.ts
@@ -58,11 +58,30 @@ export class MtcuteAdapter {
}
}
} else if (msg.text) {
+ // Track if any input has autoDelete enabled
+ let shouldDelete = false;
+
this.activeContainers.forEach(container => {
- container.container.inputCallbacks.forEach(callback => {
- callback(msg.text!);
+ container.container.inputCallbacks.forEach(inputData => {
+ // Call the callback
+ inputData.callback(msg.text!);
+
+ // Check if this input has autoDelete enabled
+ if (inputData.autoDelete) {
+ shouldDelete = true;
+ }
});
});
+
+ // Delete the user's message if any input had autoDelete enabled
+ if (shouldDelete) {
+ try {
+ await msg.delete();
+ } catch (err) {
+ // Ignore errors if message deletion fails (e.g., bot lacks permissions)
+ console.error('Failed to delete message:', err);
+ }
+ }
}
});
diff --git a/src/reconciler.ts b/src/reconciler.ts
index ce08dd8..92ccbe4 100644
--- a/src/reconciler.ts
+++ b/src/reconciler.ts
@@ -29,10 +29,17 @@ export type {
Node
};
+export type { InputCallbackData };
+
+interface InputCallbackData {
+ callback: (text: string) => void;
+ autoDelete?: boolean;
+}
+
interface Container {
root: RootNode;
buttonHandlers: Map void>;
- inputCallbacks: Array<(text: string) => void>;
+ inputCallbacks: Array;
onRenderContainer?: (root: RootNode) => void;
}
@@ -95,7 +102,7 @@ const hostConfig: ReactReconciler.HostConfig<
case 'row':
return { type: 'row', children: [] };
case 'input':
- return { type: 'input', onSubmit: props.onSubmit };
+ return { type: 'input', onSubmit: props.onSubmit, autoDelete: props.autoDelete };
default:
return { type: 'formatted', format: 'bold', children: [] };
}
@@ -161,7 +168,10 @@ const hostConfig: ReactReconciler.HostConfig<
container.inputCallbacks = [];
container.root.children.forEach((child: any) => {
if (child.type === 'input' && child.onSubmit) {
- container.inputCallbacks.push(child.onSubmit);
+ container.inputCallbacks.push({
+ callback: child.onSubmit,
+ autoDelete: child.autoDelete
+ });
}
});