Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement suggestion for edit composer #35226

Merged
merged 48 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
99c7092
test
dukenv0307 Jan 15, 2024
dee95c9
implement suggestion for edit composer
dukenv0307 Jan 15, 2024
d40e5cc
Merge branch 'main' into fix/34442
dukenv0307 Jan 25, 2024
0de2686
implement suggestion for edit composer
dukenv0307 Jan 25, 2024
a1ef1bf
Merge branch 'main' into fix/34442
dukenv0307 Jan 26, 2024
0273240
display suggestion below when composer at the top of the screen
dukenv0307 Jan 26, 2024
31bf412
fix edge case
dukenv0307 Jan 26, 2024
e5eb167
Merge branch 'main' into fix/34442
dukenv0307 Jan 29, 2024
ee43388
create global ref
dukenv0307 Jan 29, 2024
4858707
Merge branch 'main' into fix/34442
dukenv0307 Feb 6, 2024
bd0ccb7
merge main
dukenv0307 Feb 6, 2024
5f4c43a
merge main
dukenv0307 Feb 19, 2024
f11b8ed
fix lint
dukenv0307 Feb 19, 2024
a7bcde6
update suggestion
dukenv0307 Feb 19, 2024
be5faa2
rename variable
dukenv0307 Feb 19, 2024
c4094f3
merge main
dukenv0307 Feb 26, 2024
eb09849
move portal of suggestion to the correct place
dukenv0307 Feb 26, 2024
a663612
merge main
dukenv0307 Feb 29, 2024
0b5ea25
Merge branch 'main' into fix/34442
dukenv0307 Mar 1, 2024
930eb47
remove global ref and create suggestion context
dukenv0307 Mar 4, 2024
ec83df8
Merge branch 'main' into fix/34442
dukenv0307 Mar 6, 2024
5e5cd88
merge main
dukenv0307 Mar 11, 2024
01c63b8
merge main
dukenv0307 Mar 13, 2024
cc1810a
Merge branch 'main' into fix/34442
dukenv0307 Mar 15, 2024
8dcd362
fix the suggestion padding for edit composer
dukenv0307 Mar 15, 2024
05f316f
Merge branch 'main' into fix/34442
dukenv0307 Mar 19, 2024
07db2ab
update variable name
dukenv0307 Mar 19, 2024
d511cb8
merge main
dukenv0307 Mar 20, 2024
c093a99
fix portal on native
dukenv0307 Mar 20, 2024
616c3c7
rename
dukenv0307 Mar 20, 2024
8caeee3
resolve conflict
dukenv0307 Mar 22, 2024
8c961f3
resolve conflict
dukenv0307 Mar 25, 2024
a2065fd
resolve conflict
dukenv0307 Mar 25, 2024
be61ac7
merge main
dukenv0307 Mar 26, 2024
4ad4341
Merge branch 'main' into fix/34442
dukenv0307 Mar 27, 2024
265ced8
resolve conflict
dukenv0307 Apr 1, 2024
c7defeb
merge main
dukenv0307 Apr 1, 2024
d5d7f24
re-open suggestion menu after scrolling
dukenv0307 Apr 1, 2024
10cedd0
Merge branch 'main' into fix/34442
dukenv0307 Apr 5, 2024
3ff18ff
fix suggestion open after scrolling
dukenv0307 Apr 5, 2024
d923e85
Merge branch 'main' into fix/34442
dukenv0307 Apr 10, 2024
0e7eb4f
create new const for suggestion portal host name
dukenv0307 Apr 10, 2024
f57ca56
Merge branch 'main' into fix/34442
dukenv0307 Apr 12, 2024
d734b75
Merge branch 'main' into fix/34442
dukenv0307 Apr 19, 2024
b153d07
Merge branch 'main' into fix/34442
dukenv0307 Apr 22, 2024
c95b4aa
add explain comment
dukenv0307 Apr 22, 2024
cd0f980
add isGroupPolicyReport prop
dukenv0307 Apr 22, 2024
b820982
fix ts
dukenv0307 Apr 22, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ function BaseAutoCompleteSuggestions<TSuggestion>(
suggestions,
isSuggestionPickerLarge,
keyExtractor,
shouldBelowParentContainer = false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
shouldBelowParentContainer = false,
shouldBeDisplayedBelowParentContainer = false,

}: AutoCompleteSuggestionsProps<TSuggestion>,
ref: ForwardedRef<View | HTMLDivElement>,
) {
Expand Down Expand Up @@ -67,7 +68,7 @@ function BaseAutoCompleteSuggestions<TSuggestion>(
);

const innerHeight = CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT * suggestions.length;
const animatedStyles = useAnimatedStyle(() => StyleUtils.getAutoCompleteSuggestionContainerStyle(rowHeight.value));
const animatedStyles = useAnimatedStyle(() => StyleUtils.getAutoCompleteSuggestionContainerStyle(rowHeight.value, shouldBelowParentContainer));
const estimatedListSize = useMemo(
() => ({
height: CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT * suggestions.length,
Expand Down
13 changes: 11 additions & 2 deletions src/components/AutoCompleteSuggestions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {View} from 'react-native';
import useStyleUtils from '@hooks/useStyleUtils';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import {measureHeightOfSuggestioContainer} from '@libs/SuggestionUtils';
import BaseAutoCompleteSuggestions from './BaseAutoCompleteSuggestions';
import type {AutoCompleteSuggestionsProps} from './types';

Expand All @@ -18,11 +19,13 @@ function AutoCompleteSuggestions<TSuggestion>({measureParentContainer = () => {}
const StyleUtils = useStyleUtils();
const containerRef = React.useRef<HTMLDivElement>(null);
const {windowHeight, windowWidth} = useWindowDimensions();
const suggestionContainerHeight = measureHeightOfSuggestioContainer(props.suggestions.length, props.isSuggestionPickerLarge);
const [{width, left, bottom}, setContainerState] = React.useState({
width: 0,
left: 0,
bottom: 0,
});
const [shouldBelowContainer, setShouldBelowContainer] = React.useState(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const [shouldBelowContainer, setShouldBelowContainer] = React.useState(false);
const [shouldShowBelowContainer, setShouldShowBelowContainer] = React.useState(false);

React.useEffect(() => {
const container = containerRef.current;
if (!container) {
Expand All @@ -41,13 +44,19 @@ function AutoCompleteSuggestions<TSuggestion>({measureParentContainer = () => {}
if (!measureParentContainer) {
return;
}
measureParentContainer((x, y, w) => setContainerState({left: x, bottom: windowHeight - y, width: w}));
}, [measureParentContainer, windowHeight, windowWidth]);

measureParentContainer((x, y, w, h) => {
const currenBottom = y < suggestionContainerHeight ? windowHeight - y - suggestionContainerHeight - h : windowHeight - y;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const currenBottom = y < suggestionContainerHeight ? windowHeight - y - suggestionContainerHeight - h : windowHeight - y;
const currentBottom = y < suggestionsContainerHeight ? windowHeight - y - suggestionContainerHeight - h : windowHeight - y;

setShouldBelowContainer(y < suggestionContainerHeight);
setContainerState({left: x, bottom: currenBottom, width: w});
});
}, [measureParentContainer, windowHeight, windowWidth, suggestionContainerHeight]);

const componentToRender = (
<BaseAutoCompleteSuggestions<TSuggestion>
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
shouldBelowParentContainer={shouldBelowContainer}
ref={containerRef}
/>
);
Expand Down
5 changes: 4 additions & 1 deletion src/components/AutoCompleteSuggestions/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type {ReactElement} from 'react';

type MeasureParentContainerCallback = (x: number, y: number, width: number) => void;
type MeasureParentContainerCallback = (x: number, y: number, width: number, height: number) => void;

type RenderSuggestionMenuItemProps<TSuggestion> = {
item: TSuggestion;
Expand Down Expand Up @@ -33,6 +33,9 @@ type AutoCompleteSuggestionsProps<TSuggestion> = {

/** Meaures the parent container's position and dimensions. */
measureParentContainer?: (callback: MeasureParentContainerCallback) => void;

/** Whether suggestion should be displayed below the parent container or not */
shouldBelowParentContainer?: boolean;
};

export type {AutoCompleteSuggestionsProps, RenderSuggestionMenuItemProps};
4 changes: 3 additions & 1 deletion src/components/Composer/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {NativeSyntheticEvent, StyleProp, TextInputFocusEventData, TextInputKeyPressEventData, TextInputSelectionChangeEventData, TextStyle} from 'react-native';
import type {LayoutChangeEvent, NativeSyntheticEvent, StyleProp, TextInputFocusEventData, TextInputKeyPressEventData, TextInputSelectionChangeEventData, TextStyle} from 'react-native';

type TextSelection = {
start: number;
Expand Down Expand Up @@ -80,6 +80,8 @@ type ComposerProps = {

onBlur?: (event: NativeSyntheticEvent<TextInputFocusEventData>) => void;

onLayout?: (event: LayoutChangeEvent) => void;

/** Should make the input only scroll inside the element avoid scroll out to parent */
shouldContainScroll?: boolean;
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/EmojiSuggestions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import getStyledTextArray from '@libs/GetStyledTextArray';
import AutoCompleteSuggestions from './AutoCompleteSuggestions';
import Text from './Text';

type MeasureParentContainerCallback = (x: number, y: number, width: number) => void;
type MeasureParentContainerCallback = (x: number, y: number, width: number, height: number) => void;

type EmojiSuggestionsProps = {
/** The index of the highlighted emoji */
Expand Down
22 changes: 21 additions & 1 deletion src/libs/SuggestionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,24 @@ function hasEnoughSpaceForLargeSuggestionMenu(listHeight: number, composerHeight
return availableHeight > menuHeight;
}

export {trimLeadingSpace, hasEnoughSpaceForLargeSuggestionMenu};
const measureHeightOfSuggestioContainer = (numRows: number, isSuggestionPickerLarge: boolean): number => {
const borderAndPadding = CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTER_PADDING + 2;
let suggestionHeight = 0;

if (isSuggestionPickerLarge) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (isSuggestionPickerLarge) {
if (isSuggestionsPickerLarge) {

And all of the occurances below (i.e. suggestionHeight)

if (numRows > CONST.AUTO_COMPLETE_SUGGESTER.MAX_AMOUNT_OF_VISIBLE_SUGGESTIONS_IN_CONTAINER) {
// On large screens, if there are more than 5 suggestions, we display a scrollable window with a height of 5 items, indicating that there are more items available
suggestionHeight = CONST.AUTO_COMPLETE_SUGGESTER.MAX_AMOUNT_OF_VISIBLE_SUGGESTIONS_IN_CONTAINER * CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT;
} else {
suggestionHeight = numRows * CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT;
}
} else if (numRows > 2) {
// On small screens, we display a scrollable window with a height of 2.5 items, indicating that there are more items available beyond what is currently visible
suggestionHeight = CONST.AUTO_COMPLETE_SUGGESTER.SMALL_CONTAINER_HEIGHT_FACTOR * CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT;
} else {
suggestionHeight = numRows * CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT;
}
return suggestionHeight + borderAndPadding;
};

export {trimLeadingSpace, hasEnoughSpaceForLargeSuggestionMenu, measureHeightOfSuggestioContainer};
50 changes: 50 additions & 0 deletions src/libs/actions/SuggestionsAction.ts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's rename this to SuggestionsActions

Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import type {NativeSyntheticEvent, TextInputKeyPressEventData, TextInputSelectionChangeEventData} from 'react-native';

type SuggestionsRef = {
getSuggestions: () => void;
resetSuggestions: () => void;
triggerHotkeyActions: (event: NativeSyntheticEvent<TextInputKeyPressEventData> | KeyboardEvent) => boolean;
onSelectionChange: (event: NativeSyntheticEvent<TextInputSelectionChangeEventData>) => void;
updateShouldShowSuggestionMenuToFalse: () => void;
setShouldBlockSuggestionCalc: () => void;
};

const suggestionsRef = React.createRef<SuggestionsRef>();

function resetSuggestions() {
if (!suggestionsRef.current) {
return;
}

suggestionsRef.current.resetSuggestions();
}

function triggerHotkeyActions(event: NativeSyntheticEvent<TextInputKeyPressEventData> | KeyboardEvent): boolean {
if (!suggestionsRef.current) {
return false;
}

return suggestionsRef.current.triggerHotkeyActions(event);
}

function updateShouldShowSuggestionMenuToFalse() {
if (!suggestionsRef.current) {
return;
}

suggestionsRef.current.updateShouldShowSuggestionMenuToFalse();
}

function onSelectionChange(event: NativeSyntheticEvent<TextInputSelectionChangeEventData>) {
if (!suggestionsRef.current) {
return;
}

suggestionsRef.current.onSelectionChange(event);
}

export {suggestionsRef, resetSuggestions, triggerHotkeyActions, onSelectionChange, updateShouldShowSuggestionMenuToFalse};

// eslint-disable-next-line import/prefer-default-export
export type {SuggestionsRef};
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import type {Dispatch, ForwardedRef, RefObject, SetStateAction} from 'react';
import React, {useState} from 'react';
import type {TextInput} from 'react-native';
import Composer from '@components/Composer';
import type {ComposerProps} from '@components/Composer/types';
import type {SuggestionsRef} from '@libs/actions/SuggestionsAction';
import Suggestions from '@pages/home/report/ReportActionCompose/Suggestions';

type ComposerWithSuggestionsEditProps = {
setValue: Dispatch<SetStateAction<string>>;
setSelection: Dispatch<
SetStateAction<{
start: number;
end: number;
}>
>;
resetKeyboardInput: () => void;
isComposerFocused: boolean;
suggestionsRef: RefObject<SuggestionsRef>;
updateDraft: (newValue: string) => void;
measureParentContainer: (callback: () => void) => void;
};

function ComposerWithSuggestionsEdit(
{
value,
maxLines = -1,
onKeyPress = () => {},
style,
onSelectionChange = () => {},
selection = {
start: 0,
end: 0,
},
onBlur = () => {},
onFocus = () => {},
onChangeText = () => {},
setValue = () => {},
setSelection = () => {},
resetKeyboardInput = () => {},
isComposerFocused,
suggestionsRef,
updateDraft,
measureParentContainer,
id = undefined,
}: ComposerWithSuggestionsEditProps & ComposerProps,
ref: ForwardedRef<TextInput>,
) {
const [composerHeight, setComposerHeight] = useState(0);

return (
<>
<Composer
multiline
ref={ref}
id={id}
onChangeText={onChangeText} // Debounced saveDraftComment
onKeyPress={onKeyPress}
value={value}
maxLines={maxLines} // This is the same that slack has
style={style}
onFocus={onFocus}
onBlur={onBlur}
selection={selection}
onSelectionChange={onSelectionChange}
onLayout={(e) => {
const composerLayoutHeight = e.nativeEvent.layout.height;
if (composerHeight === composerLayoutHeight) {
return;
}
setComposerHeight(composerLayoutHeight);
}}
/>

<Suggestions
ref={suggestionsRef}
// @ts-expect-error TODO: Remove this once Suggestions is migrated to TypeScript.
isComposerFullSize={false}
isComposerFocused={isComposerFocused}
updateComment={updateDraft}
composerHeight={composerHeight}
measureParentContainer={measureParentContainer}
isAutoSuggestionPickerLarge
value={value}
setValue={setValue}
selection={selection}
setSelection={setSelection}
resetKeyboardInput={resetKeyboardInput}
/>
</>
);
}

export default React.forwardRef(ComposerWithSuggestionsEdit);
Loading
Loading