/** @jsxImportSource @fluentui-react-native/framework-base */ import * as React from 'react'; import { Platform, Pressable, View } from 'react-native'; import { Shadow } from '@fluentui-react-native/experimental-shadow'; import type { UseSlots } from '@fluentui-react-native/framework'; import { compose } from '@fluentui-react-native/framework'; import { mergeProps } from '@fluentui-react-native/framework-base'; import { Icon, createIconProps } from '@fluentui-react-native/icon'; import type { IPressableState } from '@fluentui-react-native/interactive-hooks'; import { TextV1 as Text } from '@fluentui-react-native/text'; import { stylingSettings } from './FAB.styling'; import type { FABProps, FABType } from './FAB.types'; import { fabName } from './FAB.types'; import { extractOuterStylePropsAndroid } from '../ExtractStyle.android'; import { useButton } from '../useButton'; /** * A function which determines if a set of styles should be applied to the component given the current state and props of the button. * * @param layer The name of the state that is being checked for * @param state The current state of the button * @param userProps The props that were passed into the button * @returns Whether the styles that are assigned to the layer should be applied to the button */ const buttonLookup = (layer: string, state: IPressableState, userProps: FABProps): boolean => { return ( layer === userProps['appearance'] || state[layer] || userProps[layer] || layer === userProps['size'] || (!userProps['size'] && layer === 'large') || (layer === 'hasContent' && !userProps.iconOnly && (userProps.showContent == undefined ? true : userProps.showContent)) ); }; export const FAB = compose({ displayName: fabName, ...stylingSettings, slots: { root: Pressable, icon: Icon, content: Text, rippleContainer: View, shadow: Shadow, }, useRender: (userProps: FABProps, useSlots: UseSlots) => { const { icon, ...rest } = userProps; const iconProps = createIconProps(userProps.icon); const button = useButton(rest); // grab the styled slots const Slots = useSlots(userProps, (layer) => buttonLookup(layer, button.state, userProps)); // now return the handler for finishing render return (final: FABProps, ...children: React.ReactNode[]) => { const { iconOnly, accessibilityLabel, showContent = true, ...mergedProps } = mergeProps(button.props, final); if (__DEV__ && iconOnly) { React.Children.forEach(children, (child) => { if (typeof child === 'string') { console.warn('iconOnly should not be set when Button has content.'); } }); } let childText = ''; if (accessibilityLabel === undefined) { React.Children.forEach(children, (child) => { if (typeof child === 'string') { childText = child; // We only automatically support the one child string. } }); } const label = accessibilityLabel ?? childText; const buttonContent = ( {icon && } {showContent && React.Children.map(children, (child) => typeof child === 'string' ? ( {child} ) : ( child ), )} ); const buttonContentWithRoot = ( {buttonContent} ); const hasShadow = Platform.OS === 'ios'; const hasRipple = Platform.OS === 'android'; if (hasShadow) { return {buttonContentWithRoot}; } else if (hasRipple) { const [outerStyleProps, innerStyleProps] = extractOuterStylePropsAndroid(mergedProps.style); return ( {buttonContent} ); } else { return buttonContentWithRoot; } }; }, });