Commit 7da7450
authored
feat: add TabsIcon component family with icon tabs, scroll overflow detection, and collapse animation (#29684)
## **Description**
Adds new `TabsIcon` components to `components-temp` and new icons to the
component library as part of the hub page discovery tabs A/B test.
Extracted into its own PR so it can be reviewed and merged independently
before the feature PR lands.
---
### `TabsIcon` Component Family
**`TabsIconTab`**
Tab item that renders an icon above a label. Icon and label have
active/disabled color states. Supports a `fillWidth` prop for
equal-width layouts and animated icon collapse via
`TabsIconAnimationContext`.
**`TabsIconBar`**
Tab bar built for icon+label tabs. Features:
- Automatic overflow detection — switches between a fixed layout and a
horizontally scrollable `ScrollView`
- Animated sliding underline indicator
- `fillWidth` mode for equal-width tabs
- Height collapse animation for hiding the bar on scroll
**`TabsIconList`**
Lazy-mounting tab list that manages active state, swipe gestures, and
`InteractionManager`-based content loading. Per-tab `keepMounted` prop
controls whether inactive tab content stays mounted or is unmounted when
the tab loses focus.
**`TabsIconAnimationContext`**
React context that carries an `Animated.Value` (`0` = icons expanded,
`1` = collapsed) from a parent provider down to `TabsIconTab` without
prop drilling.
---
### Icons
Adds three new SVG icons and registers them in `Icon.assets.ts` /
`Icon.types.ts`:
| Icon | `IconName` |
|---|---|
| Portfolio | `IconName.Portfolio` |
| Predict | `IconName.Predict` |
| Candlestick | `IconName.Candlestick` |
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-591
## **Manual testing steps**
```gherkin
Feature: Tabs component library
Scenario: user navigates between tabs
Given the app is open on any screen using TabsList
When user taps each tab
Then the animated underline slides to the active tab
And the correct tab content is displayed
Scenario: tabs overflow to scrollable mode
Given a TabsBar with more tabs than fit the container width
When the screen renders
Then the tab bar becomes horizontally scrollable
And the active tab is scrolled into view automatically
Scenario: new icons render correctly
Given any view that uses the Icon component
When IconName.Portfolio or IconName.Predict is passed
Then the correct SVG icon is displayed
```
## **Screenshots/Recordings**
Take from the feature branch using these components
[here](#29193)
### iOS
Dark Mode
https://github.com/user-attachments/assets/7df6a46d-b3b3-44cc-a697-b796581dd759
Light Mode (No Gradient)
https://github.com/user-attachments/assets/97b1f901-6092-42f9-926c-e8e6785c6f4e
### Android
Dark Mode
https://github.com/user-attachments/assets/4232f3fc-a47c-4516-93c2-104e4a3fb5cb
Light Mode (No Gradient)
https://github.com/user-attachments/assets/3f11dd8f-696f-438e-9867-1b08dc69200d
### **Before**
`~`
### **After**
`~`
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
#### Performance checks (if applicable)
- [x] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
[TMCU-591]:
https://consensyssoftware.atlassian.net/browse/TMCU-591?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Adds new tab UI components plus shared layout/list hooks involving
animations, gesture handling, and InteractionManager-based lazy loading;
regressions would primarily impact navigation/UX in screens adopting
these new components. Also extends the global `IconName` enum/assets,
which can affect consumers if mis-registered.
>
> **Overview**
> Adds a new `TabsIcon` component family under `components-temp`:
>
> `TabsIconTab` renders icon+label tabs with active/disabled states and
optional icon collapse via `TabIconAnimationContext`, `TabsIconBar`
manages underline animation plus *auto scroll overflow detection* and
optional height collapse, and `TabsIconList` composes the bar with
lazy-mounted tab content, disabled-tab handling, swipe gestures, and a
small imperative ref API.
>
> Introduces reusable hooks `useTabsBarLayout` (measures tab/container
layouts, toggles scroll mode, drives underline animations, and
resets/cleans up on layout/tab changes) and `useTabsList` (active index
normalization, InteractionManager-backed lazy loading with timeout
fallback, key-preserving tab updates, and swipe-to-switch).
>
> Extends the icon library by registering new SVGs and `IconName`
entries (`Group`, `Portfolio`, `Predictions`) and updates the
`candlestick.svg` asset. Comprehensive unit tests are added for the new
components and hooks.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
ffa57ba. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->1 parent d8db24a commit 7da7450
20 files changed
Lines changed: 2896 additions & 1 deletion
File tree
- app/component-library
- components-temp/Tabs
- TabsIconBar
- TabsIconList
- TabsIconTab
- hooks
- components/Icons/Icon
- assets
Lines changed: 500 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 178 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
Lines changed: 63 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
0 commit comments