Skip to content

Hint Refactor #3486

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

Merged
merged 42 commits into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
930a844
refactor: rename hint rendering methods for clarity
ethanshar Dec 23, 2024
084f150
fix: add second hint toggle and adjust hint message positioning
ethanshar Dec 25, 2024
26ef738
Update src/components/hint/index.tsx
ethanshar Dec 29, 2024
3414fff
fix: adjust edge margins and target position thresholds in Hint compo…
ethanshar Dec 31, 2024
019f317
Merge branch 'master' into fix/hint_position
ethanshar Jan 1, 2025
a08f6f5
Add minimum width to Hint component for better layout consistency
ethanshar Jan 2, 2025
f651253
Merge branch 'master' into fix/hint_position
ethanshar Jan 12, 2025
5afbf8f
Convert Hint class component to a function component
ethanshar Jan 13, 2025
c2c3d9b
Separate old Hint code to another file
ethanshar Jan 13, 2025
80ed235
export error for hint wrap with asBaseComponent
ethanshar Jan 13, 2025
40b18be
Extract types to another file
ethanshar Jan 13, 2025
139b8ac
Extract animation logic to useHintAnimation
ethanshar Jan 13, 2025
06006e0
Add useHintLayout hook to manage hint layout state and measurements
ethanshar Jan 13, 2025
3228021
Move HintProps to types
ethanshar Jan 13, 2025
26ceaac
cleanups
ethanshar Jan 13, 2025
1543cea
Add useHintAccessibility hook for improved accessibility handling
ethanshar Jan 13, 2025
cde322d
Add useHintPosition hook for dynamic hint positioning logic
ethanshar Jan 13, 2025
4b38f7b
Refactor and extract HintMockChildren component
ethanshar Jan 13, 2025
598312d
Add HintAnchor component for improved hint rendering and management
ethanshar Jan 14, 2025
5d230ce
Fix render overlay not rendered
ethanshar Jan 16, 2025
56bc7d9
Refactor Hint components for improved structure and layout handling
ethanshar Jan 21, 2025
4ea0f45
Refactor Hint components to use LayoutRectangle for target layout and…
ethanshar Jan 21, 2025
a9811ce
Refactor Hint components to replace TARGET_POSITIONS with TargetAlign…
ethanshar Jan 21, 2025
c6e1eca
Refactor HintAnchor and useHintPosition components to improve type de…
ethanshar Jan 21, 2025
0b12ec8
Refactor useHintPosition hook to improve target position calculations…
ethanshar Jan 21, 2025
f5016b2
Refactor useHintPosition hook to remove unused targetLayout prop and …
ethanshar Jan 21, 2025
437ced7
Merge branch 'master' into infra/hint_refactor_part3
ethanshar Jan 21, 2025
e0fb900
Refactor useHintLayout hook to accept props directly and improve targ…
ethanshar Jan 21, 2025
f36d7c7
Update HintsScreen to rename 'Middle Top' to 'Middle Tip' and improve…
ethanshar Jan 21, 2025
ce2d872
Refactor HintBubble import path and clean up useHintPosition hook by …
ethanshar Jan 21, 2025
e231f4b
Refactor useHintLayout hook to initialize target layout state correct…
ethanshar Jan 22, 2025
86bc627
Refactor Hint component drivers and tests; update useHintLayout hook …
ethanshar Jan 23, 2025
afc0866
Update Hint component snapshots
ethanshar Jan 23, 2025
563f758
Refactor useHintPosition hook to unify tip position style variable na…
ethanshar Jan 23, 2025
f3b447c
Add comment to clarify targetScreenToRelativeOffset calculation in us…
ethanshar Jan 23, 2025
c0c1700
Merge branch 'master' into infra/hint_refactor_part3
ethanshar Jan 23, 2025
5c6dac0
Merge branch 'master' into infra/hint_refactor_part3
ethanshar Feb 3, 2025
95f9e5a
HintsScreen - Update hintKey to include showCustomContent and showRea…
ethanshar Feb 3, 2025
094a94b
Merge branch 'master' into infra/hint_refactor_part3
ethanshar Feb 10, 2025
fa45014
Rename useHintAnimation to useHintVisibility and move some code
ethanshar Feb 10, 2025
e4c594d
Fix hint position calculation for RTL
ethanshar Feb 10, 2025
bdd2ff7
Merge branch 'master' into infra/hint_refactor_part3
ethanshar Feb 12, 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
25 changes: 23 additions & 2 deletions demo/src/screens/componentScreens/HintsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type HintScreenProps = {};
export default class HintsScreen extends Component<HintScreenProps> {
state = {
showHint: true,
showSecondHint: false,
useShortMessage: false,
showBottomHint: false,
showIcon: false,
Expand All @@ -28,6 +29,10 @@ export default class HintsScreen extends Component<HintScreenProps> {
this.setState({showHint: !this.state.showHint});
};

toggleSecondHint = () => {
this.setState({showSecondHint: !this.state.showSecondHint});
};

toggleHintPosition = () => {
this.setState({
showBottomHint: !this.state.showBottomHint
Expand Down Expand Up @@ -92,7 +97,7 @@ export default class HintsScreen extends Component<HintScreenProps> {

{renderMultipleSegmentOptions.call(this, 'Tip Position', 'useSideTip', [
{label: 'Side Tip', value: true},
{label: 'Middle Top', value: false}
{label: 'Middle Tip', value: false}
])}

{renderMultipleSegmentOptions.call(this, 'Hint Position', 'showBottomHint', [
Expand All @@ -118,6 +123,7 @@ export default class HintsScreen extends Component<HintScreenProps> {
render() {
const {
showHint,
showSecondHint,
showBottomHint,
showIcon,
targetPosition,
Expand All @@ -135,6 +141,8 @@ export default class HintsScreen extends Component<HintScreenProps> {
: 'Add other cool and useful stuff through adding apps to your visitors to enjoy.';
const color = !showCustomContent && showReactionStrip ? {color: Colors.$backgroundDefault} : undefined;

const hintKey = `${useSideTip}-${targetPosition}-${useShortMessage}-${showIcon}-${useTargetFrame}-${showCustomContent}-${showReactionStrip}`;

return (
<View flex>
<View
Expand Down Expand Up @@ -164,7 +172,7 @@ export default class HintsScreen extends Component<HintScreenProps> {
// offset={35}
position={showBottomHint ? Hint.positions.BOTTOM : Hint.positions.TOP}
useSideTip={useSideTip}
key={targetPosition}
key={hintKey}
onPress={this.onHintPressed}
targetFrame={useTargetFrame ? targetFrame : undefined}
// borderRadius={BorderRadiuses.br40}
Expand Down Expand Up @@ -215,6 +223,19 @@ export default class HintsScreen extends Component<HintScreenProps> {
</View>
</>
)}

<View marginT-100 row center>
{targetPosition !== 'flex-start' && <Text marginH-s3>Text pushing button</Text>}
<Hint
message={'Hint'}
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should use 'message' so we can text the long massage here as well

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The whole idea of this use case was to test short message, that's why it's hard coded
I can change it, I just need the short variation of message to be extra short

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I looked at it again, I prefer to keep it as it is

visible={showSecondHint}
onBackgroundPress={this.toggleSecondHint}
useSideTip={false}
Copy link
Collaborator

Choose a reason for hiding this comment

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

useSideTip must be false or we can play with this from the switches?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Passing true will result in a wrong UI that looks bad, it's not a bug, it's just not meant for that so I rather pass false

>
<Button label="Button" onPress={this.toggleSecondHint}/>
</Hint>
{targetPosition === 'flex-start' && <Text marginH-s3>Text pushing button</Text>}
</View>
</View>

{this.renderOptionsFAB()}
Expand Down
20 changes: 20 additions & 0 deletions src/components/hint/Hint.driver.new.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {useComponentDriver, ComponentProps} from '../../testkit/new/Component.driver';
import {ModalDriver} from '../modal/Modal.driver.new';
import {ViewDriver} from '../view/View.driver.new';

export const HintDriver = (props: ComponentProps) => {
const driver = useComponentDriver(props);

const hintBubbleDriver = ViewDriver({
renderTree: props.renderTree,
testID: `${props.testID}.message`
});

const modalDriver = ModalDriver({renderTree: props.renderTree, testID: `${props.testID}.message`});

return {
...driver,
getHintBubble: () => hintBubbleDriver,
getModal: () => modalDriver
};
};
81 changes: 81 additions & 0 deletions src/components/hint/HintAnchor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React from 'react';
import {StyleSheet, type LayoutRectangle} from 'react-native';

import View from '../view';

import {LayoutStyle, HintProps, PaddingsStyle} from './types';

interface HintAnchorProps extends HintProps {
showHint: boolean;
isUsingModal: boolean;
targetLayout?: LayoutRectangle;
hintContainerLayout: LayoutStyle;
hintPadding: PaddingsStyle;
hintAnimatedStyle: any;
}

export default function HintAnchor({
children,
showHint,
isUsingModal,
targetLayout,
containerWidth,
testID,
hintContainerLayout,
hintPadding,
hintAnimatedStyle,
style,
...others
}: HintAnchorProps) {
const renderHintContainer = () => {
if (showHint) {
return (
<View
animated
style={[
{width: containerWidth},
styles.animatedContainer,
hintContainerLayout,
hintPadding,
hintAnimatedStyle
]}
pointerEvents="box-none"
testID={testID}
>
{children}
</View>
);
}
};

return (
<View
{...others}
// Note: this view must be collapsable, don't pass testID or backgroundColor etc'.
collapsable
testID={undefined}
style={[
styles.anchor,
style,
/* containerPosition, */
{left: targetLayout?.x, top: targetLayout?.y},
!isUsingModal && styles.anchorForScreenOverlay
]}
>
{renderHintContainer()}
</View>
);
}

const styles = StyleSheet.create({
anchor: {
position: 'absolute'
},
anchorForScreenOverlay: {
zIndex: 10,
elevation: 10
},
animatedContainer: {
position: 'absolute'
}
});
102 changes: 102 additions & 0 deletions src/components/hint/HintBubble.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React from 'react';
import {StyleSheet, View as RNView, LayoutChangeEvent} from 'react-native';
import _ from 'lodash';

import {Constants} from '../../commons/new';
import {BorderRadiuses, Colors, Shadows, Spacings, Typography} from 'style';
import View from '../view';
import Text from '../text';
import Image from '../image';
import {HintProps} from './types';

const DEFAULT_COLOR = Colors.$backgroundPrimaryHeavy;
// const HINT_MIN_WIDTH = 68;

interface HintBubbleProps
extends Pick<
HintProps,
| 'testID'
| 'visible'
| 'message'
| 'messageStyle'
| 'color'
| 'removePaddings'
| 'enableShadow'
| 'borderRadius'
| 'iconStyle'
| 'icon'
| 'customContent'
> {
hintRef: React.RefObject<RNView>;
setHintLayout: (layoutChangeEvent: LayoutChangeEvent) => void;
hintPositionStyle: {left: number};
}

export default function HintBubble({
visible,
message,
messageStyle,
icon,
iconStyle,
borderRadius,
removePaddings,
enableShadow,
color,
customContent,
testID,
hintRef,
hintPositionStyle,
setHintLayout
}: HintBubbleProps) {
return (
<View
testID={`${testID}.message`}
row
centerV
style={[
styles.hint,
!removePaddings && styles.hintPaddings,
visible && enableShadow && styles.containerShadow,
{backgroundColor: color},
!_.isUndefined(borderRadius) && {borderRadius},
hintPositionStyle
]}
onLayout={setHintLayout}
ref={hintRef}
>
{customContent}
{!customContent && icon && <Image source={icon} style={[styles.icon, iconStyle]}/>}
{!customContent && (
<Text recorderTag={'unmask'} style={[styles.hintMessage, messageStyle]} testID={`${testID}.message.text`}>
{message}
</Text>
)}
</View>
);
}

const styles = StyleSheet.create({
hint: {
// minWidth: HINT_MIN_WIDTH,
maxWidth: Math.min(Constants.windowWidth - 2 * Spacings.s4, 400),
borderRadius: BorderRadiuses.br60,
backgroundColor: DEFAULT_COLOR
},
hintPaddings: {
paddingHorizontal: Spacings.s5,
paddingTop: Spacings.s3,
paddingBottom: Spacings.s4
},
containerShadow: {
...Shadows.sh30.bottom
},
hintMessage: {
...Typography.text70,
color: Colors.white,
flexShrink: 1
},
icon: {
marginRight: Spacings.s4,
tintColor: Colors.white
}
});
55 changes: 55 additions & 0 deletions src/components/hint/HintMockChildren.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React from 'react';
import {StyleSheet, LayoutRectangle} from 'react-native';

import {Constants} from '../../commons/new';
import View from '../view';
import {HintProps} from './types';

interface HintMockChildrenProps extends Pick<HintProps, 'children' | 'backdropColor'> {
targetLayout?: LayoutRectangle;
}

export default function HintMockChildren({children, backdropColor, targetLayout}: HintMockChildrenProps) {
const isBackdropColorPassed = backdropColor !== undefined;
if (children && React.isValidElement(children)) {
const layout = {
width: targetLayout?.width,
height: targetLayout?.height,
right: Constants.isRTL ? targetLayout?.x : undefined,
top: targetLayout?.y,
left: Constants.isRTL ? undefined : targetLayout?.x
};

return (
<View style={[styles.mockChildrenContainer, layout, !isBackdropColorPassed && styles.hidden]}>
{React.cloneElement<any>(children, {
collapsable: false,
key: 'mock',
style: [children.props.style, styles.mockChildren]
})}
</View>
);
}
return null;
}

const styles = StyleSheet.create({
hidden: {opacity: 0},
mockChildrenContainer: {
position: 'absolute'
},
mockChildren: {
margin: undefined,
marginVertical: undefined,
marginHorizontal: undefined,
marginTop: undefined,
marginRight: undefined,
marginBottom: undefined,
marginLeft: undefined,

top: undefined,
left: undefined,
right: undefined,
bottom: undefined
}
});
Loading