Bug 1427961 - Implement error tooltip styling. r?mattn draft
authorJared Wein <jwein@mozilla.com>
Wed, 20 Jun 2018 23:27:56 -0400
changeset 812654 6565932ba4a07413d842c2dce33be58456e86e95
parent 812653 d6d4289c8d9f7e228aeb7d5c6d0bdde23c16ac1e
push id114619
push userbmo:jaws@mozilla.com
push dateFri, 29 Jun 2018 18:32:54 +0000
reviewersmattn
bugs1427961
milestone63.0a1
Bug 1427961 - Implement error tooltip styling. r?mattn MozReview-Commit-ID: CBNUhIRGD1A
browser/components/payments/res/containers/address-form.css
browser/components/payments/res/containers/address-form.js
--- a/browser/components/payments/res/containers/address-form.css
+++ b/browser/components/payments/res/containers/address-form.css
@@ -19,26 +19,57 @@ address-form[address-fields] #postal-cod
 address-form[address-fields] #country-container,
 address-form[address-fields]:not([address-fields~='email']) #email-container,
 address-form[address-fields]:not([address-fields~='tel']) #tel-container {
   /* !important is needed because autofillEditForms.js sets
      inline styles on the form fields with display: flex; */
   display: none !important;
 }
 
-address-form .error input,
-address-form .error select,
-address-form .error textarea {
-  border: 1px solid #ce001a;
-}
-
-label[required] > span::after {
+label[required] > span:first-of-type::after {
   /* The asterisk should be localized, bug 1472278 */
   content: "*";
 }
 
 .error-text:not(:empty) {
+  color: #fff;
+  background-color: #d70022;
   border-radius: 2px;
-  background-color: #ce001a;
-  color: #f9e6e9;
-  padding: .1em .5em;
-  margin-inline-start: .1em;
+  /* The padding-top and padding-bottom are referenced by address-form.js */
+  padding: 5px 12px;
+  position: absolute;
+  z-index: 1;
+  pointer-events: none;
+}
+
+body[dir="ltr"] .error-text {
+  left: 3px;
+}
+
+body[dir="rtl"] .error-text {
+  right: 3px;
 }
+
+:-moz-any(input, textarea, select):focus + .error-text:not(:empty)::before {
+  background-color: #d70022;
+  top: -7px;
+  content: '.';
+  height: 16px;
+  position: absolute;
+  text-indent: -999px;
+  transform: rotate(45deg);
+  white-space: nowrap;
+  width: 16px;
+  z-index: -1
+}
+
+body[dir=ltr] .error-text::before {
+  left: 12px
+}
+
+body[dir=rtl] .error-text::before {
+  right: 12px
+}
+
+:-moz-any(input, textarea, select):not(:focus) + .error-text,
+:-moz-any(input, textarea, select):valid + .error-text {
+  display: none;
+}
--- a/browser/components/payments/res/containers/address-form.js
+++ b/browser/components/payments/res/containers/address-form.js
@@ -169,18 +169,40 @@ export default class AddressForm extends
       let span = container.querySelector(".error-text");
       if (!span) {
         span = document.createElement("span");
         span.className = "error-text";
         container.appendChild(span);
       }
       span.textContent = errorText;
     }
+
+    // Position the error messages all at once so layout flushes only once.
+    let formRect = this.form.getBoundingClientRect();
+    let errorSpanData = [...this.form.querySelectorAll(".error-text:not(:empty)")].map(span => {
+      let relatedInput = span.previousElementSibling;
+      let relatedRect = relatedInput.getBoundingClientRect();
+      return {
+        span,
+        top: relatedRect.bottom,
+        left: relatedRect.left - formRect.left,
+        right: formRect.right - relatedRect.right,
+      };
+    });
+    let isRTL = this.form.matches(":dir(rtl)");
+    for (let data of errorSpanData) {
+      // Subtract 10px for the padding-top and padding-bottom.
+      data.span.style.top = (data.top - 10) + "px";
+      if (isRTL) {
+        data.span.style.right = data.right + "px";
+      } else {
+        data.span.style.left = data.left + "px";
+      }
+    }
   }
-
   handleEvent(event) {
     switch (event.type) {
       case "click": {
         this.onClick(event);
         break;
       }
     }
   }