diff options
author | Mark Otto <otto@github.com> | 2019-07-13 00:52:33 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-07-13 00:52:33 +0300 |
commit | aaf03bdc9e3cfa0d625f9758ad059c0db9fe2abe (patch) | |
tree | 025c273faa4b8fe6665126c815cba4eba2a17cfb /scss | |
parent | 50f97710eb96c8c713a036f07ebd65766917ca23 (diff) |
v5: Forms update (#28450)
* Initial spike of consolidated form checks
* Stub out forms rearrangement
- Prepping to drop non-custom file and range inputs
- Prepping to merge custom and native checks and radios (with switches)
- Prepping to merge custom select with form select
- Moving docs arround so forms has it's own area given volume of CSS
* Move input group Sass file to forms subdir
* Start to split and move the docs around
* Simpler imports
* Copyediting
* delete overview file
* Remove commented out code
* remove the custom-forms import
* rewrite flex-check as form-check, replace all custom properties
* Remove old forms doc
* stub out new subpage link section
* update migration guide
* Update nav, forms overview in page nav, and descriptions
* fix check bg position
* fix margin-top calculation
* rename .custom-select to .form-select
* Update validation styles for new checks
* add some vertical margin, fix inline checks
* fix docs examples
* better way to do this contents stuff, redo the toc while i'm at it
* page restyle for docs while here
* un-callout that, edit text
* redo padding on toc
* fix toc
* start to cleanup checks docs
* Rewrite Markdown tables into HTML
* Redesign tables, redo their docs
* Replace Open Iconic icons with custom Bootstrap icons
* Redesign the docs navbar, add a subheader, redo the sidebar
* Redesign docs homepage a bit
* Simplify table style overrides for docs tables
* Simplify docs typography for page titles and reading line length
* Stub out icons page
* Part of sidebar update, remove migration from nav.yml
* Move toc CSS to separate partial
* Change appearance of overview page
* fix sidebar arrow direction
* Add footer to docs layout
* Update descriptions
* Drop the .form-group class for margin utilities
* Remove lingering form-group-margin-bottom var
* improve footer spacing
* add headings to range page
* uncomment form range css
* Rename .custom-range to .form-range
* Drop unused docs var
* Uncomment the comment
* Remove unused variable
* Fix radio image sizing
* Reboot update: reset horizontal ul and ol padding
* de-dupe IDs
* tweak toc styles
* nvm, fix dropdown versions stuff
* remove sidebar nav toggle for now
* broken html
* fix more broken html, move css
* scss linting
* comment out broken helper docs
* scope styles
* scope styles
* Fixes #25540 and fixes #26407 for v5 only
* Update sidebar once more
* Match new sidenav order
* fix syntax error
* Rename custom-file to form-file, update paths, update migration docs for previous changes in #28696
* rename back
* fix size and alignment
* rename that back too
Diffstat (limited to 'scss')
-rw-r--r-- | scss/_custom-forms.scss | 514 | ||||
-rw-r--r-- | scss/_forms.scss | 343 | ||||
-rw-r--r-- | scss/_reboot.scss | 6 | ||||
-rw-r--r-- | scss/_tables.scss | 8 | ||||
-rw-r--r-- | scss/_variables.scss | 260 | ||||
-rw-r--r-- | scss/bootstrap.scss | 2 | ||||
-rw-r--r-- | scss/forms/_form-check.scss | 116 | ||||
-rw-r--r-- | scss/forms/_form-control.scss | 115 | ||||
-rw-r--r-- | scss/forms/_form-file.scss | 72 | ||||
-rw-r--r-- | scss/forms/_form-range.scss | 142 | ||||
-rw-r--r-- | scss/forms/_form-select.scss | 76 | ||||
-rw-r--r-- | scss/forms/_input-group.scss (renamed from scss/_input-group.scss) | 36 | ||||
-rw-r--r-- | scss/forms/_labels.scss | 27 | ||||
-rw-r--r-- | scss/forms/_layout.scss | 101 | ||||
-rw-r--r-- | scss/forms/_validation.scss | 10 | ||||
-rw-r--r-- | scss/mixins/_forms.scss | 55 |
16 files changed, 846 insertions, 1037 deletions
diff --git a/scss/_custom-forms.scss b/scss/_custom-forms.scss deleted file mode 100644 index ce49f3060a..0000000000 --- a/scss/_custom-forms.scss +++ /dev/null @@ -1,514 +0,0 @@ -// Embedded icons from Open Iconic. -// Released under MIT and copyright 2014 Waybury. -// https://useiconic.com/open - - -// Checkboxes and radios -// -// Base class takes care of all the key behavioral aspects. - -.custom-control { - position: relative; - display: block; - min-height: $font-size-base * $line-height-base; - padding-left: $custom-control-gutter + $custom-control-indicator-size; -} - -.custom-control-inline { - display: inline-flex; - margin-right: $custom-control-spacer-x; -} - -.custom-control-input { - position: absolute; - z-index: -1; // Put the input behind the label so it doesn't overlay text - opacity: 0; - - &:checked ~ .custom-control-label::before { - color: $custom-control-indicator-checked-color; - border-color: $custom-control-indicator-checked-border-color; - @include gradient-bg($custom-control-indicator-checked-bg); - @include box-shadow($custom-control-indicator-checked-box-shadow); - } - - &:focus ~ .custom-control-label::before { - // the mixin is not used here to make sure there is feedback - @if $enable-shadows { - box-shadow: $input-box-shadow, $input-focus-box-shadow; - } @else { - box-shadow: $custom-control-indicator-focus-box-shadow; - } - } - - &:focus:not(:checked) ~ .custom-control-label::before { - border-color: $custom-control-indicator-focus-border-color; - } - - &:not(:disabled):active ~ .custom-control-label::before { - color: $custom-control-indicator-active-color; - background-color: $custom-control-indicator-active-bg; - border-color: $custom-control-indicator-active-border-color; - @include box-shadow($custom-control-indicator-active-box-shadow); - } - - // Use disabled attribute instead of :disabled pseudo-class - // Workaround for: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11295231 - &[disabled] { - ~ .custom-control-label { - color: $custom-control-label-disabled-color; - - &::before { - background-color: $custom-control-indicator-disabled-bg; - } - } - } -} - -// Custom control indicators -// -// Build the custom controls out of pseudo-elements. - -.custom-control-label { - position: relative; - margin-bottom: 0; - color: $custom-control-label-color; - vertical-align: top; - - // Background-color and (when enabled) gradient - &::before { - position: absolute; - top: ($font-size-base * $line-height-base - $custom-control-indicator-size) / 2; - left: -($custom-control-gutter + $custom-control-indicator-size); - display: block; - width: $custom-control-indicator-size; - height: $custom-control-indicator-size; - pointer-events: none; - content: ""; - background-color: $custom-control-indicator-bg; - border: $custom-control-indicator-border-color solid $custom-control-indicator-border-width; - @include box-shadow($custom-control-indicator-box-shadow); - } - - // Foreground (icon) - &::after { - position: absolute; - top: ($font-size-base * $line-height-base - $custom-control-indicator-size) / 2; - left: -($custom-control-gutter + $custom-control-indicator-size); - display: block; - width: $custom-control-indicator-size; - height: $custom-control-indicator-size; - content: ""; - background: no-repeat 50% / #{$custom-control-indicator-bg-size}; - } -} - - -// Checkboxes -// -// Tweak just a few things for checkboxes. - -.custom-checkbox { - .custom-control-label::before { - @include border-radius($custom-checkbox-indicator-border-radius); - } - - .custom-control-input:checked ~ .custom-control-label { - &::after { - background-image: $custom-checkbox-indicator-icon-checked; - } - } - - .custom-control-input:indeterminate ~ .custom-control-label { - &::before { - border-color: $custom-checkbox-indicator-indeterminate-border-color; - @include gradient-bg($custom-checkbox-indicator-indeterminate-bg); - @include box-shadow($custom-checkbox-indicator-indeterminate-box-shadow); - } - &::after { - background-image: $custom-checkbox-indicator-icon-indeterminate; - } - } - - .custom-control-input:disabled { - &:checked ~ .custom-control-label::before { - background-color: $custom-control-indicator-checked-disabled-bg; - } - &:indeterminate ~ .custom-control-label::before { - background-color: $custom-control-indicator-checked-disabled-bg; - } - } -} - -// Radios -// -// Tweak just a few things for radios. - -.custom-radio { - .custom-control-label::before { - // stylelint-disable-next-line property-blacklist - border-radius: $custom-radio-indicator-border-radius; - } - - .custom-control-input:checked ~ .custom-control-label { - &::after { - background-image: $custom-radio-indicator-icon-checked; - } - } - - .custom-control-input:disabled { - &:checked ~ .custom-control-label::before { - background-color: $custom-control-indicator-checked-disabled-bg; - } - } -} - - -// switches -// -// Tweak a few things for switches - -.custom-switch { - padding-left: $custom-switch-width + $custom-control-gutter; - - .custom-control-label { - &::before { - left: -($custom-switch-width + $custom-control-gutter); - width: $custom-switch-width; - pointer-events: all; - // stylelint-disable-next-line property-blacklist - border-radius: $custom-switch-indicator-border-radius; - } - - &::after { - top: calc(#{(($font-size-base * $line-height-base - $custom-control-indicator-size) / 2)} + #{$custom-control-indicator-border-width * 2}); - left: calc(#{-($custom-switch-width + $custom-control-gutter)} + #{$custom-control-indicator-border-width * 2}); - width: $custom-switch-indicator-size; - height: $custom-switch-indicator-size; - background-color: $custom-control-indicator-border-color; - // stylelint-disable-next-line property-blacklist - border-radius: $custom-switch-indicator-border-radius; - @include transition(transform .15s ease-in-out, $custom-forms-transition); - } - } - - .custom-control-input:checked ~ .custom-control-label { - &::after { - background-color: $custom-control-indicator-bg; - transform: translateX($custom-switch-width - $custom-control-indicator-size); - } - } - - .custom-control-input:disabled { - &:checked ~ .custom-control-label::before { - background-color: $custom-control-indicator-checked-disabled-bg; - } - } -} - - -// Select -// -// Replaces the browser default select with a custom one, mostly pulled from -// https://primer.github.io/. -// - -.custom-select { - display: inline-block; - width: 100%; - height: $custom-select-height; - padding: $custom-select-padding-y ($custom-select-padding-x + $custom-select-indicator-padding) $custom-select-padding-y $custom-select-padding-x; - font-family: $custom-select-font-family; - @include font-size($custom-select-font-size); - font-weight: $custom-select-font-weight; - line-height: $custom-select-line-height; - color: $custom-select-color; - vertical-align: middle; - background: $custom-select-background; - background-color: $custom-select-bg; - border: $custom-select-border-width solid $custom-select-border-color; - @include border-radius($custom-select-border-radius, 0); - @include box-shadow($custom-select-box-shadow); - appearance: none; - - &:focus { - border-color: $custom-select-focus-border-color; - outline: 0; - @if $enable-shadows { - box-shadow: $custom-select-box-shadow, $custom-select-focus-box-shadow; - } @else { - box-shadow: $custom-select-focus-box-shadow; - } - - &::-ms-value { - // For visual consistency with other platforms/browsers, - // suppress the default white text on blue background highlight given to - // the selected option text when the (still closed) <select> receives focus - // in IE and (under certain conditions) Edge. - // See https://github.com/twbs/bootstrap/issues/19398. - color: $input-color; - background-color: $input-bg; - } - } - - &[multiple], - &[size]:not([size="1"]) { - height: auto; - padding-right: $custom-select-padding-x; - background-image: none; - } - - &:disabled { - color: $custom-select-disabled-color; - background-color: $custom-select-disabled-bg; - } - - // Hides the default caret in IE11 - &::-ms-expand { - display: none; - } -} - -.custom-select-sm { - height: $custom-select-height-sm; - padding-top: $custom-select-padding-y-sm; - padding-bottom: $custom-select-padding-y-sm; - padding-left: $custom-select-padding-x-sm; - @include font-size($custom-select-font-size-sm); -} - -.custom-select-lg { - height: $custom-select-height-lg; - padding-top: $custom-select-padding-y-lg; - padding-bottom: $custom-select-padding-y-lg; - padding-left: $custom-select-padding-x-lg; - @include font-size($custom-select-font-size-lg); -} - - -// File -// -// Custom file input. - -.custom-file { - position: relative; - display: inline-block; - width: 100%; - height: $custom-file-height; - margin-bottom: 0; -} - -.custom-file-input { - position: relative; - z-index: 2; - width: 100%; - height: $custom-file-height; - margin: 0; - opacity: 0; - - &:focus ~ .custom-file-label { - border-color: $custom-file-focus-border-color; - box-shadow: $custom-file-focus-box-shadow; - } - - // Use disabled attribute instead of :disabled pseudo-class - // Workaround for: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11295231 - &[disabled] ~ .custom-file-label { - background-color: $custom-file-disabled-bg; - } -} - -.custom-file-label { - position: absolute; - top: 0; - right: 0; - left: 0; - z-index: 1; - display: flex; - height: $custom-file-height; - border-color: $custom-file-border-color; - @include border-radius($custom-file-border-radius); - @include box-shadow($custom-file-box-shadow); -} - -.custom-file-text { - display: block; - flex-grow: 1; - padding: $custom-file-padding-y $custom-file-padding-x; - overflow: hidden; - font-family: $custom-file-font-family; - font-weight: $custom-file-font-weight; - line-height: $custom-file-line-height; - color: $custom-file-color; - text-overflow: ellipsis; - white-space: nowrap; - background-color: $custom-file-bg; - border-color: inherit; - border-style: solid; - border-width: $custom-file-border-width; - @include border-left-radius(inherit); -} - -.custom-file-button { - display: block; - flex-shrink: 0; - padding: $custom-file-padding-y $custom-file-padding-x; - margin-left: -$custom-file-border-width; - line-height: $custom-file-line-height; - color: $custom-file-button-color; - @include gradient-bg($custom-file-button-bg); - border-color: inherit; - border-style: solid; - border-width: $custom-file-border-width; - @include border-right-radius(inherit); -} - -// Range -// -// Style range inputs the same across browsers. Vendor-specific rules for pseudo -// elements cannot be mixed. As such, there are no shared styles for focus or -// active states on prefixed selectors. - -.custom-range { - width: 100%; - height: calc(#{$custom-range-thumb-height} + #{$custom-range-thumb-focus-box-shadow-width * 2}); - padding: 0; // Need to reset padding - background-color: transparent; - appearance: none; - - &:focus { - outline: none; - - // Pseudo-elements must be split across multiple rulesets to have an effect. - // No box-shadow() mixin for focus accessibility. - &::-webkit-slider-thumb { box-shadow: $custom-range-thumb-focus-box-shadow; } - &::-moz-range-thumb { box-shadow: $custom-range-thumb-focus-box-shadow; } - &::-ms-thumb { box-shadow: $custom-range-thumb-focus-box-shadow; } - } - - &::-moz-focus-outer { - border: 0; - } - - &::-webkit-slider-thumb { - width: $custom-range-thumb-width; - height: $custom-range-thumb-height; - margin-top: ($custom-range-track-height - $custom-range-thumb-height) / 2; // Webkit specific - @include gradient-bg($custom-range-thumb-bg); - border: $custom-range-thumb-border; - @include border-radius($custom-range-thumb-border-radius); - @include box-shadow($custom-range-thumb-box-shadow); - @include transition($custom-forms-transition); - appearance: none; - - &:active { - @include gradient-bg($custom-range-thumb-active-bg); - } - } - - &::-webkit-slider-runnable-track { - width: $custom-range-track-width; - height: $custom-range-track-height; - color: transparent; // Why? - cursor: $custom-range-track-cursor; - background-color: $custom-range-track-bg; - border-color: transparent; - @include border-radius($custom-range-track-border-radius); - @include box-shadow($custom-range-track-box-shadow); - } - - &::-moz-range-thumb { - width: $custom-range-thumb-width; - height: $custom-range-thumb-height; - @include gradient-bg($custom-range-thumb-bg); - border: $custom-range-thumb-border; - @include border-radius($custom-range-thumb-border-radius); - @include box-shadow($custom-range-thumb-box-shadow); - @include transition($custom-forms-transition); - appearance: none; - - &:active { - @include gradient-bg($custom-range-thumb-active-bg); - } - } - - &::-moz-range-track { - width: $custom-range-track-width; - height: $custom-range-track-height; - color: transparent; - cursor: $custom-range-track-cursor; - background-color: $custom-range-track-bg; - border-color: transparent; // Firefox specific? - @include border-radius($custom-range-track-border-radius); - @include box-shadow($custom-range-track-box-shadow); - } - - &::-ms-thumb { - width: $custom-range-thumb-width; - height: $custom-range-thumb-height; - margin-top: 0; // Edge specific - margin-right: $custom-range-thumb-focus-box-shadow-width; // Workaround that overflowed box-shadow is hidden. - margin-left: $custom-range-thumb-focus-box-shadow-width; // Workaround that overflowed box-shadow is hidden. - @include gradient-bg($custom-range-thumb-bg); - border: $custom-range-thumb-border; - @include border-radius($custom-range-thumb-border-radius); - @include box-shadow($custom-range-thumb-box-shadow); - @include transition($custom-forms-transition); - appearance: none; - - &:active { - @include gradient-bg($custom-range-thumb-active-bg); - } - } - - &::-ms-track { - width: $custom-range-track-width; - height: $custom-range-track-height; - color: transparent; - cursor: $custom-range-track-cursor; - background-color: transparent; - border-color: transparent; - border-width: $custom-range-thumb-height / 2; - @include box-shadow($custom-range-track-box-shadow); - } - - &::-ms-fill-lower { - background-color: $custom-range-track-bg; - @include border-radius($custom-range-track-border-radius); - } - - &::-ms-fill-upper { - margin-right: 15px; // arbitrary? - background-color: $custom-range-track-bg; - @include border-radius($custom-range-track-border-radius); - } - - &:disabled { - &::-webkit-slider-thumb { - background-color: $custom-range-thumb-disabled-bg; - } - - &::-webkit-slider-runnable-track { - cursor: default; - } - - &::-moz-range-thumb { - background-color: $custom-range-thumb-disabled-bg; - } - - &::-moz-range-track { - cursor: default; - } - - &::-ms-thumb { - background-color: $custom-range-thumb-disabled-bg; - } - } -} - -.custom-control-label::before, -.custom-file-label, -.custom-file-text, -.custom-file-button, -.custom-select { - @include transition($custom-forms-transition); -} diff --git a/scss/_forms.scss b/scss/_forms.scss index 0bc66587e9..ff9a016de7 100644 --- a/scss/_forms.scss +++ b/scss/_forms.scss @@ -1,334 +1,9 @@ -// stylelint-disable selector-no-qualifying-type - -// -// Textual form controls -// - -.form-control { - display: block; - width: 100%; - height: $input-height; - padding: $input-padding-y $input-padding-x; - font-family: $input-font-family; - @include font-size($input-font-size); - font-weight: $input-font-weight; - line-height: $input-line-height; - color: $input-color; - background-color: $input-bg; - background-clip: padding-box; - border: $input-border-width solid $input-border-color; - - // Note: This has no effect on <select>s in some browsers, due to the limited stylability of `<select>`s in CSS. - @include border-radius($input-border-radius, 0); - - @include box-shadow($input-box-shadow); - @include transition($input-transition); - - // Unstyle the caret on `<select>`s in IE10+. - &::-ms-expand { - background-color: transparent; - border: 0; - } - - // Customize the `:focus` state to imitate native WebKit styles. - @include form-control-focus($ignore-warning: true); - - // Placeholder - &::placeholder { - color: $input-placeholder-color; - // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526. - opacity: 1; - } - - // Disabled and read-only inputs - // - // HTML5 says that controls under a fieldset > legend:first-child won't be - // disabled if the fieldset is disabled. Due to implementation difficulty, we - // don't honor that edge case; we style them as disabled anyway. - &:disabled, - &[readonly] { - background-color: $input-disabled-bg; - // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655. - opacity: 1; - } -} - -select.form-control { - &:focus::-ms-value { - // Suppress the nested default white text on blue background highlight given to - // the selected option text when the (still closed) <select> receives focus - // in IE and (under certain conditions) Edge, as it looks bad and cannot be made to - // match the appearance of the native widget. - // See https://github.com/twbs/bootstrap/issues/19398. - color: $input-color; - background-color: $input-bg; - } -} - -// Make file inputs better match text inputs by forcing them to new lines. -.form-control-file, -.form-control-range { - display: block; - width: 100%; -} - - -// -// Labels -// - -// For use with horizontal and inline forms, when you need the label (or legend) -// text to align with the form controls. -.col-form-label { - padding-top: calc(#{$input-padding-y} + #{$input-border-width}); - padding-bottom: calc(#{$input-padding-y} + #{$input-border-width}); - margin-bottom: 0; // Override the `<label>/<legend>` default - @include font-size(inherit); // Override the `<legend>` default - line-height: $input-line-height; -} - -.col-form-label-lg { - padding-top: calc(#{$input-padding-y-lg} + #{$input-border-width}); - padding-bottom: calc(#{$input-padding-y-lg} + #{$input-border-width}); - @include font-size($input-font-size-lg); - line-height: $input-line-height-lg; -} - -.col-form-label-sm { - padding-top: calc(#{$input-padding-y-sm} + #{$input-border-width}); - padding-bottom: calc(#{$input-padding-y-sm} + #{$input-border-width}); - @include font-size($input-font-size-sm); - line-height: $input-line-height-sm; -} - - -// Readonly controls as plain text -// -// Apply class to a readonly input to make it appear like regular plain -// text (without any border, background color, focus indicator) - -.form-control-plaintext { - display: block; - width: 100%; - padding: $input-padding-y 0; - margin-bottom: 0; // match inputs if this class comes on inputs with default margins - @include font-size($input-font-size); - line-height: $input-line-height; - color: $input-plaintext-color; - background-color: transparent; - border: solid transparent; - border-width: $input-border-width 0; - - &.form-control-sm, - &.form-control-lg { - padding-right: 0; - padding-left: 0; - } -} - - -// Form control sizing -// -// Build on `.form-control` with modifier classes to decrease or increase the -// height and font-size of form controls. -// -// Repeated in `_input_group.scss` to avoid Sass extend issues. - -.form-control-sm { - height: $input-height-sm; - padding: $input-padding-y-sm $input-padding-x-sm; - @include font-size($input-font-size-sm); - line-height: $input-line-height-sm; - @include border-radius($input-border-radius-sm); -} - -.form-control-lg { - height: $input-height-lg; - padding: $input-padding-y-lg $input-padding-x-lg; - @include font-size($input-font-size-lg); - line-height: $input-line-height-lg; - @include border-radius($input-border-radius-lg); -} - -// stylelint-disable-next-line no-duplicate-selectors -select.form-control { - &[size], - &[multiple] { - height: auto; - } -} - -textarea.form-control { - height: auto; -} - -// Form groups -// -// Designed to help with the organization and spacing of vertical forms. For -// horizontal forms, use the predefined grid classes. - -.form-group { - margin-bottom: $form-group-margin-bottom; -} - -.form-text { - display: block; - margin-top: $form-text-margin-top; -} - - -// Form grid -// -// Special replacement for our grid system's `.row` for tighter form layouts. - -@if $enable-grid-classes { - .form-row { - display: flex; - flex-wrap: wrap; - margin-right: -$form-grid-gutter-width / 2; - margin-left: -$form-grid-gutter-width / 2; - - > .col, - > [class*="col-"] { - padding-right: $form-grid-gutter-width / 2; - padding-left: $form-grid-gutter-width / 2; - } - } -} - - -// Checkboxes and radios -// -// Indent the labels to position radios/checkboxes as hanging controls. - -.form-check { - position: relative; - display: block; - padding-left: $form-check-input-gutter; -} - -.form-check-input { - position: absolute; - margin-top: $form-check-input-margin-y; - margin-left: -$form-check-input-gutter; - - // Use disabled attribute instead of :disabled pseudo-class - // Workaround for: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11295231 - &[disabled] ~ .form-check-label { - color: $text-muted; - } -} - -.form-check-label { - margin-bottom: 0; // Override default `<label>` bottom margin -} - -.form-check-inline { - display: inline-flex; - align-items: center; - padding-left: 0; // Override base .form-check - margin-right: $form-check-inline-margin-x; - - // Undo .form-check-input defaults and add some `margin-right`. - .form-check-input { - position: static; - margin-top: 0; - margin-right: $form-check-inline-input-margin-x; - margin-left: 0; - } -} - - -// Form validation -// -// Provide feedback to users when form field values are valid or invalid. Works -// primarily for client-side validation via scoped `:invalid` and `:valid` -// pseudo-classes but also includes `.is-invalid` and `.is-valid` classes for -// server-side validation. - -@each $state, $data in $form-validation-states { - @include form-validation-state($state, map-get($data, color), map-get($data, icon)); -} - -// Inline forms -// -// Make forms appear inline(-block) by adding the `.form-inline` class. Inline -// forms begin stacked on extra small (mobile) devices and then go inline when -// viewports reach <768px. -// -// Requires wrapping inputs and labels with `.form-group` for proper display of -// default HTML form controls and our custom form controls (e.g., input groups). - -.form-inline { - display: flex; - flex-flow: row wrap; - align-items: center; // Prevent shorter elements from growing to same height as others (e.g., small buttons growing to normal sized button height) - - // Because we use flex, the initial sizing of checkboxes is collapsed and - // doesn't occupy the full-width (which is what we want for xs grid tier), - // so we force that here. - .form-check { - width: 100%; - } - - // Kick in the inline - @include media-breakpoint-up(sm) { - label { - display: flex; - align-items: center; - justify-content: center; - margin-bottom: 0; - } - - // Inline-block all the things for "inline" - .form-group { - display: flex; - flex: 0 0 auto; - flex-flow: row wrap; - align-items: center; - margin-bottom: 0; - } - - // Allow folks to *not* use `.form-group` - .form-control { - display: inline-block; - width: auto; // Prevent labels from stacking above inputs in `.form-group` - vertical-align: middle; - } - - // Make static controls behave like regular ones - .form-control-plaintext { - display: inline-block; - } - - .input-group, - .custom-select { - width: auto; - } - - // Remove default margin on radios/checkboxes that were used for stacking, and - // then undo the floating of radios and checkboxes to match. - .form-check { - display: flex; - align-items: center; - justify-content: center; - width: auto; - padding-left: 0; - } - .form-check-input { - position: relative; - flex-shrink: 0; - margin-top: 0; - margin-right: $form-check-input-margin-x; - margin-left: 0; - } - - .custom-control { - align-items: center; - justify-content: center; - } - .custom-control-label { - margin-bottom: 0; - } - } -} +@import "forms/labels"; +@import "forms/form-control"; +@import "forms/form-select"; +@import "forms/form-check"; +@import "forms/form-file"; +@import "forms/form-range"; +@import "forms/layout"; +@import "forms/input-group"; +@import "forms/validation"; diff --git a/scss/_reboot.scss b/scss/_reboot.scss index df3eacbff8..3553c24910 100644 --- a/scss/_reboot.scss +++ b/scss/_reboot.scss @@ -158,6 +158,12 @@ address { } ol, +ul { + padding-right: 2rem; + padding-left: 2rem; +} + +ol, ul, dl { margin-top: 0; diff --git a/scss/_tables.scss b/scss/_tables.scss index 95d1c4a867..d1fbdc21d2 100644 --- a/scss/_tables.scss +++ b/scss/_tables.scss @@ -12,12 +12,16 @@ td { padding: $table-cell-padding; vertical-align: top; - border-top: $table-border-width solid $table-border-color; + border-bottom: $table-border-width solid $table-border-color; + } + + td { + border-bottom: $table-border-width solid $table-border-color; } thead th { vertical-align: bottom; - border-bottom: (2 * $table-border-width) solid $table-border-color; + border-bottom-color: $table-head-border-color; } tbody + tbody { diff --git a/scss/_variables.scss b/scss/_variables.scss index 7b28d94ddb..56bd143dbf 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -351,8 +351,8 @@ $hr-margin-y: $spacer !default; // // Customizes the `.table` component with basic values, each used across all table variations. -$table-cell-padding: .75rem !default; -$table-cell-padding-sm: .3rem !default; +$table-cell-padding: .5rem !default; +$table-cell-padding-sm: .25rem !default; $table-color: $body-color !default; $table-bg: null !default; @@ -366,6 +366,7 @@ $table-border-color: $border-color !default; $table-head-bg: $gray-200 !default; $table-head-color: $gray-700 !default; +$table-head-border-color: $gray-700 !default; $table-dark-color: $white !default; $table-dark-bg: $gray-800 !default; @@ -506,17 +507,61 @@ $input-height-lg: calc(#{$input-line-height-lg * 1em} + #{ $input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + +$form-check-input-width: 1.25em !default; +$form-check-min-height: $font-size-base * $line-height-base !default; +$form-check-padding-left: $form-check-input-width + .5em !default; +$form-check-margin-bottom: .125rem !default; + +$form-check-input-active-filter: brightness(90%) !default; + +$form-check-input-bg: $body-bg !default; +$form-check-input-border: 1px solid rgba(0, 0, 0, .25) !default; +$form-check-input-border-radius: .25em !default; +$form-check-radio-border-radius: 50% !default; +$form-check-input-focus-border: $input-focus-border-color !default; +$form-check-input-focus-box-shadow: $input-btn-focus-box-shadow !default; + +$form-check-input-checked-color: $component-active-color !default; +$form-check-input-checked-bg-color: $component-active-bg !default; +$form-check-input-checked-border-color: $form-check-input-checked-bg-color !default; +$form-check-input-checked-bg-repeat: no-repeat !default; +$form-check-input-checked-bg-position: center center !default; +$form-check-input-checked-bg-size: 1em !default; +$form-check-input-checked-bg-image: str-replace(url('data:image/svg+xml;utf8,<svg viewbox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path stroke="#{$form-check-input-checked-color}" stroke-width="3" d="M4 8.5L6.5 11l6-6" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"/></svg>'), "#", "%23") !default; +$form-check-radio-checked-bg-image: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='#{$form-check-input-checked-color}'/%3e%3c/svg%3e"), "#", "%23") !default; + +$form-check-input-indeterminate-color: $component-active-color !default; +$form-check-input-indeterminate-bg-color: $component-active-bg !default; +$form-check-input-indeterminate-border-color: $form-check-input-indeterminate-bg-color !default; +$form-check-input-indeterminate-bg-repeat: no-repeat !default; +$form-check-input-indeterminate-bg-position: center center !default; +$form-check-input-indeterminate-bg-size: 1em !default; +$form-check-input-indeterminate-bg-image: str-replace(url('data:image/svg+xml;utf8,<svg viewbox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M5 8h6" stroke="#{$form-check-input-indeterminate-color}" stroke-width="3" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"/></svg>'), "#", "%23") !default; + +$form-switch-color: rgba(0, 0, 0, .25) !default; +$form-switch-width: 2em !default; +$form-switch-height: $form-check-input-width !default; +$form-switch-padding-left: $form-switch-width + .5em !default; +$form-switch-bg-image: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='#{$form-switch-color}'/%3e%3c/svg%3e"), "#", "%23") !default; +$form-switch-border-radius: $form-switch-width !default; +$form-switch-transition: .2s ease-in-out !default; +$form-switch-transition-property: background-position, background-color !default; + +$form-switch-focus-color: hsla(211, 100%, 75%, 1) !default; +$form-switch-focus-bg-image: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='#{$form-switch-focus-color}'/%3e%3c/svg%3e"), "#", "%23") !default; + +$form-switch-checked-color: $component-active-color !default; +$form-switch-checked-bg-image: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='#{$form-switch-checked-color}'/%3e%3c/svg%3e"), "#", "%23") !default; +$form-switch-checked-bg-position: right center !default; + $form-text-margin-top: .25rem !default; -$form-check-input-gutter: 1.25rem !default; -$form-check-input-margin-y: .3rem !default; -$form-check-input-margin-x: .25rem !default; +$form-check-inline-margin-right: 1rem !default; -$form-check-inline-margin-x: .75rem !default; -$form-check-inline-input-margin-x: .3125rem !default; +$form-check-input-margin-x: .25rem !default; $form-grid-gutter-width: 10px !default; -$form-group-margin-bottom: 1rem !default; $input-group-addon-color: $input-color !default; $input-group-addon-bg: $gray-200 !default; @@ -524,128 +569,83 @@ $input-group-addon-border-color: $input-border-color !default; $custom-forms-transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; -$custom-control-gutter: .5rem !default; -$custom-control-spacer-x: 1rem !default; - -$custom-control-indicator-size: 1rem !default; -$custom-control-indicator-bg: $input-bg !default; - -$custom-control-indicator-bg-size: 50% 50% !default; -$custom-control-indicator-box-shadow: $input-box-shadow !default; -$custom-control-indicator-border-color: $gray-500 !default; -$custom-control-indicator-border-width: $input-border-width !default; - -$custom-control-label-color: null !default; - -$custom-control-indicator-disabled-bg: $input-disabled-bg !default; -$custom-control-label-disabled-color: $gray-600 !default; - -$custom-control-indicator-checked-color: $component-active-color !default; -$custom-control-indicator-checked-bg: $component-active-bg !default; -$custom-control-indicator-checked-disabled-bg: rgba(theme-color("primary"), .5) !default; -$custom-control-indicator-checked-box-shadow: none !default; -$custom-control-indicator-checked-border-color: $custom-control-indicator-checked-bg !default; - -$custom-control-indicator-focus-box-shadow: $input-focus-box-shadow !default; -$custom-control-indicator-focus-border-color: $input-focus-border-color !default; - -$custom-control-indicator-active-color: $component-active-color !default; -$custom-control-indicator-active-bg: lighten($component-active-bg, 35%) !default; -$custom-control-indicator-active-box-shadow: none !default; -$custom-control-indicator-active-border-color: $custom-control-indicator-active-bg !default; - -$custom-checkbox-indicator-border-radius: $border-radius !default; -$custom-checkbox-indicator-icon-checked: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='#{$custom-control-indicator-checked-color}' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e"), "#", "%23") !default; - -$custom-checkbox-indicator-indeterminate-bg: $component-active-bg !default; -$custom-checkbox-indicator-indeterminate-color: $custom-control-indicator-checked-color !default; -$custom-checkbox-indicator-icon-indeterminate: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3e%3cpath stroke='#{$custom-checkbox-indicator-indeterminate-color}' d='M0 2h4'/%3e%3c/svg%3e"), "#", "%23") !default; -$custom-checkbox-indicator-indeterminate-box-shadow: none !default; -$custom-checkbox-indicator-indeterminate-border-color: $custom-checkbox-indicator-indeterminate-bg !default; - -$custom-radio-indicator-border-radius: 50% !default; -$custom-radio-indicator-icon-checked: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='#{$custom-control-indicator-checked-color}'/%3e%3c/svg%3e"), "#", "%23") !default; - -$custom-switch-width: $custom-control-indicator-size * 1.75 !default; -$custom-switch-indicator-border-radius: $custom-control-indicator-size / 2 !default; -$custom-switch-indicator-size: calc(#{$custom-control-indicator-size} - #{$custom-control-indicator-border-width * 4}) !default; - -$custom-select-padding-y: $input-padding-y !default; -$custom-select-padding-x: $input-padding-x !default; -$custom-select-font-family: $input-font-family !default; -$custom-select-font-size: $input-font-size !default; -$custom-select-height: $input-height !default; -$custom-select-indicator-padding: 1rem !default; // Extra padding to account for the presence of the background-image based indicator -$custom-select-font-weight: $input-font-weight !default; -$custom-select-line-height: $input-line-height !default; -$custom-select-color: $input-color !default; -$custom-select-disabled-color: $gray-600 !default; -$custom-select-bg: $input-bg !default; -$custom-select-disabled-bg: $gray-200 !default; -$custom-select-bg-size: 8px 10px !default; // In pixels because image dimensions -$custom-select-indicator-color: $gray-800 !default; -$custom-select-indicator: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='#{$custom-select-indicator-color}' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e"), "#", "%23") !default; -$custom-select-background: $custom-select-indicator no-repeat right $custom-select-padding-x center / $custom-select-bg-size !default; // Used so we can have multiple background elements (e.g., arrow and feedback icon) - -$custom-select-feedback-icon-padding-right: calc((1em + #{2 * $custom-select-padding-y}) * 3 / 4 + #{$custom-select-padding-x + $custom-select-indicator-padding}) !default; -$custom-select-feedback-icon-position: center right ($custom-select-padding-x + $custom-select-indicator-padding) !default; -$custom-select-feedback-icon-size: $input-height-inner-half $input-height-inner-half !default; - -$custom-select-border-width: $input-border-width !default; -$custom-select-border-color: $input-border-color !default; -$custom-select-border-radius: $border-radius !default; -$custom-select-box-shadow: inset 0 1px 2px rgba($black, .075) !default; - -$custom-select-focus-border-color: $input-focus-border-color !default; -$custom-select-focus-width: $input-focus-width !default; -$custom-select-focus-box-shadow: 0 0 0 $custom-select-focus-width $input-btn-focus-color !default; - -$custom-select-padding-y-sm: $input-padding-y-sm !default; -$custom-select-padding-x-sm: $input-padding-x-sm !default; -$custom-select-font-size-sm: $input-font-size-sm !default; -$custom-select-height-sm: $input-height-sm !default; - -$custom-select-padding-y-lg: $input-padding-y-lg !default; -$custom-select-padding-x-lg: $input-padding-x-lg !default; -$custom-select-font-size-lg: $input-font-size-lg !default; -$custom-select-height-lg: $input-height-lg !default; - -$custom-range-track-width: 100% !default; -$custom-range-track-height: .5rem !default; -$custom-range-track-cursor: pointer !default; -$custom-range-track-bg: $gray-300 !default; -$custom-range-track-border-radius: 1rem !default; -$custom-range-track-box-shadow: inset 0 .25rem .25rem rgba($black, .1) !default; - -$custom-range-thumb-width: 1rem !default; -$custom-range-thumb-height: $custom-range-thumb-width !default; -$custom-range-thumb-bg: $component-active-bg !default; -$custom-range-thumb-border: 0 !default; -$custom-range-thumb-border-radius: 1rem !default; -$custom-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default; -$custom-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default; -$custom-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in IE/Edge -$custom-range-thumb-active-bg: lighten($component-active-bg, 35%) !default; -$custom-range-thumb-disabled-bg: $gray-500 !default; - -$custom-file-height: $input-height !default; -$custom-file-focus-border-color: $input-focus-border-color !default; -$custom-file-focus-box-shadow: $input-focus-box-shadow !default; -$custom-file-disabled-bg: $input-disabled-bg !default; - -$custom-file-padding-y: $input-padding-y !default; -$custom-file-padding-x: $input-padding-x !default; -$custom-file-line-height: $input-line-height !default; -$custom-file-font-family: $input-font-family !default; -$custom-file-font-weight: $input-font-weight !default; -$custom-file-color: $input-color !default; -$custom-file-bg: $input-bg !default; -$custom-file-border-width: $input-border-width !default; -$custom-file-border-color: $input-border-color !default; -$custom-file-border-radius: $input-border-radius !default; -$custom-file-box-shadow: $input-box-shadow !default; -$custom-file-button-color: $custom-file-color !default; -$custom-file-button-bg: $input-group-addon-bg !default; +$form-select-padding-y: $input-padding-y !default; +$form-select-padding-x: $input-padding-x !default; +$form-select-font-family: $input-font-family !default; +$form-select-font-size: $input-font-size !default; +$form-select-height: $input-height !default; +$form-select-indicator-padding: 1rem !default; // Extra padding to account for the presence of the background-image based indicator +$form-select-font-weight: $input-font-weight !default; +$form-select-line-height: $input-line-height !default; +$form-select-color: $input-color !default; +$form-select-disabled-color: $gray-600 !default; +$form-select-bg: $input-bg !default; +$form-select-disabled-bg: $gray-200 !default; +$form-select-bg-size: 16px 12px !default; // In pixels because image dimensions +$form-select-indicator-color: $gray-800 !default; +$form-select-indicator: str-replace(url('data:image/svg+xml;utf8,<svg viewbox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path stroke="#{$form-select-indicator-color}" stroke-width="2px" d="M2 5l6 6 6-6" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"/></svg>'), "#", "%23") !default; + +$form-select-background: $form-select-indicator no-repeat right $form-select-padding-x center / $form-select-bg-size !default; // Used so we can have multiple background elements (e.g., arrow and feedback icon) + +$form-select-feedback-icon-padding-right: calc((1em + #{2 * $form-select-padding-y}) * 3 / 4 + #{$form-select-padding-x + $form-select-indicator-padding}) !default; +$form-select-feedback-icon-position: center right ($form-select-padding-x + $form-select-indicator-padding) !default; +$form-select-feedback-icon-size: $input-height-inner-half $input-height-inner-half !default; + +$form-select-border-width: $input-border-width !default; +$form-select-border-color: $input-border-color !default; +$form-select-border-radius: $border-radius !default; +$form-select-box-shadow: inset 0 1px 2px rgba($black, .075) !default; + +$form-select-focus-border-color: $input-focus-border-color !default; +$form-select-focus-width: $input-focus-width !default; +$form-select-focus-box-shadow: 0 0 0 $form-select-focus-width $input-btn-focus-color !default; + +$form-select-padding-y-sm: $input-padding-y-sm !default; +$form-select-padding-x-sm: $input-padding-x-sm !default; +$form-select-font-size-sm: $input-font-size-sm !default; +$form-select-height-sm: $input-height-sm !default; + +$form-select-padding-y-lg: $input-padding-y-lg !default; +$form-select-padding-x-lg: $input-padding-x-lg !default; +$form-select-font-size-lg: $input-font-size-lg !default; +$form-select-height-lg: $input-height-lg !default; + +$form-range-track-width: 100% !default; +$form-range-track-height: .5rem !default; +$form-range-track-cursor: pointer !default; +$form-range-track-bg: $gray-300 !default; +$form-range-track-border-radius: 1rem !default; +$form-range-track-box-shadow: inset 0 .25rem .25rem rgba($black, .1) !default; + +$form-range-thumb-width: 1rem !default; +$form-range-thumb-height: $form-range-thumb-width !default; +$form-range-thumb-bg: $component-active-bg !default; +$form-range-thumb-border: 0 !default; +$form-range-thumb-border-radius: 1rem !default; +$form-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default; +$form-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default; +$form-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in IE/Edge +$form-range-thumb-active-bg: lighten($component-active-bg, 35%) !default; +$form-range-thumb-disabled-bg: $gray-500 !default; + +$form-file-height: $input-height !default; +$form-file-focus-border-color: $input-focus-border-color !default; +$form-file-focus-box-shadow: $input-focus-box-shadow !default; +$form-file-disabled-bg: $input-disabled-bg !default; + +$form-file-padding-y: $input-padding-y !default; +$form-file-padding-x: $input-padding-x !default; +$form-file-line-height: $input-line-height !default; +$form-file-font-family: $input-font-family !default; +$form-file-font-weight: $input-font-weight !default; +$form-file-color: $input-color !default; +$form-file-bg: $input-bg !default; +$form-file-border-width: $input-border-width !default; +$form-file-border-color: $input-border-color !default; +$form-file-border-radius: $input-border-radius !default; +$form-file-box-shadow: $input-box-shadow !default; +$form-file-button-color: $form-file-color !default; +$form-file-button-bg: $input-group-addon-bg !default; // Form validation diff --git a/scss/bootstrap.scss b/scss/bootstrap.scss index 6ded9f628f..df1d49e2ad 100644 --- a/scss/bootstrap.scss +++ b/scss/bootstrap.scss @@ -27,8 +27,6 @@ @import "transitions"; @import "dropdown"; @import "button-group"; -@import "input-group"; -@import "custom-forms"; @import "nav"; @import "navbar"; @import "card"; diff --git a/scss/forms/_form-check.scss b/scss/forms/_form-check.scss new file mode 100644 index 0000000000..b309d2e704 --- /dev/null +++ b/scss/forms/_form-check.scss @@ -0,0 +1,116 @@ +// +// Check/radio +// + +.form-check { + display: block; + min-height: $form-check-min-height; + padding-left: $form-check-padding-left; + margin-bottom: $form-check-margin-bottom; +} + +.form-check-input { + float: left; + width: $form-check-input-width; + height: $form-check-input-width; + // Todo: Change static value to base line-height? + margin-top: calc((1.5em - #{$form-check-input-width}) / 2); // line-height minus check height + margin-left: $form-check-padding-left * -1; + background-color: $form-check-input-bg; + border: $form-check-input-border; + appearance: none; + + &[type="checkbox"] { + @include border-radius($form-check-input-border-radius); + } + + &[type="radio"] { + @include border-radius($form-check-radio-border-radius); + } + + &:active { + filter: $form-check-input-active-filter; + } + + &:focus { + border-color: $form-check-input-focus-border; + outline: 0; + box-shadow: $form-check-input-focus-box-shadow; + } + + &:checked { + background-color: $form-check-input-checked-bg-color; + background-repeat: $form-check-input-checked-bg-repeat; + background-position: $form-check-input-checked-bg-position; + background-size: $form-check-input-checked-bg-size; + border-color: $form-check-input-checked-border-color; + + &[type="checkbox"] { + background-image: $form-check-input-checked-bg-image; + } + + &[type="radio"] { + background-image: $form-check-radio-checked-bg-image; + } + } + + &[type="checkbox"]:indeterminate { + background-color: $form-check-input-indeterminate-bg-color; + background-image: $form-check-input-indeterminate-bg-image; + background-repeat: $form-check-input-indeterminate-bg-repeat; + background-position: $form-check-input-indeterminate-bg-position; + background-size: $form-check-input-indeterminate-bg-size; + border-color: $form-check-input-indeterminate-border-color; + } + + // Use disabled attribute instead of :disabled pseudo-class + // Workaround for: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11295231 + &[disabled] { + pointer-events: none; + filter: none; + opacity: .5; + + ~ .form-check-label { + opacity: .5; + } + } +} + +.form-check-label { + margin-bottom: 0; +} + +// +// Switch +// + +.form-switch { + padding-left: $form-switch-padding-left; + + .form-check-input { + width: $form-switch-width; + margin-left: $form-switch-padding-left * -1; + background-image: $form-switch-bg-image; + background-repeat: no-repeat; + background-position: left center; + background-size: calc(#{$form-switch-height} - 2px); // Get a 1px separation + @include border-radius($form-switch-border-radius); + // Todo: Figure out how to tackle these, with or without mixin? + // transition: $form-switch-transition; + // transition-property: $form-switch-transition-property; + + &:focus { + background-image: $form-switch-focus-bg-image; + } + + &:checked { + background-image: $form-switch-checked-bg-image; + background-position: $form-switch-checked-bg-position; + } + } +} + +.form-check-inline { + display: inline-block; + margin-right: $form-check-inline-margin-right; +} diff --git a/scss/forms/_form-control.scss b/scss/forms/_form-control.scss new file mode 100644 index 0000000000..ce2b426627 --- /dev/null +++ b/scss/forms/_form-control.scss @@ -0,0 +1,115 @@ +// stylelint-disable selector-no-qualifying-type + +// +// Textual form controls +// + +.form-control { + display: block; + width: 100%; + height: $input-height; + padding: $input-padding-y $input-padding-x; + font-family: $input-font-family; + @include font-size($input-font-size); + font-weight: $input-font-weight; + line-height: $input-line-height; + color: $input-color; + background-color: $input-bg; + background-clip: padding-box; + border: $input-border-width solid $input-border-color; + + // Note: This has no effect on <select>s in some browsers, due to the limited stylability of `<select>`s in CSS. + @include border-radius($input-border-radius, 0); + + @include box-shadow($input-box-shadow); + @include transition($input-transition); + + // Unstyle the caret on `<select>`s in IE10+. + &::-ms-expand { + background-color: transparent; + border: 0; + } + + // Customize the `:focus` state to imitate native WebKit styles. + &:focus { + color: $input-focus-color; + background-color: $input-focus-bg; + border-color: $input-focus-border-color; + outline: 0; + // Avoid using mixin so we can pass custom focus shadow properly + @if $enable-shadows { + box-shadow: $input-box-shadow, $input-focus-box-shadow; + } @else { + box-shadow: $input-focus-box-shadow; + } + } + + // Placeholder + &::placeholder { + color: $input-placeholder-color; + // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526. + opacity: 1; + } + + // Disabled and read-only inputs + // + // HTML5 says that controls under a fieldset > legend:first-child won't be + // disabled if the fieldset is disabled. Due to implementation difficulty, we + // don't honor that edge case; we style them as disabled anyway. + &:disabled, + &[readonly] { + background-color: $input-disabled-bg; + // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655. + opacity: 1; + } +} + +// Readonly controls as plain text +// +// Apply class to a readonly input to make it appear like regular plain +// text (without any border, background color, focus indicator) + +.form-control-plaintext { + display: block; + width: 100%; + padding: $input-padding-y 0; + margin-bottom: 0; // match inputs if this class comes on inputs with default margins + line-height: $input-line-height; + color: $input-plaintext-color; + background-color: transparent; + border: solid transparent; + border-width: $input-border-width 0; + + &.form-control-sm, + &.form-control-lg { + padding-right: 0; + padding-left: 0; + } +} + +// Form control sizing +// +// Build on `.form-control` with modifier classes to decrease or increase the +// height and font-size of form controls. +// +// Repeated in `_input_group.scss` to avoid Sass extend issues. + +.form-control-sm { + height: $input-height-sm; + padding: $input-padding-y-sm $input-padding-x-sm; + @include font-size($input-font-size-sm); + line-height: $input-line-height-sm; + @include border-radius($input-border-radius-sm); +} + +.form-control-lg { + height: $input-height-lg; + padding: $input-padding-y-lg $input-padding-x-lg; + @include font-size($input-font-size-lg); + line-height: $input-line-height-lg; + @include border-radius($input-border-radius-lg); +} + +textarea.form-control { + height: auto; +} diff --git a/scss/forms/_form-file.scss b/scss/forms/_form-file.scss new file mode 100644 index 0000000000..bbc38a9f81 --- /dev/null +++ b/scss/forms/_form-file.scss @@ -0,0 +1,72 @@ +.form-file { + position: relative; + display: inline-block; + width: 100%; + height: $form-file-height; + margin-bottom: 0; +} + +.form-file-input { + position: relative; + z-index: 2; + width: 100%; + height: $form-file-height; + margin: 0; + opacity: 0; + + &:focus ~ .form-file-label { + border-color: $form-file-focus-border-color; + box-shadow: $form-file-focus-box-shadow; + } + + // Use disabled attribute instead of :disabled pseudo-class + // Workaround for: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11295231 + &[disabled] ~ .form-file-label { + background-color: $form-file-disabled-bg; + } +} + +.form-file-label { + position: absolute; + top: 0; + right: 0; + left: 0; + z-index: 1; + display: flex; + height: $form-file-height; + border-color: $form-file-border-color; + @include border-radius($form-file-border-radius); + @include box-shadow($form-file-box-shadow); +} + +.form-file-text { + display: block; + flex-grow: 1; + padding: $form-file-padding-y $form-file-padding-x; + overflow: hidden; + font-family: $form-file-font-family; + font-weight: $form-file-font-weight; + line-height: $form-file-line-height; + color: $form-file-color; + text-overflow: ellipsis; + white-space: nowrap; + background-color: $form-file-bg; + border-color: inherit; + border-style: solid; + border-width: $form-file-border-width; + @include border-left-radius(inherit); +} + +.form-file-button { + display: block; + flex-shrink: 0; + padding: $form-file-padding-y $form-file-padding-x; + margin-left: -$form-file-border-width; + line-height: $form-file-line-height; + color: $form-file-button-color; + @include gradient-bg($form-file-button-bg); + border-color: inherit; + border-style: solid; + border-width: $form-file-border-width; + @include border-right-radius(inherit); +} diff --git a/scss/forms/_form-range.scss b/scss/forms/_form-range.scss new file mode 100644 index 0000000000..b54d4d6aaf --- /dev/null +++ b/scss/forms/_form-range.scss @@ -0,0 +1,142 @@ +// Range +// +// Style range inputs the same across browsers. Vendor-specific rules for pseudo +// elements cannot be mixed. As such, there are no shared styles for focus or +// active states on prefixed selectors. + +.form-range { + width: 100%; + height: calc(#{$form-range-thumb-height} + #{$form-range-thumb-focus-box-shadow-width * 2}); + padding: 0; // Need to reset padding + background-color: transparent; + appearance: none; + + &:focus { + outline: none; + + // Pseudo-elements must be split across multiple rulesets to have an effect. + // No box-shadow() mixin for focus accessibility. + &::-webkit-slider-thumb { box-shadow: $form-range-thumb-focus-box-shadow; } + &::-moz-range-thumb { box-shadow: $form-range-thumb-focus-box-shadow; } + &::-ms-thumb { box-shadow: $form-range-thumb-focus-box-shadow; } + } + + &::-moz-focus-outer { + border: 0; + } + + &::-webkit-slider-thumb { + width: $form-range-thumb-width; + height: $form-range-thumb-height; + margin-top: ($form-range-track-height - $form-range-thumb-height) / 2; // Webkit specific + @include gradient-bg($form-range-thumb-bg); + border: $form-range-thumb-border; + @include border-radius($form-range-thumb-border-radius); + @include box-shadow($form-range-thumb-box-shadow); + @include transition($custom-forms-transition); + appearance: none; + + &:active { + @include gradient-bg($form-range-thumb-active-bg); + } + } + + &::-webkit-slider-runnable-track { + width: $form-range-track-width; + height: $form-range-track-height; + color: transparent; // Why? + cursor: $form-range-track-cursor; + background-color: $form-range-track-bg; + border-color: transparent; + @include border-radius($form-range-track-border-radius); + @include box-shadow($form-range-track-box-shadow); + } + + &::-moz-range-thumb { + width: $form-range-thumb-width; + height: $form-range-thumb-height; + @include gradient-bg($form-range-thumb-bg); + border: $form-range-thumb-border; + @include border-radius($form-range-thumb-border-radius); + @include box-shadow($form-range-thumb-box-shadow); + @include transition($custom-forms-transition); + appearance: none; + + &:active { + @include gradient-bg($form-range-thumb-active-bg); + } + } + + &::-moz-range-track { + width: $form-range-track-width; + height: $form-range-track-height; + color: transparent; + cursor: $form-range-track-cursor; + background-color: $form-range-track-bg; + border-color: transparent; // Firefox specific? + @include border-radius($form-range-track-border-radius); + @include box-shadow($form-range-track-box-shadow); + } + + &::-ms-thumb { + width: $form-range-thumb-width; + height: $form-range-thumb-height; + margin-top: 0; // Edge specific + margin-right: $form-range-thumb-focus-box-shadow-width; // Workaround that overflowed box-shadow is hidden. + margin-left: $form-range-thumb-focus-box-shadow-width; // Workaround that overflowed box-shadow is hidden. + @include gradient-bg($form-range-thumb-bg); + border: $form-range-thumb-border; + @include border-radius($form-range-thumb-border-radius); + @include box-shadow($form-range-thumb-box-shadow); + @include transition($custom-forms-transition); + appearance: none; + + &:active { + @include gradient-bg($form-range-thumb-active-bg); + } + } + + &::-ms-track { + width: $form-range-track-width; + height: $form-range-track-height; + color: transparent; + cursor: $form-range-track-cursor; + background-color: transparent; + border-color: transparent; + border-width: $form-range-thumb-height / 2; + @include box-shadow($form-range-track-box-shadow); + } + + &::-ms-fill-lower { + background-color: $form-range-track-bg; + @include border-radius($form-range-track-border-radius); + } + + &::-ms-fill-upper { + margin-right: 15px; // arbitrary? + background-color: $form-range-track-bg; + @include border-radius($form-range-track-border-radius); + } + + &:disabled { + &::-webkit-slider-thumb { + background-color: $form-range-thumb-disabled-bg; + } + + &::-webkit-slider-runnable-track { + cursor: default; + } + + &::-moz-range-thumb { + background-color: $form-range-thumb-disabled-bg; + } + + &::-moz-range-track { + cursor: default; + } + + &::-ms-thumb { + background-color: $form-range-thumb-disabled-bg; + } + } +} diff --git a/scss/forms/_form-select.scss b/scss/forms/_form-select.scss new file mode 100644 index 0000000000..e0b69c04f7 --- /dev/null +++ b/scss/forms/_form-select.scss @@ -0,0 +1,76 @@ +// Select +// +// Replaces the browser default select with a custom one, mostly pulled from +// https://primer.github.io/. + +.form-select { + display: inline-block; + width: 100%; + height: $form-select-height; + padding: $form-select-padding-y ($form-select-padding-x + $form-select-indicator-padding) $form-select-padding-y $form-select-padding-x; + font-family: $form-select-font-family; + @include font-size($form-select-font-size); + font-weight: $form-select-font-weight; + line-height: $form-select-line-height; + color: $form-select-color; + vertical-align: middle; + background: $form-select-background; + background-color: $form-select-bg; + border: $form-select-border-width solid $form-select-border-color; + @include border-radius($form-select-border-radius, 0); + @include box-shadow($form-select-box-shadow); + appearance: none; + + &:focus { + border-color: $form-select-focus-border-color; + outline: 0; + @if $enable-shadows { + box-shadow: $form-select-box-shadow, $form-select-focus-box-shadow; + } @else { + box-shadow: $form-select-focus-box-shadow; + } + + &::-ms-value { + // For visual consistency with other platforms/browsers, + // suppress the default white text on blue background highlight given to + // the selected option text when the (still closed) <select> receives focus + // in IE and (under certain conditions) Edge. + // See https://github.com/twbs/bootstrap/issues/19398. + color: $input-color; + background-color: $input-bg; + } + } + + &[multiple], + &[size]:not([size="1"]) { + height: auto; + padding-right: $form-select-padding-x; + background-image: none; + } + + &:disabled { + color: $form-select-disabled-color; + background-color: $form-select-disabled-bg; + } + + // Hides the default caret in IE11 + &::-ms-expand { + display: none; + } +} + +.form-select-sm { + height: $form-select-height-sm; + padding-top: $form-select-padding-y-sm; + padding-bottom: $form-select-padding-y-sm; + padding-left: $form-select-padding-x-sm; + @include font-size($form-select-font-size-sm); +} + +.form-select-lg { + height: $form-select-height-lg; + padding-top: $form-select-padding-y-lg; + padding-bottom: $form-select-padding-y-lg; + padding-left: $form-select-padding-x-lg; + @include font-size($form-select-font-size-lg); +} diff --git a/scss/_input-group.scss b/scss/forms/_input-group.scss index c4daddf0c4..099accecba 100644 --- a/scss/_input-group.scss +++ b/scss/forms/_input-group.scss @@ -12,45 +12,45 @@ width: 100%; > .form-control, - > .custom-select, - > .custom-file { + > .form-select, + > .form-file { position: relative; // For focus state's z-index flex: 1 1 0%; margin-bottom: 0; + .form-control, - + .custom-select, - + .custom-file { + + .form-select, + + .form-file { margin-left: -$input-border-width; } } // Bring the "active" form control to the top of surrounding elements > .form-control:focus, - > .custom-select:focus, - > .custom-file .custom-file-input:focus ~ .custom-file-label { + > .form-select:focus, + > .form-file .form-file-input:focus ~ .form-file-label { z-index: 3; } // Bring the custom file input above the label - > .custom-file .custom-file-input:focus { + > .form-file .form-file-input:focus { z-index: 4; } > .form-control, - > .custom-select { + > .form-select { &:not(:last-child) { @include border-right-radius(0); } &:not(:first-child) { @include border-left-radius(0); } } // Custom file inputs have more complex markup, thus requiring different // border-radius overrides. - > .custom-file { + > .form-file { display: flex; align-items: center; - &:not(:last-child) .custom-file-label { @include border-right-radius(0); } - &:not(:first-child) .custom-file-label { @include border-left-radius(0); } + &:not(:last-child) .form-file-label { @include border-right-radius(0); } + &:not(:first-child) .form-file-label { @include border-left-radius(0); } } } @@ -123,12 +123,12 @@ // manipulation. .input-group-lg > .form-control:not(textarea), -.input-group-lg > .custom-select { +.input-group-lg > .form-select { height: $input-height-lg; } .input-group-lg > .form-control, -.input-group-lg > .custom-select, +.input-group-lg > .form-select, .input-group-lg > .input-group-prepend > .input-group-text, .input-group-lg > .input-group-append > .input-group-text, .input-group-lg > .input-group-prepend > .btn, @@ -140,12 +140,12 @@ } .input-group-sm > .form-control:not(textarea), -.input-group-sm > .custom-select { +.input-group-sm > .form-select { height: $input-height-sm; } .input-group-sm > .form-control, -.input-group-sm > .custom-select, +.input-group-sm > .form-select, .input-group-sm > .input-group-prepend > .input-group-text, .input-group-sm > .input-group-append > .input-group-text, .input-group-sm > .input-group-prepend > .btn, @@ -156,9 +156,9 @@ @include border-radius($input-border-radius-sm); } -.input-group-lg > .custom-select, -.input-group-sm > .custom-select { - padding-right: $custom-select-padding-x + $custom-select-indicator-padding; +.input-group-lg > .form-select, +.input-group-sm > .form-select { + padding-right: $form-select-padding-x + $form-select-indicator-padding; } diff --git a/scss/forms/_labels.scss b/scss/forms/_labels.scss new file mode 100644 index 0000000000..1a4ea8c5c8 --- /dev/null +++ b/scss/forms/_labels.scss @@ -0,0 +1,27 @@ +// +// Labels +// + +// For use with horizontal and inline forms, when you need the label (or legend) +// text to align with the form controls. +.col-form-label { + padding-top: calc(#{$input-padding-y} + #{$input-border-width}); + padding-bottom: calc(#{$input-padding-y} + #{$input-border-width}); + margin-bottom: 0; // Override the `<label>/<legend>` default + @include font-size(inherit); // Override the `<legend>` default + line-height: $input-line-height; +} + +.col-form-label-lg { + padding-top: calc(#{$input-padding-y-lg} + #{$input-border-width}); + padding-bottom: calc(#{$input-padding-y-lg} + #{$input-border-width}); + @include font-size($input-font-size-lg); + line-height: $input-line-height-lg; +} + +.col-form-label-sm { + padding-top: calc(#{$input-padding-y-sm} + #{$input-border-width}); + padding-bottom: calc(#{$input-padding-y-sm} + #{$input-border-width}); + @include font-size($input-font-size-sm); + line-height: $input-line-height-sm; +} diff --git a/scss/forms/_layout.scss b/scss/forms/_layout.scss new file mode 100644 index 0000000000..f65b5493f2 --- /dev/null +++ b/scss/forms/_layout.scss @@ -0,0 +1,101 @@ +// Form grid +// +// Special replacement for our grid system's `.row` for tighter form layouts. + +@if $enable-grid-classes { + .form-row { + display: flex; + flex-wrap: wrap; + margin-right: -$form-grid-gutter-width / 2; + margin-left: -$form-grid-gutter-width / 2; + + > .col, + > [class*="col-"] { + padding-right: $form-grid-gutter-width / 2; + padding-left: $form-grid-gutter-width / 2; + } + } +} + +// Inline forms +// +// Make forms appear inline(-block) by adding the `.form-inline` class. Inline +// forms begin stacked on extra small (mobile) devices and then go inline when +// viewports reach <768px. +// +// Requires wrapping inputs and labels with `.form-group` for proper display of +// default HTML form controls and our custom form controls (e.g., input groups). + +.form-inline { + display: flex; + flex-flow: row wrap; + align-items: center; // Prevent shorter elements from growing to same height as others (e.g., small buttons growing to normal sized button height) + + // Because we use flex, the initial sizing of checkboxes is collapsed and + // doesn't occupy the full-width (which is what we want for xs grid tier), + // so we force that here. + .form-check { + width: 100%; + } + + // Kick in the inline + @include media-breakpoint-up(sm) { + label { + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 0; + } + + // Inline-block all the things for "inline" + .form-group { + display: flex; + flex: 0 0 auto; + flex-flow: row wrap; + align-items: center; + margin-bottom: 0; + } + + // Allow folks to *not* use `.form-group` + .form-control { + display: inline-block; + width: auto; // Prevent labels from stacking above inputs in `.form-group` + vertical-align: middle; + } + + // Make static controls behave like regular ones + .form-control-plaintext { + display: inline-block; + } + + .input-group, + .form-select { + width: auto; + } + + // Remove default margin on radios/checkboxes that were used for stacking, and + // then undo the floating of radios and checkboxes to match. + .form-check { + display: flex; + align-items: center; + justify-content: center; + width: auto; + padding-left: 0; + } + .form-check-input { + position: relative; + flex-shrink: 0; + margin-top: 0; + margin-right: $form-check-input-margin-x; + margin-left: 0; + } + + .custom-control { + align-items: center; + justify-content: center; + } + .custom-control-label { + margin-bottom: 0; + } + } +} diff --git a/scss/forms/_validation.scss b/scss/forms/_validation.scss new file mode 100644 index 0000000000..d15e20899e --- /dev/null +++ b/scss/forms/_validation.scss @@ -0,0 +1,10 @@ +// Form validation +// +// Provide feedback to users when form field values are valid or invalid. Works +// primarily for client-side validation via scoped `:invalid` and `:valid` +// pseudo-classes but also includes `.is-invalid` and `.is-valid` classes for +// server-side validation. + +@each $state, $data in $form-validation-states { + @include form-validation-state($state, map-get($data, color), map-get($data, icon)); +} diff --git a/scss/mixins/_forms.scss b/scss/mixins/_forms.scss index 202663daa4..2001ae0e25 100644 --- a/scss/mixins/_forms.scss +++ b/scss/mixins/_forms.scss @@ -97,13 +97,13 @@ } } - .custom-select { + .form-select { @include form-validation-state-selector($state) { border-color: $color; @if $enable-validation-icons { - padding-right: $custom-select-feedback-icon-padding-right; - background: $custom-select-background, $icon $custom-select-bg no-repeat $custom-select-feedback-icon-position / $custom-select-feedback-icon-size; + padding-right: $form-select-feedback-icon-padding-right; + background: $form-select-background, $icon $form-select-bg no-repeat $form-select-feedback-icon-position / $form-select-feedback-icon-size; } &:focus { @@ -130,55 +130,36 @@ .form-check-input { @include form-validation-state-selector($state) { - ~ .form-check-label { - color: $color; + border-color: $color; + + &:checked { + @include gradient-bg(lighten($color, 10%)); } - ~ .#{$state}-feedback, - ~ .#{$state}-tooltip { - display: block; + &:focus { + box-shadow: 0 0 0 $input-focus-width rgba($color, .25); } - } - } - .custom-control-input { - @include form-validation-state-selector($state) { - ~ .custom-control-label { + ~ .form-check-label { color: $color; - - &::before { - border-color: $color; - } } ~ .#{$state}-feedback, ~ .#{$state}-tooltip { display: block; } - - &:checked { - ~ .custom-control-label::before { - border-color: lighten($color, 10%); - @include gradient-bg(lighten($color, 10%)); - } - } - - &:focus { - ~ .custom-control-label::before { - box-shadow: 0 0 0 $input-focus-width rgba($color, .25); - } - - &:not(:checked) ~ .custom-control-label::before { - border-color: $color; - } - } + } + } + .form-check-inline .form-check-input { + ~ .#{$state}-feedback { + margin-left: .5em; } } // custom file - .custom-file-input { + .form-file-input { @include form-validation-state-selector($state) { - ~ .custom-file-label { + ~ .form-file-label { border-color: $color; } @@ -188,7 +169,7 @@ } &:focus { - ~ .custom-file-label { + ~ .form-file-label { border-color: $color; box-shadow: 0 0 0 $input-focus-width rgba($color, .25); } |