From 26b2aa174b93a8edb1a4096ffc04fda6dfbaa481 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 5 Mar 2019 15:13:12 +0000 Subject: [PATCH] Add prefix support to Fields This allows Fields to have an optional prefix component which is placed inside the border of the Field and to the left of the input. Since this label animation would be complex to get right for this case, it is instead fixed to the top left if there is a prefix component. This canonical example of this today would be a phone number field which includes a country dropdown. --- res/css/views/elements/_Field.scss | 8 +++++++- src/components/views/elements/Field.js | 22 ++++++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/res/css/views/elements/_Field.scss b/res/css/views/elements/_Field.scss index 5d5357da39..1d3a3652fb 100644 --- a/res/css/views/elements/_Field.scss +++ b/res/css/views/elements/_Field.scss @@ -17,6 +17,7 @@ limitations under the License. /* TODO: Consider unifying with general input styles in _light.scss */ .mx_Field { + display: flex; position: relative; margin: 1em 0; border-radius: 4px; @@ -24,6 +25,10 @@ limitations under the License. border: 1px solid $input-border-color; } +.mx_Field_prefix { + border-right: 1px solid $input-border-color; +} + .mx_Field input, .mx_Field select, .mx_Field textarea { @@ -106,7 +111,8 @@ limitations under the License. .mx_Field input:not(:placeholder-shown) + label, .mx_Field textarea:focus + label, .mx_Field textarea:not(:placeholder-shown) + label, -.mx_Field select + label /* Always show a select's label on top to not collide with the value */ { +.mx_Field select + label /* Always show a select's label on top to not collide with the value */, +.mx_Field_labelAlwaysTopLeft label { transition: font-size 0.25s ease-out 0s, color 0.25s ease-out 0s, diff --git a/src/components/views/elements/Field.js b/src/components/views/elements/Field.js index 1b7d9fdd73..d43cb7423c 100644 --- a/src/components/views/elements/Field.js +++ b/src/components/views/elements/Field.js @@ -16,6 +16,7 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; +import classNames from 'classnames'; export default class Field extends React.PureComponent { static propTypes = { @@ -30,6 +31,8 @@ export default class Field extends React.PureComponent { label: PropTypes.string, // The field's placeholder string. Defaults to the label. placeholder: PropTypes.string, + // Optional component to include inside the field before the input. + prefix: PropTypes.node, // All other props pass through to the . }; @@ -46,7 +49,7 @@ export default class Field extends React.PureComponent { } render() { - const { element, children, ...inputProps } = this.props; + const { element, prefix, children, ...inputProps } = this.props; const inputElement = element || "input"; @@ -57,7 +60,22 @@ export default class Field extends React.PureComponent { const fieldInput = React.createElement(inputElement, inputProps, children); - return
+ let prefixContainer = null; + if (prefix) { + prefixContainer = + {prefix} + ; + } + + const classes = classNames("mx_Field", `mx_Field_${inputElement}`, { + // If we have a prefix element, leave the label always at the top left and + // don't animate it, as it looks a bit clunky and would add complexity to do + // properly. + mx_Field_labelAlwaysTopLeft: prefix, + }); + + return
+ {prefixContainer} {fieldInput}
;