feat: SensitiveText extension#1164
Conversation
📖 Storybook Preview |
📖 Storybook Preview |
| const fallback = useMemo(() => { | ||
| let resolvedLength = length; | ||
|
|
||
| if (!(length in SensitiveTextLength) && !isValidLength(length)) { |
There was a problem hiding this comment.
Validation checks object keys instead of values
Medium Severity
The length in SensitiveTextLength check uses the in operator, which tests whether length is a key of the object (e.g. 'Short'), not a value (e.g. '6'). Since the prop type is effectively string (because CustomLength = string subsumes the literal types), a consumer can pass length="Short" instead of length={SensitiveTextLength.Short} without any TypeScript error. In that case, the in check passes, skipping validation entirely, and Number('Short') produces NaN — silently rendering zero bullets instead of falling back with a warning. The in check adds no value for correct inputs either (all enum values like '6' are already handled by isValidLength), making it purely a source of silent failures.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit ea7ef55. Configure here.
There was a problem hiding this comment.
We have the same check in react-native too, and I remember cursor was complaining about it too, but we decided to keep current codebase. Let's stick to this patter here as well 🤞
ea7ef55 to
b2fc3cb
Compare
📖 Storybook Preview |
brianacnguyen
left a comment
There was a problem hiding this comment.
Can you address Bugbot comments?
📖 Storybook Preview |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
There are 3 total unresolved issues (including 1 from previous review).
Reviewed by Cursor Bugbot for commit c30fc8d. Configure here.
|
|
||
| const numLength = Number(resolvedLength); | ||
| return '•'.repeat(Number.isNaN(numLength) ? 0 : numLength); | ||
| }, [length]); |
There was a problem hiding this comment.
Verbatim duplicated platform-agnostic logic across web and RN
Medium Severity
The new web SensitiveText.tsx is a character-for-character copy of the RN implementation. The isValidLength helper and the entire useMemo validation/fallback computation are 100% platform-agnostic — no platform-specific API is used. design-system-shared already has a utils/ directory for exactly this kind of shared logic. Duplicating it means any future bug fix (e.g., fixing the in-check to compare values instead of keys) must be applied in two files independently, risking silent divergence.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit c30fc8d. Configure here.
| import type { Meta, StoryObj } from '@storybook/react-vite'; | ||
| import React from 'react'; | ||
|
|
||
| import { TextColor, TextVariant } from '../Text'; |
There was a problem hiding this comment.
Story imports shared consts from sibling component
Low Severity
TextColor and TextVariant are imported from ../Text (a sibling component) instead of @metamask/design-system-shared. Both const objects are confirmed to exist in shared. Stories are consumer-facing examples, and newer stories in this repo (e.g., Icon.stories.tsx, Input.stories.tsx) already import these from shared. Using the shared import teaches consumers the canonical import path.
Triggered by learned rule: Import shared types from @metamask/design-system-shared
Reviewed by Cursor Bugbot for commit c30fc8d. Configure here.
## Release 40.0.0 This release updates the shared layer and both UI packages: new extension-aligned primitives and form helpers on web, new selection and multi-line input components on React Native, shared types and context for those APIs, coordinated **`BannerBase`** close behavior, and **`ButtonBase`** defaults driven by **`size`** (with migration guidance for wrappers that overrode label, icon, or spacing). ### Package versions - `@metamask/design-system-shared`: **0.18.0** - `@metamask/design-system-react`: **0.23.0** - `@metamask/design-system-react-native`: **0.25.0** ### Shared type updates (0.18.0) #### Component type additions ([#1172](#1172), [#1164](#1164), [#1169](#1169), [#1141](#1141)) **What changed** - **`SelectButton`** shared props and variants (`SelectButtonPropsShared`, `SelectButtonVariant`, `SelectButtonEndArrow`). - **`SegmentGroup`** shared props and **`SegmentGroupContext`** (`SegmentGroupPropsShared`, `SegmentGroupContext`, `SegmentGroupContextValue`). - **`SensitiveText`** shared types (`SensitiveTextLength`, `SensitiveTextPropsShared`, and related exports). - **`HelpText`** shared types (`HelpTextSeverity`, `HelpTextPropsShared`, and related exports). - **`TextAreaPropsShared`** for multi-line input wrappers. **Impact** - React and React Native stay aligned on the same ADR-0003/0004-style contracts for the new and updated surfaces above. ### React web updates (0.23.0) #### Added - **`PopoverHeader`** — popover title rows and trailing actions, extension migration patterns ([#1158](#1158)). - **`ModalHeader`** — modal title rows and accessory slots ([#1144](#1144)). - **`Label`** — captions paired with form controls ([#1152](#1152)). - **`SensitiveText`** — mask/reveal for sensitive strings with configurable visible length ([#1164](#1164)). - **`HelpText`** — helper, success, warning, and error copy under inputs and controls ([#1169](#1169)). #### Changed - **`ButtonBase`** — label **`Text`** variant, start/end icon sizes, and internal spacing are derived from **`size`** for each **`ButtonBaseSize`** ([#1150](#1150)). See [Migration guide — ButtonBase](https://github.com/MetaMask/metamask-design-system/blob/main/packages/design-system-react/MIGRATION.md#buttonbase-size-defaults). - **`BannerBase`** — close behavior uses **`onClose`** only; **`closeButtonProps.onClick`** is not the dismiss API; **`closeButtonProps`** is for customization ([#1166](#1166)). ### React Native updates (0.25.0) #### Added - **`SelectButton`**, **`SegmentButton`**, **`SegmentGroup`** ([#1172](#1172)). - **`SensitiveText`**, aligned with the shared contract ([#1164](#1164)). - **`HeaderStandardAnimated`** and **`useHeaderStandardAnimated`** ([#1151](#1151)). - **`TextArea`** ([#1141](#1141)). #### Changed - **`ButtonBase`** — same size-driven defaults as web ([#1150](#1150)). See [Migration guide — ButtonBase](https://github.com/MetaMask/metamask-design-system/blob/main/packages/design-system-react-native/MIGRATION.md#buttonbase-size-defaults). - **`BannerBase`** — close behavior uses **`onClose`** only; **`closeButtonProps.onPress`** is not the dismiss API ([#1166](#1166)). ### Breaking changes #### `BannerBase` close API (both platforms) **What changed** - **React:** Use **`onClose`** for dismiss behavior. **`closeButtonProps.onClick`** is removed from that role. The close control is tied to **`onClose`**. **`closeButtonProps`** remains for non-behavioral customization (e.g. **`data-testid`**, accessibility, styling hooks). - **React Native:** Same pattern: **`onClose`** instead of **`closeButtonProps.onPress`** for dismiss behavior. **Migration** - Move any close action from **`closeButtonProps.onClick`** / **`closeButtonProps.onPress`** to **`onClose`**. - If you previously forced a close button with only **`closeButtonProps`**, also provide **`onClose`**. **Impact** - Call sites that dismissed via **`closeButtonProps`** or showed a close button without **`onClose`** must be updated. See: - [React — From version 0.22.0 to 0.x.0](https://github.com/MetaMask/metamask-design-system/blob/main/packages/design-system-react/MIGRATION.md#from-version-0220-to-0x0) - [React Native — From version 0.24.0 to 0.x.0](https://github.com/MetaMask/metamask-design-system/blob/main/packages/design-system-react-native/MIGRATION.md#from-version-0240-to-0x0) **`ButtonBase`:** not called out here as a semver-breaking API change; consumers who overrode typography, icon size, or spacing on **`ButtonBase`** wrappers should follow the ButtonBase migration sections linked above. ### Checklist - [x] Changelogs updated with human-readable descriptions - [x] `yarn changelog:validate` passes - [x] Version bumps follow semantic versioning - [x] `@metamask/design-system-shared`: **minor** (0.17.x → 0.18.0) — new shared exports for select/segment, sensitive text, help text, text area - [x] `@metamask/design-system-react`: **minor** (0.22.x → 0.23.0) — new components; **`BannerBase`** / **`ButtonBase`** behavior - [x] `@metamask/design-system-react-native`: **minor** (0.24.x → 0.25.0) — new components; **`BannerBase`** / **`ButtonBase`** behavior - [x] Breaking changes documented (**`BannerBase`**) in MIGRATION with before/after examples - [x] PR references present in changelog entries ## Pre-merge author checklist - [ ] [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) - [ ] [Release Workflow](https://github.com/MetaMask/metamask-design-system/blob/main/.cursor/rules/release-workflow.md) - [ ] `yarn build && yarn test && yarn lint` - [ ] `yarn changelog:validate` ## Pre-merge reviewer checklist - [ ] [Reviewing Release PRs](https://github.com/MetaMask/metamask-design-system/blob/main/docs/reviewing-release-prs.md) - [ ] Package versions and semver match what this PR actually publishes - [ ] Changelogs are consumer-facing - [ ] Breaking changes covered in MIGRATION.md - [ ] No unpublished package is missing from the changelogs / version list for **this** PR


Description
Added
SensitiveTextto DSR.Related issues
Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-312
Manual testing steps
SensitiveTextcomponentScreenshots/Recordings
Before
After
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Low Risk
Mostly additive: introduces a new
SensitiveTextcomponent fordesign-system-reactand centralizesSensitiveTextLength/shared prop types indesign-system-shared. Low risk aside from potential minor import/type churn for consumers relying on the old React Native-local constants/types.Overview
Adds
SensitiveTextto@metamask/design-system-react(component, stories, docs, and tests) with the same hide-to-bullets behavior and length validation/warning logic.Centralizes
SensitiveTextLengthand shared prop/type definitions in@metamask/design-system-shared, updates React NativeSensitiveTextto consume/re-export these shared constants/types, and documents the new import paths in the React migration guide.Reviewed by Cursor Bugbot for commit c30fc8d. Bugbot is set up for automated code reviews on this repo. Configure here.