Skip to content

FloatingButton - add 'fullWidth' prop #2974

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 3 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion demo/src/screens/componentScreens/FloatingButtonScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export default class FloatingButtonScreen extends Component<{}, State> {
state = {
showButton: true,
showSecondary: true,
showVertical: true
showVertical: true,
fullWidth: false
};

notNow = () => {
Expand All @@ -34,6 +35,7 @@ export default class FloatingButtonScreen extends Component<{}, State> {
Trigger Floating Button
</Text>
{renderBooleanOption.call(this, 'Show Floating Button', 'showButton')}
{renderBooleanOption.call(this, 'Full Width Button', 'fullWidth')}
{renderBooleanOption.call(this, 'Show Secondary Button', 'showSecondary')}
{renderBooleanOption.call(this, 'Button Layout Vertical', 'showVertical')}

Expand Down Expand Up @@ -64,6 +66,7 @@ export default class FloatingButtonScreen extends Component<{}, State> {

<FloatingButton
visible={this.state.showButton}
fullWidth={this.state.fullWidth}
button={{
label: 'Approve',
onPress: this.close
Expand Down
62 changes: 62 additions & 0 deletions src/components/floatingButton/__tests__/index.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';
import {render} from '@testing-library/react-native';
import FloatingButton/* , {FloatingButtonLayouts} */ from '../index';
import {ButtonDriver} from '../../button/Button.driver.new';

const TEST_ID = 'floating_button';
const button = {
label: 'First'
};
const secondaryButton = {
label: 'Second'
};
// buttonLayout={showVertical ? FloatingButtonLayouts.VERTICAL : FloatingButtonLayouts.HORIZONTAL}


const TestCase = (props) => {
return <FloatingButton {...props} testID={TEST_ID}/>;
};

describe('FloatingButton', () => {
describe('visible', () => {
it('should render a button according to visibility', async () => {
const props = {};
const renderTree = render(<TestCase {...props}/>);
const buttonDriver = ButtonDriver({renderTree, testID: `${TEST_ID}.button`});
expect(await buttonDriver.exists()).not.toBeTruthy();

renderTree.rerender(<TestCase visible/>);
expect(await buttonDriver.exists()).toBeTruthy();
});
});

describe('buttons', () => {
it('should render a button', async () => {
const props = {visible: true};
const renderTree = render(<TestCase {...props}/>);
const buttonDriver = ButtonDriver({renderTree, testID: `${TEST_ID}.button`});
expect(await buttonDriver.exists()).toBeTruthy();
});

it('should not render a secondary button', async () => {
const props = {visible: true};
const renderTree = render(<TestCase {...props}/>);
const buttonDriver = ButtonDriver({renderTree, testID: `${TEST_ID}.secondaryButton`});
expect(await buttonDriver.exists()).not.toBeTruthy();
});

it('should render a button with a label', async () => {
const props = {visible: true, button};
const renderTree = render(<TestCase {...props}/>);
const buttonDriver = ButtonDriver({renderTree, testID: `${TEST_ID}.button`});
expect(await buttonDriver.getLabel().getText()).toEqual(button.label);
});

it('should render secondary button with label', async () => {
const props = {visible: true, secondaryButton};
const renderTree = render(<TestCase {...props}/>);
const buttonDriver = ButtonDriver({renderTree, testID: `${TEST_ID}.secondaryButton`});
expect(await buttonDriver.getLabel().getText()).toEqual(secondaryButton.label);
});
});
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you should test the fullWidth prop also, check for the style of the button since this is the feature in this PR eventuality, WDYT ?

Or we should add the test file in separate PR since this PR is for the fullWidth feature ?

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 fullWidth prop doesn't effect the Buttons' style, but the container's. How do you suggest to test it?

Copy link
Contributor

Choose a reason for hiding this comment

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

We can leave it a side for now.

});
2 changes: 2 additions & 0 deletions src/components/floatingButton/floatingButton.api.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
"type": "number",
"description": "The bottom margin of the button, or secondary button if passed"
},
{"name": "fullWidth", "type": "boolean", "description": "Whether the buttons get the container's full with", "note": "Relevant to vertical layout only"},
{"name": "buttonLayout", "type": "FloatingButtonLayouts", "description": "Button layout direction: vertical or horizontal"},
{"name": "duration", "type": "number", "description": "The duration of the button's animations (show/hide)"},
{"name": "withoutAnimation", "type": "boolean", "description": "Whether to show/hide the button without animation"},
{"name": "hideBackgroundOverlay", "type": "boolean", "description": "Whether to show background overlay"},
Expand Down
45 changes: 20 additions & 25 deletions src/components/floatingButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import {StyleSheet, Animated} from 'react-native';
import {Constants, asBaseComponent} from '../../commons/new';
import {Colors, Spacings} from '../../style';
import View from '../view';
import Button, {ButtonProps} from '../button';
import Image from '../image';
import Button, {ButtonProps} from '../button';

export enum FloatingButtonLayouts {
VERTICAL = 'Vertical',
Expand All @@ -27,6 +27,14 @@ export interface FloatingButtonProps {
* The bottom margin of the button, or secondary button if passed
*/
bottomMargin?: number;
/**
* Whether the buttons get the container's full with (vertical layout only)
*/
fullWidth?: boolean;
/**
* Button layout direction: vertical or horizontal
*/
buttonLayout?: FloatingButtonLayouts | `${FloatingButtonLayouts}`;
/**
* The duration of the button's animations (show/hide)
*/
Expand All @@ -46,10 +54,6 @@ export interface FloatingButtonProps {
* <TestID>.secondaryButton - the floatingButton secondaryButton
*/
testID?: string;
/**
* Button layout direction: vertical or horizontal
*/
buttonLayout?: FloatingButtonLayouts | `${FloatingButtonLayouts}`;
}

const gradientImage = () => require('./gradient.png');
Expand Down Expand Up @@ -156,35 +160,26 @@ class FloatingButton extends PureComponent<FloatingButtonProps> {
const {secondaryButton, bottomMargin, testID, buttonLayout} = this.props;

const bgColor = secondaryButton?.backgroundColor || Colors.$backgroundDefault;

if (buttonLayout === FloatingButtonLayouts.HORIZONTAL) {
return (
<Button
outline
flex
size={Button.sizes.large}
testID={`${testID}.secondaryButton`}
{...secondaryButton}
style={[styles.shadow, styles.secondaryMargin, {backgroundColor: bgColor}]}
enableShadow={false}
/>
);
}

const isHorizontal = buttonLayout === FloatingButtonLayouts.HORIZONTAL;
const buttonStyle = isHorizontal ?
[styles.shadow, styles.secondaryMargin, {backgroundColor: bgColor}] : {marginBottom: bottomMargin || Spacings.s7};

return (
<Button
link
outline={isHorizontal}
flex={isHorizontal}
link={!isHorizontal}
size={Button.sizes.large}
testID={`${testID}.secondaryButton`}
{...secondaryButton}
style={{marginBottom: bottomMargin || Spacings.s7}}
style={buttonStyle}
enableShadow={false}
/>
);
}

render() {
const {withoutAnimation, visible, testID} = this.props;
const {withoutAnimation, visible, fullWidth, testID} = this.props;
// NOTE: keep this.firstLoad as true as long as the visibility changed to true
this.firstLoad && !visible ? (this.firstLoad = true) : (this.firstLoad = false);

Expand All @@ -199,7 +194,8 @@ class FloatingButton extends PureComponent<FloatingButtonProps> {
return (
<View
row={!!this.isSecondaryHorizontal}
center={!!this.isSecondaryHorizontal}
center={!!this.isSecondaryHorizontal || !fullWidth}
paddingH-16={!this.isSecondaryHorizontal && fullWidth}
pointerEvents="box-none"
animated
style={[styles.container, this.getAnimatedStyle()]}
Expand All @@ -218,7 +214,6 @@ const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
top: undefined,
alignItems: 'center',
zIndex: Constants.isAndroid ? 99 : undefined
},
image: {
Expand Down