diff --git a/src/demo-app/baseline/baseline-demo.html b/src/demo-app/baseline/baseline-demo.html index cfcf7e6470ee..932e0eca08f6 100644 --- a/src/demo-app/baseline/baseline-demo.html +++ b/src/demo-app/baseline/baseline-demo.html @@ -14,6 +14,10 @@ | Text 5 | + + Option + + | Text 6 | @@ -38,6 +42,10 @@

| Text 5 | + + Option + + | Text 6 | diff --git a/src/demo-app/input/input-demo.html b/src/demo-app/input/input-demo.html index 75b35dc052a3..55b9b669b7da 100644 --- a/src/demo-app/input/input-demo.html +++ b/src/demo-app/input/input-demo.html @@ -8,7 +8,7 @@ @@ -113,6 +113,13 @@

Icons

attach_moneymode_edit + +

Icon buttons

+ + + + + diff --git a/src/lib/core/typography/_typography.scss b/src/lib/core/typography/_typography.scss index 8aaa7cd15f86..f39186eb39b0 100644 --- a/src/lib/core/typography/_typography.scss +++ b/src/lib/core/typography/_typography.scss @@ -23,7 +23,9 @@ $body-2: mat-typography-level(14px, 24px, 500), $body-1: mat-typography-level(14px, 20px, 400), $caption: mat-typography-level(12px, 12px, 400), - $button: mat-typography-level(14px, 14px, 500) + $button: mat-typography-level(14px, 14px, 500), + // Line-height must be unit-less fraction of the font-size. + $input: mat-typography-level(inherit, 1.125, 400) ) { @return ( font-family: $font-family, @@ -37,7 +39,8 @@ body-2: $body-2, body-1: $body-1, caption: $caption, - button: $button + button: $button, + input: $input, ); } @@ -61,7 +64,7 @@ } .mat-h2, #{$selector} h2 { - @include mat-typography-level-to-styles($config, display-2) + @include mat-typography-level-to-styles($config, display-2); // Note: The spec doesn't mention letter spacing. The value comes from // eyeballing it until it looked exactly like the spec examples.; diff --git a/src/lib/input/_input-theme.scss b/src/lib/input/_input-theme.scss index 5c8bb4ab9805..ed15940be785 100644 --- a/src/lib/input/_input-theme.scss +++ b/src/lib/input/_input-theme.scss @@ -52,7 +52,7 @@ } .mat-input-underline { - border-color: $input-underline-color; + background-color: $input-underline-color; } .mat-input-ripple { @@ -91,20 +91,121 @@ } @mixin mat-input-typography($config) { + // The unit-less line-height from the font config. + $mat-input-line-height: mat-line-height($config, input); + + // The amount to scale the font for the floating label and subscript. + $mat-input-subscript-font-scale: 0.75; + // The amount to scale the font for the prefix and suffix icons. + $mat-input-prefix-suffix-icon-font-scale: 1.5; + + // The amount of space between the top of the line and the top of the actual text + // (as a fraction of the font-size). + $mat-input-line-spacing: ($mat-input-line-height - 1) / 2; + // The padding on the infix. Mocks show half of the text size, but seem to measure from the edge + // of the text itself, not the edge of the line; therefore we subtract off the line spacing. + $mat-input-infix-padding: 0.5em - $mat-input-line-spacing; + // The margin applied to the input-infix to reserve space for the floating label. + $mat-input-infix-margin-top: 1em * $mat-input-line-height * $mat-input-subscript-font-scale; + // Font size to use for the label and subscript text. + $mat-input-subscript-font-size: $mat-input-subscript-font-scale * 100%; + // Font size to use for the for the prefix and suffix icons. + $mat-input-prefix-suffix-icon-font-size: $mat-input-prefix-suffix-icon-font-scale * 100%; + // The space between the bottom of the input table and the subscript container. Mocks show half of + // the text size, but this margin is applied to an element with the subscript text font size, so + // we need to divide by the scale factor to make it half of the original text size. We again need + // to subtract off the line spacing since the mocks measure to the edge of the text, not the edge + // of the line. + $mat-input-subscript-margin-top: + 0.5em / $mat-input-subscript-font-scale - $mat-input-line-spacing; + // The padding applied to the input-wrapper to reserve space for the subscript, since it's + // absolutely positioned. This is a combination of the subscript's margin and line-height, but we + // need to multiply by the subscript font scale factor since the wrapper has a larger font size. + $mat-input-wrapper-padding-bottom: + ($mat-input-subscript-margin-top + $mat-input-line-height) * $mat-input-subscript-font-scale; + + // Applies a floating placeholder above the input itself. + @mixin mat-input-placeholder-floating { + transform: translateY(-$mat-input-infix-margin-top - $mat-input-infix-padding) + scale($mat-input-subscript-font-scale) + // We use perspecitve to fix the text blurriness as described here: + // http://www.useragentman.com/blog/2014/05/04/fixing-typography-inside-of-2-d-css-transforms/ + // This results in a small jitter after the label floats on Firefox, which the + // translateZ fixes. + perspective(100px) translateZ(0.001px); + // The tricks above used to smooth out the animation on chrome and firefox actually make things + // worse on IE, so we don't include them in the IE version. + -ms-transform: translateY(-$mat-input-infix-margin-top - $mat-input-infix-padding) + scale($mat-input-subscript-font-scale); + + width: 100% / $mat-input-subscript-font-scale; + } + .mat-input-container { - font-family: mat-font-family($config); - line-height: normal; + @include mat-typography-level-to-styles($config, input); + } + + .mat-input-wrapper { + padding-bottom: $mat-input-wrapper-padding-bottom; + } + + .mat-input-prefix, + .mat-input-suffix { + // Allow icons in a prefix or suffix to adapt to the correct size. + .mat-icon, + .mat-datepicker-toggle { + font-size: $mat-input-prefix-suffix-icon-font-size; + } + + // Allow icon buttons in a prefix or suffix to adapt to the correct size. + .mat-icon-button { + height: $mat-input-prefix-suffix-icon-font-scale * 1em; + width: $mat-input-prefix-suffix-icon-font-scale * 1em; + + .mat-icon { + line-height: $mat-input-prefix-suffix-icon-font-scale; + } + } + } + + .mat-input-infix { + padding: $mat-input-infix-padding 0; + // Throws off the baseline if we do it as a real margin, so we do it as a border instead. + border-top: $mat-input-infix-margin-top solid transparent; + } - .mat-icon { - font-size: 100%; + .mat-input-element { + &:-webkit-autofill + .mat-input-placeholder-wrapper .mat-float { + @include mat-input-placeholder-floating; } } + .mat-input-placeholder-wrapper { + top: -$mat-input-infix-margin-top; + padding-top: $mat-input-infix-margin-top; + } + .mat-input-placeholder { - font-size: 100%; + top: $mat-input-infix-margin-top + $mat-input-infix-padding; + + // Show the placeholder above the input when it's not empty, or focused. + &.mat-float:not(.mat-empty), .mat-focused &.mat-float { + @include mat-input-placeholder-floating; + } + } + + .mat-input-underline { + // We want the underline to start at the end of the content box, not the padding box, + // so we move it up by the padding amount; + bottom: $mat-input-wrapper-padding-bottom; } .mat-input-subscript-wrapper { - font-size: 75%; + font-size: $mat-input-subscript-font-size; + margin-top: $mat-input-subscript-margin-top; + + // We want the subscript to start at the end of the content box, not the padding box, + // so we move it up by the padding amount (adjusted for the smaller font size); + top: calc(100% - #{$mat-input-wrapper-padding-bottom / $mat-input-subscript-font-scale}); } } diff --git a/src/lib/input/input-container.html b/src/lib/input/input-container.html index f5b1c8745ee3..5a95d29c6b64 100644 --- a/src/lib/input/input-container.html +++ b/src/lib/input/input-container.html @@ -1,8 +1,7 @@
-
+
- - +
@@ -24,8 +23,7 @@
- - +
diff --git a/src/lib/input/input-container.scss b/src/lib/input/input-container.scss index 70059e047a1e..34740a494e3c 100644 --- a/src/lib/input/input-container.scss +++ b/src/lib/input/input-container.scss @@ -3,20 +3,11 @@ @import '../core/style/form-common'; -$mat-input-floating-placeholder-scale-factor: 0.75 !default; -$mat-input-wrapper-spacing: 1em !default; -$mat-input-hint-min-space: 10px !default; +// Min amount of space between start and end hint. +$mat-input-hint-min-space: 1em !default; +// The height of the underline. +$mat-input-underline-height: 1px !default; -// Gradient for showing the dashed line when the input is disabled. -$mat-input-underline-disabled-background-image: - linear-gradient(to right, rgba(0, 0, 0, 0.26) 0%, rgba(0, 0, 0, 0.26) 33%, transparent 0%); - -// Applies a floating placeholder above the input itself. -@mixin mat-input-placeholder-floating { - display: block; - transform: translate3d(0, -1.35em, 0) scale($mat-input-floating-placeholder-scale-factor); - width: 100% / $mat-input-floating-placeholder-scale-factor; -} .mat-input-container { display: inline-block; @@ -28,42 +19,53 @@ $mat-input-underline-disabled-background-image: [dir='rtl'] & { text-align: right; } - - // Allow icons in a prefix/suffix/hint/etc to adapt to the correct size. - & .mat-icon, - & .mat-datepicker-toggle { - width: 1em; - height: 1em; - vertical-align: top; - } } // Global wrapper. We need to apply margin to the element for spacing, but // cannot apply it to the host element directly. .mat-input-wrapper { - margin: $mat-input-wrapper-spacing 0; - // Account for the underline which has 4px of margin + 2px of border. - padding-bottom: 6px; + position: relative; } -// We use a table layout to baseline align the prefix and suffix classes. -// The underline is outside of it so it can cover all of the elements under -// this table. -// Flex does not respect the baseline. What we really want is akin to a table -// as want an inline-block where elements don't wrap. -.mat-input-table { - display: inline-table; - flex-flow: column; - vertical-align: bottom; +// We use a flex layout to baseline align the prefix and suffix elements. +// The underline is outside of it so it can cover all of the elements under this flex container. +.mat-input-flex { + display: inline-flex; + align-items: baseline; width: 100%; +} + +.mat-input-prefix, +.mat-input-suffix { + white-space: nowrap; + flex: none; - & > * { - display: table-cell; + // Allow icons in a prefix or suffix to adapt to the correct size. + .mat-icon, + .mat-datepicker-toggle { + width: 1em; + height: 1em; + vertical-align: text-bottom; + } + + // Allow icon buttons in a prefix or suffix to adapt to the correct size. + .mat-icon-button { + font: inherit; + vertical-align: baseline; + + .mat-icon { + font-size: inherit; + width: 1em; + height: 1em; + vertical-align: baseline; + } } } .mat-input-infix { + display: block; position: relative; + flex: auto; } // The Input element proper. @@ -106,9 +108,17 @@ $mat-input-underline-disabled-background-image: // Once the autofill is committed, a change event happen and the regular md-input-container // classes take over to fulfill this behaviour. // Assumes the autofill is non-empty. - &:-webkit-autofill + .mat-input-placeholder-wrapper .mat-float { - @include mat-input-placeholder-floating; - transition: none; + &:-webkit-autofill + .mat-input-placeholder-wrapper { + // The input is still technically empty at this point, so we need to hide non-floating + // placeholders to prevent overlapping with the autofilled value. + .mat-input-placeholder { + display: none; + } + + .mat-float { + display: block; + transition: none; + } } // Note that we can't use something like visibility: hidden or @@ -121,6 +131,18 @@ $mat-input-underline-disabled-background-image: } } +// Used to hide the placeholder overflow on IE, since IE doesn't take transform into account when +// determining overflow. +.mat-input-placeholder-wrapper { + position: absolute; + left: 0; + box-sizing: content-box; + width: 100%; + height: 100%; + overflow: hidden; + pointer-events: none; // We shouldn't catch mouse events (let them through). +} + // The placeholder label. This is invisible unless it is. The logic to show it is // basically `empty || (float && (!empty || focused))`. Float is dependent on the // `floatingPlaceholder` input. @@ -129,37 +151,36 @@ $mat-input-underline-disabled-background-image: // infix
. position: absolute; left: 0; - top: 0; + font: inherit; pointer-events: none; // We shouldn't catch mouse events (let them through). - z-index: 1; - padding-top: 1em; // Put ellipsis text overflow. width: 100%; - display: none; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; - transform: translate3d(0, 0, 0); - transform-origin: bottom left; + // The perspective helps smooth out animations on Chrome and Firefox but isn't needed on IE. + transform: perspective(100px); + -ms-transform: none; + + transform-origin: 0 0; transition: transform $swift-ease-out-duration $swift-ease-out-timing-function, color $swift-ease-out-duration $swift-ease-out-timing-function, width $swift-ease-out-duration $swift-ease-out-timing-function; - &.mat-empty { - display: block; - cursor: text; - } + // Hide the placeholder initially, and only show it when it's floating or the input is empty. + display: none; - // Show the placeholder above the input when it's not empty, or focused. - &.mat-float:not(.mat-empty), .mat-focused &.mat-float { - @include mat-input-placeholder-floating; + &.mat-empty, + &.mat-float:not(.mat-empty), + .mat-focused &.mat-float { + display: block; } [dir='rtl'] & { - transform-origin: bottom right; + transform-origin: 100% 0; left: auto; right: 0; } @@ -171,47 +192,23 @@ $mat-input-underline-disabled-background-image: transition: none; } -// Used to hide the placeholder overflow on IE, since IE doesn't take transform into account when -// determining overflow. -.mat-input-placeholder-wrapper { - position: absolute; - left: 0; - top: -1em; - width: 100%; - padding-top: 1em; - overflow: hidden; - pointer-events: none; // We shouldn't catch mouse events (let them through). - transform: translate3d(0, 0, 0); // Prevents the label from shifting after the animation is done. - - // Keeps the element height since the placeholder text is `position: absolute`. - &::after { - content: ''; - display: inline-table; - } -} - - // The underline is what's shown under the input, its prefix and its suffix. // The ripple is the blue animation coming on top of it. .mat-input-underline { position: absolute; - height: 1px; + height: $mat-input-underline-height; width: 100%; - margin-top: 4px; - border-top-width: 1px; - border-top-style: solid; &.mat-disabled { @include mat-control-disabled-underline(); - border-top: 0; background-position: 0; + background-color: transparent; } .mat-input-ripple { position: absolute; - height: 2px; - z-index: 1; - top: -1px; + height: $mat-input-underline-height * 2; + top: 0; width: 100%; transform-origin: 50%; transform: scaleX(0.5); @@ -223,7 +220,7 @@ $mat-input-underline-disabled-background-image: visibility: visible; transform: scaleX(1); transition: transform 150ms linear, - background-color $swift-ease-in-duration $swift-ease-in-timing-function; + background-color $swift-ease-in-duration $swift-ease-in-timing-function; } } } @@ -231,21 +228,29 @@ $mat-input-underline-disabled-background-image: // Wrapper for the hints and error messages. Provides positioning and text size. // Note that we're using `top` in order to allow for stacked children to flow downwards. .mat-input-subscript-wrapper { - $line-height: 1.2em; - position: absolute; - top: 100%; width: 100%; - margin-top: -$line-height; - line-height: $line-height; overflow: hidden; // prevents multi-line errors from overlapping the input } +// Scale down icons in the placeholder and hint to be the same size as the text. +.mat-input-subscript-wrapper, +.mat-input-placeholder-wrapper { + .mat-icon, + .mat-datepicker-toggle { + width: 1em; + height: 1em; + font-size: inherit; + vertical-align: baseline; + } +} + // Clears the floats on the hints. This is necessary for the hint animation to work. .mat-input-hint-wrapper { display: flex; } +// Spacer used to make sure start and end hints have enough space between them. .mat-input-hint-spacer { flex: 1 0 $mat-input-hint-min-space; } @@ -254,9 +259,3 @@ $mat-input-underline-disabled-background-image: .mat-input-error { display: block; } - -.mat-input-prefix, .mat-input-suffix { - // Prevents the prefix and suffix from stretching together with the container. - width: 0.1px; - white-space: nowrap; -}
- +