Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/components/src/base-control/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
* That element should be passed as a child.
* @property {import('react').ReactNode} help If this property is added, a help text will be
* generated using help property as the content.
* @property {import('react').ReactNode} label If this property is added, a label will be generated
* @property {import('react').ReactNode} [label] If this property is added, a label will be generated
* using label property as the content.
* @property {boolean} [hideLabelFromVision] If true, the label will only be visible to screen readers.
* @property {string} [className] The class that will be added with "components-base-control" to the
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
/**
* External dependencies
*/
import { isEmpty, noop } from 'lodash';
import { isEmpty, noop, omit } from 'lodash';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just realised this — can the omit import be removed now? I don't see any further usages.
We may want to apply this change directly in #33696

import classNames from 'classnames';
// eslint-disable-next-line no-restricted-imports
import type { ChangeEvent, FocusEvent, Ref } from 'react';

/**
* WordPress dependencies
Expand All @@ -16,15 +18,39 @@ import { Icon, chevronDown } from '@wordpress/icons';
*/
import BaseControl from '../base-control';
import InputBase from '../input-control/input-base';
import type { InputBaseProps, LabelPosition } from '../input-control/types';
import { Select, DownArrowWrapper } from './styles/select-control-styles';
import type { Size } from './types';
import type { PolymorphicComponentProps } from '../ui/context';

function useUniqueId( idProp ) {
function useUniqueId( idProp?: string ) {
const instanceId = useInstanceId( SelectControl );
const id = `inspector-select-control-${ instanceId }`;

return idProp || id;
}

export interface SelectControlProps extends Omit< InputBaseProps, 'children' > {
help?: string;
hideLabelFromVision?: boolean;
multiple?: boolean;
onBlur?: ( event: FocusEvent< HTMLSelectElement > ) => void;
onFocus?: ( event: FocusEvent< HTMLSelectElement > ) => void;
onChange?: (
value: string | string[],
extra?: { event?: ChangeEvent< HTMLSelectElement > }
) => void;
options?: {
label: string;
value: string;
id?: string;
disabled?: boolean;
}[];
size?: Size;
value?: string | string[];
labelPosition?: LabelPosition;
}

function SelectControl(
{
className,
Expand All @@ -42,8 +68,8 @@ function SelectControl(
value: valueProp,
labelPosition = 'top',
...props
},
ref
}: PolymorphicComponentProps< SelectControlProps, 'select', false >,
ref: Ref< HTMLSelectElement >
) {
const [ isFocused, setIsFocused ] = useState( false );
const id = useUniqueId( idProp );
Expand All @@ -52,17 +78,17 @@ function SelectControl(
// Disable reason: A select with an onchange throws a warning
if ( isEmpty( options ) ) return null;

const handleOnBlur = ( event ) => {
const handleOnBlur = ( event: FocusEvent< HTMLSelectElement > ) => {
onBlur( event );
setIsFocused( false );
};

const handleOnFocus = ( event ) => {
const handleOnFocus = ( event: FocusEvent< HTMLSelectElement > ) => {
onFocus( event );
setIsFocused( true );
};

const handleOnChange = ( event ) => {
const handleOnChange = ( event: ChangeEvent< HTMLSelectElement > ) => {
if ( multiple ) {
const selectedOptions = [ ...event.target.options ].filter(
( { selected } ) => selected
Expand All @@ -79,7 +105,7 @@ function SelectControl(

/* eslint-disable jsx-a11y/no-onchange */
return (
<BaseControl help={ help }>
<BaseControl help={ help } id={ id }>
<InputBase
className={ classes }
disabled={ disabled }
Expand All @@ -89,15 +115,17 @@ function SelectControl(
label={ label }
size={ size }
suffix={
<DownArrowWrapper>
<Icon icon={ chevronDown } size={ 18 } />
</DownArrowWrapper>
props.suffix || (
<DownArrowWrapper>
<Icon icon={ chevronDown } size={ 18 } />
</DownArrowWrapper>
)
}
prefix={ props.prefix }
labelPosition={ labelPosition }
{ ...props }
>
<Select
{ ...props }
{ ...omit( props, 'prefix', 'suffix' ) }
aria-describedby={ helpId }
className="components-select-control__input"
disabled={ disabled }
Expand All @@ -107,7 +135,7 @@ function SelectControl(
onChange={ handleOnChange }
onFocus={ handleOnFocus }
ref={ ref }
size={ size }
selectSize={ size }
value={ valueProp }
>
{ options.map( ( option, index ) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,28 @@ import styled from '@emotion/styled';
* Internal dependencies
*/
import { COLORS, rtl } from '../../utils';
import type { Size } from '../types';

const disabledStyles = ( { disabled } ) => {
interface SelectProps {
disabled?: boolean;
selectSize?: Size;
}

const disabledStyles = ( { disabled }: SelectProps ) => {
if ( ! disabled ) return '';

return css( {
color: COLORS.ui.textDisabled,
} );
};

const fontSizeStyles = ( { size } ) => {
const fontSizeStyles = ( { selectSize }: SelectProps ) => {
const sizes = {
default: '13px',
small: '11px',
};

const fontSize = sizes[ size ];
const fontSize = sizes[ selectSize ];
const fontSizeMobile = '16px';

if ( ! fontSize ) return '';
Expand All @@ -37,7 +43,7 @@ const fontSizeStyles = ( { size } ) => {
`;
};

const sizeStyles = ( { size } ) => {
const sizeStyles = ( { selectSize }: SelectProps ) => {
const sizes = {
default: {
height: 30,
Expand All @@ -51,15 +57,15 @@ const sizeStyles = ( { size } ) => {
},
};

const style = sizes[ size ] || sizes.default;
const style = sizes[ selectSize ] || sizes.default;

return css( style );
};

// TODO: Resolve need to use &&& to increase specificity
// https://github.com/WordPress/gutenberg/issues/18483

export const Select = styled.select`
export const Select = styled.select< SelectProps >`
&&& {
appearance: none;
background: transparent;
Expand All @@ -75,7 +81,7 @@ export const Select = styled.select`
${ fontSizeStyles };
${ sizeStyles };

${ rtl( { paddingLeft: 8, paddingRight: 24 } )() }
${ rtl( { paddingLeft: 8, paddingRight: 24 } ) }
}
`;

Expand All @@ -89,7 +95,7 @@ export const DownArrowWrapper = styled.div`
position: absolute;
top: 0;

${ rtl( { right: 0 } )() }
${ rtl( { right: 0 } ) }

svg {
display: block;
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/select-control/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type Size = 'default' | 'small';