From 1912e26644b17b1d7ed2b896adc603fcf4bf69bb Mon Sep 17 00:00:00 2001 From: tfomkin Date: Thu, 22 Jan 2026 21:44:48 +0700 Subject: [PATCH 1/3] fix: use GestureAppPressable instead of AppPressable for modals IconButton --- .../ui/ui-kit/src/icon-button/component.tsx | 61 +++++++++++++++---- .../shared/ui/ui-kit/src/modal/component.tsx | 1 + 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/libs/mobile/shared/ui/ui-kit/src/icon-button/component.tsx b/libs/mobile/shared/ui/ui-kit/src/icon-button/component.tsx index eb3eb23..b0da0db 100644 --- a/libs/mobile/shared/ui/ui-kit/src/icon-button/component.tsx +++ b/libs/mobile/shared/ui/ui-kit/src/icon-button/component.tsx @@ -1,31 +1,68 @@ import { ReactElement } from 'react'; +import { PressableProps as GesturePressableProps } from 'react-native-gesture-handler'; import { cn } from '@open-webui-react-native/mobile/shared/ui/styles'; import { Icon, IconProps } from '../icon/component'; import { IconName } from '../icon/types'; -import { AppPressable, AppPressableProps } from '../pressable'; +import { AppPressable, AppPressableProps, GestureAppPressable } from '../pressable'; import { AppSpinner } from '../spinner'; -export interface IconButtonProps extends AppPressableProps { +interface BaseIconButtonProps { iconName: IconName; iconProps?: Omit; isLoading?: boolean; + className?: string; } -export function IconButton({ - className, +export type IconButtonProps = + | (BaseIconButtonProps & + AppPressableProps & { + useGestureHandler?: false; + }) + | (BaseIconButtonProps & + GesturePressableProps & { + useGestureHandler: true; + }); + +const IconButtonContent = ({ + isLoading, iconName, iconProps, - isLoading, - disabled, - ...restProps -}: IconButtonProps): ReactElement { +}: Pick): ReactElement => + isLoading ? : ; + +export function IconButton(props: IconButtonProps): ReactElement { + const baseClassName = cn('p-8 disabled:opacity-30 items-center justify-center', props.className); + + // NOTE: Pressable from react-native does not work correctly with react-native-modal - https://github.com/react-native-modal/react-native-modal/issues/582#issuecomment-1156723062 + if (props.useGestureHandler) { + const { useGestureHandler, iconName, iconProps, isLoading, className, ...gestureProps } = props; + + return ( + + + + ); + } + + const { useGestureHandler, iconName, iconProps, isLoading, className, ...rnProps } = props; + return ( - {isLoading ? : } + className={baseClassName} + disabled={rnProps.disabled || isLoading}> + ); } diff --git a/libs/mobile/shared/ui/ui-kit/src/modal/component.tsx b/libs/mobile/shared/ui/ui-kit/src/modal/component.tsx index 1b9dc29..f29454c 100644 --- a/libs/mobile/shared/ui/ui-kit/src/modal/component.tsx +++ b/libs/mobile/shared/ui/ui-kit/src/modal/component.tsx @@ -43,6 +43,7 @@ export function AppModal({ modalRef, children, ...modalProps }: AppModalProps): onPress={close} className='absolute active:opacity-1 active:bg-background-secondary bg-background-primary border border-text-secondary p-0 rounded-full items-center justify-center w-[24] h-[24] top-4 right-4' iconProps={{ className: 'color-text-primary', width: 16 }} + useGestureHandler /> )} From 056d58d48634446f867e6fc979edb1d3e3fb6eda Mon Sep 17 00:00:00 2001 From: tfomkin Date: Fri, 23 Jan 2026 01:34:50 +0700 Subject: [PATCH 2/3] fix: created a separate component for GesturePressableIconButton --- .../component.tsx | 33 ++++++++++ .../gesture-pressable-icon-button/index.ts | 1 + .../ui/ui-kit/src/icon-button/component.tsx | 61 ++++--------------- libs/mobile/shared/ui/ui-kit/src/index.ts | 1 + .../shared/ui/ui-kit/src/modal/component.tsx | 5 +- 5 files changed, 49 insertions(+), 52 deletions(-) create mode 100644 libs/mobile/shared/ui/ui-kit/src/gesture-pressable-icon-button/component.tsx create mode 100644 libs/mobile/shared/ui/ui-kit/src/gesture-pressable-icon-button/index.ts diff --git a/libs/mobile/shared/ui/ui-kit/src/gesture-pressable-icon-button/component.tsx b/libs/mobile/shared/ui/ui-kit/src/gesture-pressable-icon-button/component.tsx new file mode 100644 index 0000000..af754b9 --- /dev/null +++ b/libs/mobile/shared/ui/ui-kit/src/gesture-pressable-icon-button/component.tsx @@ -0,0 +1,33 @@ +import { ReactElement } from 'react'; +import { PressableProps as GesturePressableProps } from 'react-native-gesture-handler'; +import { cn } from '@open-webui-react-native/mobile/shared/ui/styles'; +import { Icon, IconProps } from '../icon/component'; +import { IconName } from '../icon/types'; +import { GestureAppPressable } from '../pressable'; +import { AppSpinner } from '../spinner'; + +export interface GesturePressableIconButtonProps extends GesturePressableProps { + iconName: IconName; + iconProps?: Omit; + isLoading?: boolean; + className?: string; +} + +export function GesturePressableIconButton({ + iconName, + iconProps, + isLoading, + disabled, + className, + ...pressableProps +}: GesturePressableIconButtonProps): ReactElement { + return ( + + {isLoading ? : } + + ); +} diff --git a/libs/mobile/shared/ui/ui-kit/src/gesture-pressable-icon-button/index.ts b/libs/mobile/shared/ui/ui-kit/src/gesture-pressable-icon-button/index.ts new file mode 100644 index 0000000..bb82484 --- /dev/null +++ b/libs/mobile/shared/ui/ui-kit/src/gesture-pressable-icon-button/index.ts @@ -0,0 +1 @@ +export * from './component'; diff --git a/libs/mobile/shared/ui/ui-kit/src/icon-button/component.tsx b/libs/mobile/shared/ui/ui-kit/src/icon-button/component.tsx index b0da0db..eb3eb23 100644 --- a/libs/mobile/shared/ui/ui-kit/src/icon-button/component.tsx +++ b/libs/mobile/shared/ui/ui-kit/src/icon-button/component.tsx @@ -1,68 +1,31 @@ import { ReactElement } from 'react'; -import { PressableProps as GesturePressableProps } from 'react-native-gesture-handler'; import { cn } from '@open-webui-react-native/mobile/shared/ui/styles'; import { Icon, IconProps } from '../icon/component'; import { IconName } from '../icon/types'; -import { AppPressable, AppPressableProps, GestureAppPressable } from '../pressable'; +import { AppPressable, AppPressableProps } from '../pressable'; import { AppSpinner } from '../spinner'; -interface BaseIconButtonProps { +export interface IconButtonProps extends AppPressableProps { iconName: IconName; iconProps?: Omit; isLoading?: boolean; - className?: string; } -export type IconButtonProps = - | (BaseIconButtonProps & - AppPressableProps & { - useGestureHandler?: false; - }) - | (BaseIconButtonProps & - GesturePressableProps & { - useGestureHandler: true; - }); - -const IconButtonContent = ({ - isLoading, +export function IconButton({ + className, iconName, iconProps, -}: Pick): ReactElement => - isLoading ? : ; - -export function IconButton(props: IconButtonProps): ReactElement { - const baseClassName = cn('p-8 disabled:opacity-30 items-center justify-center', props.className); - - // NOTE: Pressable from react-native does not work correctly with react-native-modal - https://github.com/react-native-modal/react-native-modal/issues/582#issuecomment-1156723062 - if (props.useGestureHandler) { - const { useGestureHandler, iconName, iconProps, isLoading, className, ...gestureProps } = props; - - return ( - - - - ); - } - - const { useGestureHandler, iconName, iconProps, isLoading, className, ...rnProps } = props; - + isLoading, + disabled, + ...restProps +}: IconButtonProps): ReactElement { return ( - + disabled={disabled || isLoading} + className={cn('p-8 disabled:opacity-30 items-center justify-center', className)} + {...restProps}> + {isLoading ? : } ); } diff --git a/libs/mobile/shared/ui/ui-kit/src/index.ts b/libs/mobile/shared/ui/ui-kit/src/index.ts index 3e9fca8..0e4305f 100644 --- a/libs/mobile/shared/ui/ui-kit/src/index.ts +++ b/libs/mobile/shared/ui/ui-kit/src/index.ts @@ -41,3 +41,4 @@ export * from './sheet-header'; export * from './keyboard-aware-scroll-view'; export * from './pressable-search-input'; export * from './full-screen-search-modal'; +export * from './gesture-pressable-icon-button'; diff --git a/libs/mobile/shared/ui/ui-kit/src/modal/component.tsx b/libs/mobile/shared/ui/ui-kit/src/modal/component.tsx index f29454c..f114d1d 100644 --- a/libs/mobile/shared/ui/ui-kit/src/modal/component.tsx +++ b/libs/mobile/shared/ui/ui-kit/src/modal/component.tsx @@ -1,6 +1,6 @@ import { useState, ReactElement, PropsWithChildren, useImperativeHandle, ForwardedRef } from 'react'; import Modal, { ModalProps } from 'react-native-modal'; -import { IconButton } from '../icon-button'; +import { GesturePressableIconButton } from '../gesture-pressable-icon-button'; import { AppToast } from '../toast'; import { View } from '../view'; @@ -37,13 +37,12 @@ export function AppModal({ modalRef, children, ...modalProps }: AppModalProps): {isVisible && ( {children} - )} From 58e962249a4605c86cee47bab41545f8c3faa9cb Mon Sep 17 00:00:00 2001 From: tfomkin Date: Fri, 23 Jan 2026 02:42:00 +0700 Subject: [PATCH 3/3] fix: use platform specific icon button components --- .../shared/ui/ui-kit/src/modal/component.tsx | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/libs/mobile/shared/ui/ui-kit/src/modal/component.tsx b/libs/mobile/shared/ui/ui-kit/src/modal/component.tsx index f114d1d..183cb19 100644 --- a/libs/mobile/shared/ui/ui-kit/src/modal/component.tsx +++ b/libs/mobile/shared/ui/ui-kit/src/modal/component.tsx @@ -1,6 +1,8 @@ import { useState, ReactElement, PropsWithChildren, useImperativeHandle, ForwardedRef } from 'react'; +import { Platform } from 'react-native'; import Modal, { ModalProps } from 'react-native-modal'; import { GesturePressableIconButton } from '../gesture-pressable-icon-button'; +import { IconButton } from '../icon-button'; import { AppToast } from '../toast'; import { View } from '../view'; @@ -37,13 +39,23 @@ export function AppModal({ modalRef, children, ...modalProps }: AppModalProps): {isVisible && ( {children} - + {Platform.OS === 'ios' ? ( + + ) : ( + + )} )}