@function formDefaults($form) { // First, find variables that are referenced below $form: map-merge(( "input-background": #fdfdfd, "input-border-color--active": $primary, "input-padding": 13px 19px, "toggle-height": 1.8em, ), $form); @return map-merge(( // Error "error-font-size": 0.85rem, // Input "input-background": map-get($form, "input-background"), "input-background--active": map-get($form, "input-background"), "input-background--invalid": map-get($form, "input-background"), "input-border-color": #efefef, "input-border-color--active": map-get($form, "input-border-color--active"), "input-border-color--invalid": $danger, "input-border-radius": 4px, "input-border-width": 2px, "input-box-shadow": map-get($form, "input-box-shadow"), "input-box-shadow--active": map-get($form, "input-box-shadow"), "input-box-shadow--invalid": map-get($form, "input-box-shadow"), "input-color": $text, "input-color--invalid": $text, "input-font-family": $body-font-family, "input-font-size": 16px, // 0.95rem, "input-font-weight": inherit, "input-icon-width": 18px, "input-margin-bottom": 1.5rem, "input-padding": map-get($form, "input-padding"), "input-placeholder-color": rgba($text, 0.5), // Label "label-color": $text-light, "label-font-size": 0.85rem, "label-margin-bottom": 0.45rem, // Textarea "textarea-min-height": 7em, "textarea-padding": map-get($form, "input-padding"), // Variable inputs "variable-color": darken(map-get($form, "input-background"), 12%), "variable-color--active": map-get($form, "input-border-color--active"), "checkbox-height": 20px, // determines width "checkbox-inner-height": 10px, // determines width "checkbox-padding-left": 12px, "checkbox-padding-right": 16px, "toggle-height": map-get($form, "toggle-height"), "toggle-width": map-get($form, "toggle-height") * 1.8, ), $form); } @function empty-map($x: x) { @return map-remove(($x:$x), $x); } // Note that in SASS, a list with a single map == a map @if type-of($forms) == 'map' { $forms: append((), $forms); } @if (length($forms) == 0) { $forms: append($forms, empty-map()); } @for $i from 1 through length($forms) { $form: nth($forms, $i); @if type-of($form) != map { $form: empty-map(); } $map: formDefaults($form); $class: ".form-#{$i}"; @if $i == 1 { $class: ".form"; } #{$class} { /* ---- Main ------------------------- */ input, select, textarea, .input, .vs__dropdown-toggle { width: 100%; padding: map-get($map, "input-padding"); font-family: map-get($map, "input-font-family"); color: map-get($map, "input-color"); font-size: map-get($map, "input-font-size"); font-weight: map-get($map, "input-font-weight"); line-height: 1.5rem; background: map-get($map, "input-background"); box-shadow: 0 0 0 map-get($map, "input-border-width") map-get($map, "input-border-color") inset, map-get($map, "input-box-shadow"); border: 0; box-sizing: border-box; border-radius: map-get($map, "input-border-radius"); vertical-align: top; transition: background-color ease 0.2s, border-color ease 0.2s, box-shadow ease 0.2s; -webkit-appearance: none; } .input, .input-grp, .radio-grp, .checkbox-grp, .toggle-grp { margin-bottom: map-get($map, "input-margin-bottom"); } input[type="password"]:not(:placeholder-shown) { letter-spacing: 1px; } input[type="file"] { // padding: 10px 19px 11px; } textarea { padding: map-get($map, "textarea-padding"); max-height: 40em; min-height: map-get($map, "textarea-min-height"); resize: vertical; } .input-grp, .radio-grp, .checkbox-grp, .toggle-grp { text-align: left; position: relative; } /* ---- Placeholder & autofill ------- */ ::-webkit-input-placeholder { color: map-get($map, "input-placeholder-color"); } input:-webkit-autofill { -webkit-text-fill-color: map-get($map, "input-color"); -webkit-box-shadow: 0 0 0 map-get($map, "input-border-width") map-get($map, "input-border-color") inset, 0 0 0 1000px map-get($map, "input-background") inset, map-get($map, "input-box-shadow"); } input:-webkit-autofill::first-line { font-family: map-get($map, "input-font-family"); font-size: map-get($map, "input-font-size"); font-weight: map-get($map, "input-font-weight"); } /* ---- Elements --------------------- */ /* Input + button element */ .input-btn { display: flex; } .input-btn input { flex: 1; border-top-right-radius: 0; border-bottom-right-radius: 0; } .input-btn .btn { width: auto !important; min-width: 0; font-size: 0.8em; line-height: 1.5rem; border-radius: map-get($map, "input-border-radius"); padding: map-get($map, "input-padding"); margin-left: -5px; border-top-left-radius: 0; border-bottom-left-radius: 0; } /* Form error */ .form-error { display: none; color: $danger; } .toggle-grp .form-error, .checkbox-grp .form-error, .radio-grp .form-error, .input-grp .form-error { font-size: map-get($map, "error-font-size"); line-height: 1.4em; } .form-error:empty { margin: 0 !important; } .is-invalid .form-error, &.is-invalid .form-error, .form-error.form-error-show { display: block; } /* ---- Labels ----------------------- */ label, .label, .label-right { display: inline-block; vertical-align: top; font-size: map-get($map, "label-font-size"); line-height: 1.4em; margin-bottom: 0.45em; cursor: pointer; user-select: none; } label, .label { /* matches util.errorElement */ transition: opacity 0.15s ease, color 0.25s ease, text-decoration-color 0.25s ease; } label, .label, .text-label { color: map-get($map, "label-color"); text-decoration-color: map-get($map, "label-color"); } label.invalid-out { //opacity: 0.2; } label.invalid-in { //opacity: 1; color: $danger; } .label-right, a.label-right { display: block; float: right; margin-right: 1px; } .label-bottom { position: absolute; right: 0; bottom: 0; } /* Floating labels */ .has-float-label input + label, .has-float-label select + label, .has-float-label textarea + label { position: absolute; left: 0; top: 0; cursor: text; color: map-get($map, "label-color"); font-size: map-get($map, "label-font-size"); opacity: 0; transform: translateY(3px); transition: transform 0.2s, opacity 0.2s; } .has-float-label input:not(:placeholder-shown) + *, .has-float-label select:not(:placeholder-shown) + *, .has-float-label textarea:not(:placeholder-shown) + *, .has-float-label input:-webkit-autofill + * { transform: translateY(0px); opacity: 1; } /* ---- Icons ------------------------ */ $ip: map-get($map, "input-padding"); $ip-left: null; $ip-right: null; @if length($ip) > 3 { $ip-left: nth($ip, 4); $ip-right: nth($ip, 2); } @else if length($ip) > 1 { $ip-left: nth($ip, 2); $ip-right: nth($ip, 2); } @else { $ip-left: $ip; $ip-right: $ip; } .icon-left, .icon-right { position: absolute; top: 0px; bottom: 0px; width: map-get($map, "input-icon-width"); pointer-events: none; align-items: center; display: inline-flex; justify-content: center; } .has-icon-left { position: relative; input, select, .input, .vs__dropdown-toggle { padding-left: calc(#{$ip-left} - 2px + #{map-get($map, "input-icon-width")} + 0.8em); } .icon-left { left: calc(#{$ip-left} - 2px); } } .has-icon-right { position: relative; input, select, .input, .vs__dropdown-toggle { padding-right: calc(#{$ip-right} - 2px + #{map-get($map, "input-icon-width")} + 0.4em); } .icon-right { right: calc(#{$ip-right} - 2px); } } /* ---- Select ----------------------- */ select, .vs__dropdown-toggle { background-image: url("data:image/svg+xml;utf8,"); appearance: none; background-repeat: no-repeat; background-size: auto 7px; background-position: right 17px center; transition: all 200ms ease; } /* ---- Variable inputs -------------- */ .radio-grp, .checkbox-grp { $checkbox-width: map-get($map, "checkbox-height"); $checkbox-inner-width: map-get($map, "checkbox-inner-height"); input { position: absolute; left: -9999px; } label { display: block; } .has-tooltip { display: inline; padding: 0; } input + label { position: relative; display: inline-block; padding: map-get($map, "input-padding"); padding-left: $checkbox-width + map-get($map, "checkbox-padding-left"); //0.8em; padding-right: map-get($map, "checkbox-padding-right"); user-select: none; margin-bottom: 0; } input + label:before { content: ""; position: absolute; left: 0; top: 50%; width: $checkbox-width; height: map-get($map, "checkbox-height"); margin-top: -(map-get($map, "checkbox-height") / 2); background: map-get($map, "input-background"); border: 2px solid map-get($map, "variable-color"); border-radius: 3px; box-sizing: border-box; transition: all 0.2s ease; } input + label:after { content: ""; position: absolute; left: 0; top: 50%; width: $checkbox-inner-width; height: map-get($map, "checkbox-inner-height"); margin-left: ($checkbox-width - $checkbox-inner-width) / 2; margin-top: -(map-get($map, "checkbox-inner-height") / 2); border-radius: 3px; transition: all 0.2s ease; } input:checked + label:before { border-color: map-get($map, "variable-color--active"); } input:checked + label:after { background-color: map-get($map, "variable-color--active"); } } .radio-grp input + label:before, .radio-grp input + label:after { border-radius: 100% !important; } .toggle-grp { input { position: absolute; left: -9999px; } label { display: block; } input + label { position: relative; display: inline-block; min-height: map-get($map, "toggle-height"); //1em;height: padding: map-get($map, "input-padding"); padding-left: map-get($map, "toggle-width") + 0.8em; padding-right: 1.2em; margin-bottom: 0; user-select: none; } input + label:before, input + label:after { content: ""; position: absolute; left: 0; top: 50%; margin-top: -(map-get($map, "toggle-height")/2); background: map-get($map, "variable-color"); border-radius: map-get($map, "toggle-height"); width: map-get($map, "toggle-width"); height: map-get($map, "toggle-height"); box-sizing: border-box; transition: all 0.2s ease; } input + label:after { width: map-get($map, "toggle-height"); border: 2px solid transparent; border-color: transparent; background-color: #fff; background-clip: content-box; } input:checked + label:before { background-color: map-get($map, "variable-color--active"); } input:checked + label:after { left: map-get($map, "toggle-width") - map-get($map, "toggle-height"); } &.has-no-label input + label { padding-left: map-get($map, "toggle-width"); padding-right: 0; padding-top: 0; padding-bottom: 0; } } /* ---- States ----------------------- */ input:active, input:focus, select:active, select:focus, textarea:active, textarea:focus, .vs--open .vs__dropdown-toggle { outline: 0; box-shadow: 0 0 0 map-get($map, "input-border-width") map-get($map, "input-border-color--active") inset, map-get($map, "input-box-shadow--active"); background-color: map-get($map, "input-background--active"); &:-webkit-autofill { -webkit-box-shadow: 0 0 0 map-get($map, "input-border-width") map-get($map, "input-border-color--active") inset, 0 0 0 1000px map-get($map, "input-background--active") inset, map-get($map, "input-box-shadow--active"); } } input.is-invalid, select.is-invalid, textarea.is-invalid, .vs__dropdown-toggle.is-invalid, .input-grp.is-invalid input, .input-grp.is-invalid select, .input-grp.is-invalid textarea, .input-grp.is-invalid .vs__dropdown-toggle { color: map-get($map, "input-color--invalid"); box-shadow: 0 0 0 map-get($map, "input-border-width") $danger inset, map-get($map, "input-box-shadow--invalid"); // doesnt work for dropdown/toggle background-color: map-get($map, "input-background--invalid"); animation: shake 0.4s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; transform: translate3d(0, 0, 0); backface-visibility: hidden; &:-webkit-autofill { -webkit-text-fill-color: map-get($map, "input-color--invalid"); -webkit-box-shadow: 0 0 0 map-get($map, "input-border-width") map-get($map, "input-border-color--invalid") inset, 0 0 0 1000px map-get($map, "input-background--invalid") inset, map-get($map, "input-box-shadow--invalid"); } } input[type="radio"].is-invalid + label, input[type="checkbox"].is-invalid + label, input[type="radio"].is-invalid + label, input[type="checkbox"].is-invalid + label { animation: shake 0.4s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; transform: translate3d(0, 0, 0); backface-visibility: hidden; color: #7b1a1a; } input[type="radio"].is-invalid + label:before, input[type="checkbox"].is-invalid + label:before { border-color: $danger; background-color: map-get($map, "input-background--invalid"); } textarea:disabled, input:disabled { background-color: #f7f7f7; color: #a5a5a5; } /* ---- Miscellaneous ---------------- */ /* Stop autofill background flash */ .onloading input, .onloading select, .onloading textarea, .onloading .input, .onloading .vs__dropdown-toggle { transition: none; } /* Animations */ @keyframes shake { 30% { transform: translate3d(-1px, 0, 0); } 60% { transform: translate3d(1px, 0, 0); } 80% { transform: translate3d(0px, 0, 0); } } /* Prevent input zooming */ @media (max-width: 550px) { .form-mobile { input[type="color"], input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="email"], input[type="month"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="time"], input[type="url"], input[type="week"], select, textarea { font-size: 16px; letter-spacing: 0; } ::-moz-placeholder { font-size: 16px; letter-spacing: 0; } :-ms-input-placeholder { font-size: 16px; letter-spacing: 0; } ::-webkit-input-placeholder { font-size: 16px; letter-spacing: 0; } } } } }