@@ -18,6 +18,7 @@ import classNames from "classnames";
1818import * as React from "react" ;
1919import { polyfill } from "react-lifecycles-compat" ;
2020import { AbstractPureComponent2 , Classes } from "../../common" ;
21+ import * as Errors from "../../common/errors" ;
2122import {
2223 DISPLAYNAME_PREFIX ,
2324 HTMLInputProps ,
@@ -29,8 +30,6 @@ import {
2930} from "../../common/props" ;
3031import { Icon , IconName } from "../icon/icon" ;
3132
32- const DEFAULT_RIGHT_ELEMENT_WIDTH = 10 ;
33-
3433// NOTE: This interface does not extend HTMLInputProps due to incompatiblity with `IControlledProps`.
3534// Instead, we union the props in the component definition, which does work and properly disallows `string[]` values.
3635export interface IInputGroupProps extends IControlledProps , IIntentProps , IProps {
@@ -50,8 +49,15 @@ export interface IInputGroupProps extends IControlledProps, IIntentProps, IProps
5049 inputRef ?: ( ref : HTMLInputElement | null ) => any ;
5150
5251 /**
53- * Name of a Blueprint UI icon (or an icon element) to render on the left side of the input group,
54- * before the user's cursor.
52+ * Element to render on the left side of input. This prop is mutually exclusive
53+ * with `leftIcon`.
54+ */
55+ leftElement ?: JSX . Element ;
56+
57+ /**
58+ * Name of a Blueprint UI icon to render on the left side of the input group,
59+ * before the user's cursor. This prop is mutually exclusive with `leftElement`.
60+ * Usage with content is deprecated. Use `leftElement` for elements.
5561 */
5662 leftIcon ?: IconName | MaybeElement ;
5763
@@ -81,24 +87,26 @@ export interface IInputGroupProps extends IControlledProps, IIntentProps, IProps
8187}
8288
8389export interface IInputGroupState {
84- rightElementWidth : number ;
90+ leftElementWidth ?: number ;
91+ rightElementWidth ?: number ;
8592}
8693
8794@polyfill
8895export class InputGroup extends AbstractPureComponent2 < IInputGroupProps & HTMLInputProps , IInputGroupState > {
8996 public static displayName = `${ DISPLAYNAME_PREFIX } .InputGroup` ;
9097
91- public state : IInputGroupState = {
92- rightElementWidth : DEFAULT_RIGHT_ELEMENT_WIDTH ,
93- } ;
98+ public state : IInputGroupState = { } ;
9499
100+ private leftElement : HTMLElement ;
95101 private rightElement : HTMLElement ;
102+
96103 private refHandlers = {
104+ leftElement : ( ref : HTMLSpanElement ) => ( this . leftElement = ref ) ,
97105 rightElement : ( ref : HTMLSpanElement ) => ( this . rightElement = ref ) ,
98106 } ;
99107
100108 public render ( ) {
101- const { className, disabled, fill, intent, large, small, leftIcon , round } = this . props ;
109+ const { className, disabled, fill, intent, large, small, round } = this . props ;
102110 const classes = classNames (
103111 Classes . INPUT_GROUP ,
104112 Classes . intentClass ( intent ) ,
@@ -111,11 +119,16 @@ export class InputGroup extends AbstractPureComponent2<IInputGroupProps & HTMLIn
111119 } ,
112120 className ,
113121 ) ;
114- const style : React . CSSProperties = { ...this . props . style , paddingRight : this . state . rightElementWidth } ;
122+
123+ const style : React . CSSProperties = {
124+ ...this . props . style ,
125+ paddingLeft : this . state . leftElementWidth ,
126+ paddingRight : this . state . rightElementWidth ,
127+ } ;
115128
116129 return (
117130 < div className = { classes } >
118- < Icon icon = { leftIcon } />
131+ { this . maybeRenderLeftElement ( ) }
119132 < input
120133 type = "text"
121134 { ...removeNonHTMLProps ( this . props ) }
@@ -133,11 +146,34 @@ export class InputGroup extends AbstractPureComponent2<IInputGroupProps & HTMLIn
133146 }
134147
135148 public componentDidUpdate ( prevProps : IInputGroupProps & HTMLInputProps ) {
136- if ( prevProps . rightElement !== this . props . rightElement ) {
149+ const { leftElement, rightElement } = this . props ;
150+ if ( prevProps . leftElement !== leftElement || prevProps . rightElement !== rightElement ) {
137151 this . updateInputWidth ( ) ;
138152 }
139153 }
140154
155+ protected validateProps ( props : IInputGroupProps ) {
156+ if ( props . leftElement != null && props . leftIcon != null ) {
157+ console . warn ( Errors . INPUT_WARN_LEFT_ELEMENT_LEFT_ICON_MUTEX ) ;
158+ }
159+ }
160+
161+ private maybeRenderLeftElement ( ) {
162+ const { leftElement, leftIcon } = this . props ;
163+
164+ if ( leftElement != null ) {
165+ return (
166+ < span className = { Classes . INPUT_LEFT_CONTAINER } ref = { this . refHandlers . leftElement } >
167+ { leftElement }
168+ </ span >
169+ ) ;
170+ } else if ( leftIcon != null ) {
171+ return < Icon icon = { leftIcon } /> ;
172+ }
173+
174+ return undefined ;
175+ }
176+
141177 private maybeRenderRightElement ( ) {
142178 const { rightElement } = this . props ;
143179 if ( rightElement == null ) {
@@ -151,14 +187,26 @@ export class InputGroup extends AbstractPureComponent2<IInputGroupProps & HTMLIn
151187 }
152188
153189 private updateInputWidth ( ) {
190+ const { leftElementWidth, rightElementWidth } = this . state ;
191+
192+ if ( this . leftElement != null ) {
193+ const { clientWidth } = this . leftElement ;
194+ // small threshold to prevent infinite loops
195+ if ( leftElementWidth === undefined || Math . abs ( clientWidth - leftElementWidth ) > 2 ) {
196+ this . setState ( { leftElementWidth : clientWidth } ) ;
197+ }
198+ } else {
199+ this . setState ( { leftElementWidth : undefined } ) ;
200+ }
201+
154202 if ( this . rightElement != null ) {
155203 const { clientWidth } = this . rightElement ;
156204 // small threshold to prevent infinite loops
157- if ( Math . abs ( clientWidth - this . state . rightElementWidth ) > 2 ) {
205+ if ( rightElementWidth === undefined || Math . abs ( clientWidth - rightElementWidth ) > 2 ) {
158206 this . setState ( { rightElementWidth : clientWidth } ) ;
159207 }
160208 } else {
161- this . setState ( { rightElementWidth : DEFAULT_RIGHT_ELEMENT_WIDTH } ) ;
209+ this . setState ( { rightElementWidth : undefined } ) ;
162210 }
163211 }
164212}
0 commit comments