diff --git a/.nx/version-plans/cds-2620-dismiss-android-keyboard.md b/.nx/version-plans/cds-2620-dismiss-android-keyboard.md deleted file mode 100644 index 31e4a3913f..0000000000 --- a/.nx/version-plans/cds-2620-dismiss-android-keyboard.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -cds: patch ---- - -Fix: dismiss the Android soft keyboard when the mobile `TextInput` unmounts while focused. diff --git a/.nx/version-plans/illustrations-sync-tooling.md b/.nx/version-plans/illustrations-sync-tooling.md deleted file mode 100644 index 0da6798b3d..0000000000 --- a/.nx/version-plans/illustrations-sync-tooling.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -illustrations: patch ---- - -Add the `illustrations:sync-illustrations` target, which syncs illustrations from Figma and writes a version plan describing what changed. Adds sync-only devDependencies; no runtime change for consumers. diff --git a/packages/common/CHANGELOG.md b/packages/common/CHANGELOG.md index db5db24ce0..b393ee23b9 100644 --- a/packages/common/CHANGELOG.md +++ b/packages/common/CHANGELOG.md @@ -1,3 +1,14 @@ +## 9.26.2 (2026-09-11) + +### 🩹 Fixes + +- Fix: vertically align the helper-text error icon with the text in web and mobile inputs. +- Fix: dismiss the Android soft keyboard when the mobile `TextInput` unmounts while focused. + +### 🧱 Updated Dependencies + +- Updated illustrations to 4.48.1 + ## 9.26.1 (2026-09-03) ### 🩹 Fixes diff --git a/packages/common/package.json b/packages/common/package.json index ef5f563116..763409e8f3 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -1,6 +1,6 @@ { "name": "@coinbase/cds-common", - "version": "9.26.1", + "version": "9.26.2", "description": "Coinbase Design System - Common", "repository": { "type": "git", diff --git a/packages/illustrations/CHANGELOG.md b/packages/illustrations/CHANGELOG.md index 2a391d8082..8276060189 100644 --- a/packages/illustrations/CHANGELOG.md +++ b/packages/illustrations/CHANGELOG.md @@ -1,3 +1,9 @@ +## 4.48.1 (2026-09-11) + +### 🩹 Fixes + +- Add the `illustrations:sync-illustrations` target, which syncs illustrations from Figma and writes a version plan describing what changed. Adds sync-only devDependencies; no runtime change for consumers. + ## 4.48.0 (8/12/2026 PST) #### 🚀 Updates diff --git a/packages/illustrations/package.json b/packages/illustrations/package.json index 4e16fdb754..dd538bba62 100644 --- a/packages/illustrations/package.json +++ b/packages/illustrations/package.json @@ -1,6 +1,6 @@ { "name": "@coinbase/cds-illustrations", - "version": "4.48.0", + "version": "4.48.1", "description": "CDS illustrations", "repository": { "type": "git", diff --git a/packages/mcp-server/CHANGELOG.md b/packages/mcp-server/CHANGELOG.md index ee2793393f..e46242f071 100644 --- a/packages/mcp-server/CHANGELOG.md +++ b/packages/mcp-server/CHANGELOG.md @@ -1,3 +1,10 @@ +## 9.26.2 (2026-09-11) + +### 🩹 Fixes + +- Fix: vertically align the helper-text error icon with the text in web and mobile inputs. +- Fix: dismiss the Android soft keyboard when the mobile `TextInput` unmounts while focused. + ## 9.26.1 (2026-09-03) ### 🩹 Fixes diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 70171a4b02..208730404c 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "@coinbase/cds-mcp-server", - "version": "9.26.1", + "version": "9.26.2", "description": "Coinbase Design System - MCP Server", "repository": { "type": "git", diff --git a/packages/mobile/CHANGELOG.md b/packages/mobile/CHANGELOG.md index b3e22e6d4c..05fd765e5f 100644 --- a/packages/mobile/CHANGELOG.md +++ b/packages/mobile/CHANGELOG.md @@ -1,3 +1,14 @@ +## 9.26.2 (2026-09-11) + +### 🩹 Fixes + +- Fix: vertically align the helper-text error icon with the text in web and mobile inputs. +- Fix: dismiss the Android soft keyboard when the mobile `TextInput` unmounts while focused. + +### 🧱 Updated Dependencies + +- Updated illustrations to 4.48.1 + ## 9.26.1 (2026-09-03) ### 🩹 Fixes diff --git a/packages/mobile/package.json b/packages/mobile/package.json index 5741a11b40..79f8ac95be 100644 --- a/packages/mobile/package.json +++ b/packages/mobile/package.json @@ -1,6 +1,6 @@ { "name": "@coinbase/cds-mobile", - "version": "9.26.1", + "version": "9.26.2", "description": "Coinbase Design System - Mobile", "repository": { "type": "git", diff --git a/packages/mobile/src/controls/HelperText.tsx b/packages/mobile/src/controls/HelperText.tsx index 275d0413ab..04d0f6ce63 100644 --- a/packages/mobile/src/controls/HelperText.tsx +++ b/packages/mobile/src/controls/HelperText.tsx @@ -1,9 +1,9 @@ import React, { memo, useMemo } from 'react'; import type { ThemeVars } from '@coinbase/cds-common/core/theme'; -import { glyphMap } from '@coinbase/cds-icons/glyphMap'; import { useTheme } from '../hooks/useTheme'; -import { getIconSourceSize } from '../icons/Icon'; +import { Icon } from '../icons/Icon'; +import { HStack } from '../layout/HStack'; import type { TextProps } from '../typography/Text'; import { Text } from '../typography/Text'; @@ -30,64 +30,49 @@ export const HelperText = memo(function HelperText({ color, errorIconAccessibilityLabel, errorIconTestID, - children, - align, - dangerouslySetColor, - style, styles, ...props }: HelperTextProps) { const theme = useTheme(); - // Get info icon for negative variant - const iconSize = theme.iconSize.xs; - const sourceSize = getIconSourceSize(iconSize); - const glyphKey = `info-${sourceSize}-active` as const; - const glyph = glyphMap[glyphKey]; - + const rootStyle = [props.style, styles?.root]; + // TODO: when we actually remove dangerouslySetColor: + // when migrating from dangerouslySetColor to style.color, + // root style/className color will not automatically style the error icon like dangerouslySetColor. + // Consumers must set both styles.root and styles.icon (or classNames equivalents). + // We need to have a migrator handle this or document in future migration guide. const iconStyle = useMemo( () => [ { - fontFamily: 'CoinbaseIcons', - fontSize: iconSize, - height: iconSize, - width: iconSize, - letterSpacing: 4, + // Sit on the first line of label2, matching nested-text alignment. + marginTop: (theme.lineHeight.label2 - theme.iconSize.xs) / 2, }, - // TODO: when we actually remove dangerouslySetColor: - // when migrating from dangerouslySetColor to style.color, - // root style/className color will not automatically style the error icon like dangerouslySetColor. - // Consumers must set both styles.root and styles.icon (or classNames equivalents). - // We need to have a migrator handle this or document in future migration guide. styles?.icon, ], - [iconSize, styles?.icon], + [styles?.icon, theme.iconSize.xs, theme.lineHeight.label2], ); + const justifyContent = + props.align === 'end' ? 'flex-end' : props.align === 'center' ? 'center' : 'flex-start'; - return ( - - {color === 'fgNegative' && ( - + - {glyph} - - )} - {children} - - ); + /> + + + ); + } + + return ; }); diff --git a/packages/mobile/src/controls/__tests__/HelperText.test.tsx b/packages/mobile/src/controls/__tests__/HelperText.test.tsx index 76f674c2df..a5376aae21 100644 --- a/packages/mobile/src/controls/__tests__/HelperText.test.tsx +++ b/packages/mobile/src/controls/__tests__/HelperText.test.tsx @@ -33,6 +33,44 @@ describe('HelperText.test', () => { expect(screen.getByTestId('error-icon')).toHaveStyle({ color: 'yellow' }); }); + it('sizes the error icon to the xs icon token', () => { + render( + + + Test text + + , + ); + + expect(screen.getByTestId('error-icon')).toBeTruthy(); + expect(screen.getByLabelText('Error')).toHaveStyle({ + fontSize: 12, + }); + }); + + it('passes dangerouslySetColor to the helper text and error icon', () => { + render( + + + Test text + + , + ); + + expect(screen.getByTestId('helper-text')).toHaveStyle({ color: 'red' }); + expect(screen.getByLabelText('Error')).toHaveStyle({ color: 'red' }); + }); + it('renders custom spacing', () => { render( diff --git a/packages/web/CHANGELOG.md b/packages/web/CHANGELOG.md index 84c876f8b4..09f9ef0156 100644 --- a/packages/web/CHANGELOG.md +++ b/packages/web/CHANGELOG.md @@ -1,3 +1,14 @@ +## 9.26.2 (2026-09-11) + +### 🩹 Fixes + +- Fix: vertically align the helper-text error icon with the text in web and mobile inputs. +- Fix: dismiss the Android soft keyboard when the mobile `TextInput` unmounts while focused. + +### 🧱 Updated Dependencies + +- Updated illustrations to 4.48.1 + ## 9.26.1 (2026-09-03) ### 🩹 Fixes diff --git a/packages/web/package.json b/packages/web/package.json index 2e0d842a05..db438c5ba5 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,6 +1,6 @@ { "name": "@coinbase/cds-web", - "version": "9.26.1", + "version": "9.26.2", "description": "Coinbase Design System - Web", "repository": { "type": "git", diff --git a/packages/web/src/controls/HelperText.tsx b/packages/web/src/controls/HelperText.tsx index 055de71bf4..d28da1326b 100644 --- a/packages/web/src/controls/HelperText.tsx +++ b/packages/web/src/controls/HelperText.tsx @@ -1,10 +1,9 @@ -import React, { memo } from 'react'; +import React, { memo, useMemo } from 'react'; import type { ThemeVars } from '@coinbase/cds-common/core/theme'; -import { css } from '@linaria/core'; import { cx } from '../cx'; import { Icon } from '../icons/Icon'; -import { Box } from '../layout/Box'; +import { HStack } from '../layout/HStack'; import { Text, type TextDefaultElement, type TextProps } from '../typography/Text'; export type HelperTextProps = { @@ -32,61 +31,66 @@ export type HelperTextProps = { }; } & TextProps; -const iconCss = css` - display: inline-block; - padding-inline-end: var(--space-0_5); -`; - export const HelperText = memo(function HelperTex({ color, - id, errorIconAccessibilityLabel, errorIconTestID, - children, - dangerouslySetColor, - textAlign = 'start', - style, styles, - className, classNames, ...props }: HelperTextProps) { - const rootStyle = { ...style, ...styles?.root }; + const rootStyle = { ...props.style, ...styles?.root }; // TODO: when we actually remove dangerouslySetColor: // when migrating from dangerouslySetColor to style.color, // root style/className color will not automatically style the error icon like dangerouslySetColor. // Consumers must set both styles.root and styles.icon (or classNames equivalents). // We need to have a migrator handle this or document in future migration guide. - const iconStyle = styles?.icon; + const iconStyle = useMemo( + () => ({ + // Sit on the first line of label2, matching nested-text alignment. + marginTop: 'calc((var(--lineHeight-label2) - var(--iconSize-xs)) / 2)', + ...styles?.icon, + }), + [styles?.icon], + ); + const justifyContent = + props.textAlign === 'end' ? 'flex-end' : props.textAlign === 'center' ? 'center' : 'flex-start'; + + if (color === 'fgNegative') { + return ( + + + + + ); + } return ( - {color === 'fgNegative' && ( - - - - )} - {children} - + className={cx(props.className, classNames?.root)} + style={rootStyle} + /> ); }); diff --git a/packages/web/src/controls/__stories__/HelperText.stories.tsx b/packages/web/src/controls/__stories__/HelperText.stories.tsx index a2102f86bb..2c9fbf6217 100644 --- a/packages/web/src/controls/__stories__/HelperText.stories.tsx +++ b/packages/web/src/controls/__stories__/HelperText.stories.tsx @@ -37,7 +37,14 @@ export const TextAlign = () => { return (
{alignments.map((alignment) => ( - {`${alignment} message`} + + {`${alignment} message`} + + ))} + {alignments.map((alignment) => ( + + {`${alignment} error message that can wrap onto multiple lines to check icon alignment`} + ))}
); diff --git a/packages/web/src/controls/__tests__/HelperText.test.tsx b/packages/web/src/controls/__tests__/HelperText.test.tsx index 0ca277a0cf..08fa9a670c 100644 --- a/packages/web/src/controls/__tests__/HelperText.test.tsx +++ b/packages/web/src/controls/__tests__/HelperText.test.tsx @@ -81,4 +81,16 @@ describe('HelperText.test', () => { expect(screen.getByTestId('helper-text-test').className).toContain('4'); }); + + it('keeps the error icon and message together when textAlign is end', () => { + render( + + + Test text + + , + ); + + expect(screen.getByTestId('error-icon').parentElement?.className).toContain('flex-end'); + }); });