anchor.diff:    _InputState createState() => new _InputState();
   }
   
  -const Duration _kTransitionDuration = const Duration(milliseconds: 200);
  -const Curve _kTransitionCurve = Curves.fastOutSlowIn;
  -
   class _InputState extends State<Input> {
  -  GlobalKey<_InputFieldState> _inputFieldKey = new GlobalKey<_InputFieldState>(debugLabel: '_InputState _inputFieldKey');
  -  GlobalKey<_InputFieldState> _focusKey = new GlobalKey(debugLabel: '_InputState _focusKey');
  +  final GlobalKey<_InputFieldState> _inputFieldKey = new GlobalKey<_InputFieldState>();
  +  final GlobalKey _focusKey = new GlobalKey();
   
     GlobalKey get focusKey => config.key is GlobalKey ? config.key : _focusKey;
   
     @override
     Widget build(BuildContext context) {
  -    assert(debugCheckHasMaterial(context));
  -    ThemeData themeData = Theme.of(context);
  -    BuildContext focusContext = focusKey.currentContext;
  -    bool focused = focusContext != null && Focus.at(focusContext, autofocus: config.autofocus);
  -    InputValue value = config.value ?? InputValue.empty;
  -    String errorText = config.errorText;
  -
  -    TextStyle textStyle = config.style ?? themeData.textTheme.subhead;
  -    Color activeColor = themeData.hintColor;
  -    if (focused) {
  -      switch (themeData.brightness) {
  -        case Brightness.dark:
  -          activeColor = themeData.accentColor;
  -          break;
  -        case Brightness.light:
  -          activeColor = themeData.primaryColor;
  -          break;
  -      }
  -    }
  -    double topPadding = config.isDense ? 12.0 : 16.0;
  -
  -    List<Widget> stackChildren = <Widget>[];
  -
  -    final bool hasInlineLabel = config.labelText != null && !focused && !value.text.isNotEmpty;
  -    if (config.labelText != null) {
  -      final TextStyle labelStyle = hasInlineLabel ?
  -        themeData.textTheme.subhead.copyWith(color: themeData.hintColor) :
  -        themeData.textTheme.caption.copyWith(color: activeColor);
  -
  -      final double topPaddingIncrement = themeData.textTheme.caption.fontSize + (config.isDense ? 4.0 : 8.0);
  -      double top = topPadding;
  -      if (hasInlineLabel)
  -        top += topPaddingIncrement + textStyle.fontSize - labelStyle.fontSize;
  -
  -      stackChildren.add(
  -        new AnimatedPositioned(
  -          left: 0.0,
  -          top: top,
  -          duration: _kTransitionDuration,
  -          curve: _kTransitionCurve,
  -          child: new AnimatedOpacity(
  -            opacity: focused ? 1.0 : 0.0,
  -            curve: _kTransitionCurve,
  -            duration: _kTransitionDuration,
  -            child: new Text(config.labelText, style: labelStyle)
  -          ),
  -        ),
  -      );
  -
  -      topPadding += topPaddingIncrement;
  -    }
  -
  -    Color borderColor = activeColor;
  -    double bottomPadding = 8.0;
  -    double bottomBorder = focused ? 2.0 : 1.0;
  -    double bottomHeight = config.isDense ? 14.0 : 18.0;
  -
  -    if (errorText != null) {
  -      borderColor = themeData.errorColor;
  -      bottomBorder = 2.0;
  -      if (!config.isDense)
  -        bottomPadding = 1.0;
  -    }
  -
  -    EdgeInsets padding = new EdgeInsets.only(top: topPadding, bottom: bottomPadding);
  -    Border border = new Border(
  -      bottom: new BorderSide(
  -        color: borderColor,
  -        width: bottomBorder,
  -      )
  -    );
  -    EdgeInsets margin = new EdgeInsets.only(bottom: bottomHeight - (bottomPadding + bottomBorder));
  -
  -    stackChildren.add(new AnimatedContainer(
  -      margin: margin,
  -      padding: padding,
  -      duration: _kTransitionDuration,
  -      curve: _kTransitionCurve,
  -      decoration: new BoxDecoration(
  -        border: border,
  -      ),
  -      // Since the focusKey may have been created here, defer building the
  -      // InputField until the focusKey's context has been set. This is necessary
  -      // because our descendants may check the focus, like Focus.at(focusContext),
  -      // when they build.
  -      child: new Builder(
  -        builder: (BuildContext context) {
  -          return new InputField(
  -            key: _inputFieldKey,
  -            focusKey: focusKey,
  -            value: value,
  -            style: textStyle,
  -            hideText: config.hideText,
  -            maxLines: config.maxLines,
  -            keyboardType: config.keyboardType,
  -            hintText: config.hintText,
  -            onChanged: config.onChanged,
  -            onSubmitted: config.onSubmitted,
  -          );
  -        }
  -      ),
  -    ));
  -
  -    if (errorText != null && !config.isDense) {
  -      TextStyle errorStyle = themeData.textTheme.caption.copyWith(color: themeData.errorColor);
  -      stackChildren.add(new Positioned(
  -        left: 0.0,
  -        bottom: 0.0,
  -        child: new Text(errorText, style: errorStyle)
  -      ));
  -    }
  -
  -    Widget child = new Stack(children: stackChildren);
  -
  -    if (config.icon != null) {
  -      double iconSize = config.isDense ? 18.0 : 24.0;
  -      double iconTop = topPadding + (textStyle.fontSize - iconSize) / 2.0;
  -      child = new Row(
  -        crossAxisAlignment: CrossAxisAlignment.start,
  -        children: <Widget>[
  -          new Container(
  -            margin: new EdgeInsets.only(right: 16.0, top: iconTop),
  -            width: config.isDense ? 40.0 : 48.0,
  -            child: new IconTheme.merge(
  -              context: context,
  -              data: new IconThemeData(
  -                color: focused ? activeColor : Colors.black45,
  -                size: config.isDense ? 18.0 : 24.0
  -              ),
  -              child: config.icon
  -            )
  -          ),
  -          new Flexible(child: child)
  -        ]
  -      );
  -    }
  -
       return new GestureDetector(
  -      key: config.key is GlobalKey ? null : focusKey,
  -      behavior: HitTestBehavior.opaque,
  +      key: focusKey == _focusKey ? _focusKey : null,
         onTap: () {
           _inputFieldKey.currentState?.requestKeyboard();
         },
  -      child: child,
  +      // Since the focusKey may have been created here, defer building the
  +      // InputContainer until the focusKey's context has been set. This is
  +      // necessary because we're passing the value of Focus.at() along.
  +      child: new Builder(
  +        builder: (BuildContext context) {
  +          final bool focused = Focus.at(focusKey.currentContext, autofocus: config.autofocus);
  +          final bool isEmpty = (config.value ?? InputValue.empty).text.isEmpty;
  +          return new InputContainer(
  +            focused: focused,
  +            isEmpty: isEmpty,
  +            icon: config.icon,
  +            labelText: config.labelText,
  +            hintText: config.hintText,
  +            errorText: config.errorText,
  +            style: config.style,
  +            isDense: config.isDense,
  +            child: new InputField(
  +              key: _inputFieldKey,
  +              focusKey: focusKey,
  +              value: config.value,
  +              style: config.style,
  +              hideText: config.hideText,
  +              maxLines: config.maxLines,
  +              keyboardType: config.keyboardType,
  +              onChanged: config.onChanged,
  +              onSubmitted: config.onSubmitted,
  +            ),
  +          );
  +        },
  +      ),
       );
     }
   }
  
positive.code: import 'icon.dart';
  import 'icon_theme.dart';
  import 'icon_theme_data.dart';
  import 'material.dart';
  import 'text_selection.dart';
  import 'theme.dart';
  
  export 'package:flutter/services.dart' show TextInputType;
  
  class InputField extends StatefulWidget {
    InputField({
      Key key,
  
negative.code:     ];
  
      if (config.hintText != null && value.text.isEmpty) {
  
        TextStyle hintStyle = textStyle.copyWith(color: themeData.hintColor);
        stackChildren.add(
          new Positioned(
            left: 0.0,
  