From a7a5e62c6904a5b71aa351a1dfbb17f898f68bf3 Mon Sep 17 00:00:00 2001 From: Yauheni Mileika Date: Mon, 30 Jun 2025 16:14:56 +0300 Subject: [PATCH 1/5] feat(ui-react): implement multiple buttons support --- .../src/components/TonConnectButton.tsx | 28 +++++++++++++------ .../src/utils/tonconnect-button-ids.ts | 19 +++++++++++++ 2 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 packages/ui-react/src/utils/tonconnect-button-ids.ts diff --git a/packages/ui-react/src/components/TonConnectButton.tsx b/packages/ui-react/src/components/TonConnectButton.tsx index 9479a5a43..ef5f32efd 100644 --- a/packages/ui-react/src/components/TonConnectButton.tsx +++ b/packages/ui-react/src/components/TonConnectButton.tsx @@ -1,12 +1,12 @@ -import { CSSProperties, FunctionComponent, memo, useEffect } from 'react'; +import { CSSProperties, FunctionComponent, memo, useEffect, useRef } from 'react'; import { useTonConnectUI } from '../hooks/useTonConnectUI'; - -const buttonRootId = 'ton-connect-button'; +import { addButtonId, removeButtonId, getButtonIds, DEFAULT_BUTTON_ID } from '../utils/tonconnect-button-ids'; export interface TonConnectButtonProps { className?: string; - style?: CSSProperties; + + id?: string; } /** @@ -15,18 +15,28 @@ export interface TonConnectButtonProps { * @param [className] css class to add to the button container. * @param [style] style to add to the button container. * @constructor - */ -const TonConnectButton: FunctionComponent = ({ className, style }) => { + */const TonConnectButton: FunctionComponent = ({ className, style, id }) => { const [_, setOptions] = useTonConnectUI(); + const buttonId = useRef( + id ?? + (getButtonIds().length === 0 + ? DEFAULT_BUTTON_ID + : `ton-connect-button-${Math.random().toString(36).slice(2, 10)}`) + ); useEffect(() => { - setOptions({ buttonRootId }); - return () => setOptions({ buttonRootId: null }); + const newIds = addButtonId(buttonId.current); + setOptions({ buttonRootId: newIds }); + + return () => { + const newIds = removeButtonId(buttonId.current); + setOptions({ buttonRootId: newIds.length > 0 ? newIds : null }); + }; }, [setOptions]); return (
diff --git a/packages/ui-react/src/utils/tonconnect-button-ids.ts b/packages/ui-react/src/utils/tonconnect-button-ids.ts new file mode 100644 index 000000000..44518f9cd --- /dev/null +++ b/packages/ui-react/src/utils/tonconnect-button-ids.ts @@ -0,0 +1,19 @@ +export const DEFAULT_BUTTON_ID = 'ton-connect-button'; + +let ids: string[] = []; + +export function getButtonIds() { + return [...ids]; +} + +export function addButtonId(id: string) { + if (!ids.includes(id)) { + ids.push(id); + } + return getButtonIds(); +} + +export function removeButtonId(id: string) { + ids = ids.filter(existingId => existingId !== id); + return getButtonIds(); +} \ No newline at end of file From de5207af8872da114dc3d22290ae7f2a7c12e7c4 Mon Sep 17 00:00:00 2001 From: Yauheni Mileika Date: Mon, 30 Jun 2025 16:15:08 +0300 Subject: [PATCH 2/5] feat(ui): implement multiple buttons support --- packages/ui/src/app/App.tsx | 12 ++++++++---- packages/ui/src/app/state/app.state.ts | 2 +- packages/ui/src/models/ton-connect-ui-options.ts | 2 +- packages/ui/src/ton-connect-ui.ts | 12 +++++++++++- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/ui/src/app/App.tsx b/packages/ui/src/app/App.tsx index 4feef6c39..e635e7f65 100644 --- a/packages/ui/src/app/App.tsx +++ b/packages/ui/src/app/App.tsx @@ -33,10 +33,14 @@ const App: Component = props => { - - - - + 0}> + <> + {appState.buttonRootId && (appState.buttonRootId as string[]).map((id) => ( + + + + ))} + diff --git a/packages/ui/src/app/state/app.state.ts b/packages/ui/src/app/state/app.state.ts index f924f5bbb..33dcb8c1f 100644 --- a/packages/ui/src/app/state/app.state.ts +++ b/packages/ui/src/app/state/app.state.ts @@ -7,7 +7,7 @@ import { Loadable } from 'src/models/loadable'; export type AppState = { connector: ITonConnect; - buttonRootId: string | null; + buttonRootId: string | null | string[]; language: Locales; walletsListConfiguration: WalletsListConfiguration | {}; connectRequestParameters?: Loadable | null; diff --git a/packages/ui/src/models/ton-connect-ui-options.ts b/packages/ui/src/models/ton-connect-ui-options.ts index 10c1b4e1f..c0708b37c 100644 --- a/packages/ui/src/models/ton-connect-ui-options.ts +++ b/packages/ui/src/models/ton-connect-ui-options.ts @@ -14,7 +14,7 @@ export interface TonConnectUiOptions { * HTML element id to attach the wallet connect button. If not passed button won't appear. * @default null. */ - buttonRootId?: string | null; + buttonRootId?: string | null | string[]; /** * Language for the phrases it the UI elements. diff --git a/packages/ui/src/ton-connect-ui.ts b/packages/ui/src/ton-connect-ui.ts index 2e8fecd79..5c02eaba8 100644 --- a/packages/ui/src/ton-connect-ui.ts +++ b/packages/ui/src/ton-connect-ui.ts @@ -993,11 +993,21 @@ export class TonConnectUI { return rootId; } - private checkButtonRootExist(buttonRootId: string | null | undefined): void | never { + private checkButtonRootExist(buttonRootId: string | string[] | null | undefined): void | never { if (buttonRootId == null) { return; } + if (Array.isArray(buttonRootId)) { + for (const buttonId of buttonRootId) { + if (document.getElementById(buttonId)) { + return; + } + } + + throw new TonConnectUIError(`${buttonRootId} element not found in the document.`); + } + if (!document.getElementById(buttonRootId)) { throw new TonConnectUIError(`${buttonRootId} element not found in the document.`); } From d73562c369728500fb44bf919f9f839a412fe570 Mon Sep 17 00:00:00 2001 From: thekiba Date: Fri, 25 Jul 2025 19:14:46 +0400 Subject: [PATCH 3/5] refactor(ui-react): fix linter errors --- .../ui-react/src/components/TonConnectButton.tsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/ui-react/src/components/TonConnectButton.tsx b/packages/ui-react/src/components/TonConnectButton.tsx index ef5f32efd..d0c7a4eb1 100644 --- a/packages/ui-react/src/components/TonConnectButton.tsx +++ b/packages/ui-react/src/components/TonConnectButton.tsx @@ -1,6 +1,11 @@ import { CSSProperties, FunctionComponent, memo, useEffect, useRef } from 'react'; import { useTonConnectUI } from '../hooks/useTonConnectUI'; -import { addButtonId, removeButtonId, getButtonIds, DEFAULT_BUTTON_ID } from '../utils/tonconnect-button-ids'; +import { + addButtonId, + removeButtonId, + getButtonIds, + DEFAULT_BUTTON_ID +} from '../utils/tonconnect-button-ids'; export interface TonConnectButtonProps { className?: string; @@ -15,13 +20,14 @@ export interface TonConnectButtonProps { * @param [className] css class to add to the button container. * @param [style] style to add to the button container. * @constructor - */const TonConnectButton: FunctionComponent = ({ className, style, id }) => { + */ +const TonConnectButton: FunctionComponent = ({ className, style, id }) => { const [_, setOptions] = useTonConnectUI(); const buttonId = useRef( id ?? - (getButtonIds().length === 0 - ? DEFAULT_BUTTON_ID - : `ton-connect-button-${Math.random().toString(36).slice(2, 10)}`) + (getButtonIds().length === 0 + ? DEFAULT_BUTTON_ID + : `ton-connect-button-${Math.random().toString(36).slice(2, 10)}`) ); useEffect(() => { From 14410fffee28cfdedfb8bbea48fe0bf3d136d346 Mon Sep 17 00:00:00 2001 From: thekiba Date: Fri, 25 Jul 2025 19:27:28 +0400 Subject: [PATCH 4/5] refactor(ui-react): rewrite button ids using Set --- .../src/utils/tonconnect-button-ids.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/ui-react/src/utils/tonconnect-button-ids.ts b/packages/ui-react/src/utils/tonconnect-button-ids.ts index 44518f9cd..706abc216 100644 --- a/packages/ui-react/src/utils/tonconnect-button-ids.ts +++ b/packages/ui-react/src/utils/tonconnect-button-ids.ts @@ -1,19 +1,19 @@ export const DEFAULT_BUTTON_ID = 'ton-connect-button'; -let ids: string[] = []; +const ids: Set = new Set(); -export function getButtonIds() { - return [...ids]; +export function getButtonIds(): string[] { + return Array.from(ids); } -export function addButtonId(id: string) { - if (!ids.includes(id)) { - ids.push(id); +export function addButtonId(id: string): string[] { + if (!ids.has(id)) { + ids.add(id); } return getButtonIds(); } -export function removeButtonId(id: string) { - ids = ids.filter(existingId => existingId !== id); +export function removeButtonId(id: string): string[] { + ids.delete(id); return getButtonIds(); -} \ No newline at end of file +} From 1239b6c05d424d7b05b974c51d12549e98da073f Mon Sep 17 00:00:00 2001 From: thekiba Date: Fri, 25 Jul 2025 19:27:56 +0400 Subject: [PATCH 5/5] refactor(ui): rearrange types for buttonRootId type --- packages/ui/src/models/ton-connect-ui-options.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/models/ton-connect-ui-options.ts b/packages/ui/src/models/ton-connect-ui-options.ts index c0708b37c..9286dc2d5 100644 --- a/packages/ui/src/models/ton-connect-ui-options.ts +++ b/packages/ui/src/models/ton-connect-ui-options.ts @@ -14,7 +14,7 @@ export interface TonConnectUiOptions { * HTML element id to attach the wallet connect button. If not passed button won't appear. * @default null. */ - buttonRootId?: string | null | string[]; + buttonRootId?: string | string[] | null; /** * Language for the phrases it the UI elements.