diff --git a/packages/common/CHANGELOG.md b/packages/common/CHANGELOG.md index b012b5492f..0579e7b2d1 100644 --- a/packages/common/CHANGELOG.md +++ b/packages/common/CHANGELOG.md @@ -8,6 +8,10 @@ All notable changes to this project will be documented in this file. +## 8.58.0 ((3/25/2026, 11:42 AM PST)) + +This is an artificial version bump with no new change. + ## 8.57.1 ((3/24/2026, 01:14 PM PST)) This is an artificial version bump with no new change. diff --git a/packages/common/package.json b/packages/common/package.json index 88631171a0..10a4f8e0aa 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -1,6 +1,6 @@ { "name": "@coinbase/cds-common", - "version": "8.57.1", + "version": "8.58.0", "description": "Coinbase Design System - Common", "repository": { "type": "git", diff --git a/packages/mcp-server/CHANGELOG.md b/packages/mcp-server/CHANGELOG.md index 2c22828811..770b1b9ff3 100644 --- a/packages/mcp-server/CHANGELOG.md +++ b/packages/mcp-server/CHANGELOG.md @@ -8,6 +8,10 @@ All notable changes to this project will be documented in this file. +## 8.58.0 ((3/25/2026, 11:42 AM PST)) + +This is an artificial version bump with no new change. + ## 8.57.1 ((3/24/2026, 01:14 PM PST)) This is an artificial version bump with no new change. diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 0cf828ca2c..d2ac24a62f 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "@coinbase/cds-mcp-server", - "version": "8.57.1", + "version": "8.58.0", "description": "Coinbase Design System - MCP Server", "repository": { "type": "git", diff --git a/packages/mobile/CHANGELOG.md b/packages/mobile/CHANGELOG.md index 852fcd9cec..f0bdea36df 100644 --- a/packages/mobile/CHANGELOG.md +++ b/packages/mobile/CHANGELOG.md @@ -8,6 +8,13 @@ All notable changes to this project will be documented in this file. +## 8.58.0 (3/25/2026 PST) + +#### 🚀 Updates + +- Feat: support inputFont on inputs. [[#545](https://github.com/coinbase/cds/pull/545)] +- Feat: support borderRadius on SearchInput. [[#545](https://github.com/coinbase/cds/pull/545)] + ## 8.57.1 ((3/24/2026, 01:14 PM PST)) This is an artificial version bump with no new change. diff --git a/packages/mobile/package.json b/packages/mobile/package.json index 0f1795be25..46c77dba8f 100644 --- a/packages/mobile/package.json +++ b/packages/mobile/package.json @@ -1,6 +1,6 @@ { "name": "@coinbase/cds-mobile", - "version": "8.57.1", + "version": "8.58.0", "description": "Coinbase Design System - Mobile", "repository": { "type": "git", diff --git a/packages/mobile/src/alpha/combobox/Combobox.tsx b/packages/mobile/src/alpha/combobox/Combobox.tsx index 74fd9c6968..ec7e4ba63b 100644 --- a/packages/mobile/src/alpha/combobox/Combobox.tsx +++ b/packages/mobile/src/alpha/combobox/Combobox.tsx @@ -66,7 +66,7 @@ export type ComboboxControlProps< Type extends SelectType = 'single', SelectOptionValue extends string = string, > = SelectControlProps & - Pick, 'hideSearchInput'> & { + Pick, 'hideSearchInput' | 'inputFont'> & { /** Search text value */ searchText: string; /** Search text change handler */ @@ -191,6 +191,7 @@ const ComboboxBase = memo( ComboboxControlComponent = DefaultComboboxControl, SelectDropdownComponent = DefaultSelectDropdown, hideSearchInput, + inputFont, ...props }: ComboboxProps, ref: React.Ref, @@ -261,11 +262,12 @@ const ComboboxBase = memo( ComboboxControlComponent={ComboboxControlComponent} SelectControlComponent={SelectControlComponent} controlRef={controlRef} + inputFont={inputFont} searchInputRef={searchInputRef} /> ); }, - [ComboboxControlComponent, SelectControlComponent, searchInputRef], + [ComboboxControlComponent, SelectControlComponent, inputFont, searchInputRef], ); const ComboboxDropdown = useCallback( diff --git a/packages/mobile/src/alpha/combobox/DefaultComboboxControl.tsx b/packages/mobile/src/alpha/combobox/DefaultComboboxControl.tsx index f0769d3bd9..2a462be060 100644 --- a/packages/mobile/src/alpha/combobox/DefaultComboboxControl.tsx +++ b/packages/mobile/src/alpha/combobox/DefaultComboboxControl.tsx @@ -29,6 +29,7 @@ export const DefaultComboboxControl = < options, searchText, onSearch, + inputFont = 'body', searchInputRef, hideSearchInput, accessibilityLabel, @@ -56,6 +57,7 @@ export const DefaultComboboxControl = < accessibilityLabel={computedAccessibilityLabel} align={align} disabled={disabled} + inputFont={inputFont} open={open} options={options} setOpen={setOpen} @@ -67,6 +69,7 @@ export const DefaultComboboxControl = < !disabled && setOpen(true)} placeholder={typeof placeholder === 'string' ? placeholder : undefined} @@ -76,7 +79,7 @@ export const DefaultComboboxControl = < flexShrink: 1, minWidth: 0, padding: 0, - height: hasValue ? 24 : 48, + height: hasValue ? theme.lineHeight[inputFont] : 48, marginTop: hasValue ? 0 : -24, marginBottom: hasValue ? -12 : -24, paddingTop: hasValue ? 8 : 0, @@ -91,7 +94,7 @@ export const DefaultComboboxControl = < ) : ( <> {hasValue ? null : ( - + {typeof placeholder === 'string' ? placeholder : ''} )} diff --git a/packages/mobile/src/alpha/combobox/__tests__/Combobox.test.tsx b/packages/mobile/src/alpha/combobox/__tests__/Combobox.test.tsx index ac91ac75aa..1126e8dccf 100644 --- a/packages/mobile/src/alpha/combobox/__tests__/Combobox.test.tsx +++ b/packages/mobile/src/alpha/combobox/__tests__/Combobox.test.tsx @@ -1,6 +1,8 @@ import { createRef } from 'react'; +import { StyleSheet } from 'react-native'; import { fireEvent, render, screen } from '@testing-library/react-native'; +import { defaultTheme } from '../../../themes/defaultTheme'; import { DefaultThemeProvider } from '../../../utils/testHelpers'; import type { SelectOption } from '../../select/Select'; import { Combobox, type ComboboxProps, type ComboboxRef } from '../Combobox'; @@ -129,6 +131,26 @@ describe('Combobox', () => { expect(input).toBeTruthy(); }); + it('passes inputFont to the search input', () => { + render( + + + , + ); + + const inputs = screen.getAllByPlaceholderText('Search and select...'); + expect( + inputs.some((input) => { + const flattenedStyle = StyleSheet.flatten(input.props.style); + return ( + flattenedStyle?.fontSize === defaultTheme.fontSize.label1 && + flattenedStyle?.lineHeight === defaultTheme.lineHeight.label1 && + flattenedStyle?.fontWeight === defaultTheme.fontWeight.label1 + ); + }), + ).toBe(true); + }); + it('throws error when searchText is provided without onSearch', () => { const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); diff --git a/packages/mobile/src/alpha/select/DefaultSelectControl.tsx b/packages/mobile/src/alpha/select/DefaultSelectControl.tsx index 619dec3256..8409bf4e98 100644 --- a/packages/mobile/src/alpha/select/DefaultSelectControl.tsx +++ b/packages/mobile/src/alpha/select/DefaultSelectControl.tsx @@ -59,6 +59,7 @@ export const DefaultSelectControlComponent = memo( endNode: customEndNode, compact, align = 'start', + inputFont = 'body', bordered = true, borderWidth = bordered ? 100 : 0, focusedBorderWidth = bordered ? undefined : 200, @@ -264,7 +265,7 @@ export const DefaultSelectControlComponent = memo( } return typeof singleValueContent === 'string' ? ( - + {singleValueContent} ) : ( @@ -274,6 +275,7 @@ export const DefaultSelectControlComponent = memo( hasValue, isMultiSelect, singleValueContent, + inputFont, align, value, maxSelectedOptionsToShow, diff --git a/packages/mobile/src/alpha/select/Select.tsx b/packages/mobile/src/alpha/select/Select.tsx index 4a3a3100f3..9667851fdd 100644 --- a/packages/mobile/src/alpha/select/Select.tsx +++ b/packages/mobile/src/alpha/select/Select.tsx @@ -80,6 +80,7 @@ const SelectBase = memo( media, end, align, + inputFont, bordered = true, SelectOptionComponent = DefaultSelectOption, SelectAllOptionComponent = DefaultSelectAllOption, @@ -180,6 +181,7 @@ const SelectBase = memo( endNode={endNode} helperText={helperText} hiddenSelectedOptionsLabel={hiddenSelectedOptionsLabel} + inputFont={inputFont} label={label} labelVariant={labelVariant} maxSelectedOptionsToShow={maxSelectedOptionsToShow} diff --git a/packages/mobile/src/alpha/select/types.ts b/packages/mobile/src/alpha/select/types.ts index b380e065b5..2ec7646517 100644 --- a/packages/mobile/src/alpha/select/types.ts +++ b/packages/mobile/src/alpha/select/types.ts @@ -1,5 +1,6 @@ import type React from 'react'; import type { AccessibilityRole, StyleProp, TouchableOpacity, View, ViewStyle } from 'react-native'; +import type { ThemeVars } from '@coinbase/cds-common/core/theme'; import type { SharedAccessibilityProps } from '@coinbase/cds-common/types'; import type { CellBaseProps } from '../../cells/Cell'; @@ -250,6 +251,11 @@ export type SelectControlProps< * @default 'start' */ align?: 'start' | 'center' | 'end'; + /** + * Typography font token used for typed search input text in select controls that render inputs. + * @default body + */ + inputFont?: ThemeVars.Font; /** * Determines if the control should have a default border. * @note focusedBorderWidth on the control still shows a border when focused by default. @@ -414,6 +420,7 @@ export type SelectBaseProps< | 'labelVariant' | 'endNode' | 'align' + | 'inputFont' | 'bordered' > & Pick, 'accessory' | 'media' | 'end'> & diff --git a/packages/mobile/src/controls/NativeInput.tsx b/packages/mobile/src/controls/NativeInput.tsx index 0600962f6d..529ac6a72b 100644 --- a/packages/mobile/src/controls/NativeInput.tsx +++ b/packages/mobile/src/controls/NativeInput.tsx @@ -1,6 +1,7 @@ import React, { forwardRef, memo, useMemo } from 'react'; import { TextInput } from 'react-native'; -import type { TextInputProps, ViewStyle } from 'react-native'; +import type { StyleProp, TextInputProps, TextStyle, ViewStyle } from 'react-native'; +import type { ThemeVars } from '@coinbase/cds-common/core/theme'; import type { SharedProps } from '@coinbase/cds-common/types'; import type { SharedAccessibilityProps } from '@coinbase/cds-common/types/SharedAccessibilityProps'; @@ -29,6 +30,11 @@ export type NativeInputProps = { * @warning Setting this to unset will break alignment for RTL languages. */ textAlign?: TextInputProps['textAlign'] | 'unset'; + /** + * Typography font token used for typed input text. + * @default body + */ + inputFont?: ThemeVars.Font; } & SharedProps & Pick & Pick< @@ -46,6 +52,7 @@ export const NativeInput = memo( align = 'start', disabled, textAlign, + inputFont = 'body', accessibilityLabel, compact, style, @@ -56,16 +63,25 @@ export const NativeInput = memo( const theme = useTheme(); const textAlignInputTransformed = useTextAlign(align).textAlign; - const inputTextStyle = useMemo( + const inputTextStyle: TextStyle = useMemo( () => ({ - fontSize: theme.fontSize.body, - fontFamily: theme.fontFamily.body, - minHeight: theme.lineHeight.body, + fontSize: theme.fontSize[inputFont], + fontFamily: theme.fontFamily[inputFont], + lineHeight: theme.lineHeight[inputFont], + minHeight: theme.lineHeight[inputFont], + fontWeight: theme.fontWeight[inputFont] as TextStyle['fontWeight'], padding: 0, margin: 0, color: theme.color.fg, }), - [theme.fontSize, theme.fontFamily, theme.lineHeight, theme.color.fg], + [ + theme.fontSize, + theme.fontFamily, + theme.lineHeight, + theme.fontWeight, + theme.color.fg, + inputFont, + ], ); const containerStyle: ViewStyle = useMemo(() => { @@ -87,7 +103,7 @@ export const NativeInput = memo( disabled, ]); - const inputRootStyles = useMemo(() => { + const inputRootStyles: StyleProp = useMemo(() => { return [ inputTextStyle, containerStyle, diff --git a/packages/mobile/src/controls/SearchInput.tsx b/packages/mobile/src/controls/SearchInput.tsx index 55cbec3e65..81850b65be 100644 --- a/packages/mobile/src/controls/SearchInput.tsx +++ b/packages/mobile/src/controls/SearchInput.tsx @@ -21,11 +21,13 @@ export type SearchInputBaseProps = Pick< | 'accessibilityLabel' | 'accessibilityLabelledBy' | 'bordered' + | 'borderRadius' | 'compact' | 'disabled' | 'enableColorSurge' | 'focusedBorderWidth' | 'helperTextErrorIconAccessibilityLabel' + | 'inputFont' | 'placeholder' | 'testID' | 'testIDMap' @@ -107,6 +109,7 @@ export const SearchInput = memo( end, startIconAccessibilityLabel = 'Back', clearIconAccessibilityLabel = 'Clear text', + borderRadius = 1000, ...props }: SearchInputProps, ref: ForwardedRef, @@ -174,7 +177,7 @@ export const SearchInput = memo( diff --git a/packages/mobile/src/controls/__stories__/SearchInput.stories.tsx b/packages/mobile/src/controls/__stories__/SearchInput.stories.tsx index 4f612e91c4..ca992a737b 100644 --- a/packages/mobile/src/controls/__stories__/SearchInput.stories.tsx +++ b/packages/mobile/src/controls/__stories__/SearchInput.stories.tsx @@ -24,6 +24,7 @@ const BorderlessVariants = () => { return ( { expect(screen.getByRole('search').props.value).toBe('value'); }); + it('passes inputFont to the text input', () => { + render( + + + , + ); + + const flattenedStyle = StyleSheet.flatten(screen.getByRole('search').props.style); + expect(flattenedStyle).toEqual( + expect.objectContaining({ + fontSize: defaultTheme.fontSize.label1, + lineHeight: defaultTheme.lineHeight.label1, + fontWeight: defaultTheme.fontWeight.label1, + }), + ); + }); + it('keeps focused border width at 0 by default when bordered is false', () => { render( diff --git a/packages/mobile/src/controls/__tests__/TextInput.test.tsx b/packages/mobile/src/controls/__tests__/TextInput.test.tsx index b8c06c6dc3..b517c80e30 100644 --- a/packages/mobile/src/controls/__tests__/TextInput.test.tsx +++ b/packages/mobile/src/controls/__tests__/TextInput.test.tsx @@ -2,6 +2,7 @@ import { Animated, StyleSheet } from 'react-native'; import { focusedInputBorderWidth } from '@coinbase/cds-common/tokens/input'; import { fireEvent, render, screen } from '@testing-library/react-native'; +import { defaultTheme } from '../../themes/defaultTheme'; import { Text } from '../../typography/Text'; import { DefaultThemeProvider } from '../../utils/testHelpers'; import { TextInput } from '../TextInput'; @@ -69,6 +70,24 @@ describe('TextInput', () => { expect(screen.getByTestId(testID).props.value).toBe(value); }); + it('passes inputFont to native input', () => { + const testID = 'textinput-id'; + render( + + + , + ); + + const flattenedStyle = StyleSheet.flatten(screen.getByTestId(testID).props.style); + expect(flattenedStyle).toEqual( + expect.objectContaining({ + fontSize: defaultTheme.fontSize.label1, + lineHeight: defaultTheme.lineHeight.label1, + fontWeight: defaultTheme.fontWeight.label1, + }), + ); + }); + it('renders a label', () => { const testID = 'label-testid'; const labelText = 'Example label'; diff --git a/packages/web/CHANGELOG.md b/packages/web/CHANGELOG.md index c780375689..f057b053ba 100644 --- a/packages/web/CHANGELOG.md +++ b/packages/web/CHANGELOG.md @@ -8,6 +8,13 @@ All notable changes to this project will be documented in this file. +## 8.58.0 (3/25/2026 PST) + +#### 🚀 Updates + +- Feat: support inputFont on inputs. [[#545](https://github.com/coinbase/cds/pull/545)] +- Feat: support borderRadius on SearchInput. [[#545](https://github.com/coinbase/cds/pull/545)] + ## 8.57.1 (3/24/2026 PST) #### 🐞 Fixes diff --git a/packages/web/package.json b/packages/web/package.json index e2727bd508..11382cf198 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,6 +1,6 @@ { "name": "@coinbase/cds-web", - "version": "8.57.1", + "version": "8.58.0", "description": "Coinbase Design System - Web", "repository": { "type": "git", diff --git a/packages/web/src/alpha/combobox/Combobox.tsx b/packages/web/src/alpha/combobox/Combobox.tsx index b690f8f77e..6ad4f18858 100644 --- a/packages/web/src/alpha/combobox/Combobox.tsx +++ b/packages/web/src/alpha/combobox/Combobox.tsx @@ -60,7 +60,7 @@ export type ComboboxControlProps< Type extends SelectType = 'single', SelectOptionValue extends string = string, > = SelectControlProps & - Pick, 'hideSearchInput'> & { + Pick, 'hideSearchInput' | 'inputFont'> & { /** Search text value */ searchText: string; /** Search text change handler */ @@ -173,6 +173,7 @@ const ComboboxBase = memo( SelectControlComponent = DefaultSelectControl, ComboboxControlComponent = DefaultComboboxControl, hideSearchInput, + inputFont, ...props }: ComboboxProps, ref: React.Ref, @@ -235,9 +236,10 @@ const ComboboxBase = memo( ComboboxControlComponent={ComboboxControlComponent} SelectControlComponent={SelectControlComponent} controlRef={controlRef} + inputFont={inputFont} /> ), - [SelectControlComponent, ComboboxControlComponent], + [SelectControlComponent, ComboboxControlComponent, inputFont], ); return ( diff --git a/packages/web/src/alpha/combobox/DefaultComboboxControl.tsx b/packages/web/src/alpha/combobox/DefaultComboboxControl.tsx index 317eabd087..c0ea6e88e5 100644 --- a/packages/web/src/alpha/combobox/DefaultComboboxControl.tsx +++ b/packages/web/src/alpha/combobox/DefaultComboboxControl.tsx @@ -28,6 +28,7 @@ export const DefaultComboboxControl = memo( align, searchText, onSearch, + inputFont = 'body', accessibilityLabel, ...props }: ComboboxControlProps) => { @@ -70,6 +71,7 @@ export const DefaultComboboxControl = memo( accessibilityLabel={computedAccessibilityLabel} align={align} compact={compact} + inputFont={inputFont} open={open} options={options} role="combobox" @@ -81,6 +83,7 @@ export const DefaultComboboxControl = memo( { @@ -98,7 +101,7 @@ export const DefaultComboboxControl = memo( style={{ paddingLeft: 0, paddingRight: 0, - height: hasValue ? 24 : compact ? 40 : 48, + height: hasValue ? `var(--lineHeight-${inputFont})` : compact ? 40 : 48, minWidth: 0, flexGrow: 1, width: '100%', @@ -118,7 +121,7 @@ export const DefaultComboboxControl = memo( as="p" color="fgMuted" display="block" - font="body" + font={inputFont} overflow="truncate" paddingY={0} textAlign={align} diff --git a/packages/web/src/alpha/combobox/__tests__/Combobox.test.tsx b/packages/web/src/alpha/combobox/__tests__/Combobox.test.tsx index ef5cee4e64..485975b8dc 100644 --- a/packages/web/src/alpha/combobox/__tests__/Combobox.test.tsx +++ b/packages/web/src/alpha/combobox/__tests__/Combobox.test.tsx @@ -115,6 +115,16 @@ describe('Combobox', () => { expect(input).toBeInTheDocument(); }); + it('passes inputFont to the search input', () => { + render( + + + , + ); + + expect(screen.getByRole('textbox')).toHaveStyle('font-size: var(--fontSize-label1);'); + }); + it('filters options based on search text', async () => { render( diff --git a/packages/web/src/alpha/select/DefaultSelectControl.tsx b/packages/web/src/alpha/select/DefaultSelectControl.tsx index 7beafed34b..6f1553e806 100644 --- a/packages/web/src/alpha/select/DefaultSelectControl.tsx +++ b/packages/web/src/alpha/select/DefaultSelectControl.tsx @@ -85,6 +85,7 @@ const DefaultSelectControlComponent = memo( compact, blendStyles, align = 'start', + inputFont = 'body', bordered = true, borderWidth = bordered ? 100 : 0, focusedBorderWidth = bordered ? undefined : 200, @@ -317,7 +318,7 @@ const DefaultSelectControlComponent = memo( as="p" color={hasValue ? 'fg' : 'fgMuted'} display="block" - font="body" + font={inputFont} overflow="truncate" textAlign={align} width="100%" @@ -331,6 +332,7 @@ const DefaultSelectControlComponent = memo( hasValue, isMultiSelect, singleValueContent, + inputFont, align, value, maxSelectedOptionsToShow, diff --git a/packages/web/src/alpha/select/Select.tsx b/packages/web/src/alpha/select/Select.tsx index 3fe96ab49f..42dd60061f 100644 --- a/packages/web/src/alpha/select/Select.tsx +++ b/packages/web/src/alpha/select/Select.tsx @@ -92,6 +92,7 @@ const SelectBase = memo( media, end, align, + inputFont, bordered = true, SelectOptionComponent = DefaultSelectOption, SelectAllOptionComponent = DefaultSelectAllOption, @@ -265,6 +266,7 @@ const SelectBase = memo( endNode={endNode} helperText={helperText} hiddenSelectedOptionsLabel={hiddenSelectedOptionsLabel} + inputFont={inputFont} label={label} labelVariant={labelVariant} maxSelectedOptionsToShow={maxSelectedOptionsToShow} diff --git a/packages/web/src/alpha/select/types.ts b/packages/web/src/alpha/select/types.ts index 1c9f826a8f..db8ee596b0 100644 --- a/packages/web/src/alpha/select/types.ts +++ b/packages/web/src/alpha/select/types.ts @@ -1,5 +1,6 @@ import type React from 'react'; import type { SharedAccessibilityProps } from '@coinbase/cds-common'; +import type { ThemeVars } from '@coinbase/cds-common/core/theme'; import type { CellBaseProps } from '../../cells/Cell'; import type { InputStackBaseProps } from '../../controls/InputStack'; @@ -396,6 +397,11 @@ export type SelectControlProps< * @default 'start' */ align?: 'start' | 'center' | 'end'; + /** + * Typography font token used for typed search input text in select controls that render inputs. + * @default body + */ + inputFont?: ThemeVars.Font; /** * Determines if the control should have a default border. * @note focusedBorderWidth on the control still shows a border when focused by default. @@ -503,6 +509,7 @@ export type SelectBaseProps< | 'labelVariant' | 'endNode' | 'align' + | 'inputFont' | 'bordered' > & Pick, 'accessory' | 'media' | 'end'> & diff --git a/packages/web/src/controls/NativeInput.tsx b/packages/web/src/controls/NativeInput.tsx index 79444bae44..9ac7d48909 100644 --- a/packages/web/src/controls/NativeInput.tsx +++ b/packages/web/src/controls/NativeInput.tsx @@ -1,4 +1,5 @@ import React, { forwardRef, memo, useMemo } from 'react'; +import type { ThemeVars } from '@coinbase/cds-common/core/theme'; import type { SharedAccessibilityProps } from '@coinbase/cds-common/types/SharedAccessibilityProps'; import type { SharedProps } from '@coinbase/cds-common/types/SharedProps'; import type { TextAlignProps } from '@coinbase/cds-common/types/TextBaseProps'; @@ -8,10 +9,10 @@ import { cx } from '../cx'; import { useTheme } from '../hooks/useTheme'; const baseCss = css` - font-size: var(--fontSize-body); - line-height: var(--lineHeight-body); - font-weight: var(--fontWeight-body); - font-family: var(--fontFamily-body); + font-size: var(--nativeInput-fontSize, var(--fontSize-body)); + line-height: var(--nativeInput-lineHeight, var(--lineHeight-body)); + font-weight: var(--nativeInput-fontWeight, var(--fontWeight-body)); + font-family: var(--nativeInput-fontFamily, var(--fontFamily-body)); min-width: 0; flex-grow: 2; background-color: transparent; @@ -91,6 +92,11 @@ export type NativeInputProps = { * @default start * */ align?: TextAlignProps['align']; + /** + * Typography font token used for typed input text. + * @default body + */ + inputFont?: ThemeVars.Font; /** * Callback fired when pressed/clicked */ @@ -108,6 +114,7 @@ export const NativeInput = memo( containerSpacing, testID, align = 'start', + inputFont = 'body', onFocus, onClick, onBlur, @@ -129,12 +136,21 @@ export const NativeInput = memo( : originalContainerPaddingCss; const dynamicStyles = useMemo( - () => ({ - textAlign: align, - colorScheme: activeColorScheme, - ...style, - }), - [align, activeColorScheme, style], + () => + ({ + '--nativeInput-fontSize': `var(--fontSize-${inputFont})`, + '--nativeInput-lineHeight': `var(--lineHeight-${inputFont})`, + '--nativeInput-fontWeight': `var(--fontWeight-${inputFont})`, + '--nativeInput-fontFamily': `var(--fontFamily-${inputFont})`, + fontSize: `var(--fontSize-${inputFont})`, + lineHeight: `var(--lineHeight-${inputFont})`, + fontWeight: `var(--fontWeight-${inputFont})`, + fontFamily: `var(--fontFamily-${inputFont})`, + textAlign: align, + colorScheme: activeColorScheme, + ...style, + }) as React.CSSProperties, + [align, activeColorScheme, inputFont, style], ); return ( diff --git a/packages/web/src/controls/SearchInput.tsx b/packages/web/src/controls/SearchInput.tsx index c8037d2606..2452d8ecd0 100644 --- a/packages/web/src/controls/SearchInput.tsx +++ b/packages/web/src/controls/SearchInput.tsx @@ -32,11 +32,13 @@ export type SearchInputBaseProps = Pick< | 'accessibilityLabel' | 'accessibilityLabelledBy' | 'bordered' + | 'borderRadius' | 'compact' | 'disabled' | 'enableColorSurge' | 'focusedBorderWidth' | 'helperTextErrorIconAccessibilityLabel' + | 'inputFont' | 'placeholder' | 'testID' | 'testIDMap' @@ -107,6 +109,7 @@ export const SearchInput = memo( end, startIconAccessibilityLabel = 'Back', clearIconAccessibilityLabel = 'Clear search query', + borderRadius = 1000, ...props }: SearchInputProps, ref: React.ForwardedRef, @@ -149,7 +152,7 @@ export const SearchInput = memo( return ( { , ); - expect(screen.getByTestId(TEST_ID)).toHaveAttribute( - 'style', - 'text-align: start; color-scheme: dark;', - ); + expect(screen.getByTestId(TEST_ID)).toHaveStyle('text-align: start;'); + expect(screen.getByTestId(TEST_ID)).toHaveStyle('color-scheme: dark;'); + expect(screen.getByTestId(TEST_ID)).toHaveStyle('font-size: var(--fontSize-body);'); + expect(screen.getByTestId(TEST_ID)).toHaveStyle('line-height: var(--lineHeight-body);'); + expect(screen.getByTestId(TEST_ID)).toHaveStyle('font-weight: var(--fontWeight-body);'); + expect(screen.getByTestId(TEST_ID)).toHaveStyle('font-family: var(--fontFamily-body);'); }); it('changes align style if override passed as align prop', () => { @@ -71,10 +73,21 @@ describe('NativeInput', () => { , ); - expect(screen.getByTestId(TEST_ID)).toHaveAttribute( - 'style', - 'text-align: center; color-scheme: light;', + expect(screen.getByTestId(TEST_ID)).toHaveStyle('text-align: center;'); + expect(screen.getByTestId(TEST_ID)).toHaveStyle('color-scheme: light;'); + }); + + it('changes typography token when inputFont is provided', () => { + render( + + + , ); + + expect(screen.getByTestId(TEST_ID)).toHaveStyle('font-size: var(--fontSize-label1);'); + expect(screen.getByTestId(TEST_ID)).toHaveStyle('line-height: var(--lineHeight-label1);'); + expect(screen.getByTestId(TEST_ID)).toHaveStyle('font-weight: var(--fontWeight-label1);'); + expect(screen.getByTestId(TEST_ID)).toHaveStyle('font-family: var(--fontFamily-label1);'); }); }); diff --git a/packages/web/src/controls/__tests__/SearchInput.test.tsx b/packages/web/src/controls/__tests__/SearchInput.test.tsx index d638a84687..042c5aa025 100644 --- a/packages/web/src/controls/__tests__/SearchInput.test.tsx +++ b/packages/web/src/controls/__tests__/SearchInput.test.tsx @@ -43,6 +43,21 @@ describe('Search', () => { expect(screen.getByRole('searchbox')).toHaveValue('value'); }); + it('passes inputFont through to the text input', () => { + render( + + + , + ); + + expect(screen.getByRole('searchbox')).toHaveStyle('font-size: var(--fontSize-label1);'); + }); + /** Testing for existence of components */ it('renders a search', () => { render( diff --git a/packages/web/src/controls/__tests__/TextInput.test.tsx b/packages/web/src/controls/__tests__/TextInput.test.tsx index 2b014cf45a..06bdee8aaf 100644 --- a/packages/web/src/controls/__tests__/TextInput.test.tsx +++ b/packages/web/src/controls/__tests__/TextInput.test.tsx @@ -45,6 +45,16 @@ describe('TextInput', () => { expect(screen.getByRole('textbox')).toHaveValue(value); }); + it('passes inputFont to native input', () => { + render( + + + , + ); + + expect(screen.getByRole('textbox')).toHaveStyle('font-size: var(--fontSize-label1);'); + }); + it('renders a label', () => { const testID = 'label-testid'; const labelText = 'Example label';