Repository navigation
MenuItemWithTopDescription decomposition - simplest usages
#100191
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
roryabraham
merged 28 commits into
Expensify:main
from
software-mansion-labs:war-in/menu-item-with-top-description-decomposition
Sep 9, 2026
Merged
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
85331ef
feat: add basic title style
war-in 324e0c5
chore: prepare gallery with the simplest MenuItemWithTopDescription u…
war-in ae95a97
Merge branch 'war-in/menu-item-decomposition-entity' into war-in/menu…
war-in 8d91c69
Merge branch 'war-in/menu-item-decomposition-entity' into war-in/menu…
war-in 68adeb9
feat: add MenuItemField preset
war-in 97dbdf7
chore: migrate MenuItemWithTopDescription basic usages
war-in 24672e5
chore: update sotrybook `Phase 3`
war-in a107059
Merge branch 'war-in/menu-item-decomposition-entity' into war-in/menu…
war-in 840d245
Merge branch 'main' into war-in/menu-item-with-top-description-decomp…
war-in cfa7d51
refactor: split variants into two components
war-in f8bac59
fix: make `onPress` optional
war-in 7b6fc93
refactor: make `MenuItemField` display empty state
war-in 398e092
refactor: rename title to title strong
war-in fa85b4b
refactor: add FieldName and FieldValue leaves
war-in 5b477d1
Merge branch 'main' into war-in/menu-item-with-top-description-decomp…
war-in a6b633a
refactor: move `value` to MenuItemField
war-in fde619e
refactor: migrate migratable MenuItemWithTopDescription
war-in 931d732
chore: improve MenuItemComparison
war-in 0b8fbe5
chore: improve comments
war-in 9bc9742
Merge branch 'main' into war-in/menu-item-with-top-description-decomp…
war-in d799fad
fix: don't pass value for empty strings
war-in bc17dd6
Merge branch 'main' into war-in/menu-item-with-top-description-decomp…
war-in 35d3b89
tests: MenuItemField
war-in 5893c1e
chore: update comments
war-in 0d41cd4
Merge branch 'main' into war-in/menu-item-with-top-description-decomp…
war-in c07330b
chore: post-merge fixes
war-in 533b678
Merge branch 'main' into war-in/menu-item-with-top-description-decomp…
war-in 91d90b8
chore: post-merge fixes
war-in File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
src/components/MenuItem/leaves/content/MenuItemDescription.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import useThemeStyles from '@hooks/useThemeStyles'; | ||
|
|
||
| import React from 'react'; | ||
|
|
||
| import type {MenuItemSupportingTextProps} from './base/types'; | ||
|
|
||
| import BaseMenuItemSupportingText from './base/BaseMenuItemSupportingText'; | ||
|
|
||
| /** Supporting text under a `MenuItem.Title`, the bottom line of a `MenuItem.Content` */ | ||
| function MenuItemDescription(props: MenuItemSupportingTextProps) { | ||
| const styles = useThemeStyles(); | ||
|
|
||
| return ( | ||
| <BaseMenuItemSupportingText | ||
| {...props} | ||
| slot="bottom" | ||
| style={styles.textLineHeightNormal} | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| export default MenuItemDescription; |
22 changes: 22 additions & 0 deletions
22
src/components/MenuItem/leaves/content/MenuItemFieldName.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import useThemeStyles from '@hooks/useThemeStyles'; | ||
|
|
||
| import React from 'react'; | ||
|
|
||
| import type {MenuItemSupportingTextProps} from './base/types'; | ||
|
|
||
| import BaseMenuItemSupportingText from './base/BaseMenuItemSupportingText'; | ||
|
|
||
| /** Name of a filled field */ | ||
| function MenuItemFieldName(props: MenuItemSupportingTextProps) { | ||
| const styles = useThemeStyles(); | ||
|
|
||
| return ( | ||
| <BaseMenuItemSupportingText | ||
| {...props} | ||
| slot="top" | ||
| style={styles.textLineHeightNormal} | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| export default MenuItemFieldName; |
24 changes: 24 additions & 0 deletions
24
src/components/MenuItem/leaves/content/MenuItemFieldNamePlaceholder.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import useStyleUtils from '@hooks/useStyleUtils'; | ||
|
|
||
| import {fontScale, lineHeightScale} from '@styles/typography'; | ||
|
|
||
| import React from 'react'; | ||
|
|
||
| import type {MenuItemSupportingTextProps} from './base/types'; | ||
|
|
||
| import BaseMenuItemSupportingText from './base/BaseMenuItemSupportingText'; | ||
|
|
||
| /** Name of an empty field, standing in for the missing value */ | ||
| function MenuItemFieldNamePlaceholder(props: MenuItemSupportingTextProps) { | ||
| const StyleUtils = useStyleUtils(); | ||
|
|
||
| return ( | ||
| <BaseMenuItemSupportingText | ||
| {...props} | ||
| slot="top" | ||
| style={[StyleUtils.getFontSizeStyle(fontScale.text), StyleUtils.getLineHeightStyle(lineHeightScale.text)]} | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| export default MenuItemFieldNamePlaceholder; |
17 changes: 17 additions & 0 deletions
17
src/components/MenuItem/leaves/content/MenuItemFieldValue.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import React from 'react'; | ||
|
|
||
| import type {MenuItemPrimaryTextProps} from './base/types'; | ||
|
|
||
| import BaseMenuItemPrimaryText from './base/BaseMenuItemPrimaryText'; | ||
|
|
||
| /** Value a field holds */ | ||
| function MenuItemFieldValue(props: MenuItemPrimaryTextProps) { | ||
| return ( | ||
| <BaseMenuItemPrimaryText | ||
| {...props} | ||
| slot="bottom" | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| export default MenuItemFieldValue; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import useThemeStyles from '@hooks/useThemeStyles'; | ||
|
|
||
| import React from 'react'; | ||
|
|
||
| import type {MenuItemSupportingTextProps} from './base/types'; | ||
|
|
||
| import BaseMenuItemSupportingText from './base/BaseMenuItemSupportingText'; | ||
|
|
||
| /** | ||
| * Text naming what the row holds, the top line of a `MenuItem.Content`. | ||
| * | ||
| * Use this when the label and the value should read as one lockup — it lives inside `Root`, so it | ||
| * shares the row's press target and hover background. Reach for the `MenuItemWithLabel` preset | ||
| * instead when the label should stay outside both. | ||
| */ | ||
| function MenuItemLabel(props: MenuItemSupportingTextProps) { | ||
| const styles = useThemeStyles(); | ||
|
|
||
| return ( | ||
| <BaseMenuItemSupportingText | ||
| {...props} | ||
| slot="top" | ||
| style={[styles.optionAlternateText, styles.pre]} | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| export default MenuItemLabel; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import useThemeStyles from '@hooks/useThemeStyles'; | ||
|
|
||
| import React from 'react'; | ||
|
|
||
| import type {MenuItemPrimaryTextProps} from './base/types'; | ||
|
|
||
| import BaseMenuItemPrimaryText from './base/BaseMenuItemPrimaryText'; | ||
|
|
||
| /** The title block of a `MenuItem.Content`. Bold, single line */ | ||
| function MenuItemTitle(props: MenuItemPrimaryTextProps) { | ||
| const styles = useThemeStyles(); | ||
|
|
||
| return ( | ||
| <BaseMenuItemPrimaryText | ||
| {...props} | ||
| slot="top" | ||
| style={styles.textStrong} | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| export default MenuItemTitle; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
src/components/MenuItem/leaves/content/base/BaseMenuItemSupportingText.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import {useMenuItemAccessibilityLabel} from '@components/MenuItem/MenuItemAccessibilityContext'; | ||
| import Text from '@components/Text'; | ||
|
|
||
| import useThemeStyles from '@hooks/useThemeStyles'; | ||
|
|
||
| import React from 'react'; | ||
|
|
||
| import type {BaseMenuItemTextProps, MenuItemSupportingTextProps} from './types'; | ||
|
|
||
| /** Base of the muted leaves */ | ||
| function BaseMenuItemSupportingText({children, numberOfLines = 2, slot, style}: MenuItemSupportingTextProps & BaseMenuItemTextProps) { | ||
| const styles = useThemeStyles(); | ||
|
|
||
| useMenuItemAccessibilityLabel(slot, String(children)); | ||
|
|
||
| return ( | ||
| <Text | ||
| style={[styles.textLabelSupporting, styles.breakWord, style]} | ||
| numberOfLines={numberOfLines} | ||
| > | ||
| {children} | ||
| </Text> | ||
| ); | ||
| } | ||
|
|
||
| export default BaseMenuItemSupportingText; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| import type {MenuItemLabelSlot} from '@components/MenuItem/MenuItemAccessibilityContext'; | ||
|
|
||
| import type {ReactElement} from 'react'; | ||
| import type {StyleProp, TextStyle} from 'react-native'; | ||
|
|
||
| /** Props of the full-contrast leaves */ | ||
| type MenuItemPrimaryTextProps = | ||
| | { | ||
| /** Plain text to render as the primary content */ | ||
| children: string | number; | ||
|
|
||
| accessibilityLabel?: never; | ||
| } | ||
| | { | ||
| /** For content plain text can't express, e.g. `DisplayNames` with per-name tooltips */ | ||
| children: ReactElement; | ||
|
|
||
|
war-in marked this conversation as resolved.
|
||
| /** Required here because the row builds its label from strings and can't read one out of an element */ | ||
| accessibilityLabel: string; | ||
| }; | ||
|
|
||
| /** Props of the muted leaves */ | ||
| type MenuItemSupportingTextProps = { | ||
|
war-in marked this conversation as resolved.
|
||
| /** Text to render */ | ||
| children: string | number; | ||
|
|
||
|
war-in marked this conversation as resolved.
|
||
| /** Defaults to 2. Supporting text wraps, unlike primary text, which is always one line */ | ||
| numberOfLines?: number; | ||
| }; | ||
|
|
||
| /** Props shared by MenuItem's content text */ | ||
| type BaseMenuItemTextProps = { | ||
| /** Which line of the row this leaf occupies, so the row announces its text in visual order */ | ||
| slot: MenuItemLabelSlot; | ||
|
|
||
|
war-in marked this conversation as resolved.
|
||
| /** Typography layered on top of the shared base. Each leaf brings its own size and line height */ | ||
| style?: StyleProp<TextStyle>; | ||
| }; | ||
|
|
||
| export type {MenuItemSupportingTextProps, MenuItemPrimaryTextProps, BaseMenuItemTextProps}; | ||
This file was deleted.
Oops, something went wrong.
26 changes: 0 additions & 26 deletions
26
src/components/MenuItem/leaves/text/description/MenuItemDescription.tsx
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.