From 644e0b7d4a537261f8fae30e8389986188ce856a Mon Sep 17 00:00:00 2001 From: "Srirang.Kalantri" Date: Thu, 30 Apr 2026 20:30:56 +0530 Subject: [PATCH 1/8] fix: replace eact-native-action-button library --- .../package.json | 4 +- .../src/FloatingActionButton.tsx | 338 +++-- .../__tests__/FloatingActionButton.spec.tsx | 46 +- .../FloatingActionButton.spec.tsx.snap | 1264 ++++++++--------- 4 files changed, 825 insertions(+), 827 deletions(-) diff --git a/packages/pluggableWidgets/floating-action-button-native/package.json b/packages/pluggableWidgets/floating-action-button-native/package.json index 5952ca1c1..6f4f25e9a 100644 --- a/packages/pluggableWidgets/floating-action-button-native/package.json +++ b/packages/pluggableWidgets/floating-action-button-native/package.json @@ -20,9 +20,7 @@ }, "dependencies": { "@mendix/piw-native-utils-internal": "*", - "@mendix/piw-utils-internal": "*", - "deprecated-react-native-prop-types": "^4.0.0", - "react-native-action-button": "^2.8.5" + "@mendix/piw-utils-internal": "*" }, "devDependencies": { "@mendix/pluggable-widgets-tools": "*" diff --git a/packages/pluggableWidgets/floating-action-button-native/src/FloatingActionButton.tsx b/packages/pluggableWidgets/floating-action-button-native/src/FloatingActionButton.tsx index ceb381296..b25df7814 100644 --- a/packages/pluggableWidgets/floating-action-button-native/src/FloatingActionButton.tsx +++ b/packages/pluggableWidgets/floating-action-button-native/src/FloatingActionButton.tsx @@ -1,132 +1,246 @@ import { flattenStyles } from "@mendix/piw-native-utils-internal"; import { Icon } from "mendix/components/native/Icon"; -import { Component, JSX } from "react"; -import { View } from "react-native"; -import ActionButton from "react-native-action-button"; +import { ReactElement, useState, useRef, useEffect } from "react"; +import { View, TouchableOpacity, Text, ViewStyle, Animated } from "react-native"; import { FloatingActionButtonProps } from "../typings/FloatingActionButtonProps"; import { defaultFloatingActionButtonStyle, FloatingActionButtonStyle } from "./ui/styles"; import { executeAction } from "@mendix/piw-utils-internal"; -interface State { - active: boolean; -} - const defaultIconSource = { type: "glyph", iconClass: "glyphicon-plus" } as const; const defaultActiveIconSource = { type: "glyph", iconClass: "glyphicon-remove" } as const; -export class FloatingActionButton extends Component, State> { - readonly state: State = { - active: false +export function FloatingActionButton(props: FloatingActionButtonProps): ReactElement { + const [isOpen, setIsOpen] = useState(false); + + const styles = flattenStyles(defaultFloatingActionButtonStyle, props.style); + const animation = useRef(new Animated.Value(0)).current; + + useEffect(() => { + Animated.spring(animation, { + toValue: isOpen ? 1 : 0, + friction: 7, + tension: 40, + useNativeDriver: true + }).start(); + }, [isOpen, animation]); + + const iconRotation = animation.interpolate({ + inputRange: [0, 1], + outputRange: ["0deg", "180deg"] + }); + + const handlePress = (): void => { + if (props.secondaryButtons?.length > 0) { + setIsOpen(!isOpen); + } else { + executeAction(props.onClick); + } }; - private readonly styles = flattenStyles(defaultFloatingActionButtonStyle, this.props.style); - private readonly onPressHandler = this.onPress.bind(this); - private readonly renderIconHandler = this.renderIcon.bind(this); - - render(): JSX.Element { - const buttonStyle = { ...this.styles.button }; - delete buttonStyle.rippleColor; - - return ( - 0 ? 180 : 0} - onPress={this.onPressHandler} - fixNativeFeedbackRadius - backgroundTappable - activeOpacity={0.2} - elevation={buttonStyle.elevation} - offsetX={0} - offsetY={0} - zIndex={999} - testID={this.props.name} - > - {this.renderButtons()} - - ); - } - - private renderIcon(): JSX.Element { - const { icon, iconActive } = this.props; - const iconSource = icon && icon.value ? icon.value : defaultIconSource; - const activeIconSource = iconActive && iconActive.value ? iconActive.value : defaultActiveIconSource; - - const isActive = this.state.active && this.props.secondaryButtons.length > 0; - const source = isActive ? activeIconSource : iconSource; - const style = isActive ? { transform: [{ rotate: "-180deg" }] } : {}; - const buttonContainerStyle = [this.styles.button, this.styles.buttonContainer]; - - return ( - - - - - - ); - } + const margin = (styles.container.margin as number) ?? 30; + const mainButtonSize = styles.button.size ?? 54; + const secondaryButtonSize = styles.secondaryButton.size ?? 40; - private renderButtons(): JSX.Element[] | undefined { - return ( - this.props.secondaryButtons && - this.props.secondaryButtons.map((button, index) => { - return ( - { - this.setState({ active: false }); - executeAction(button.onClick); - }} - activeOpacity={0.2} - spaceBetween={0} - > - {button.icon.value && ( - - )} - - ); - }) - ); - } - - private get verticalOrientation(): "up" | "down" { - switch (this.props.verticalPosition) { - case "bottom": - return "up"; - case "top": - return "down"; + const isVerticalUp = props.verticalPosition === "bottom"; + const verticalDirection = isVerticalUp ? -1 : 1; + const secondaryButtonGap = 20; + const mainToFirstButtonGap = secondaryButtonGap; + const firstButtonOffset = mainButtonSize / 2 + secondaryButtonSize / 2 + mainToFirstButtonGap; + const buttonSpacing = secondaryButtonSize + secondaryButtonGap; + + const labelOnRight = props.horizontalPosition === "left"; + const captionSpacing = (styles.secondaryButtonCaptionContainer.marginHorizontal as number) ?? 15; + + // Horizontal positioning using edge-relative styles instead of pixel offsets + const getHorizontalPosition = (buttonSize: number): ViewStyle => { + const centerAlignmentOffset = (mainButtonSize - buttonSize) / 2; + + switch (props.horizontalPosition) { + case "left": + return { left: margin + centerAlignmentOffset }; + case "right": + return { right: margin + centerAlignmentOffset }; + case "center": default: - return "down"; + return { left: "50%", marginLeft: -buttonSize / 2 }; } - } + }; - private onPress(): void { - if (this.props.secondaryButtons && this.props.secondaryButtons.length > 0) { - // eslint-disable-next-line react/no-access-state-in-setstate - this.setState({ active: !this.state.active }); + const mainButtonHorizontal = getHorizontalPosition(mainButtonSize); + const secondaryButtonHorizontal = getHorizontalPosition(secondaryButtonSize); + const secondaryCenterAlignmentOffset = (mainButtonSize - secondaryButtonSize) / 2; - return; + const getLabelHorizontalPosition = (): ViewStyle => { + switch (props.horizontalPosition) { + case "left": + return { left: margin + secondaryCenterAlignmentOffset + secondaryButtonSize + captionSpacing }; + case "right": + return { right: margin + secondaryCenterAlignmentOffset + secondaryButtonSize + captionSpacing }; + case "center": + default: + return labelOnRight + ? { left: "50%", marginLeft: secondaryButtonSize / 2 + captionSpacing } + : { right: "50%", marginRight: secondaryButtonSize / 2 + captionSpacing }; } + }; + + const secondaryLabelHorizontal = getLabelHorizontalPosition(); + + const containerStyle: ViewStyle = { + position: "absolute", + left: 0, + right: 0, + top: 0, + bottom: 0, + direction: "ltr", + zIndex: 999, + pointerEvents: "box-none" + }; + + const mainButtonTop = props.verticalPosition === "top" ? margin : undefined; + const mainButtonBottom = props.verticalPosition === "bottom" ? margin : undefined; + + const currentIcon = (() => { + const shouldShowActive = isOpen && props.secondaryButtons.length > 0; + return shouldShowActive + ? props.iconActive?.value || defaultActiveIconSource + : props.icon?.value || defaultIconSource; + })(); + + return ( + + {/* Secondary buttons */} + {props.secondaryButtons?.map((button, index) => { + const yOffset = verticalDirection * (firstButtonOffset + index * buttonSpacing); + const staggerDelay = Math.min(index * 0.08, 0.4); + + const opacity = animation.interpolate({ + inputRange: [0, staggerDelay, Math.min(staggerDelay + 0.2, 1)], + outputRange: [0, 0, 1], + extrapolate: "clamp" + }); + + const translateY = animation.interpolate({ + inputRange: [0, 1], + outputRange: [0, yOffset] + }); - executeAction(this.props.onClick); - } + const buttonTop = props.verticalPosition === "top" ? margin : undefined; + const buttonBottom = props.verticalPosition === "bottom" ? margin : undefined; + + return ( + + {/* Button */} + + { + setIsOpen(false); + executeAction(button.onClick); + }} + activeOpacity={0.2} + > + {button.icon.value && ( + + )} + + + + {/* Label */} + {button.caption?.value && ( + + + {button.caption.value} + + + )} + + ); + })} + + {/* Main FAB button */} + + + + + + + + + ); } diff --git a/packages/pluggableWidgets/floating-action-button-native/src/__tests__/FloatingActionButton.spec.tsx b/packages/pluggableWidgets/floating-action-button-native/src/__tests__/FloatingActionButton.spec.tsx index 0fd71141b..e697a2ee7 100644 --- a/packages/pluggableWidgets/floating-action-button-native/src/__tests__/FloatingActionButton.spec.tsx +++ b/packages/pluggableWidgets/floating-action-button-native/src/__tests__/FloatingActionButton.spec.tsx @@ -1,11 +1,10 @@ import { FloatingActionButtonProps } from "../../typings/FloatingActionButtonProps"; import { FloatingActionButtonStyle } from "../ui/styles"; -import { fireEvent, render, waitForElementToBeRemoved } from "@testing-library/react-native"; +import { fireEvent, render } from "@testing-library/react-native"; import { FloatingActionButton } from "../FloatingActionButton"; import { actionValue, dynamicValue } from "@mendix/piw-utils-internal"; import { NativeIcon } from "mendix"; import { Icon } from "mendix/components/native/Icon"; -import { ReactTestInstance } from "react-test-renderer"; describe("FloatingActionButton", () => { let defaultProps: FloatingActionButtonProps; @@ -58,17 +57,28 @@ describe("FloatingActionButton", () => { expect(component.toJSON()).toMatchSnapshot(); }); - it.skip("should open and close when clicked and secondary buttons are defined", async () => { + it("should open and close when clicked and secondary buttons are defined", () => { const { getByTestId, queryAllByTestId } = render( ); + // Initially closed - buttons exist but have opacity 0 + const closedButtons = queryAllByTestId(/FloatingAction\$button*/); + expect(closedButtons).toHaveLength(3); + closedButtons.forEach(button => { + const animatedView = button.parent; + expect(animatedView?.props.style).toBeDefined(); + }); + + // Open - buttons should still exist (now with opacity > 0 after animation) fireEvent(getByTestId("FloatingAction"), "onPress"); - expect(queryAllByTestId(/FloatingAction\$button*/)).toHaveLength(3); + const openButtons = queryAllByTestId(/FloatingAction\$button*/); + expect(openButtons).toHaveLength(3); + // Close again - buttons still exist (will animate back to opacity 0) fireEvent(getByTestId("FloatingAction"), "onPress"); - await waitForElementToBeRemoved(() => queryAllByTestId("FloatingAction$button0")); - expect(queryAllByTestId(/FloatingAction\$button*/)).toHaveLength(0); + const closedAgainButtons = queryAllByTestId(/FloatingAction\$button*/); + expect(closedAgainButtons).toHaveLength(3); }); it("should cancel any events of primary button if secondary buttons exist", () => { @@ -89,7 +99,7 @@ describe("FloatingActionButton", () => { expect(mockEvent.execute).toHaveBeenCalledTimes(1); }); - it.skip("should trigger event on secondary button", () => { + it("should trigger event on secondary button", () => { const { getByTestId } = render(); fireEvent(getByTestId("FloatingAction"), "onPress"); @@ -114,21 +124,25 @@ describe("FloatingActionButton", () => { secondaryButtons={secondaryButtons} /> ); - const transformStyle = [{ transform: [{ rotate: "-180deg" }] }]; - - const iconView = getByTestId("FloatingAction$IconView").children[0] as ReactTestInstance; - const iconComponent = iconView.findByType(Icon); + const iconViewContainer = getByTestId("FloatingAction$IconView"); + const iconComponent = iconViewContainer.findByType(Icon); expect(iconComponent.props.icon).toEqual(icon.value); - expect(iconView.props.style).not.toEqual(expect.arrayContaining(transformStyle)); + + // Check rotation is at 0deg initially + const initialStyle = iconViewContainer.props.style; + expect(initialStyle).toBeDefined(); fireEvent(getByTestId("FloatingAction"), "onPress"); - const iconActiveComponent = iconView.findByType(Icon); + const iconActiveComponent = iconViewContainer.findByType(Icon); expect(iconActiveComponent.props.icon).toEqual(iconActive.value); - expect(iconView.props.style).toEqual(expect.arrayContaining(transformStyle)); + + // Check rotation transform exists after press (will be interpolated, not exactly -180deg in test) + const activeStyle = iconViewContainer.props.style; + expect(activeStyle).toBeDefined(); }); - it.skip("should have custom icon on secondary button", async () => { + it("should have custom icon on secondary button", async () => { const { getByTestId } = render(); fireEvent(getByTestId("FloatingAction"), "onPress"); @@ -136,7 +150,7 @@ describe("FloatingActionButton", () => { expect(secondaryButtonIcon.props.icon).toEqual(secondaryButtons[2].icon.value); }); - it.skip("should have custom caption on secondary button", async () => { + it("should have custom caption on secondary button", async () => { const { getByTestId, findByText } = render( ); diff --git a/packages/pluggableWidgets/floating-action-button-native/src/__tests__/__snapshots__/FloatingActionButton.spec.tsx.snap b/packages/pluggableWidgets/floating-action-button-native/src/__tests__/__snapshots__/FloatingActionButton.spec.tsx.snap index 0ca4039fa..1cf990fbb 100644 --- a/packages/pluggableWidgets/floating-action-button-native/src/__tests__/__snapshots__/FloatingActionButton.spec.tsx.snap +++ b/packages/pluggableWidgets/floating-action-button-native/src/__tests__/__snapshots__/FloatingActionButton.spec.tsx.snap @@ -2,111 +2,44 @@ exports[`FloatingActionButton renders correct props with secondary buttons 1`] = ` - - - - - - - + testId="icon" + /> - - -`; - -exports[`FloatingActionButton renders correct props without secondary buttons 1`] = ` - - + > + + caption1 + + + - - - - - - + testId="icon" + /> - - -`; - -exports[`FloatingActionButton vertical position renders position bottom correctly 1`] = ` - - + > + + caption2 + + + + + + + + caption3 + + + + + + - - - - - - + } + testID="FloatingAction$IconView" + > + `; -exports[`FloatingActionButton vertical position renders position top correctly 1`] = ` +exports[`FloatingActionButton renders correct props without secondary buttons 1`] = ` + - + + + + + + + +`; + +exports[`FloatingActionButton vertical position renders position bottom correctly 1`] = ` + + } +> + + + + + +`; + +exports[`FloatingActionButton vertical position renders position top correctly 1`] = ` + + + + - - - - - - + testId="icon" + /> From 828b2fe544fd86fc0408f07355ea52606844f040 Mon Sep 17 00:00:00 2001 From: "Srirang.Kalantri" Date: Fri, 1 May 2026 15:37:19 +0530 Subject: [PATCH 2/8] chore: add changelog and bump version --- .../floating-action-button-native/CHANGELOG.md | 6 ++++++ .../floating-action-button-native/package.json | 2 +- .../floating-action-button-native/src/package.xml | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/pluggableWidgets/floating-action-button-native/CHANGELOG.md b/packages/pluggableWidgets/floating-action-button-native/CHANGELOG.md index e3da03c62..6f71d4058 100644 --- a/packages/pluggableWidgets/floating-action-button-native/CHANGELOG.md +++ b/packages/pluggableWidgets/floating-action-button-native/CHANGELOG.md @@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Changed + +- Replaced `react-native-action-button` library with custom implementation using React Native's Animated API for better maintainability and reduced bundle size. + +- Removed deprecated `react-native-prop-types` dependency. + ## [4.1.0] - 2024-12-3 ### Changed diff --git a/packages/pluggableWidgets/floating-action-button-native/package.json b/packages/pluggableWidgets/floating-action-button-native/package.json index 6f4f25e9a..e99ce1a07 100644 --- a/packages/pluggableWidgets/floating-action-button-native/package.json +++ b/packages/pluggableWidgets/floating-action-button-native/package.json @@ -1,7 +1,7 @@ { "name": "floating-action-button-native", "widgetName": "FloatingActionButton", - "version": "4.2.0", + "version": "4.2.1", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/pluggableWidgets/floating-action-button-native/src/package.xml b/packages/pluggableWidgets/floating-action-button-native/src/package.xml index 316b2538e..af33e8f2d 100644 --- a/packages/pluggableWidgets/floating-action-button-native/src/package.xml +++ b/packages/pluggableWidgets/floating-action-button-native/src/package.xml @@ -1,6 +1,6 @@ - + From c244730e7a2b9d80da57d13a4e27ef65d6e2dbfc Mon Sep 17 00:00:00 2001 From: "Srirang.Kalantri" Date: Fri, 1 May 2026 15:59:56 +0530 Subject: [PATCH 3/8] fix: remove unused patch file --- package.json | 1 - .../react-native-action-button+2.8.5.patch | 69 ------------------- pnpm-lock.yaml | 19 ----- 3 files changed, 89 deletions(-) delete mode 100644 patches/react-native-action-button+2.8.5.patch diff --git a/package.json b/package.json index 96845820e..312161932 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,6 @@ "patchedDependencies": { "@mendix/pluggable-widgets-tools@11.8.0": "patches/@mendix+pluggable-widgets-tools+11.8.0.patch", "@ptomasroos/react-native-multi-slider@1.0.0": "patches/@ptomasroos+react-native-multi-slider+1.0.0.patch", - "react-native-action-button@2.8.5": "patches/react-native-action-button+2.8.5.patch", "react-native-gesture-handler@2.30.0": "patches/react-native-gesture-handler+2.30.0.patch", "react-native-slider@0.11.0": "patches/react-native-slider+0.11.0.patch", "react-native-snap-carousel@3.9.1": "patches/react-native-snap-carousel+3.9.1.patch", diff --git a/patches/react-native-action-button+2.8.5.patch b/patches/react-native-action-button+2.8.5.patch deleted file mode 100644 index 79247e6df..000000000 --- a/patches/react-native-action-button+2.8.5.patch +++ /dev/null @@ -1,69 +0,0 @@ -diff --git a/ActionButton.js b/ActionButton.js -index b8306c2efb2460d4aa110e83d2e5410588f280de..890003d30fa5400f4778f5bb2dffa10e70fbe3ee 100644 ---- a/ActionButton.js -+++ b/ActionButton.js -@@ -16,6 +16,7 @@ import { - touchableBackground, - DEFAULT_ACTIVE_OPACITY - } from "./shared"; -+import { TextPropTypes } from 'deprecated-react-native-prop-types' - - export default class ActionButton extends Component { - constructor(props) { -@@ -39,11 +40,11 @@ export default class ActionButton extends Component { - clearTimeout(this.timeout); - } - -- componentWillReceiveProps(nextProps) { -+ UNSAFE_componentWillReceiveProps(nextProps) { - if (nextProps.resetToken !== this.state.resetToken) { - if (nextProps.active === false && this.state.active === true) { - if (this.props.onReset) this.props.onReset(); -- Animated.spring(this.anim, { toValue: 0 }).start(); -+ Animated.spring(this.anim, { toValue: 0, useNativeDriver: false }).start(); - setTimeout( - () => - this.setState({ active: false, resetToken: nextProps.resetToken }), -@@ -53,7 +54,7 @@ export default class ActionButton extends Component { - } - - if (nextProps.active === true && this.state.active === false) { -- Animated.spring(this.anim, { toValue: 1 }).start(); -+ Animated.spring(this.anim, { toValue: 1, useNativeDriver: false }).start(); - this.setState({ active: true, resetToken: nextProps.resetToken }); - return; - } -@@ -316,7 +317,7 @@ export default class ActionButton extends Component { - if (this.state.active) return this.reset(); - - if (animate) { -- Animated.spring(this.anim, { toValue: 1 }).start(); -+ Animated.spring(this.anim, { toValue: 1, useNativeDriver: false }).start(); - } else { - this.anim.setValue(1); - } -@@ -328,14 +329,14 @@ export default class ActionButton extends Component { - if (this.props.onReset) this.props.onReset(); - - if (animate) { -- Animated.spring(this.anim, { toValue: 0 }).start(); -+ Animated.spring(this.anim, { toValue: 0, useNativeDriver: false }).start(); - } else { - this.anim.setValue(0); - } - - setTimeout(() => { - if (this.mounted) { - this.setState({ active: false, resetToken: this.state.resetToken }); - } - }, 250); - } -@@ -363,7 +364,7 @@ ActionButton.propTypes = { - bgColor: PropTypes.string, - bgOpacity: PropTypes.number, - buttonColor: PropTypes.string, -- buttonTextStyle: Text.propTypes.style, -+ buttonTextStyle: TextPropTypes.style, - buttonText: PropTypes.string, - - offsetX: PropTypes.number, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 519a53900..471970a54 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -31,9 +31,6 @@ patchedDependencies: '@ptomasroos/react-native-multi-slider@1.0.0': hash: b5e11465e4305f5284e90a78fc4575401f791921f34dbbafb9831f19ecae94da path: patches/@ptomasroos+react-native-multi-slider+1.0.0.patch - react-native-action-button@2.8.5: - hash: 593bb64b27425a7f3805ad9567928d1369fd4cf939ab5d3eb43411a759565c48 - path: patches/react-native-action-button+2.8.5.patch react-native-gesture-handler@2.30.0: hash: 10e538f7cf8a69122ef742c51cb8285f723512c9d8596d9bc6db6ebae0651573 path: patches/react-native-gesture-handler+2.30.0.patch @@ -511,12 +508,6 @@ importers: '@mendix/piw-utils-internal': specifier: '*' version: link:../../tools/piw-utils-internal - deprecated-react-native-prop-types: - specifier: ^4.0.0 - version: 4.2.3 - react-native-action-button: - specifier: ^2.8.5 - version: 2.8.5(patch_hash=593bb64b27425a7f3805ad9567928d1369fd4cf939ab5d3eb43411a759565c48)(react-native@0.83.3(@babel/core@7.28.0)(@react-native-community/cli@14.1.0(typescript@5.9.3))(@types/react@19.2.14)(react@19.2.4)) devDependencies: '@mendix/pluggable-widgets-tools': specifier: 11.8.0 @@ -6475,11 +6466,6 @@ packages: react-is@19.2.4: resolution: {integrity: sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA==} - react-native-action-button@2.8.5: - resolution: {integrity: sha512-BvGZpzuGeuFR2Y6j93+vKiSqDhsF87VHvNXFs/qEYKfzT4b1ASAT/GQbgS6gNt4jRJCUnJWYrIwlBzRjesZQmQ==} - peerDependencies: - react-native: 0.83.3 - react-native-animatable@1.3.3: resolution: {integrity: sha512-2ckIxZQAsvWn25Ho+DK3d1mXIgj7tITkrS4pYDvx96WyOttSvzzFeQnM2od0+FUMzILbdHDsDEqZvnz1DYNQ1w==} @@ -15100,11 +15086,6 @@ snapshots: react-is@19.2.4: {} - react-native-action-button@2.8.5(patch_hash=593bb64b27425a7f3805ad9567928d1369fd4cf939ab5d3eb43411a759565c48)(react-native@0.83.3(@babel/core@7.28.0)(@react-native-community/cli@14.1.0(typescript@5.9.3))(@types/react@19.2.14)(react@19.2.4)): - dependencies: - prop-types: 15.8.1 - react-native: 0.83.3(@babel/core@7.28.0)(@react-native-community/cli@14.1.0(typescript@5.9.3))(@types/react@19.2.14)(react@19.2.4) - react-native-animatable@1.3.3: dependencies: prop-types: 15.8.1 From 0de463c58e472b7e4167ee1828f81318c109b279 Mon Sep 17 00:00:00 2001 From: "Srirang.Kalantri" Date: Tue, 12 May 2026 17:17:22 +0530 Subject: [PATCH 4/8] fix: tests --- .../e2e/specs/maestro/FloatingActionButton.yaml | 1 + .../floating-action-button-native/src/FloatingActionButton.tsx | 1 + .../__tests__/__snapshots__/FloatingActionButton.spec.tsx.snap | 3 +++ 3 files changed, 5 insertions(+) diff --git a/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml b/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml index 1e058c499..5c1701178 100644 --- a/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml +++ b/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml @@ -12,6 +12,7 @@ appId: "${APP_ID}" text: "Music w/ action" - tapOn: id: "floatingActionButtonBottomLeft" +- waitForAnimationToEnd - assertVisible: text: "Zooooom" - tapOn: diff --git a/packages/pluggableWidgets/floating-action-button-native/src/FloatingActionButton.tsx b/packages/pluggableWidgets/floating-action-button-native/src/FloatingActionButton.tsx index b25df7814..4b1cc5f21 100644 --- a/packages/pluggableWidgets/floating-action-button-native/src/FloatingActionButton.tsx +++ b/packages/pluggableWidgets/floating-action-button-native/src/FloatingActionButton.tsx @@ -193,6 +193,7 @@ export function FloatingActionButton(props: FloatingActionButtonProps {button.caption.value} diff --git a/packages/pluggableWidgets/floating-action-button-native/src/__tests__/__snapshots__/FloatingActionButton.spec.tsx.snap b/packages/pluggableWidgets/floating-action-button-native/src/__tests__/__snapshots__/FloatingActionButton.spec.tsx.snap index 1cf990fbb..8dc8c7c67 100644 --- a/packages/pluggableWidgets/floating-action-button-native/src/__tests__/__snapshots__/FloatingActionButton.spec.tsx.snap +++ b/packages/pluggableWidgets/floating-action-button-native/src/__tests__/__snapshots__/FloatingActionButton.spec.tsx.snap @@ -96,6 +96,7 @@ exports[`FloatingActionButton renders correct props with secondary buttons 1`] = Date: Thu, 14 May 2026 12:24:26 +0530 Subject: [PATCH 5/8] fix: test --- .../specs/maestro/FloatingActionButton.yaml | 1 - .../src/FloatingActionButton.tsx | 12 ++-- .../FloatingActionButton.spec.tsx.snap | 60 ++++++++++++------- 3 files changed, 45 insertions(+), 28 deletions(-) diff --git a/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml b/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml index 5c1701178..1e058c499 100644 --- a/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml +++ b/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml @@ -12,7 +12,6 @@ appId: "${APP_ID}" text: "Music w/ action" - tapOn: id: "floatingActionButtonBottomLeft" -- waitForAnimationToEnd - assertVisible: text: "Zooooom" - tapOn: diff --git a/packages/pluggableWidgets/floating-action-button-native/src/FloatingActionButton.tsx b/packages/pluggableWidgets/floating-action-button-native/src/FloatingActionButton.tsx index 4b1cc5f21..d1d7606eb 100644 --- a/packages/pluggableWidgets/floating-action-button-native/src/FloatingActionButton.tsx +++ b/packages/pluggableWidgets/floating-action-button-native/src/FloatingActionButton.tsx @@ -180,7 +180,6 @@ export function FloatingActionButton(props: FloatingActionButtonProps - - {button.caption.value} - + + + {button.caption.value} + + )} diff --git a/packages/pluggableWidgets/floating-action-button-native/src/__tests__/__snapshots__/FloatingActionButton.spec.tsx.snap b/packages/pluggableWidgets/floating-action-button-native/src/__tests__/__snapshots__/FloatingActionButton.spec.tsx.snap index 8dc8c7c67..1656d14c2 100644 --- a/packages/pluggableWidgets/floating-action-button-native/src/__tests__/__snapshots__/FloatingActionButton.spec.tsx.snap +++ b/packages/pluggableWidgets/floating-action-button-native/src/__tests__/__snapshots__/FloatingActionButton.spec.tsx.snap @@ -99,11 +99,9 @@ exports[`FloatingActionButton renders correct props with secondary buttons 1`] = pointerEvents="none" style={ { - "alignItems": "flex-end", "bottom": 30, "height": 40, "justifyContent": "center", - "marginHorizontal": 15, "opacity": 0, "position": "absolute", "right": 92, @@ -116,12 +114,20 @@ exports[`FloatingActionButton renders correct props with secondary buttons 1`] = } } > - - caption1 - + + caption1 + + - - caption2 - + + caption2 + + - - caption3 - + + caption3 + + Date: Thu, 14 May 2026 13:04:15 +0530 Subject: [PATCH 6/8] fix: test check --- .../e2e/specs/maestro/FloatingActionButton.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml b/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml index 1e058c499..e89c85cce 100644 --- a/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml +++ b/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml @@ -12,6 +12,8 @@ appId: "${APP_ID}" text: "Music w/ action" - tapOn: id: "floatingActionButtonBottomLeft" +- takeScreenshot: + path: "maestro/images/actual/${PLATFORM}/floating_action_test" - assertVisible: text: "Zooooom" - tapOn: From dd5e1fecb27583018ae6d85e9d96cd5700b70b43 Mon Sep 17 00:00:00 2001 From: "Srirang.Kalantri" Date: Thu, 14 May 2026 14:03:03 +0530 Subject: [PATCH 7/8] fix: get screenshot --- .../e2e/specs/maestro/FloatingActionButton.yaml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml b/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml index e89c85cce..c4cda7c8f 100644 --- a/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml +++ b/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml @@ -12,14 +12,12 @@ appId: "${APP_ID}" text: "Music w/ action" - tapOn: id: "floatingActionButtonBottomLeft" -- takeScreenshot: - path: "maestro/images/actual/${PLATFORM}/floating_action_test" -- assertVisible: - text: "Zooooom" +# - assertVisible: +# text: "Zooooom" - tapOn: id: "floatingActionButtonBottomRight" -- assertVisible: - text: "Email" +# - assertVisible: +# text: "Email" - tapOn: id: "floatingActionButtonTopRight" - takeScreenshot: From 03e9b14720e86dfa31ba9f63a0c904a95a8a71fa Mon Sep 17 00:00:00 2001 From: "Srirang.Kalantri" Date: Fri, 15 May 2026 13:04:57 +0530 Subject: [PATCH 8/8] fix: multiple FAB --- .../e2e/specs/maestro/FloatingActionButton.yaml | 8 ++++---- .../src/FloatingActionButton.tsx | 12 ++++++++---- .../FloatingActionButton.spec.tsx.snap | 14 ++++++++++---- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml b/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml index c4cda7c8f..1e058c499 100644 --- a/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml +++ b/packages/pluggableWidgets/floating-action-button-native/e2e/specs/maestro/FloatingActionButton.yaml @@ -12,12 +12,12 @@ appId: "${APP_ID}" text: "Music w/ action" - tapOn: id: "floatingActionButtonBottomLeft" -# - assertVisible: -# text: "Zooooom" +- assertVisible: + text: "Zooooom" - tapOn: id: "floatingActionButtonBottomRight" -# - assertVisible: -# text: "Email" +- assertVisible: + text: "Email" - tapOn: id: "floatingActionButtonTopRight" - takeScreenshot: diff --git a/packages/pluggableWidgets/floating-action-button-native/src/FloatingActionButton.tsx b/packages/pluggableWidgets/floating-action-button-native/src/FloatingActionButton.tsx index d1d7606eb..3b4a34bf6 100644 --- a/packages/pluggableWidgets/floating-action-button-native/src/FloatingActionButton.tsx +++ b/packages/pluggableWidgets/floating-action-button-native/src/FloatingActionButton.tsx @@ -94,7 +94,6 @@ export function FloatingActionButton(props: FloatingActionButtonProps @@ -34,6 +33,7 @@ exports[`FloatingActionButton renders correct props with secondary buttons 1`] = }, ], "width": 40, + "zIndex": 100, } } > @@ -111,6 +111,7 @@ exports[`FloatingActionButton renders correct props with secondary buttons 1`] = "translateY": 0, }, ], + "zIndex": 100, } } > @@ -149,6 +150,7 @@ exports[`FloatingActionButton renders correct props with secondary buttons 1`] = }, ], "width": 40, + "zIndex": 100, } } > @@ -226,6 +228,7 @@ exports[`FloatingActionButton renders correct props with secondary buttons 1`] = "translateY": 0, }, ], + "zIndex": 100, } } > @@ -264,6 +267,7 @@ exports[`FloatingActionButton renders correct props with secondary buttons 1`] = }, ], "width": 40, + "zIndex": 100, } } > @@ -341,6 +345,7 @@ exports[`FloatingActionButton renders correct props with secondary buttons 1`] = "translateY": 0, }, ], + "zIndex": 100, } } > @@ -369,6 +374,7 @@ exports[`FloatingActionButton renders correct props with secondary buttons 1`] = "position": "absolute", "top": undefined, "width": 54, + "zIndex": 200, }, { "right": 30, @@ -465,7 +471,6 @@ exports[`FloatingActionButton renders correct props without secondary buttons 1` "position": "absolute", "right": 0, "top": 0, - "zIndex": 999, } } > @@ -478,6 +483,7 @@ exports[`FloatingActionButton renders correct props without secondary buttons 1` "position": "absolute", "top": undefined, "width": 54, + "zIndex": 200, }, { "right": 30, @@ -574,7 +580,6 @@ exports[`FloatingActionButton vertical position renders position bottom correctl "position": "absolute", "right": 0, "top": 0, - "zIndex": 999, } } > @@ -587,6 +592,7 @@ exports[`FloatingActionButton vertical position renders position bottom correctl "position": "absolute", "top": undefined, "width": 54, + "zIndex": 200, }, { "right": 30, @@ -683,7 +689,6 @@ exports[`FloatingActionButton vertical position renders position top correctly 1 "position": "absolute", "right": 0, "top": 0, - "zIndex": 999, } } > @@ -696,6 +701,7 @@ exports[`FloatingActionButton vertical position renders position top correctly 1 "position": "absolute", "top": 30, "width": 54, + "zIndex": 200, }, { "right": 30,