| @use "../config" as *; |
| @use "../functions" as *; |
| @use "../mixins/border-radius" as *; |
| @use "../mixins/focus-ring" as *; |
| @use "form-variables" as *; |
| @use "../tooltip" as *; // bring in tooltip variables |
| |
| // 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. |
| |
| // This mixin uses an `if()` technique to be compatible with Dart Sass |
| // See https://github.com/sass/sass/issues/1873#issuecomment-152293725 for more details |
| |
| // scss-docs-start form-validation-mixins |
| @mixin form-validation-state-selector($state) { |
| @if ($state == "valid" or $state == "invalid") { |
| .was-validated #{if(sass(&): "&"; else: "")}:#{$state}, |
| #{if(sass(&): "&"; else: "")}.is-#{$state} { |
| @content; |
| } |
| } @else { |
| #{if(sass(&): "&"; else: "")}.is-#{$state} { |
| @content; |
| } |
| } |
| } |
| |
| @mixin form-validation-state( |
| $state, |
| $color, |
| $icon, |
| $tooltip-color: color-contrast($color), |
| $tooltip-bg-color: rgba($color, $form-feedback-tooltip-opacity), |
| $focus-ring-color: null, // mdo-do: fix |
| $border-color: $color |
| ) { |
| .#{$state}-feedback { |
| display: none; |
| width: 100%; |
| margin-top: $form-feedback-margin-top; |
| font-size: $form-feedback-font-size; |
| font-style: $form-feedback-font-style; |
| color: $color; |
| } |
| |
| .#{$state}-tooltip { |
| position: absolute; |
| top: 100%; |
| z-index: 5; |
| display: none; |
| max-width: 100%; // Contain to parent when possible |
| padding: $form-feedback-tooltip-padding-y $form-feedback-tooltip-padding-x; |
| margin-top: .1rem; |
| font-size: $form-feedback-tooltip-font-size; |
| line-height: $form-feedback-tooltip-line-height; |
| color: $tooltip-color; |
| background-color: $tooltip-bg-color; |
| @include border-radius($form-feedback-tooltip-border-radius); |
| } |
| |
| @include form-validation-state-selector($state) { |
| ~ .#{$state}-feedback, |
| ~ .#{$state}-tooltip { |
| display: block; |
| } |
| } |
| |
| .form-control { |
| @include form-validation-state-selector($state) { |
| border-color: $border-color; |
| |
| @if $enable-validation-icons { |
| padding-inline-end: calc(var(--control-padding-x) * 3.5); |
| background-image: escape-svg($icon); |
| background-repeat: no-repeat; |
| background-position: right var(--control-padding-x) center; |
| background-size: 1rem; |
| } |
| |
| &:focus-visible { |
| @include focus-ring(true, $color: $focus-ring-color); |
| border-color: $border-color; |
| } |
| } |
| |
| &::-webkit-contacts-auto-fill-button { |
| @if $enable-validation-icons { |
| // margin-inline-end: calc(var(--control-padding-x) * 3); |
| } |
| } |
| } |
| |
| // stylelint-disable-next-line selector-no-qualifying-type |
| textarea.form-control { |
| @include form-validation-state-selector($state) { |
| @if $enable-validation-icons { |
| // padding-inline-end: $input-height-inner; |
| background-position: right var(--control-padding-x) top var(--control-padding-x); |
| // background-position: top $input-height-inner-quarter right $input-height-inner-quarter; |
| } |
| } |
| } |
| |
| .form-control-color { |
| @include form-validation-state-selector($state) { |
| @if $enable-validation-icons { |
| // width: calc($form-color-width + $input-height-inner); |
| } |
| } |
| } |
| |
| .form-check-input { |
| @include form-validation-state-selector($state) { |
| border-color: $border-color; |
| |
| &:checked { |
| background-color: $color; |
| } |
| |
| &:focus { |
| // box-shadow: $focus-box-shadow; |
| } |
| |
| ~ .form-check-label { |
| color: $color; |
| } |
| } |
| } |
| .form-check-inline .form-check-input { |
| ~ .#{$state}-feedback { |
| margin-inline-start: .5em; |
| } |
| } |
| |
| .input-group { |
| > .form-control:not(:focus), |
| > .form-select:not(:focus), |
| > .form-floating:not(:focus-within) { |
| @include form-validation-state-selector($state) { |
| @if $state == "valid" { |
| z-index: 3; |
| } @else if $state == "invalid" { |
| z-index: 4; |
| } |
| } |
| } |
| } |
| } |
| // scss-docs-end form-validation-mixins |
| |
| @layer components { |
| // scss-docs-start form-validation-states-loop |
| @each $state, $data in $form-validation-states { |
| @include form-validation-state($state, $data...); |
| } |
| // scss-docs-end form-validation-states-loop |
| } |