Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ export * from './radio';
export { default as Section } from './section';
export * from './section';

export { default as Select } from './select';
export * from './select';

export { default as TimeInput } from './time-input';
export * from './time-input';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type Props = {
/** Label displayed for the input */
label: React.Node,
labelTooltip?: string,
name: string,
name?: string,
Comment thread
bonchevskyi marked this conversation as resolved.
/** Handler for the change event on the select element */
onChange?: Function,
showErrorOutline?: boolean,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @flow
import * as React from 'react';

import Select from './Select';
Expand Down
107 changes: 107 additions & 0 deletions src/components/select/Select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React, { useState } from 'react';
import classNames from 'classnames';
import { FormattedMessage } from 'react-intl';

import IconInfo from '../../icons/general/IconInfo';
import type { Icon } from '../../icons/iconTypes';

import { ButtonType } from '../button';
import Tooltip, { TooltipPosition, TooltipTheme } from '../tooltip';
import Label from '../label';
import PlainButton from '../plain-button';
import messages from './messages';
import './Select.scss';

export interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {
/** Input `<option />`'s */
children?: React.ReactNode;
/** Custom class name for the select container */
className?: string;
/** Error displayed in a tooltip */
error?: React.ReactNode;
/** Props forwarded to the information icon */
infoIconProps?: Partial<Icon> & Record<string, unknown>;
/** Content displayed in the information tooltip */
infoTooltip?: React.ReactNode;
/** Whether the select is disabled */
isDisabled?: boolean;
/** Label displayed for the input */
label: React.ReactNode;
/** Tooltip displayed for the label */
labelTooltip?: string;
/** Name of the select input */
name?: string;
/** Handler for the change event on the select element */
onChange?: React.ChangeEventHandler<HTMLSelectElement>;
/** Whether to show the error outline without error content */
showErrorOutline?: boolean;
/** Whether to visibly display the label */
showLabel?: boolean;
}

const Select = ({
children,
className = '',
error,
infoTooltip,
infoIconProps,
isDisabled,
label,
name,
labelTooltip,
onChange,
showErrorOutline = false,
showLabel = true,
...rest
}: SelectProps) => {
const classes = classNames(className, 'select-input-container', {
'show-error': !!error || showErrorOutline,
'is-disabled': isDisabled,
'bdl-is-disabled': isDisabled,
});
const [infoTooltipIsOpen, setInfoTooltipIsOpen] = useState(false);
return (
<div className={classes}>
<Label hideLabel={!showLabel} text={label} tooltip={labelTooltip}>
<Tooltip
isShown={!!error}
position={TooltipPosition.MIDDLE_RIGHT}
text={error || ''}
Comment thread
bonchevskyi marked this conversation as resolved.
theme={TooltipTheme.ERROR}
>
<span className="select-container">
<span className="select-container-inner">
{/* eslint-disable-next-line jsx-a11y/no-onchange */}
<select disabled={isDisabled} name={name} onChange={onChange} {...rest}>
Comment thread
bonchevskyi marked this conversation as resolved.
{children}
</select>
Comment thread
bonchevskyi marked this conversation as resolved.
<span className="select-overlay" />
</span>
{infoTooltip && (
<Tooltip
targetWrapperClassName="tooltip-icon-container"
isShown={infoTooltipIsOpen}
position={TooltipPosition.MIDDLE_RIGHT}
text={infoTooltip}
>
<PlainButton
type={ButtonType.BUTTON}
onClick={() => setInfoTooltipIsOpen(!infoTooltipIsOpen)}
>
<IconInfo
height={16}
width={16}
title={<FormattedMessage {...messages.moreInfo} />}
{...infoIconProps}
/>
</PlainButton>
</Tooltip>
)}
</span>
</Tooltip>
</Label>
</div>
);
};

export default Select;
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import sinon from 'sinon';

import PlainButton from '../../plain-button';
import Tooltip from '../../tooltip';
import Select from '..';

const sandbox = sinon.sandbox.create();
Expand Down Expand Up @@ -74,20 +77,16 @@ describe('components/select/Select', () => {
const wrapper = shallow(
<Select infoIconProps={{ title: 'hello' }} infoTooltip="hello!!!" label="Album" name="select" />,
);
const getButton = () => wrapper.find('PlainButton');
const getInfoTooltip = () => wrapper.find('Tooltip[text="hello!!!"]');
expect(getInfoTooltip().props().isShown).toBe(false);
const getButton = () => wrapper.find(PlainButton);
const getInfoTooltip = () => wrapper.find(Tooltip).filterWhere(node => node.prop('text') === 'hello!!!');
expect(getInfoTooltip().prop('isShown')).toBe(false);
// Toggle on
getButton()
.props()
.onClick();
expect(getInfoTooltip().props().isShown).toBe(true);
getButton().simulate('click');
expect(getInfoTooltip().prop('isShown')).toBe(true);
// Toggle off
getButton()
.props()
.onClick();
getButton().simulate('click');

expect(getInfoTooltip().props().isShown).toBe(false);
expect(getInfoTooltip().prop('isShown')).toBe(false);
});

test('should show Tooltip when error exists', () => {
Expand Down
File renamed without changes.
2 changes: 2 additions & 0 deletions src/components/select/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from './Select';
export type { SelectProps } from './Select';
11 changes: 11 additions & 0 deletions src/components/select/messages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { defineMessages } from 'react-intl';

const messages = defineMessages({
moreInfo: {
defaultMessage: 'More Info',
description: 'Alt text for info icon',
id: 'boxui.select.moreInfo',
},
});

export default messages;
Loading