diff --git a/src/mtcute-adapter.ts b/src/mtcute-adapter.ts index 190b298..e83dbb0 100644 --- a/src/mtcute-adapter.ts +++ b/src/mtcute-adapter.ts @@ -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); diff --git a/src/reconciler.test.tsx b/src/reconciler.test.tsx index e78d931..4edaffc 100644 --- a/src/reconciler.test.tsx +++ b/src/reconciler.test.tsx @@ -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( + + + + ); + + 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( + + + + + + ); + + 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( + <> + + + + ); + + 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'); + }); }); \ No newline at end of file diff --git a/src/reconciler.ts b/src/reconciler.ts index 92ccbe4..b975735 100644 --- a/src/reconciler.ts +++ b/src/reconciler.ts @@ -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: [] };