diff --git a/common/changes/textfield-flexbox_2017-04-21-21-33.json b/common/changes/textfield-flexbox_2017-04-21-21-33.json new file mode 100644 index 0000000000000..5051df8e73857 --- /dev/null +++ b/common/changes/textfield-flexbox_2017-04-21-21-33.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "office-ui-fabric-react", + "comment": "TextField: Convert to flexbox, support addons", + "type": "minor" + } + ], + "email": "micahgodbolt@gmail.com" +} \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/components/TextField/TextField.Props.ts b/packages/office-ui-fabric-react/src/components/TextField/TextField.Props.ts index 2e7a5930498db..5bb3619f4cb7e 100644 --- a/packages/office-ui-fabric-react/src/components/TextField/TextField.Props.ts +++ b/packages/office-ui-fabric-react/src/components/TextField/TextField.Props.ts @@ -1,4 +1,5 @@ import * as React from 'react'; +import { IRenderFunction } from '../../Utilities'; export interface ITextField { /** Gets the current value of the input. */ @@ -61,6 +62,16 @@ export interface ITextFieldProps extends React.HTMLProps; + /** * CSS class for the icon. */ diff --git a/packages/office-ui-fabric-react/src/components/TextField/TextField.scss b/packages/office-ui-fabric-react/src/components/TextField/TextField.scss index 88effe6973efd..298b70332e933 100644 --- a/packages/office-ui-fabric-react/src/components/TextField/TextField.scss +++ b/packages/office-ui-fabric-react/src/components/TextField/TextField.scss @@ -70,24 +70,17 @@ top: auto; } -.field { +.fieldGroup { @include ms-u-normalize; @include ms-baseFont; - border: 1px solid $ms-color-neutralTertiaryAlt; - border-radius: 0; font-weight: $ms-font-weight-regular; font-size: $ms-font-size-m; - color: $ms-color-neutralPrimary; + border: 1px solid $ms-color-neutralTertiaryAlt; height: 32px; - @include padding(0, 12px, 1px, 12px); - width: 100%; - outline: 0; - text-overflow: ellipsis; - - &.hasIcon { - @include padding-right(24px); - } - + display: flex; + flex-direction: row; + align-items: stretch; + position: relative; &:hover { border-color: $ms-color-neutralSecondaryAlt; } @@ -95,7 +88,6 @@ &:focus { border-color: $ms-color-themePrimary; } - &:hover, &:focus { @media screen and (-ms-high-contrast: active) { @@ -106,13 +98,42 @@ border-color: $ms-color-contrastWhiteSelected; } } - - &[disabled] { + .rootIsDisabled > & { background-color: $ms-color-neutralLighter; border-color: $ms-color-neutralLighter; pointer-events: none; cursor: default; } +} + +.fieldAddon { + background: $ms-color-neutralLighter; + color: $ms-color-neutralSecondary; + display: flex; + align-items: center; + padding: 0 10px; + line-height: 1; +} + +.field { + border-radius: 0; + border: none; + color: $ms-color-neutralPrimary; + @include padding(0, 12px, 0, 12px); + width: 100%; + outline: 0; + text-overflow: ellipsis; + + &.hasIcon { + @include padding-right(24px); + } + + &[disabled] { + background-color: transparent; + border-color: transparent; + pointer-events: none; + cursor: default; + } @include input-placeholder { color: $ms-color-neutralSecondary; @@ -133,7 +154,7 @@ // .root.rootIsUnderlined { border-bottom: 1px solid $ms-color-neutralTertiaryAlt; - display: table; + display: flex; width: 100%; &:hover { @@ -156,23 +177,15 @@ :global(.ms-Label) { font-size: $ms-font-size-m; @include margin-right(8px); - display: table-cell; - vertical-align: top; @include padding-left(12px); - padding-top: 9px; + line-height: 22px; // 32px minus 5px padding top/bottom height: 32px; - width: 1%; - white-space: nowrap; } - .field { + .fieldGroup { + flex: 1 1 0; border: 0; - @include float(left); - display: table-cell; @include text-align(left); - padding-top: 8px; - padding-bottom: 3px; - &:active, &:focus, &:hover { @@ -209,20 +222,26 @@ //== Modifier: Multiline textfield // -.root.rootIsMultiline .field { - @include ms-baseFont; - color: $ms-color-neutralPrimary; - font-family: $ms-font-family-base; - font-size: $ms-font-size-m; - font-weight: $ms-font-weight-regular; - line-height: 17px; - min-height: 60px; - height: auto; - padding-top: 6px; - overflow: auto; - - &.hasIcon { - @include padding-right(40px); +.root.rootIsMultiline { + .fieldGroup { + min-height: 60px; + height: auto; + display: flex; + } + .field { + @include ms-baseFont; + color: $ms-color-neutralPrimary; + font-family: $ms-font-family-base; + font-size: $ms-font-size-m; + font-weight: $ms-font-weight-regular; + line-height: 17px; + flex-grow: 1; + padding-top: 6px; + overflow: auto; + width: 100%; + &.hasIcon { + @include padding-right(40px); + } } } @@ -255,7 +274,9 @@ .root.rootIsMultiline { .icon { - @include right(24px); + @include padding-right(24px); + padding-bottom: 8px; + align-items: flex-end; } .field.fieldIsUnresizable { diff --git a/packages/office-ui-fabric-react/src/components/TextField/TextField.tsx b/packages/office-ui-fabric-react/src/components/TextField/TextField.tsx index 5de0b8176e804..6ebac0170d5c0 100644 --- a/packages/office-ui-fabric-react/src/components/TextField/TextField.tsx +++ b/packages/office-ui-fabric-react/src/components/TextField/TextField.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { ITextField, ITextFieldProps } from './TextField.Props'; import { Label } from '../../Label'; +import { Icon } from '../../Icon'; import { DelayedRender, BaseComponent, @@ -127,7 +128,9 @@ export class TextField extends BaseComponent i label, multiline, required, - underlined + underlined, + addonString, + onRenderAddon = this._onRenderAddon } = this.props; let { isFocused } = this.state; const errorMessage: string = this._errorMessage; @@ -144,8 +147,15 @@ export class TextField extends BaseComponent i return (
{ label && } - { iconClass && } - { multiline ? this._renderTextArea() : this._renderInput() } +
+ { (addonString !== undefined || this.props.onRenderAddon) && ( +
+ { onRenderAddon(this.props, this._onRenderAddon) } +
+ ) } + { multiline ? this._renderTextArea() : this._renderInput() } + { iconClass && } +
{ this._isDescriptionAvailable && { description && { description } } @@ -225,6 +235,13 @@ export class TextField extends BaseComponent i } } + private _onRenderAddon(props: ITextFieldProps): JSX.Element { + let { addonString } = props; + return ( + { addonString } + ); + } + private _getTextElementClassName(): string { const errorMessage: string = this._errorMessage; let textFieldClassName: string; diff --git a/packages/office-ui-fabric-react/src/components/TextField/examples/TextField.Basic.Example.tsx b/packages/office-ui-fabric-react/src/components/TextField/examples/TextField.Basic.Example.tsx index cc8fefe71ed8b..ef45531d17008 100644 --- a/packages/office-ui-fabric-react/src/components/TextField/examples/TextField.Basic.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/TextField/examples/TextField.Basic.Example.tsx @@ -1,12 +1,15 @@ import * as React from 'react'; import { TextField } from 'office-ui-fabric-react/lib/TextField'; +import { Icon } from 'office-ui-fabric-react/lib/Icon'; import { autobind } from 'office-ui-fabric-react/lib/Utilities'; export class TextFieldBasicExample extends React.Component { public render() { return (
- +