Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5299a47
Revert "Revert "fix: messages content overlap when bottom sheet is sh…
kirillzyusko Jan 2, 2025
5b05167
fix: when message is not obscured by bottom-sheet (keyboard open) and…
kirillzyusko Jan 7, 2025
37a5e71
fix: eslint
kirillzyusko Jan 7, 2025
7103426
Merge branch 'main' into fix/bottom-sheet-message-overlap
kirillzyusko Jan 7, 2025
adb9c9e
trigger CLOSE_POPOVER
perunt Jan 17, 2025
e0e0c69
fix empty space
perunt Jan 20, 2025
560cc60
Merge branch 'main' of https://github.com/Expensify/App into fix/bott…
perunt Jan 21, 2025
feb5268
remove previous position fix
perunt Jan 21, 2025
c7c0746
fix test
perunt Jan 21, 2025
168c5c7
fix: new eslint rules in EmojiPickerButton, ImageRenderer, PreRendere…
perunt Jan 21, 2025
0321cec
Merge branch 'main' of https://github.com/Expensify/App into fix/bott…
perunt Jan 21, 2025
5141f6a
mock executeOnUIRuntimeSync
perunt Jan 21, 2025
bd1adc3
Merge branch 'main' of https://github.com/Expensify/App into fix/bott…
perunt Jan 24, 2025
3b99c6f
Merge branch 'main' of https://github.com/Expensify/App into fix/bott…
perunt Feb 27, 2025
0a02f19
white gap fix
perunt Feb 27, 2025
236f114
fix: new eslint rules
perunt Feb 27, 2025
c1529d2
Merge branch 'main' of https://github.com/Expensify/App into fix/bott…
perunt Mar 13, 2025
1fb7fdd
Merge branch 'main' of https://github.com/Expensify/App into fix/bott…
perunt Mar 18, 2025
8d3ac6a
fix after merge: use react-native-keyboard-controller
perunt Mar 18, 2025
11a6ad3
position tracking
perunt Mar 20, 2025
6160627
refactor gap detection, fix for simulator
perunt Mar 20, 2025
fcc706c
lint
perunt Mar 20, 2025
91e601d
mock
perunt Mar 20, 2025
b9ab870
Merge branch 'main' of https://github.com/Expensify/App into fix/bott…
perunt Apr 4, 2025
bfc394e
Merge branch 'main' of https://github.com/Expensify/App into fix/bott…
perunt Apr 14, 2025
737cf83
fix typo
perunt Apr 16, 2025
e5290d5
rename fy to frameY
perunt Apr 16, 2025
20b2085
Merge branch 'main' of https://github.com/Expensify/App into fix/bott…
perunt Apr 16, 2025
f56f64a
style: change text indentations
perunt May 13, 2025
b39f5bd
update types
perunt May 13, 2025
c35e42c
Merge branch 'main' of https://github.com/Expensify/App into fix/bott…
perunt May 13, 2025
37fd2db
chore: fix due to new eslint rule
perunt May 13, 2025
b2fbadc
trigger test
perunt May 13, 2025
0dcead9
Merge branch 'main' of https://github.com/Expensify/App into fix/bott…
perunt May 20, 2025
0e2cf07
use fastMerge
perunt May 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions jest/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ jest.mock('react-native-reanimated', () => ({
...jest.requireActual<typeof Animated>('react-native-reanimated/mock'),
createAnimatedPropAdapter: jest.fn,
useReducedMotion: jest.fn,
useScrollViewOffset: jest.fn(() => 0),
useAnimatedRef: jest.fn(() => jest.fn()),
LayoutAnimationConfig: jest.fn,
}));

Expand Down Expand Up @@ -164,3 +166,9 @@ jest.mock('@libs/prepareRequestPayload/index.native.ts', () => ({
return Promise.resolve(formData);
}),
}));

jest.mock('@src/hooks/useWorkletStateMachine/executeOnUIRuntimeSync', () => ({
// eslint-disable-next-line @typescript-eslint/naming-convention
__esModule: true,
default: jest.fn(() => jest.fn()), // Return a function that returns a function
}));
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {GestureHandlerRootView} from 'react-native-gesture-handler';
import {PickerStateProvider} from 'react-native-picker-select';
import {SafeAreaProvider} from 'react-native-safe-area-context';
import '../wdyr';
import {ActionSheetAwareScrollViewProvider} from './components/ActionSheetAwareScrollView';
import ActiveElementRoleProvider from './components/ActiveElementRoleProvider';
import ColorSchemeWrapper from './components/ColorSchemeWrapper';
import ComposeProviders from './components/ComposeProviders';
Expand Down Expand Up @@ -102,6 +103,7 @@ function App({url, hybridAppSettings, timestamp}: AppProps) {
EnvironmentProvider,
CustomStatusBarAndBackgroundContextProvider,
ActiveElementRoleProvider,
ActionSheetAwareScrollViewProvider,
PlaybackContextProvider,
FullScreenContextProvider,
VolumeContextProvider,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import noop from 'lodash/noop';
import PropTypes from 'prop-types';
import type {PropsWithChildren} from 'react';
import React, {createContext, useMemo} from 'react';
import type {SharedValue} from 'react-native-reanimated';
import type {ValueOf} from 'type-fest';
import type {ActionWithPayload, State, StateMachine} from '@hooks/useWorkletStateMachine';
import useWorkletStateMachine from '@hooks/useWorkletStateMachine';

type MeasuredElements = {
frameY?: number;
popoverHeight?: number;
height?: number;
composerHeight?: number;
};

type Context = {
currentActionSheetState: SharedValue<State<MeasuredElements>>;
transitionActionSheetState: (action: ActionWithPayload) => void;
transitionActionSheetStateWorklet: (action: ActionWithPayload) => void;
resetStateMachine: () => void;
};

/** Holds all information that is needed to coordinate the state value for the action sheet state machine. */
const currentActionSheetStateValue = {
previous: {
state: 'idle',
payload: null,
},
current: {
state: 'idle',
payload: null,
},
};
const defaultValue: Context = {
currentActionSheetState: {
value: currentActionSheetStateValue,
addListener: noop,
removeListener: noop,
modify: noop,
get: () => currentActionSheetStateValue,
set: noop,
},
transitionActionSheetState: noop,
transitionActionSheetStateWorklet: noop,
resetStateMachine: noop,
};

const ActionSheetAwareScrollViewContext = createContext<Context>(defaultValue);

const Actions = {
OPEN_KEYBOARD: 'KEYBOARD_OPEN',
CLOSE_KEYBOARD: 'CLOSE_KEYBOARD',
OPEN_POPOVER: 'OPEN_POPOVER',
CLOSE_POPOVER: 'CLOSE_POPOVER',
MEASURE_POPOVER: 'MEASURE_POPOVER',
MEASURE_COMPOSER: 'MEASURE_COMPOSER',
POPOVER_ANY_ACTION: 'POPOVER_ANY_ACTION',
HIDE_WITHOUT_ANIMATION: 'HIDE_WITHOUT_ANIMATION',
END_TRANSITION: 'END_TRANSITION',
} as const;

const States = {
IDLE: 'idle',
KEYBOARD_OPEN: 'keyboardOpen',
POPOVER_OPEN: 'popoverOpen',
POPOVER_CLOSED: 'popoverClosed',
KEYBOARD_POPOVER_CLOSED: 'keyboardPopoverClosed',
KEYBOARD_POPOVER_OPEN: 'keyboardPopoverOpen',
KEYBOARD_CLOSED_POPOVER: 'keyboardClosingPopover',
POPOVER_MEASURED: 'popoverMeasured',
MODAL_WITH_KEYBOARD_OPEN_DELETED: 'modalWithKeyboardOpenDeleted',
} as const;

const STATE_MACHINE: StateMachine<ValueOf<typeof States>, ValueOf<typeof Actions>> = {
[States.IDLE]: {
[Actions.OPEN_POPOVER]: States.POPOVER_OPEN,
[Actions.OPEN_KEYBOARD]: States.KEYBOARD_OPEN,
[Actions.MEASURE_POPOVER]: States.IDLE,
[Actions.MEASURE_COMPOSER]: States.IDLE,
},
[States.POPOVER_OPEN]: {
[Actions.CLOSE_POPOVER]: States.POPOVER_CLOSED,
[Actions.MEASURE_POPOVER]: States.POPOVER_OPEN,
[Actions.MEASURE_COMPOSER]: States.POPOVER_OPEN,
[Actions.POPOVER_ANY_ACTION]: States.POPOVER_CLOSED,
[Actions.HIDE_WITHOUT_ANIMATION]: States.IDLE,
},
[States.POPOVER_CLOSED]: {
[Actions.END_TRANSITION]: States.IDLE,
},
[States.KEYBOARD_OPEN]: {
[Actions.OPEN_KEYBOARD]: States.KEYBOARD_OPEN,
[Actions.OPEN_POPOVER]: States.KEYBOARD_POPOVER_OPEN,
[Actions.CLOSE_KEYBOARD]: States.IDLE,
[Actions.MEASURE_COMPOSER]: States.KEYBOARD_OPEN,
},
[States.KEYBOARD_POPOVER_OPEN]: {
[Actions.MEASURE_POPOVER]: States.KEYBOARD_POPOVER_OPEN,
[Actions.CLOSE_POPOVER]: States.KEYBOARD_CLOSED_POPOVER,
[Actions.OPEN_KEYBOARD]: States.KEYBOARD_OPEN,
},
[States.KEYBOARD_POPOVER_CLOSED]: {
[Actions.OPEN_KEYBOARD]: States.KEYBOARD_OPEN,
},
[States.KEYBOARD_CLOSED_POPOVER]: {
[Actions.OPEN_KEYBOARD]: States.KEYBOARD_OPEN,
[Actions.END_TRANSITION]: States.KEYBOARD_OPEN,
},
};

function ActionSheetAwareScrollViewProvider(props: PropsWithChildren<unknown>) {
const {currentState, transition, transitionWorklet, reset} = useWorkletStateMachine<typeof STATE_MACHINE, MeasuredElements>(STATE_MACHINE, {
previous: {
state: 'idle',
payload: null,
},
current: {
state: 'idle',
payload: null,
},
});

const value = useMemo(
() => ({
currentActionSheetState: currentState,
transitionActionSheetState: transition,
transitionActionSheetStateWorklet: transitionWorklet,
resetStateMachine: reset,
}),
[currentState, reset, transition, transitionWorklet],
);

return <ActionSheetAwareScrollViewContext.Provider value={value}>{props.children}</ActionSheetAwareScrollViewContext.Provider>;
}

ActionSheetAwareScrollViewProvider.propTypes = {
children: PropTypes.node.isRequired,
};

export {ActionSheetAwareScrollViewContext, ActionSheetAwareScrollViewProvider, Actions, States};
Loading