diff --git a/src/components/Appbar/Appbar.tsx b/src/components/Appbar/Appbar.tsx index e1b251ea9a..231b4a9774 100644 --- a/src/components/Appbar/Appbar.tsx +++ b/src/components/Appbar/Appbar.tsx @@ -18,6 +18,7 @@ import { getAppbarBackgroundColor, modeAppbarHeight, renderAppbarContent, + filterAppbarActions, } from './utils'; import { useInternalTheme } from '../../core/theming'; import type { MD3Elevation, ThemeProp } from '../../types'; @@ -210,12 +211,14 @@ const Appbar = ({ React.Children.forEach(children, (child) => { if (React.isValidElement(child)) { + const isLeading = child.props.isLeading === true; + if (child.type === AppbarContent) { hasAppbarContent = true; - } else if (hasAppbarContent) { - rightItemsCount++; - } else { + } else if (isLeading || !hasAppbarContent) { leftItemsCount++; + } else { + rightItemsCount++; } } }); @@ -228,15 +231,6 @@ const Appbar = ({ shouldAddRightSpacing = shouldCenterContent && rightItemsCount === 0; } - const filterAppbarActions = React.useCallback( - (isLeading = false) => - React.Children.toArray(children).filter((child) => - // @ts-expect-error: TypeScript complains about the type of type but it doesn't matter - isLeading ? child.props.isLeading : !child.props.isLeading - ), - [children] - ); - const spacingStyle = isV3 ? styles.v3Spacing : styles.spacing; const insets = { @@ -262,14 +256,32 @@ const Appbar = ({ {...rest} > {shouldAddLeftSpacing ? : null} - {(!isV3 || isMode('small') || isMode('center-aligned')) && - renderAppbarContent({ - children, - isDark, - theme, - isV3, - shouldCenterContent: isV3CenterAlignedMode || shouldCenterContent, - })} + {(!isV3 || isMode('small') || isMode('center-aligned')) && ( + <> + {/* Render only the back action at first place */} + {renderAppbarContent({ + children, + isDark, + theme, + isV3, + renderOnly: ['Appbar.BackAction'], + shouldCenterContent: isV3CenterAlignedMode || shouldCenterContent, + })} + {/* Render the rest of the content except the back action */} + {renderAppbarContent({ + // Filter appbar actions - first leading icons, then trailing icons + children: [ + ...filterAppbarActions(children, true), + ...filterAppbarActions(children), + ], + isDark, + theme, + isV3, + renderExcept: ['Appbar.BackAction'], + shouldCenterContent: isV3CenterAlignedMode || shouldCenterContent, + })} + + )} {(isMode('medium') || isMode('large')) && ( {renderAppbarContent({ - children: filterAppbarActions(false), + children: filterAppbarActions(children), isDark, isV3, renderExcept: [ @@ -310,7 +322,6 @@ const Appbar = ({ })} - {/* Middle of the row, can contain only AppbarContent */} {renderAppbarContent({ children, isDark, diff --git a/src/components/Appbar/AppbarAction.tsx b/src/components/Appbar/AppbarAction.tsx index 1fbec55652..bc87e335ba 100644 --- a/src/components/Appbar/AppbarAction.tsx +++ b/src/components/Appbar/AppbarAction.tsx @@ -48,7 +48,7 @@ export type Props = React.ComponentPropsWithoutRef & { /** * @supported Available in v5.x with theme version 3 * - * Whether it's the leading button. + * Whether it's the leading button. Note: If `Appbar.BackAction` is present, it will be rendered before any `isLeading` icons. */ isLeading?: boolean; style?: Animated.WithAnimatedValue>; diff --git a/src/components/Appbar/utils.ts b/src/components/Appbar/utils.ts index c69cd67a5a..f5780b0c9d 100644 --- a/src/components/Appbar/utils.ts +++ b/src/components/Appbar/utils.ts @@ -113,6 +113,22 @@ export const modeTextVariant = { 'center-aligned': 'titleLarge', } as const; +/** + * Filtruje akcje w Appbarze na podstawie właściwości isLeading. + * @param children - Dzieci komponentu Appbar do przefiltrowania + * @param isLeading - Czy filtrować akcje wiodące (true) czy niewiodące (false). Domyślnie false. + * @returns Przefiltrowana tablica elementów React + */ +export const filterAppbarActions = ( + children: React.ReactNode, + isLeading = false +) => { + return React.Children.toArray(children).filter((child) => { + if (!React.isValidElement(child)) return false; + return isLeading ? child.props.isLeading : !child.props.isLeading; + }); +}; + export const renderAppbarContent = ({ children, isDark, diff --git a/src/components/__tests__/Appbar/__snapshots__/Appbar.test.tsx.snap b/src/components/__tests__/Appbar/__snapshots__/Appbar.test.tsx.snap index 9b00150ddf..0eca20beef 100644 --- a/src/components/__tests__/Appbar/__snapshots__/Appbar.test.tsx.snap +++ b/src/components/__tests__/Appbar/__snapshots__/Appbar.test.tsx.snap @@ -652,7 +652,9 @@ exports[`Appbar passes additional props to AppbarBackAction, AppbarContent and A "paddingHorizontal": 0, }, [ - false, + { + "marginLeft": 12, + }, false, undefined, ],