Skip to content

Commit

Permalink
Add quiet styling to S2 Picker (adobe#6812)
Browse files Browse the repository at this point in the history
* add quiet styling

* remove spacing

* fix spacing

* simplify outline style

* have label on a single line

* long content in quiet picker to truncate in fixed width container

* small fixes

* offset dropdown when align is start

* fix width of quiet picker dropdown

* remove unused import

* remove another unused import

* update offset

---------

Co-authored-by: Robert Snow <[email protected]>
  • Loading branch information
yihuiliao and snowystinger committed Aug 9, 2024
1 parent 81e3804 commit f56a787
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 17 deletions.
7 changes: 5 additions & 2 deletions packages/@react-spectrum/s2/src/Field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ interface FieldLabelProps extends Omit<LabelProps, 'className' | 'style' | 'chil
includeNecessityIndicatorInAccessibilityName?: boolean,
staticColor?: 'white' | 'black',
contextualHelp?: ReactNode,
isQuiet?: boolean,
children?: ReactNode
}

Expand All @@ -49,6 +50,7 @@ function FieldLabel(props: FieldLabelProps, ref: DOMRef<HTMLLabelElement>) {
labelPosition,
staticColor,
contextualHelp,
isQuiet,
UNSAFE_style,
UNSAFE_className = '',
...labelProps
Expand Down Expand Up @@ -80,9 +82,10 @@ function FieldLabel(props: FieldLabelProps, ref: DOMRef<HTMLLabelElement>) {
contain: {
labelPosition: {
top: 'inline-size'
}
},
isQuiet: 'none'
}
})({labelAlign, labelPosition})}>
})({labelAlign, labelPosition, isQuiet})}>
<Label
{...labelProps}
ref={domRef}
Expand Down
73 changes: 59 additions & 14 deletions packages/@react-spectrum/s2/src/Picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,12 @@ export interface PickerStyleProps {
*
* @default 'M'
*/
size?: 'S' | 'M' | 'L' | 'XL'
size?: 'S' | 'M' | 'L' | 'XL',
/**
* Whether the picker should be displayed with a quiet style.
* @private
*/
isQuiet?: boolean
}

export interface PickerProps<T extends object> extends
Expand Down Expand Up @@ -101,6 +106,9 @@ interface PickerButtonProps extends PickerStyleProps, ButtonRenderProps {}
const inputButton = style<PickerButtonProps | AriaSelectRenderProps>({
...focusRing(),
...fieldInput(),
outlineStyle: {
isQuiet: 'none'
},
position: 'relative',
font: 'control',
display: 'flex',
Expand All @@ -110,19 +118,42 @@ const inputButton = style<PickerButtonProps | AriaSelectRenderProps>({
alignItems: 'center',
height: 'control',
transition: 'default',
columnGap: 'text-to-control',
paddingX: 'edge-to-text',
columnGap: {
default: 'text-to-control',
isQuiet: 'text-to-visual'
},
paddingX: {
default: 'edge-to-text',
isQuiet: 0
},
backgroundColor: {
default: baseColor('gray-100'),
isOpen: 'gray-200',
isDisabled: 'disabled'
isDisabled: 'disabled',
isQuiet: 'transparent'
},
color: {
default: 'neutral',
isDisabled: 'disabled'
},
maxWidth: {
isQuiet: 'max'
}
});

const quietFocusLine = style({
width: 'full',
// Use pixels since we are emulating a border.
height: `[2px]`,
position: 'absolute',
bottom: 0,
borderRadius: 'full',
backgroundColor: {
default: 'blue-800',
forcedColors: 'Highlight'
}
})

export let menu = style({
outlineStyle: 'none',
display: 'grid',
Expand Down Expand Up @@ -157,7 +188,10 @@ const invalidBorder = style({
});

const valueStyles = style({
flexGrow: 1,
flexGrow: {
default: 1,
isQuiet: 0
},
truncate: true,
display: 'flex',
alignItems: 'center'
Expand Down Expand Up @@ -195,7 +229,8 @@ function Picker<T extends object>(props: PickerProps<T>, ref: FocusableRef<HTMLB
necessityIndicator,
UNSAFE_className = '',
UNSAFE_style,
placeholder = 'Select an option...',
placeholder = 'Select...',
isQuiet,
...pickerProps
} = props;

Expand All @@ -221,7 +256,7 @@ function Picker<T extends object>(props: PickerProps<T>, ref: FocusableRef<HTMLB
labelPosition,
size
}, props.styles)}>
{({isDisabled, isOpen, isInvalid, isRequired}) => (
{({isDisabled, isOpen, isFocusVisible, isInvalid, isRequired}) => (
<>
<InternalPickerContext.Provider value={{size}}>
<FieldLabel
Expand All @@ -230,6 +265,7 @@ function Picker<T extends object>(props: PickerProps<T>, ref: FocusableRef<HTMLB
size={size}
labelPosition={labelPosition}
labelAlign={labelAlign}
isQuiet={isQuiet}
necessityIndicator={necessityIndicator}
contextualHelp={props.contextualHelp}>
{label}
Expand All @@ -240,11 +276,12 @@ function Picker<T extends object>(props: PickerProps<T>, ref: FocusableRef<HTMLB
className={renderProps => inputButton({
...renderProps,
size: size,
isOpen
isOpen,
isQuiet
})}>
{(renderProps) => (
<>
<SelectValue className={valueStyles + ' ' + raw('&> * {display: none;}')}>
<SelectValue className={valueStyles({isQuiet}) + ' ' + raw('&> * {display: none;}')}>
{({defaultChildren}) => {
return (
<Provider
Expand Down Expand Up @@ -280,7 +317,8 @@ function Picker<T extends object>(props: PickerProps<T>, ref: FocusableRef<HTMLB
<ChevronIcon
size={size}
className={iconStyles} />
{isInvalid && !isDisabled &&
{isFocusVisible && isQuiet && <span className={quietFocusLine} /> }
{isInvalid && !isDisabled && !isQuiet &&
// @ts-ignore known limitation detecting functions from the theme
<div className={invalidBorder({...renderProps, size})} />
}
Expand All @@ -300,14 +338,21 @@ function Picker<T extends object>(props: PickerProps<T>, ref: FocusableRef<HTMLB
placement={`${direction} ${align}` as Placement}
shouldFlip={shouldFlip}
UNSAFE_style={{
width: menuWidth ? `${menuWidth}px` : undefined
width: menuWidth && !isQuiet ? `${menuWidth}px` : undefined
}}
styles={style({
marginStart: {
isQuiet: -12
},
minWidth: {
default: '[var(--trigger-width)]'
default: '[var(--trigger-width)]',
isQuiet: 192
},
width: '[var(--trigger-width)]'
})}>
width: {
default: '[var(--trigger-width)]',
isQuiet: '[calc(var(--trigger-width) + (-2 * self(marginStart)))]'
}
})(props)}>
<Provider
values={[
[HeaderContext, {className: sectionHeader({size})}],
Expand Down
3 changes: 2 additions & 1 deletion packages/@react-spectrum/s2/src/style-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ export const fieldInput = () => ({
contain: {
// Only apply size containment if contain-intrinsic-width is supported.
// In older browsers, this will fall back to the default browser intrinsic width.
'@supports (contain-intrinsic-width: 1px)': 'inline-size'
'@supports (contain-intrinsic-width: 1px)': 'inline-size',
isQuiet: 'none'
},
'--defaultWidth': {
type: 'width',
Expand Down

0 comments on commit f56a787

Please sign in to comment.