mirror of
https://github.com/lockin-bot/react-telegram.git
synced 2026-01-12 15:13:56 +08:00
fix: improve button text extraction for complex children
- Fixed button text extraction to handle arrays, expressions, and mixed content
- Buttons with template literals now display correctly (e.g., "Switch to {mode} Mode")
- Added comprehensive tests for button text extraction edge cases
- Removed accidentally committed editReactMessage method
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -280,37 +280,6 @@ export class MtcuteAdapter {
|
||||
return containerId;
|
||||
}
|
||||
|
||||
// Edit an existing message with a new React tree
|
||||
async editReactMessage(
|
||||
chatId: number | string,
|
||||
messageId: number,
|
||||
app: ReactElement
|
||||
) {
|
||||
const containerId = `${chatId}_${messageId}`;
|
||||
let container = this.activeContainers.get(containerId);
|
||||
|
||||
if (!container) {
|
||||
container = createContainer();
|
||||
this.activeContainers.set(containerId, container);
|
||||
}
|
||||
|
||||
// Set up edit callback
|
||||
container.container.onRenderContainer = async (root) => {
|
||||
const textWithEntities = this.rootNodeToTextWithEntities(root);
|
||||
const replyMarkup = this.rootNodeToInlineKeyboard(root, containerId);
|
||||
|
||||
await this.client.editMessage({
|
||||
chatId,
|
||||
message: messageId,
|
||||
text: textWithEntities,
|
||||
replyMarkup
|
||||
});
|
||||
};
|
||||
|
||||
// Render the app
|
||||
container.render(app);
|
||||
}
|
||||
|
||||
// Convenience method to handle commands with React
|
||||
onCommand(command: string, handler: (ctx: any) => ReactElement) {
|
||||
this.commandHandlers.set(command, handler);
|
||||
|
||||
@@ -187,6 +187,50 @@ describe('Telegram Reconciler', () => {
|
||||
expect(onClick).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should handle buttons with complex children', async () => {
|
||||
const { container, render } = createContainer();
|
||||
const onClick = vi.fn();
|
||||
const mode = 'normal';
|
||||
|
||||
render(
|
||||
<row>
|
||||
<button onClick={onClick}>
|
||||
Switch to {mode === 'normal' ? 'Secret' : 'Normal'} Mode
|
||||
</button>
|
||||
</row>
|
||||
);
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 0));
|
||||
|
||||
const row = container.root.children[0];
|
||||
expect(row?.type).toBe('row');
|
||||
if (row?.type === 'row') {
|
||||
expect(row.children[0]?.text).toBe('Switch to Secret Mode');
|
||||
}
|
||||
});
|
||||
|
||||
it('should handle buttons with array children', async () => {
|
||||
const { container, render } = createContainer();
|
||||
|
||||
render(
|
||||
<row>
|
||||
<button>{'Hello'}{' '}{'World'}</button>
|
||||
<button>{['One', ' ', 'Two', ' ', 'Three']}</button>
|
||||
<button>{123} items</button>
|
||||
</row>
|
||||
);
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 0));
|
||||
|
||||
const row = container.root.children[0];
|
||||
expect(row?.type).toBe('row');
|
||||
if (row?.type === 'row') {
|
||||
expect(row.children[0]?.text).toBe('Hello World');
|
||||
expect(row.children[1]?.text).toBe('One Two Three');
|
||||
expect(row.children[2]?.text).toBe('123 items');
|
||||
}
|
||||
});
|
||||
|
||||
it('should work with React state', async () => {
|
||||
const { container, render, clickButton } = createContainer();
|
||||
|
||||
@@ -239,4 +283,45 @@ describe('Telegram Reconciler', () => {
|
||||
content: '0'
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle input elements', async () => {
|
||||
const { container, render } = createContainer();
|
||||
const onSubmit = vi.fn();
|
||||
|
||||
render(
|
||||
<>
|
||||
<input onSubmit={onSubmit} />
|
||||
<input onSubmit={onSubmit} autoDelete />
|
||||
</>
|
||||
);
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 0));
|
||||
|
||||
expect(container.root.children).toHaveLength(2);
|
||||
expect(container.root.children[0]).toEqual({
|
||||
type: 'input',
|
||||
onSubmit: expect.any(Function),
|
||||
autoDelete: undefined
|
||||
});
|
||||
expect(container.root.children[1]).toEqual({
|
||||
type: 'input',
|
||||
onSubmit: expect.any(Function),
|
||||
autoDelete: true
|
||||
});
|
||||
|
||||
// Check input callbacks
|
||||
expect(container.inputCallbacks).toHaveLength(2);
|
||||
expect(container.inputCallbacks[0]).toEqual({
|
||||
callback: expect.any(Function),
|
||||
autoDelete: undefined
|
||||
});
|
||||
expect(container.inputCallbacks[1]).toEqual({
|
||||
callback: expect.any(Function),
|
||||
autoDelete: true
|
||||
});
|
||||
|
||||
// Test callback execution
|
||||
container.inputCallbacks[0]?.callback('test message');
|
||||
expect(onSubmit).toHaveBeenCalledWith('test message');
|
||||
});
|
||||
});
|
||||
@@ -97,7 +97,18 @@ const hostConfig: ReactReconciler.HostConfig<
|
||||
case 'blockquote':
|
||||
return { type: 'blockquote', children: [], expandable: props.expandable };
|
||||
case 'button':
|
||||
const buttonText = typeof props.children === 'string' ? props.children : '';
|
||||
// Extract text from children - handle string, array, or other types
|
||||
let buttonText = '';
|
||||
if (typeof props.children === 'string') {
|
||||
buttonText = props.children;
|
||||
} else if (Array.isArray(props.children)) {
|
||||
// Join array elements, converting non-strings to strings
|
||||
buttonText = props.children.map((child: any) =>
|
||||
typeof child === 'string' ? child : String(child)
|
||||
).join('');
|
||||
} else if (props.children != null) {
|
||||
buttonText = String(props.children);
|
||||
}
|
||||
return { type: 'button', id: '', text: buttonText, onClick: props.onClick };
|
||||
case 'row':
|
||||
return { type: 'row', children: [] };
|
||||
|
||||
Reference in New Issue
Block a user