Browse Source

Re-implement base form field styles based on new page editor designs

Co-authored-by: LB Johnston <mail@lb.ee>
Thibaud Colas 2 years ago
parent
commit
af9b16e93d
63 changed files with 691 additions and 1014 deletions
  1. 1 0
      client/scss/_tools.scss
  2. 4 0
      client/scss/components/_button-select.scss
  3. 6 3
      client/scss/components/_button.scss
  4. 55 0
      client/scss/components/_footer.scss
  5. 1 372
      client/scss/components/_forms.scss
  6. 11 0
      client/scss/components/_search-bar.scss
  7. 5 0
      client/scss/components/forms/_daterange.scss
  8. 17 0
      client/scss/components/forms/_drop-zone.scss
  9. 23 0
      client/scss/components/forms/_error-message.scss
  10. 110 0
      client/scss/components/forms/_field-comment-control.scss
  11. 20 0
      client/scss/components/forms/_file.scss
  12. 4 0
      client/scss/components/forms/_help.scss
  13. 32 0
      client/scss/components/forms/_input-base.scss
  14. 30 0
      client/scss/components/forms/_input-text.scss
  15. 18 0
      client/scss/components/forms/_radio-checkbox-multiple.scss
  16. 62 0
      client/scss/components/forms/_radio-checkbox.scss
  17. 4 0
      client/scss/components/forms/_required-mark.scss
  18. 35 0
      client/scss/components/forms/_select.scss
  19. 24 15
      client/scss/components/forms/_switch.scss
  20. 23 0
      client/scss/components/forms/_tagit.scss
  21. 30 0
      client/scss/components/forms/_title.scss
  22. 15 1
      client/scss/core.scss
  23. 18 0
      client/scss/elements/_elements.scss
  24. 0 216
      client/scss/elements/_forms.scss
  25. 2 4
      client/scss/elements/_typography.scss
  26. 0 7
      client/scss/layouts/_home.scss
  27. 28 35
      client/scss/layouts/_login.scss
  28. 0 183
      client/scss/layouts/_page-editor.scss
  29. 13 6
      client/scss/settings/_variables.scss
  30. 15 0
      client/scss/tools/_functions.general.scss
  31. 0 2
      client/src/components/CommentApp/main.scss
  32. 20 41
      client/src/components/Draftail/Draftail.scss
  33. 1 2
      client/src/components/Draftail/EditorFallback/EditorFallback.scss
  34. 2 6
      client/src/components/Draftail/index.js
  35. 0 4
      client/src/components/PageExplorer/PageExplorerHeader.tsx
  36. 1 1
      client/src/components/StreamField/StreamField.scss
  37. 0 1
      client/src/components/StreamField/blocks/FieldBlock.js
  38. 0 4
      client/src/components/StreamField/blocks/__snapshots__/FieldBlock.test.js.snap
  39. 0 18
      client/src/components/StreamField/blocks/__snapshots__/ListBlock.test.js.snap
  40. 0 15
      client/src/components/StreamField/blocks/__snapshots__/StreamBlock.test.js.snap
  41. 2 8
      client/src/components/StreamField/blocks/__snapshots__/StructBlock.test.js.snap
  42. 1 1
      client/src/entrypoints/admin/expanding-formset.test.js
  43. 1 5
      client/src/entrypoints/contrib/typed_table_block/__snapshots__/typed_table_block.test.js.snap
  44. 1 3
      docs/reference/pages/panels.md
  45. 1 0
      wagtail/admin/static_src/wagtailadmin/scss/panels/draftail.scss
  46. 1 1
      wagtail/admin/templates/wagtailadmin/account/password_reset/form.html
  47. 3 3
      wagtail/admin/templates/wagtailadmin/login.html
  48. 1 1
      wagtail/admin/templates/wagtailadmin/pages/confirm_delete.html
  49. 1 1
      wagtail/admin/templates/wagtailadmin/pages/confirm_unpublish.html
  50. 1 1
      wagtail/admin/templates/wagtailadmin/panels/help_panel.html
  51. 0 1
      wagtail/admin/templates/wagtailadmin/shared/collection_chooser.html
  52. 0 2
      wagtail/admin/templates/wagtailadmin/shared/field.html
  53. 0 2
      wagtail/admin/templates/wagtailadmin/shared/side_panels/preview.html
  54. 4 1
      wagtail/admin/templates/wagtailadmin/widgets/switch.html
  55. 3 3
      wagtail/contrib/forms/templates/wagtailforms/panels/form_responses_panel.html
  56. 0 1
      wagtail/contrib/modeladmin/templates/modeladmin/includes/search_form.html
  57. 1 1
      wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/includes/searchpromotion_form.html
  58. 0 1
      wagtail/contrib/settings/templates/wagtailsettings/edit.html
  59. 1 1
      wagtail/images/templates/wagtailimages/images/edit.html
  60. 1 3
      wagtail/images/templates/wagtailimages/images/index.html
  61. 11 11
      wagtail/test/demosite/models.py
  62. 24 24
      wagtail/test/testapp/models.py
  63. 3 3
      wagtail/users/templates/wagtailusers/groups/includes/formatted_permissions.html

+ 1 - 0
client/scss/_tools.scss

@@ -3,6 +3,7 @@ These are functions and mixins.
 No CSS should be produced by these files.
 */
 
+@import 'tools/functions.general';
 @import 'tools/functions.breakpoints';
 @import 'tools/mixins.breakpoints';
 @import 'tools/mixins.general';

+ 4 - 0
client/scss/components/_button-select.scss

@@ -12,6 +12,10 @@
       background-color: $color-teal;
       color: $color-white;
     }
+
+    @media (forced-colors: active) {
+      background-color: SelectedItem;
+    }
   }
 }
 

+ 6 - 3
client/scss/components/_button.scss

@@ -121,6 +121,7 @@
       top: 0;
       width: 3em;
       height: 100%;
+      box-sizing: content-box;
       text-align: center;
       // Remove once we drop support for Safari 14.
       // stylelint-disable-next-line property-disallowed-list
@@ -352,6 +353,7 @@
   font-size: 0; // unavoidable duplication of setting in icons.scss
   width: 1.8rem;
   height: 1.8rem;
+  box-sizing: content-box;
 
   &:before {
     line-height: 1.7em;
@@ -384,6 +386,7 @@
     font-size: initial;
     @include svg-icon(1rem, middle);
     padding: 0.5em;
+    box-sizing: content-box;
   }
 
   &.button-small {
@@ -506,16 +509,16 @@ button {
 
 .multiple {
   padding: 0;
-  max-width: 1024px - 50px;
   overflow: hidden;
 
   > li {
-    @include row();
+    @include row(1.5em);
     border-radius: 2px;
     position: relative;
     overflow: hidden;
     background-color: $color-white;
-    padding: 1em 10em 1em 1.5em; // 10em padding leaves room for controls
+    padding: 1em 1.5em;
+    padding-inline-end: 10em; // 10em padding leaves room for controls
     margin-bottom: 1em;
     border: 1px solid theme('colors.grey.100');
   }

+ 55 - 0
client/scss/components/_footer.scss

@@ -166,3 +166,58 @@
     }
   }
 }
+
+// Footer control bar for performing actions on the page
+footer .actions,
+footer .preview {
+  .button {
+    @apply w-leading-none w-inline-flex w-items-center;
+
+    .icon {
+      margin-inline-end: theme('spacing.2');
+    }
+  }
+}
+
+footer .actions {
+  .button {
+    font-weight: 600;
+    text-overflow: ellipsis;
+  }
+}
+
+footer .preview {
+  button,
+  .button {
+    padding: 0 1em;
+
+    @include media-breakpoint-down(xs) {
+      width: 100%;
+      margin-top: 2px;
+      margin-bottom: 2px;
+      height: 3em;
+    }
+
+    background-color: $color-grey-2;
+    border-color: $color-grey-2;
+  }
+
+  .dropdown {
+    input[type='button'],
+    input[type='submit'],
+    button,
+    .button {
+      background-color: $color-grey-2;
+      border-color: $color-grey-2;
+    }
+
+    ul,
+    .dropdown-toggle {
+      background-color: $color-grey-2;
+    }
+
+    &.open > .button + .dropdown-toggle {
+      background-color: $color-grey-2;
+    }
+  }
+}

+ 1 - 372
client/scss/components/_forms.scss

@@ -1,180 +1,8 @@
 @use 'sass:map';
 @use 'sass:math';
-// stylelint-disable scss/comment-no-empty
-// These are the generic stylings for forms of any type.
-// If you're styling something specific to the page editing interface,
-// it probably ought to go in layouts/page-editor.scss
-
-// TODO: mixin,
-// These these styles are currently in elements
-// but the ones for the class should be here
-//
-// label,
-// .label {
-//     font-weight: bold;
-//     color: $color-grey-1;
-//     font-size: 1.1em;
-//     display: block;
-//     padding: 0 0 0.8em;
-//     margin: 0;
-//     line-height: 1.3em;
-//
-//     .checkbox &,
-//     .radio & {
-//         display: inline;
-//     }
-// }
-.plain-checkbox-label {
-  // cancel heavy / floated label styles, for labels that should appear inline against checkboxes
-
-  float: none;
-  color: inherit;
-  font-weight: inherit;
-  font-size: inherit;
-}
-
-// TODO: mixin,
-// These these styles are currently in elements
-// but the ones for the classes should be here
-//
-// input,
-// textarea,
-// select,
-// .tagit {
-//     appearance: none;
-//     box-sizing: border-box;
-//     border-radius: 6px;
-//     width: 100%;
-//     font-family: $font-sans;
-//     border: 1px solid $color-input-border;
-//     padding: 0.9em 1.2em;
-//     background-color: $color-fieldset-hover;
-//     color: $color-text-input;
-//     font-size: 1.2em;
-//     font-weight: 300;
-//
-//     &:hover {
-//         background-color: $color-white;
-//     }
-//
-//     &:focus {
-//         background-color: $color-input-focus;
-//         border-color: $color-input-focus-border;
-//     }
-//
-//     &:disabled,
-//     &[disabled],
-//     &:disabled:hover,
-//     &[disabled]:hover {
-//         background-color: inherit;
-//         cursor: default;
-//         color: $color-grey-4;
-//     }
-// }
-
-// select boxes
-.collection_choice_field .input,
-.choice_field .input,
-.model_choice_field .input,
-.typed_choice_field .input {
-  position: relative;
-
-  // Add select arrow back on browsers where native ui has been removed
-  select ~ span:after {
-    border-radius: 0 6px 6px 0;
-    z-index: 0;
-    position: absolute;
-    inset-inline-end: 0;
-    top: 1px;
-    bottom: 0;
-    width: 1.5em;
-    font-family: $font-wagtail-icons;
-    content: map.get($icons, 'arrow-down'); // UI-Redesign: to be removed
-    border: 1px solid $color-input-border;
-    border-width: 0 0 0 1px;
-    text-align: center;
-    line-height: 1.4em;
-    font-size: 3em;
-    pointer-events: none;
-    color: $color-grey-3;
-    margin: 0 1px 1px 0;
-
-    .ie & {
-      display: none;
-    }
-  }
-
-  // Override default select padding so the chevron will overlap with long option text
-  select {
-    padding-inline-end: 5em;
-  }
-}
-
-// Other text
-.help,
-.error-message {
-  border: 1px solid transparent; // ensure visible separation in Windows High Contrast mode
-  font-size: 0.85em;
-  font-weight: normal;
-  margin: 0.5em 0 0;
-}
-
-.error-message {
-  font-size: 1em;
-  font-weight: bold;
-  color: theme('colors.critical.200');
-
-  @media (forced-colors: $media-forced-colours) {
-    forced-color-adjust: none;
-  }
-
-  // UI-Redesign: to be added via js and styled here
-  &::before {
-    font-family: $font-wagtail-icons;
-    vertical-align: -10%;
-    content: map.get($icons, 'cross');
-  }
-}
-
-.help {
-  color: $color-grey-2;
-}
-
-fieldset:hover > .help,
-.field.focused + .help,
-.field:focus + .help,
-.field:hover + .help,
-li.focused > .help {
-  opacity: 1;
-}
-
-.required .field > label:after,
-label.required:after {
-  content: '*';
-  color: theme('colors.critical.200');
-  font-weight: bold;
-  display: inline-block;
-  margin-inline-start: 0.5em;
-  line-height: 1em;
-  font-size: 13px;
-}
-
-.error input,
-.error textarea,
-.error select,
-.error .tagit {
-  border-color: theme('colors.critical.200');
-  background-color: $color-input-error-bg;
-}
 
 // Layouts for particular kinds of of fields
 
-// permanently show checkbox/radio help as they have no focus state
-.boolean_field .help,
-.radio .help {
-  opacity: 1;
-}
-
 // This is expected to go on the parent of the input/select/textarea
 // so in most cases .input
 .iconfield, // generic
@@ -208,10 +36,7 @@ label.required:after {
     }
   }
 
-  input:not([type='radio']),
-  input:not([type='checkbox']),
-  input:not([type='submit']),
-  input:not([type='button']) {
+  input {
     padding-inline-start: 2.5em;
   }
 
@@ -261,31 +86,6 @@ label.required:after {
   }
 }
 
-.daterange_field {
-  input:last-of-type {
-    margin-top: 1.2em; // Mirrors the label 1.2em top padding.
-  }
-}
-
-// This is specifically for list of radios/checkboxes
-.model_multiple_choice_field .input li,
-.checkbox_select_multiple .input li,
-.multiple_choice_field .input li,
-.choice_field .input li,
-.model_multiple_choice_field .input > div > div,
-.checkbox_select_multiple .input > div > div,
-.multiple_choice_field .input > div > div,
-.choice_field .input > div > div {
-  label {
-    display: inline-flex;
-    align-items: center;
-    width: auto;
-    float: none;
-    padding-top: 0; // Negates padding added to label for the group of fields as a whole
-    padding-bottom: 0.8em;
-  }
-}
-
 .fields > li,
 .field-col {
   @include clearfix();
@@ -356,48 +156,7 @@ li.inline:first-child {
   margin-inline-start: math.div(-$grid-gutter-width, 2);
 }
 
-// search-bars
-.search-bar {
-  .required .field > label:after {
-    display: none;
-  }
-
-  .button-filter {
-    height: 2.71em;
-    border-color: transparent;
-  }
-}
-
-// file drop zones
-.drop-zone {
-  border-radius: 5px;
-  border: 2px dashed $color-grey-4;
-  padding: $mobile-nice-padding;
-  background-color: $color-grey-5;
-  margin-bottom: 1em;
-  text-align: center;
-
-  .drop-zone-help {
-    border: 0;
-  }
-
-  &.hovered {
-    border-color: $color-teal;
-    background-color: $color-input-focus;
-  }
-}
-
-// Transitions
-// stylelint-disable-next-line no-duplicate-selectors
-.help {
-  @include transition(opacity 0.2s ease);
-}
-
 @include media-breakpoint-up(sm) {
-  .help {
-    opacity: 1;
-  }
-
   .fields {
     max-width: 800px;
   }
@@ -448,133 +207,3 @@ li.inline:first-child {
     }
   }
 }
-
-.field-comment-control {
-  display: none;
-}
-
-.tab-content--comments-enabled {
-  .field {
-    position: relative;
-  }
-
-  .field-content {
-    padding-inline-end: 45px;
-
-    @include media-breakpoint-up(sm) {
-      padding-inline-end: 60px;
-    }
-  }
-
-  .widget-draftail_rich_text_area .field-content {
-    padding-inline-end: 0;
-  }
-
-  .field-comment-control {
-    position: absolute;
-    display: block;
-    top: 0;
-    inset-inline-end: 0;
-    height: 100%;
-    line-height: 100%;
-
-    &--object {
-      inset-inline-end: 20px;
-
-      @include media-breakpoint-up(lg) {
-        inset-inline-end: 350px;
-      }
-    }
-
-    button {
-      @include transition(opacity 0.2s ease);
-      border: 0;
-      background: none;
-      width: 30px;
-      height: 30px;
-      padding: 0;
-      border-radius: 3px;
-      position: absolute;
-      top: 50%;
-      inset-inline-end: 0;
-
-      @include media-breakpoint-up(sm) {
-        inset-inline-end: 10px;
-      }
-
-      // Hide by default, reveal on hover of parent
-      @include media-breakpoint-up(md) {
-        opacity: 0;
-        pointer-events: none;
-        transform: translateY(-50%);
-        inset-inline-end: 0;
-      }
-
-      .icon-reversed {
-        display: none;
-      }
-
-      &:hover {
-        cursor: pointer;
-
-        // stylelint-disable max-nesting-depth
-        .icon-default {
-          display: none;
-        }
-
-        .icon-reversed {
-          display: block;
-        }
-      }
-
-      &:focus {
-        opacity: 1;
-        pointer-events: initial;
-      }
-
-      > svg {
-        width: 35px;
-        height: 35px;
-        color: $color-teal;
-
-        @media (forced-colors: $media-forced-colours) {
-          color: ButtonText;
-          border: 1px solid;
-        }
-      }
-
-      .icon-comment {
-        width: 20px;
-        height: 20px;
-      }
-    }
-  }
-
-  .field-row .field-comment-control {
-    top: 0;
-  }
-
-  .field:not(.block_field) {
-    &:hover {
-      .field-comment-control button {
-        opacity: 1;
-        pointer-events: initial;
-      }
-    }
-  }
-
-  .object {
-    &:hover {
-      .field-comment-control--object button {
-        opacity: 1;
-        pointer-events: initial;
-      }
-    }
-  }
-
-  .object.model_choice_field {
-    .object-help {
-      inset-inline-end: 153px;
-    }
-  }
-}

+ 11 - 0
client/scss/components/_search-bar.scss

@@ -0,0 +1,11 @@
+// search-bars
+.search-bar {
+  .required .field > label:after {
+    display: none;
+  }
+
+  .button-filter {
+    height: 2.71em;
+    border-color: transparent;
+  }
+}

+ 5 - 0
client/scss/components/forms/_daterange.scss

@@ -0,0 +1,5 @@
+.daterange_field {
+  input:last-of-type {
+    margin-top: 1.2em; // Mirrors the label 1.2em top padding.
+  }
+}

+ 17 - 0
client/scss/components/forms/_drop-zone.scss

@@ -0,0 +1,17 @@
+// file drop zones
+.drop-zone {
+  border-radius: 5px;
+  border: 2px dashed $color-grey-4;
+  padding: $mobile-nice-padding;
+  background-color: $color-grey-5;
+  margin-bottom: 1em;
+  text-align: center;
+
+  .drop-zone-help {
+    border: 0;
+  }
+
+  &.hovered {
+    border-color: $color-teal;
+  }
+}

+ 23 - 0
client/scss/components/forms/_error-message.scss

@@ -0,0 +1,23 @@
+@use 'sass:map';
+
+.error-message {
+  border: 1px solid transparent; // ensure visible separation in Windows High Contrast mode
+  font-size: 0.85em;
+  font-weight: normal;
+  margin: 0.5em 0 0;
+  font-size: 1em;
+  font-weight: bold;
+  color: theme('colors.critical.200');
+
+  @media (forced-colors: $media-forced-colours) {
+    forced-color-adjust: none;
+  }
+
+  // UI-Redesign: to be added via js and styled here
+  // TODO Forms
+  &::before {
+    font-family: $font-wagtail-icons;
+    vertical-align: -10%;
+    content: map.get($icons, 'warning');
+  }
+}

+ 110 - 0
client/scss/components/forms/_field-comment-control.scss

@@ -0,0 +1,110 @@
+.field-comment-control {
+  display: none;
+}
+
+.tab-content--comments-enabled {
+  .field-comment-control {
+    position: absolute;
+    display: block;
+    top: 0;
+    inset-inline-end: 0;
+    height: 100%;
+    line-height: 100%;
+
+    &--object {
+      inset-inline-end: 20px;
+
+      @include media-breakpoint-up(lg) {
+        inset-inline-end: 350px;
+      }
+    }
+
+    button {
+      @include transition(opacity 0.2s ease);
+      border: 0;
+      background: none;
+      width: 30px;
+      height: 30px;
+      padding: 0;
+      border-radius: 3px;
+      position: absolute;
+      top: 50%;
+      inset-inline-end: 0;
+
+      @include media-breakpoint-up(sm) {
+        inset-inline-end: 10px;
+      }
+
+      // Hide by default, reveal on hover of parent
+      @include media-breakpoint-up(md) {
+        opacity: 0;
+        pointer-events: none;
+        transform: translateY(-50%);
+        inset-inline-end: 0;
+      }
+
+      .icon-reversed {
+        display: none;
+      }
+
+      &:hover {
+        cursor: pointer;
+
+        // stylelint-disable max-nesting-depth
+        .icon-default {
+          display: none;
+        }
+
+        .icon-reversed {
+          display: block;
+        }
+      }
+
+      &:focus {
+        opacity: 1;
+        pointer-events: initial;
+      }
+
+      > svg {
+        width: 35px;
+        height: 35px;
+        color: $color-teal;
+
+        @media (forced-colors: $media-forced-colours) {
+          color: ButtonText;
+          border: 1px solid;
+        }
+      }
+
+      .icon-comment {
+        width: 20px;
+        height: 20px;
+      }
+    }
+  }
+
+  // TODO Forms
+  .field-row .field-comment-control {
+    top: 0;
+  }
+
+  // TODO Forms
+  .field:not(.block_field) {
+    &:hover {
+      .field-comment-control button {
+        opacity: 1;
+        pointer-events: initial;
+      }
+    }
+  }
+
+  // TODO Forms
+  .object {
+    &:hover {
+      .field-comment-control--object button {
+        opacity: 1;
+        pointer-events: initial;
+      }
+    }
+  }
+}

+ 20 - 0
client/scss/components/forms/_file.scss

@@ -0,0 +1,20 @@
+.file_field {
+  .input {
+    label {
+      float: none;
+      display: inline;
+      padding: 0;
+    }
+
+    input[type='checkbox'] {
+      margin-top: 5px;
+    }
+
+    a {
+      &:after {
+        content: ' ';
+        display: block;
+      }
+    }
+  }
+}

+ 4 - 0
client/scss/components/forms/_help.scss

@@ -0,0 +1,4 @@
+.help {
+  @apply w-help-text;
+  margin-top: theme('spacing.[1.5]');
+}

+ 32 - 0
client/scss/components/forms/_input-base.scss

@@ -0,0 +1,32 @@
+/**
+ * Field styles reusable across **all** fields, including:
+ * Text input, textarea, checkbox, radio, select, etc.
+ */
+@mixin input-base() {
+  appearance: none;
+  border-radius: theme('borderRadius.DEFAULT');
+  color: $color-input-text;
+  background-color: $color-input-bg;
+  border: 1px solid $color-input-border;
+
+  &:hover {
+    border-color: $color-input-hover-border;
+  }
+
+  &[disabled],
+  &[disabled]:hover {
+    color: $color-input-disabled-text;
+    background-color: $color-input-disabled-bg;
+    border-color: $color-input-disabled-border;
+    cursor: not-allowed;
+  }
+
+  .error &,
+  &[aria-invalid='true'] {
+    border-color: $color-input-error-border;
+  }
+
+  &::placeholder {
+    color: $color-input-disabled-text;
+  }
+}

+ 30 - 0
client/scss/components/forms/_input-text.scss

@@ -0,0 +1,30 @@
+// All HTML5 input types, with irrelevant ones commented out.
+// input[type="button"],
+// input[type="checkbox"],
+// input[type="color"],
+input[type="date"],
+input[type="datetime-local"],
+input[type="email"],
+input[type="file"],
+// input[type="hidden"],
+// input[type="image"],
+input[type="month"],
+input[type="number"],
+input[type="password"],
+// input[type="radio"],
+// input[type="range"],
+// input[type="reset"],
+input[type="search"],
+// input[type="submit"],
+input[type="tel"],
+input[type="text"],
+input[type="time"],
+input[type="url"],
+input[type="week"],
+textarea {
+  @include input-base();
+  @apply w-body-text-large;
+  width: 100%;
+  padding: theme('spacing.[1.5]') theme('spacing.5');
+  min-height: rem($text-input-height);
+}

+ 18 - 0
client/scss/components/forms/_radio-checkbox-multiple.scss

@@ -0,0 +1,18 @@
+$radio-checkbox-line-gap: theme('spacing.[2.5]');
+
+.w-field--checkbox_select_multiple,
+.w-field--radio_select {
+  ul {
+    list-style: none;
+    padding: 0;
+    margin: 0;
+  }
+
+  label {
+    @apply w-label-3;
+    display: inline-flex;
+    align-items: center;
+    line-height: normal;
+    margin-bottom: $radio-checkbox-line-gap;
+  }
+}

+ 62 - 0
client/scss/components/forms/_radio-checkbox.scss

@@ -0,0 +1,62 @@
+@use 'sass:math';
+
+$size: 30;
+$marker-size: 18;
+$marker-offset: math.div($size - $marker-size, 2) - 1;
+$radio-checkbox-label-gap: theme('spacing.[2.5]');
+$radio-checkbox-line-gap: theme('spacing.[2.5]');
+
+// Both input types are very similar in appearance and layout.
+@mixin radio-checkbox-base() {
+  @include input-base();
+  display: inline-block;
+  position: relative;
+  height: rem($size);
+  width: rem($size);
+  cursor: pointer;
+  margin-inline-end: $radio-checkbox-label-gap;
+
+  &::before {
+    content: '';
+    position: absolute;
+    top: rem($marker-offset);
+    inset-inline-start: rem($marker-offset);
+    width: rem($marker-size);
+    height: rem($marker-size);
+  }
+
+  &:checked::before {
+    background: $color-teal;
+
+    @media (forced-colors: active) {
+      background: Highlight;
+    }
+  }
+}
+
+input[type='radio'] {
+  @include radio-checkbox-base();
+  display: inline-block;
+  border-radius: theme('borderRadius.full');
+
+  &:checked::before {
+    mask-image: url('#{$images-root}icons/radio-full.svg');
+  }
+}
+
+input[type='checkbox'] {
+  @include radio-checkbox-base();
+  border-radius: theme('borderRadius.sm');
+  // Legacy alignment for checkboxes, particularly within listings.
+  vertical-align: bottom;
+
+  &::before {
+    // Checkboxes look better with a slightly larger offset.
+    top: rem($marker-offset + 1);
+    inset-inline-start: rem($marker-offset + 1);
+  }
+
+  &:checked::before {
+    mask-image: url('#{$images-root}icons/tick.svg');
+  }
+}

+ 4 - 0
client/scss/components/forms/_required-mark.scss

@@ -0,0 +1,4 @@
+.w-required-mark {
+  color: theme('colors.critical.200');
+  margin-inline-start: 0.5ch;
+}

+ 35 - 0
client/scss/components/forms/_select.scss

@@ -0,0 +1,35 @@
+@use 'sass:map';
+@use 'sass:math';
+
+$select-size: $text-input-height;
+$chevron-width: 16px;
+$chevron-height: 8px;
+$chevron-top-offset: math.div($select-size - $chevron-height, 2);
+$chevron-inline-end-offset: math.div($select-size - $chevron-width, 2);
+
+@mixin select-arrow() {
+  background-image: url('#{$images-root}icons/chevron-down.svg');
+  background-repeat: no-repeat;
+  background-size: rem($chevron-width);
+  background-position: calc(100% - rem($chevron-inline-end-offset))
+    rem($chevron-top-offset);
+}
+
+select {
+  @include input-base();
+  @include select-arrow();
+  @apply w-body-text-large;
+  min-height: rem($select-size);
+  padding: 0 theme('spacing.5');
+  padding-inline-end: rem($select-size);
+}
+
+select[multiple] {
+  background-image: none;
+  min-height: theme('spacing.40');
+  padding: 0;
+
+  option {
+    padding: 0 theme('spacing.5');
+  }
+}

+ 24 - 15
client/scss/components/_switch.scss → client/scss/components/forms/_switch.scss

@@ -1,12 +1,11 @@
 @use 'sass:math';
 
-$switch-width: 40px;
-$switch-height: 20px;
+$switch-width: 36px;
+$switch-height: 18px;
 $switch-border: 2px;
 $switch-outline: 3px;
 
 $switch-border-radius: math.div(($switch-height + $switch-border * 2), 2);
-$switch-outline-radius: $switch-border-radius + $switch-outline;
 
 .switch {
   display: inline-flex;
@@ -18,6 +17,19 @@ $switch-outline-radius: $switch-border-radius + $switch-outline;
   width: unset;
   float: unset;
 
+  &__tick {
+    width: 12px;
+    height: $switch-height;
+    position: absolute;
+    top: 50%;
+    transform: translate(5px, -50%);
+    color: $color-white;
+
+    @media (forced-colors: active) {
+      color: SelectedItemText;
+    }
+  }
+
   &__toggle {
     position: relative;
     cursor: pointer;
@@ -30,8 +42,8 @@ $switch-outline-radius: $switch-border-radius + $switch-outline;
     }
 
     &::before {
-      height: $switch-height;
-      width: $switch-width;
+      height: $switch-height + $switch-border * 2;
+      width: $switch-width + $switch-border * 2;
       border-radius: $switch-border-radius;
       background: theme('colors.grey.400');
       border: $switch-border solid theme('colors.grey.400');
@@ -45,7 +57,7 @@ $switch-outline-radius: $switch-border-radius + $switch-outline;
       height: $switch-height;
       width: $switch-height;
       border: $switch-border solid $color-white;
-      border-radius: 50%;
+      border-radius: theme('borderRadius.full');
       background-color: $color-white;
     }
   }
@@ -53,13 +65,15 @@ $switch-outline-radius: $switch-border-radius + $switch-outline;
   [type='checkbox']:checked + &__toggle::before {
     background: $color-teal;
     border-color: $color-teal;
+
+    @media (forced-colors: active) {
+      background: SelectedItem;
+      border-color: SelectedItem;
+    }
   }
 
   [type='checkbox']:checked + &__toggle::after {
-    transform: translate(
-      calc(#{$switch-width} + #{$switch-border} - 100%),
-      -50%
-    );
+    transform: translate(calc(#{$switch-width + $switch-border} - 100%), -50%);
   }
 
   [type='checkbox']:disabled + &__toggle {
@@ -68,11 +82,6 @@ $switch-outline-radius: $switch-border-radius + $switch-outline;
     opacity: 0.3;
   }
 
-  [type='checkbox']:disabled + &__toggle::after {
-    opacity: 0.5;
-    box-shadow: none;
-  }
-
   [type='checkbox']:focus + &__toggle {
     outline: $color-focus-outline solid $switch-outline;
   }

+ 23 - 0
client/scss/components/forms/_tagit.scss

@@ -0,0 +1,23 @@
+.tagit {
+  @include input-base();
+
+  input[type='text'] {
+    min-height: 0;
+  }
+}
+
+@media (forced-colors: $media-forced-colours) {
+  .tagit,
+  .field-content .tagit .tagit-choice,
+  .tagit .tagit-new .ui-widget-content {
+    box-shadow: inset 1000px 0 0 0 $color-black;
+    color: $color-white;
+    forced-color-adjust: none;
+  }
+
+  .tagit span.tagit-label:before,
+  .tagit span.tagit-label {
+    color: $color-black;
+    forced-color-adjust: none;
+  }
+}

+ 30 - 0
client/scss/components/forms/_title.scss

@@ -0,0 +1,30 @@
+// Styles for title fields throughout the page.
+.title {
+  input,
+  textarea,
+  .Draftail-Editor .public-DraftEditor-content {
+    @apply w-h2;
+    color: $color-input-text;
+  }
+}
+
+// Styles for the title field when at the top of the page.
+.w-panel.title:first-child {
+  .w-panel__header {
+    @apply w-sr-only;
+  }
+
+  input,
+  textarea,
+  .Draftail-Editor .public-DraftEditor-content {
+    @apply w-h1;
+    color: $color-input-text;
+    // Slightly out-dented so the field’s is horizontally aligned.
+    padding-inline-start: theme('spacing[1.5]');
+    margin-inline-start: calc(-1 * theme('spacing[1.5]'));
+
+    &:not(:hover, :focus, [aria-invalid='true']) {
+      border-color: transparent;
+    }
+  }
+}

+ 15 - 1
client/scss/core.scss

@@ -106,6 +106,20 @@ These are classes for components.
 
 // Legacy
 @import 'components/icons';
+@import 'components/forms/input-base';
+@import 'components/forms/input-text';
+@import 'components/forms/radio-checkbox';
+@import 'components/forms/select';
+@import 'components/forms/tagit';
+@import 'components/forms/radio-checkbox-multiple';
+@import 'components/forms/error-message';
+@import 'components/forms/required-mark';
+@import 'components/forms/help';
+@import 'components/forms/drop-zone';
+@import 'components/forms/daterange';
+@import 'components/forms/file';
+@import 'components/forms/switch';
+@import 'components/forms/title';
 @import 'components/tabs';
 @import 'components/dialog';
 @import 'components/dropdown';
@@ -122,6 +136,7 @@ These are classes for components.
 @import 'components/messages.capability';
 @import 'components/messages.status';
 @import 'components/header';
+@import 'components/search-bar';
 @import 'components/progressbar';
 @import 'components/summary';
 @import 'components/tooltips';
@@ -136,7 +151,6 @@ These are classes for components.
 @import 'components/skiplink';
 @import 'components/workflow-tasks';
 @import 'components/workflow-timeline';
-@import 'components/switch';
 @import 'components/bulk_actions';
 @import 'components/preview-panel';
 @import 'components/preview-error';

+ 18 - 0
client/scss/elements/_elements.scss

@@ -1,6 +1,24 @@
+*,
+::before,
+::after {
+  // Reset border styles so tailwinds default border class works as expected
+  // https://tailwindcss.com/docs/preflight#border-styles-are-reset-globally
+  border-width: 0;
+  border-style: solid;
+  // Set all elements to inherit their parent’s (border-box) box-sizing.
+  box-sizing: inherit;
+}
+
+::before,
+::after {
+  --tw-content: '';
+}
+
 html {
   background: $color-grey-4;
   height: 100%;
+  // Set the whole admin to border-box by default.
+  box-sizing: border-box;
 }
 
 body {

+ 0 - 216
client/scss/elements/_forms.scss

@@ -20,214 +20,6 @@ fieldset {
   margin: 0;
 }
 
-legend {
-  @include visuallyhidden();
-}
-
-label,
-.label {
-  font-weight: bold;
-  color: $color-grey-1;
-  font-size: 1.1em;
-  display: block;
-  padding: 0 0 0.8em;
-  margin: 0;
-  line-height: 1.3em;
-
-  .checkbox &,
-  .radio & {
-    display: inline;
-  }
-
-  &.no-float {
-    float: none;
-  }
-
-  &.disabled {
-    opacity: 0.7;
-    cursor: not-allowed;
-  }
-
-  @include media-breakpoint-up(sm) {
-    @include column(2);
-    padding-top: 1.2em;
-    padding-inline-start: 0;
-
-    .radio_select &,
-    .multiple_choice_field &,
-    .model_multiple_choice_field &,
-    .checkbox_select_multiple &,
-    .boolean_field &,
-    .model_choice_field &,
-    .image_field & {
-      padding-top: 0;
-    }
-
-    // Horrid specificity war
-    .model_choice_field.select & {
-      padding-top: 1.2em;
-    }
-  }
-}
-
-input:not([type='submit']),
-textarea,
-select,
-.tagit {
-  appearance: none;
-  box-sizing: border-box;
-  border-radius: 6px;
-  width: 100%;
-  font-family: $font-sans;
-  border: 1px solid $color-input-border;
-  padding: 0.9em 1.2em;
-  background-color: $color-fieldset-hover;
-  color: $color-text-input;
-  font-size: 1.2em;
-  font-weight: 300;
-
-  &:hover {
-    background-color: $color-white;
-  }
-
-  &:focus {
-    background-color: $color-input-focus;
-    border-color: $color-input-focus-border;
-  }
-
-  &:disabled,
-  &[disabled],
-  &:disabled:hover,
-  &[disabled]:hover {
-    background-color: $color-grey-4;
-    cursor: not-allowed;
-    color: $color-grey-2;
-  }
-}
-
-.tagit {
-  background-color: $color-white;
-}
-
-@media (forced-colors: $media-forced-colours) {
-  .tagit,
-  .field-content .tagit .tagit-choice,
-  .tagit .tagit-new .ui-widget-content {
-    box-shadow: inset 1000px 0 0 0 $color-black;
-    color: $color-white;
-    forced-color-adjust: none;
-  }
-
-  .tagit span.tagit-label:before,
-  .tagit span.tagit-label {
-    color: $color-black;
-    forced-color-adjust: none;
-  }
-}
-
-.file_field {
-  .input {
-    label {
-      float: none;
-      display: inline;
-      padding: 0;
-    }
-
-    input[type='checkbox'] {
-      margin-top: 5px;
-    }
-
-    a {
-      &:after {
-        content: ' ';
-        display: block;
-      }
-    }
-  }
-}
-
-// radio and check boxes
-input[type='radio'],
-input[type='checkbox'] {
-  border-radius: 0;
-  cursor: pointer;
-  border: 0;
-  padding: 0;
-}
-
-input[type='radio'] {
-  display: inline-block;
-  height: 1.75rem;
-  width: 1.75rem;
-  margin-inline-end: 0.625rem;
-  position: relative;
-  background: $color-white;
-  border-radius: 100%;
-  border: 1px solid $color-grey-4;
-}
-
-input[type='radio']:before {
-  content: '';
-  text-align: center;
-  position: absolute;
-  top: 0.1875rem;
-  inset-inline-start: 0.1875rem;
-  cursor: pointer;
-  display: block;
-  width: 0.75rem;
-  height: 0.75rem;
-  padding: 4px;
-  background: $color-grey-4;
-  mask-image: url('#{$images-root}icons/radio-full.svg');
-  mask-repeat: no-repeat;
-}
-
-input[type='radio']:checked:before {
-  mask-repeat: no-repeat;
-  background: $color-teal;
-}
-
-input[type='checkbox'] {
-  height: 1.375rem;
-  width: 1.375rem;
-  position: relative;
-  margin-inline-end: 5px;
-  background: $color-white;
-  border: 1px solid $color-grey-4;
-  vertical-align: bottom;
-}
-
-input[type='checkbox']:before {
-  content: '';
-  position: absolute;
-  top: 2px;
-  inset-inline-start: 2px;
-  cursor: pointer;
-  display: block;
-  line-height: 20px;
-  width: 1rem;
-  height: 1rem;
-  background: transparent;
-}
-
-input[type='checkbox']:checked:before {
-  background: $color-teal;
-  mask-image: url('#{$images-root}icons/tick.svg');
-  mask-repeat: no-repeat;
-  width: 1rem;
-  height: 1rem;
-  top: 2px;
-  inset-inline-start: 2px;
-
-  @media (forced-colors: active) {
-    background: ButtonText;
-  }
-}
-
-input[type='checkbox'][disabled]:before {
-  cursor: not-allowed;
-}
-
 // Special styles to counteract Firefox's completely unwarranted assumptions about button styles
 input[type='submit'],
 input[type='reset'],
@@ -241,11 +33,3 @@ button {
     }
   }
 }
-
-// Transitions
-fieldset,
-input,
-textarea,
-select {
-  @include transition(background-color 0.2s ease);
-}

+ 2 - 4
client/scss/elements/_typography.scss

@@ -13,12 +13,12 @@ h4,
 h5,
 h6 {
   font-weight: normal;
+  line-height: theme('lineHeight.tight');
+  color: theme('colors.primary.DEFAULT');
 }
 
 h1 {
-  line-height: 1.3em;
   font-size: 1.5em;
-  color: $color-grey-1;
   font-weight: 700;
 
   span {
@@ -28,9 +28,7 @@ h1 {
 
 h2 {
   font-size: 1.3em;
-  font-family: $font-sans;
   font-weight: 600;
-  color: $color-grey-2;
 }
 
 p {

+ 0 - 7
client/scss/layouts/_home.scss

@@ -1,11 +1,4 @@
 .homepage {
-  .object.collapsible {
-    .object-layout .title-wrapper::before {
-      // fix for legacy icons
-      display: none;
-    }
-  }
-
   .listing tbody {
     border-bottom: 0;
   }

+ 28 - 35
client/scss/layouts/_login.scss

@@ -61,18 +61,15 @@ $desktop-nice-padding: 100px;
 
   .fields li {
     padding: 1em 0;
+    position: relative;
+    padding: 0;
 
-    &.full {
-      position: relative;
-      padding: 0;
-
-      label {
-        @include visuallyhidden;
-      }
+    label {
+      @include visuallyhidden;
+    }
 
-      input {
-        border-top: 1px dashed $color-input-border;
-      }
+    input {
+      border-top: 1px dashed $color-input-border;
     }
 
     &:first-child input {
@@ -94,7 +91,7 @@ $desktop-nice-padding: 100px;
   }
 
   // Special full-width, one-off fields i.e a single text or textarea input
-  .full input {
+  input {
     border-radius: 0;
     font-weight: 300;
     border: 0;
@@ -171,30 +168,26 @@ $desktop-nice-padding: 100px;
       font-size: 4em;
     }
 
-    .full {
-      margin: 0 (-$desktop-nice-padding);
-
-      .iconfield {
-        // stylelint-disable-next-line max-nesting-depth
-        .input:before {
-          display: inline-block;
-          position: absolute;
-          color: theme('colors.grey.200');
-          border: 2px solid theme('colors.grey.200');
-          border-radius: 100%;
-          width: 1em;
-          height: 1em;
-          padding: 0.3em;
-          inset-inline-start: $desktop-nice-padding;
-          margin-top: -1.1rem;
-          top: 50%;
-          font-size: 1.3rem;
-        }
-
-        // stylelint-disable-next-line max-nesting-depth
-        input {
-          padding-inline-start: ($desktop-nice-padding + 50px);
-        }
+    .iconfield {
+      // stylelint-disable-next-line max-nesting-depth
+      .input:before {
+        display: inline-block;
+        position: absolute;
+        color: theme('colors.grey.200');
+        border: 2px solid theme('colors.grey.200');
+        border-radius: 100%;
+        width: 1em;
+        height: 1em;
+        padding: 0.3em;
+        inset-inline-start: $desktop-nice-padding;
+        margin-top: -1.1rem;
+        top: 50%;
+        font-size: 1.3rem;
+      }
+
+      // stylelint-disable-next-line max-nesting-depth
+      input {
+        padding-inline-start: ($desktop-nice-padding + 50px);
       }
     }
   }

+ 0 - 183
client/scss/layouts/_page-editor.scss

@@ -40,25 +40,6 @@
     }
   }
 
-  .object-help {
-    display: block;
-    position: relative;
-    z-index: 1;
-    top: $object-title-height;
-    margin-top: 0;
-    margin-bottom: -1em;
-    padding: 1em math.div($grid-gutter-width, 2) 1em 3em;
-    opacity: 1;
-
-    .icon-help {
-      margin-inline-start: -1.75em;
-    }
-  }
-
-  &:hover .object-help {
-    opacity: 1;
-  }
-
   > .title-wrapper {
     box-sizing: border-box;
     height: $object-title-height;
@@ -120,29 +101,6 @@
     }
   }
 
-  // Special full-width, one-off fields i.e a single text or textarea input
-  &.full {
-    fieldset {
-      display: block;
-      float: none;
-    }
-
-    li {
-      padding: 0;
-    }
-
-    .error-message {
-      @include nice-padding();
-      padding-bottom: 2em;
-    }
-
-    .error,
-    .error input:not([type='submit']),
-    .error textarea {
-      background-color: $color-input-error-bg;
-    }
-  }
-
   // cursory styling for streamfield. Main styling in client/src/components/StreamField/StreamField.scss
   &.block_field {
     padding-inline-start: 20px;
@@ -164,17 +122,6 @@
     }
   }
 
-  // special panel for the publishing fields, requires a bit more pizzazz
-  &.publishing {
-    > .title-wrapper:before {
-      // UI Redesign: To be removed in page editor redesign
-      content: map.get($icons, 'date');
-      font-size: 1.8rem;
-      line-height: 1.4em;
-      width: 1.4em;
-    }
-  }
-
   .multiple {
     padding: 4.5em 0 0;
 
@@ -265,83 +212,6 @@
   }
 }
 
-// Custom styles that make some fields look more important
-.full {
-  input:not([type='submit']),
-  textarea {
-    @include nice-padding;
-    border-radius: 0;
-    padding-top: 1.5em;
-    padding-bottom: 1.5em;
-    font-size: 1.2em;
-    line-height: 1.6em;
-  }
-}
-
-.title {
-  input:not([type='submit']),
-  textarea {
-    font-size: 2em;
-    font-family: $font-sans;
-    font-weight: 800;
-  }
-}
-
-// Footer control bar for performing actions on the page
-footer .actions,
-footer .preview {
-  .button {
-    @apply w-leading-none w-inline-flex w-items-center;
-
-    .icon {
-      margin-inline-end: theme('spacing.2');
-    }
-  }
-}
-
-footer .actions {
-  .button {
-    font-weight: 600;
-    text-overflow: ellipsis;
-  }
-}
-
-footer .preview {
-  button,
-  .button {
-    padding: 0 1em;
-
-    @include media-breakpoint-down(xs) {
-      width: 100%;
-      margin-top: 2px;
-      margin-bottom: 2px;
-      height: 3em;
-    }
-
-    background-color: $color-grey-2;
-    border-color: $color-grey-2;
-  }
-
-  .dropdown {
-    input[type='button'],
-    input[type='submit'],
-    button,
-    .button {
-      background-color: $color-grey-2;
-      border-color: $color-grey-2;
-    }
-
-    ul,
-    .dropdown-toggle {
-      background-color: $color-grey-2;
-    }
-
-    &.open > .button + .dropdown-toggle {
-      background-color: $color-grey-2;
-    }
-  }
-}
-
 @include media-breakpoint-up(sm) {
   .object {
     fieldset {
@@ -371,47 +241,6 @@ footer .preview {
       }
     }
 
-    .object-help {
-      padding-bottom: 40px;
-      margin-inline-start: 10px;
-      margin-bottom: 0;
-      opacity: 0;
-    }
-
-    &.block_field {
-      .object-help {
-        padding-inline-start: 6.4em;
-      }
-    }
-
-    &.full {
-      fieldset {
-        // Override column mixin for column items.
-        display: block;
-        // Override column mixin for column items.
-        float: none;
-        margin-inline-start: -51px;
-        padding: 0;
-        padding-top: $object-title-height;
-      }
-
-      input:not([type='submit']),
-      textarea {
-        border-width: 0 1px;
-      }
-
-      .field {
-        padding: 0;
-      }
-
-      .field-content {
-        display: block;
-        float: none;
-        width: auto;
-        padding: inherit;
-      }
-    }
-
     .multiple {
       @include column(10);
       padding-inline-start: 0;
@@ -431,16 +260,8 @@ footer .preview {
   .tab-content--comments-enabled .object {
     padding-inline-end: 27%;
 
-    &.full {
-      padding-inline-end: 36%;
-    }
-
     @include media-breakpoint-up(lg) {
       padding-inline-end: 30%;
-
-      &.full {
-        padding-inline-end: 36%;
-      }
     }
   }
 }
@@ -449,9 +270,5 @@ footer .preview {
 @media (forced-colors: $media-forced-colours) {
   .object {
     border-top: 1px solid GrayText;
-
-    .object-help {
-      margin-bottom: 0;
-    }
   }
 }

+ 13 - 6
client/scss/settings/_variables.scss

@@ -17,6 +17,9 @@ $grid-content-indent: 0.7;
 $mobile-nice-padding: 20px;
 $desktop-nice-padding: 50px;
 
+// All text inputs have a set height to simplify alignment.
+$text-input-height: 42px;
+
 // screen breakpoints
 $breakpoints: (
   xs: 0,
@@ -49,11 +52,18 @@ $color-grey-5: theme('colors.grey.50');
 
 $color-menu-text: theme('colors.white-80');
 
-$color-fieldset-hover: $color-white;
-$color-input-border: $color-grey-4;
-$color-input-focus: theme('colors.secondary.50');
+$color-text-base: theme('colors.grey.600');
+
+$color-input-text: $color-text-base;
+$color-input-bg: theme('colors.white.DEFAULT');
+$color-input-border: theme('colors.grey.150');
+$color-input-disabled-text: theme('colors.grey.400');
+$color-input-disabled-bg: theme('colors.grey.50');
+$color-input-disabled-border: theme('colors.grey.100');
+$color-input-hover-border: theme('colors.grey.200');
 $color-input-focus-border: theme('colors.secondary.100');
 $color-input-error-bg: theme('colors.critical.50');
+$color-input-error-border: theme('colors.critical.200');
 
 $color-button: $color-teal;
 $color-button-hover: $color-teal-darker;
@@ -68,9 +78,6 @@ $color-link-hover: $color-teal-dark;
 // because it shouldn’t be reused for anything else in the UI.
 $color-focus-outline: #ffbf47;
 
-$color-text-base: theme('colors.grey.600');
-$color-text-input: theme('colors.grey.600');
-
 // System Colors
 $media-forced-colours: active;
 $system-color-link-text: LinkText;

+ 15 - 0
client/scss/tools/_functions.general.scss

@@ -0,0 +1,15 @@
+@use 'sass:math';
+
+@function strip-unit($value) {
+  @return math.div($value, ($value * 0 + 1));
+}
+
+// Returns a value in rem
+@function rem($val, $context: 16) {
+  @return #{math.div(strip-unit($val), strip-unit($context))}rem;
+}
+
+// Returns a value in em
+@function em($val, $context: 16) {
+  @return #{math.div(strip-unit($val), strip-unit($context))}em;
+}

+ 0 - 2
client/src/components/CommentApp/main.scss

@@ -7,7 +7,6 @@ $color-box-border: $color-grey-3;
 $color-box-border-focused: $color-grey-2;
 $color-box-text: $color-black;
 $color-textarea-background: theme('colors.grey.50');
-$color-textarea-background-focused: $color-input-focus;
 $color-textarea-border: $color-input-border;
 $color-textarea-border-focused: $color-input-focus-border;
 $color-textarea-placeholder-text: $color-grey-2;
@@ -47,7 +46,6 @@ $box-padding: 10px;
     }
 
     &:focus {
-      background-color: $color-textarea-background-focused;
       border-color: $color-textarea-border-focused;
       outline: unset;
     }

+ 20 - 41
client/src/components/Draftail/Draftail.scss

@@ -1,4 +1,4 @@
-$draftail-editor-text: $color-text-input;
+$draftail-editor-text: $color-input-text;
 $draftail-editor-chrome: theme('colors.primary.DEFAULT');
 $draftail-editor-chrome-text: $color-white;
 // This needs to remain a Sass value due to a limitation in Draftail.
@@ -7,10 +7,12 @@ $draftail-editor-chrome-active: #fff;
 $draftail-editor-chrome-accent: transparent;
 
 $draftail-base-spacing: 0.375rem;
+$draftail-editor-radius: 0;
 $draftail-editor-border: 0;
-$draftail-editor-padding: 0.75rem;
+$draftail-editor-padding: 0 theme('spacing.5');
 $draftail-editor-background: $color-white;
-$draftail-toolbar-radius: 5px;
+$draftail-block-spacing: theme('spacing.2');
+$draftail-toolbar-radius: theme('borderRadius.DEFAULT');
 $draftail-toolbar-icon-size: 1em;
 
 $draftail-editor-font-family: $font-sans;
@@ -35,9 +37,8 @@ $draftail-editor-font-family: $font-sans;
   h4,
   h5,
   h6 {
-    // Overrides for other parts of the Wagtail admin.
-    font-family: inherit;
-    clear: both;
+    // Overrides for heading styles of Wagtail itself.
+    color: inherit;
     line-height: 1;
   }
 
@@ -68,13 +69,9 @@ $draftail-editor-font-family: $font-sans;
   }
 }
 
-.Draftail-Editor {
-  border-radius: 0;
-
-  &__wrapper {
-    // Ensure elements within the editor are positioned according to this container.
-    position: relative;
-  }
+.Draftail-Editor__wrapper {
+  // Ensure elements within the editor are positioned according to this container.
+  position: relative;
 }
 
 .Draftail-ToolbarButton,
@@ -95,36 +92,14 @@ $draftail-editor-font-family: $font-sans;
   }
 }
 
-// When in a .full container, the editor has a specific appearance
-// so the whole area appears like a focusable area, and the editor
-// receives focus on click.
-.full .Draftail-Editor {
-  padding-top: 2em;
-  padding-bottom: 2em;
-  background-color: $color-fieldset-hover;
-  border-inline-end: 1px solid $color-input-border;
-
-  &--focus {
-    background-color: $color-input-focus;
-    border-color: $color-input-focus-border;
-  }
-}
-
-.full .Draftail-Editor .public-DraftEditor-content,
-.full .Draftail-Editor .public-DraftEditorPlaceholder-root {
-  @include nice-padding;
-}
-
-.full .Draftail-Toolbar {
-  @include nice-margin;
-}
-
 .Draftail-Toolbar {
   border: 1px solid $color-grey-3;
 }
 
 .Draftail-MetaToolbar {
-  padding: 0;
+  position: absolute;
+  inset-inline-end: 0;
+  visibility: hidden;
 
   // Make sure the toolbar is always visible for devices that do not hover.
   @media (hover: hover) {
@@ -172,9 +147,9 @@ $draftail-editor-font-family: $font-sans;
   }
 }
 
-.title .Draftail-Editor .public-DraftEditor-content,
-.title .Draftail-Editor .public-DraftEditorPlaceholder-root {
-  font-size: 2em;
+.Draftail-Editor .public-DraftEditor-content {
+  @include input-base();
+  @include show-focus-outline-inside();
 }
 
 .Draftail-block--blockquote {
@@ -183,3 +158,7 @@ $draftail-editor-font-family: $font-sans;
   margin: 1em 0;
   padding: 1em 2em;
 }
+
+.DraftEditor-editorContainer {
+  border: 0;
+}

+ 1 - 2
client/src/components/Draftail/EditorFallback/EditorFallback.scss

@@ -11,8 +11,7 @@
   border-radius: 6px;
 }
 
-.EditorFallback__textarea,
-.object.full .EditorFallback__textarea {
+.EditorFallback__textarea {
   @include wagtail-textarea-overrides;
 }
 

+ 2 - 6
client/src/components/Draftail/index.js

@@ -142,12 +142,8 @@ const initEditor = (selector, originalOptions, currentScript) => {
         description: gettext('Line break'),
         icon: BR_ICON,
       },
-      bottomToolbar: (props) => (
-        <>
-          <InlineToolbar {...props} />
-          <MetaToolbar {...props} />
-        </>
-      ),
+      topToolbar: InlineToolbar,
+      bottomToolbar: MetaToolbar,
       commandPalette: (props) => (
         <CommandPalette {...props} noResultsText={gettext('No results')} />
       ),

+ 0 - 4
client/src/components/PageExplorer/PageExplorerHeader.tsx

@@ -40,10 +40,6 @@ const SelectLocale: React.FunctionComponent<SelectLocaleProps> = ({
       <select value={locale} onChange={onChange} disabled={options.length < 2}>
         {options}
       </select>
-      <Icon
-        name="arrow-down"
-        className="c-page-explorer__header__select-icon"
-      />
     </div>
   );
 };

+ 1 - 1
client/src/components/StreamField/StreamField.scss

@@ -22,7 +22,7 @@ $block-border-color: $color-grey-4;
 $block-border-color-focus: $color-grey-3;
 $block-hover-background: $color-grey-5;
 $error-border-color: theme('colors.critical.100');
-$error-background-color: $color-input-error-bg;
+$error-background-color: $color-input-bg;
 $add-panel-gutter: 8px;
 
 @import 'scss/components/c-sf-add-button';

+ 0 - 1
client/src/components/StreamField/blocks/FieldBlock.js

@@ -21,7 +21,6 @@ export class FieldBlock {
         <div class="field-content">
           <div class="input">
             <div data-streamfield-widget></div>
-            <span></span>
           </div>
         </div>
       </div>

+ 0 - 4
client/src/components/StreamField/blocks/__snapshots__/FieldBlock.test.js.snap

@@ -5,7 +5,6 @@ exports[`telepath: wagtail.blocks.FieldBlock catches widget render errors it ren
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <div data-streamfield-widget=\\"\\"></div>
-            <span></span>
           </div>
         <p class=\\"error-message\\"><span>This widget failed to render, please check the console for details</span></p></div>
       </div>"
@@ -16,7 +15,6 @@ exports[`telepath: wagtail.blocks.FieldBlock it renders correctly 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix\\" id=\\"the-prefix\\">The widget</p>
-            <span></span>
           </div>
         <p class=\\"help\\">drink <em>more</em> water</p></div>
       </div>"
@@ -27,7 +25,6 @@ exports[`telepath: wagtail.blocks.FieldBlock setError() renders errors 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix\\" id=\\"the-prefix\\">The widget</p>
-            <span></span>
           </div>
         <p class=\\"help\\">drink <em>more</em> water</p><p class=\\"error-message\\"><span>Field must not contain the letter E</span><span>Field must contain a story about kittens</span></p></div>
       </div>"
@@ -38,7 +35,6 @@ exports[`telepath: wagtail.blocks.FieldBlock with comments enabled it renders co
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix\\" id=\\"the-prefix\\">The widget</p>
-            <span></span>
           </div>
         <p class=\\"help\\">drink <em>more</em> water</p></div>
       <div class=\\"field-comment-control\\"><button type=\\"button\\" aria-label=\\"Add Comment\\" data-comment-add=\\"\\" class=\\"button button-secondary button-small u-hidden\\"><svg class=\\"icon icon-comment-add icon-default\\" aria-hidden=\\"true\\"><use href=\\"#icon-comment-add\\"></use></svg><svg class=\\"icon icon-comment-add-reversed icon-reversed\\" aria-hidden=\\"true\\"><use href=\\"#icon-comment-add-reversed\\"></use></svg></button></div></div>"

+ 0 - 18
client/src/components/StreamField/blocks/__snapshots__/ListBlock.test.js.snap

@@ -51,7 +51,6 @@ exports[`telepath: wagtail.blocks.ListBlock blocks can be duplicated 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-0-value\\" id=\\"the-prefix-0-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -102,7 +101,6 @@ exports[`telepath: wagtail.blocks.ListBlock blocks can be duplicated 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-1-value\\" id=\\"the-prefix-1-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -153,7 +151,6 @@ exports[`telepath: wagtail.blocks.ListBlock blocks can be duplicated 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-2-value\\" id=\\"the-prefix-2-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -219,7 +216,6 @@ exports[`telepath: wagtail.blocks.ListBlock blocks can be reordered downward 1`]
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-1-value\\" id=\\"the-prefix-1-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -270,7 +266,6 @@ exports[`telepath: wagtail.blocks.ListBlock blocks can be reordered downward 1`]
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-0-value\\" id=\\"the-prefix-0-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -336,7 +331,6 @@ exports[`telepath: wagtail.blocks.ListBlock blocks can be reordered upward 1`] =
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-1-value\\" id=\\"the-prefix-1-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -387,7 +381,6 @@ exports[`telepath: wagtail.blocks.ListBlock blocks can be reordered upward 1`] =
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-0-value\\" id=\\"the-prefix-0-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -453,7 +446,6 @@ exports[`telepath: wagtail.blocks.ListBlock blocks can be split 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-0-value\\" id=\\"the-prefix-0-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -504,7 +496,6 @@ exports[`telepath: wagtail.blocks.ListBlock blocks can be split 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-2-value\\" id=\\"the-prefix-2-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -555,7 +546,6 @@ exports[`telepath: wagtail.blocks.ListBlock blocks can be split 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-1-value\\" id=\\"the-prefix-1-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -621,7 +611,6 @@ exports[`telepath: wagtail.blocks.ListBlock deleteBlock() deletes a block 1`] =
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-0-value\\" id=\\"the-prefix-0-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -672,7 +661,6 @@ exports[`telepath: wagtail.blocks.ListBlock deleteBlock() deletes a block 1`] =
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-1-value\\" id=\\"the-prefix-1-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -738,7 +726,6 @@ exports[`telepath: wagtail.blocks.ListBlock it renders correctly 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-0-value\\" id=\\"the-prefix-0-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -789,7 +776,6 @@ exports[`telepath: wagtail.blocks.ListBlock it renders correctly 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-1-value\\" id=\\"the-prefix-1-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -855,7 +841,6 @@ exports[`telepath: wagtail.blocks.ListBlock setError passes error messages to ch
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-0-value\\" id=\\"the-prefix-0-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -906,7 +891,6 @@ exports[`telepath: wagtail.blocks.ListBlock setError passes error messages to ch
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-1-value\\" id=\\"the-prefix-1-value\\">The widget</p>
-            <span></span>
           </div>
         <p class=\\"error-message\\"><span>Not as good as the first one</span></p></div>
       </div>
@@ -972,7 +956,6 @@ exports[`telepath: wagtail.blocks.ListBlock setError renders non-block errors 1`
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-0-value\\" id=\\"the-prefix-0-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -1023,7 +1006,6 @@ exports[`telepath: wagtail.blocks.ListBlock setError renders non-block errors 1`
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-1-value\\" id=\\"the-prefix-1-value\\">The widget</p>
-            <span></span>
           </div>
         </div>
       </div>

+ 0 - 15
client/src/components/StreamField/blocks/__snapshots__/StreamBlock.test.js.snap

@@ -55,7 +55,6 @@ exports[`telepath: wagtail.blocks.StreamBlock blocks can be duplicated 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-0-value\\" id=\\"the-prefix-0-value\\">Block A widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -111,7 +110,6 @@ exports[`telepath: wagtail.blocks.StreamBlock blocks can be duplicated 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-1-value\\" id=\\"the-prefix-1-value\\">Block B widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -167,7 +165,6 @@ exports[`telepath: wagtail.blocks.StreamBlock blocks can be duplicated 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-2-value\\" id=\\"the-prefix-2-value\\">Block B widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -242,7 +239,6 @@ exports[`telepath: wagtail.blocks.StreamBlock blocks can be reordered downward 1
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-1-value\\" id=\\"the-prefix-1-value\\">Block B widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -298,7 +294,6 @@ exports[`telepath: wagtail.blocks.StreamBlock blocks can be reordered downward 1
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-0-value\\" id=\\"the-prefix-0-value\\">Block A widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -373,7 +368,6 @@ exports[`telepath: wagtail.blocks.StreamBlock blocks can be reordered upward 1`]
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-1-value\\" id=\\"the-prefix-1-value\\">Block B widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -429,7 +423,6 @@ exports[`telepath: wagtail.blocks.StreamBlock blocks can be reordered upward 1`]
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-0-value\\" id=\\"the-prefix-0-value\\">Block A widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -504,7 +497,6 @@ exports[`telepath: wagtail.blocks.StreamBlock it renders correctly 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-0-value\\" id=\\"the-prefix-0-value\\">Block A widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -560,7 +552,6 @@ exports[`telepath: wagtail.blocks.StreamBlock it renders correctly 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-1-value\\" id=\\"the-prefix-1-value\\">Block B widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -635,7 +626,6 @@ exports[`telepath: wagtail.blocks.StreamBlock it renders menus on opening 1`] =
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-0-value\\" id=\\"the-prefix-0-value\\">Block A widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -701,7 +691,6 @@ exports[`telepath: wagtail.blocks.StreamBlock it renders menus on opening 1`] =
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-1-value\\" id=\\"the-prefix-1-value\\">Block B widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -776,7 +765,6 @@ exports[`telepath: wagtail.blocks.StreamBlock setError renders error messages 1`
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-0-value\\" id=\\"the-prefix-0-value\\">Block A widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -832,7 +820,6 @@ exports[`telepath: wagtail.blocks.StreamBlock setError renders error messages 1`
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-1-value\\" id=\\"the-prefix-1-value\\">Block B widget</p>
-            <span></span>
           </div>
         <p class=\\"error-message\\"><span>Not as good as the first one</span></p></div>
       </div>
@@ -917,7 +904,6 @@ exports[`telepath: wagtail.blocks.StreamBlock with labels that need escaping it
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-0-value\\" id=\\"the-prefix-0-value\\">Block A widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -973,7 +959,6 @@ exports[`telepath: wagtail.blocks.StreamBlock with labels that need escaping it
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-1-value\\" id=\\"the-prefix-1-value\\">Block B widget</p>
-            <span></span>
           </div>
         </div>
       </div>

+ 2 - 8
client/src/components/StreamField/blocks/__snapshots__/StructBlock.test.js.snap

@@ -2,7 +2,7 @@
 
 exports[`telepath: wagtail.blocks.StructBlock it renders correctly 1`] = `
 "<div class=\\"struct-block\\">
-        
+
           <span>
             <div class=\\"help\\">
               <div class=\\"icon-help\\">?</div>
@@ -15,7 +15,6 @@ exports[`telepath: wagtail.blocks.StructBlock it renders correctly 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-heading_text\\" id=\\"the-prefix-heading_text\\">Heading widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -25,7 +24,6 @@ exports[`telepath: wagtail.blocks.StructBlock it renders correctly 1`] = `
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-size\\" id=\\"the-prefix-size\\">Size widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -34,7 +32,7 @@ exports[`telepath: wagtail.blocks.StructBlock it renders correctly 1`] = `
 
 exports[`telepath: wagtail.blocks.StructBlock setError passes error messages to children 1`] = `
 "<div class=\\"struct-block\\">
-        
+
           <span>
             <div class=\\"help\\">
               <div class=\\"icon-help\\">?</div>
@@ -47,7 +45,6 @@ exports[`telepath: wagtail.blocks.StructBlock setError passes error messages to
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-heading_text\\" id=\\"the-prefix-heading_text\\">Heading widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -57,7 +54,6 @@ exports[`telepath: wagtail.blocks.StructBlock setError passes error messages to
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-size\\" id=\\"the-prefix-size\\">Size widget</p>
-            <span></span>
           </div>
         <p class=\\"error-message\\"><span>This is too big</span></p></div>
       </div>
@@ -71,7 +67,6 @@ exports[`telepath: wagtail.blocks.StructBlock with formTemplate it renders corre
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-heading_text\\" id=\\"the-prefix-heading_text\\">Heading widget</p>
-            <span></span>
           </div>
         </div>
       </div>
@@ -80,7 +75,6 @@ exports[`telepath: wagtail.blocks.StructBlock with formTemplate it renders corre
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"the-prefix-size\\" id=\\"the-prefix-size\\">Size widget</p>
-            <span></span>
           </div>
         </div>
       </div>

+ 1 - 1
client/src/entrypoints/admin/expanding-formset.test.js

@@ -169,7 +169,7 @@ describe('buildExpandingFormset', () => {
     </li>
   </ul>
   <fieldset>
-    <legend>Events</legend>
+    <legend class="w-sr-only">Events</legend>
     <input type="text" name="venues-__prefix__-events-__prefix__-name" id="id_venues-__prefix__-events-__prefix__-name">
   </fieldset>
 <-/script>

+ 1 - 5
client/src/entrypoints/contrib/typed_table_block/__snapshots__/typed_table_block.test.js.snap

@@ -26,14 +26,12 @@ exports[`wagtail.contrib.typed_table_block.blocks.TypedTableBlock it renders cor
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"mytable-cell-0-0\\" id=\\"mytable-cell-0-0\\">Block A widget</p>
-            <span></span>
           </div>
         </div>
       </div></td><td><div class=\\"field char_field widget-admin_auto_height_text_input fieldname-test_textblock\\">
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"mytable-cell-0-1\\" id=\\"mytable-cell-0-1\\">Block B widget</p>
-            <span></span>
           </div>
         </div>
       </div></td><td class=\\"control-cell\\"><input type=\\"hidden\\" name=\\"mytable-row-0-order\\" value=\\"0\\"><button type=\\"button\\" class=\\"button button-secondary button-small button--icon text-replace no delete-row\\" aria-label=\\"Delete row\\" title=\\"Delete row\\">
@@ -44,14 +42,12 @@ exports[`wagtail.contrib.typed_table_block.blocks.TypedTableBlock it renders cor
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"mytable-cell-1-0\\" id=\\"mytable-cell-1-0\\">Block A widget</p>
-            <span></span>
           </div>
         </div>
       </div></td><td><div class=\\"field char_field widget-admin_auto_height_text_input fieldname-test_textblock\\">
         <div class=\\"field-content\\">
           <div class=\\"input\\">
             <p name=\\"mytable-cell-1-1\\" id=\\"mytable-cell-1-1\\">Block B widget</p>
-            <span></span>
           </div>
         </div>
       </div></td><td class=\\"control-cell\\"><input type=\\"hidden\\" name=\\"mytable-row-1-order\\" value=\\"1\\"><button type=\\"button\\" class=\\"button button-secondary button-small button--icon text-replace no delete-row\\" aria-label=\\"Delete row\\" title=\\"Delete row\\">
@@ -69,7 +65,7 @@ exports[`wagtail.contrib.typed_table_block.blocks.TypedTableBlock it renders cor
             </tfoot>
           </table>
         </div>
-      
+
         <span>
           <div class=\\"help\\">
             <div class=\\"icon-help\\">?</div>

+ 1 - 3
docs/reference/pages/panels.md

@@ -29,9 +29,7 @@ Here are some Wagtail-specific types that you might include as fields in your mo
 
     .. attribute:: FieldPanel.classname
 
-        This is a string of optional CSS classes given to the panel which are used in formatting and scripted interactivity. By default, panels are formatted as inset fields.
-
-        The CSS class ``full`` can be used to format the panel so it covers the full width of the Wagtail page editor.
+        This is a string of optional CSS classes given to the panel which are used in formatting and scripted interactivity.
 
         The CSS class ``title`` can be used to give the field a larger text size, suitable for representing page titles and section headings.
 

+ 1 - 0
wagtail/admin/static_src/wagtailadmin/scss/panels/draftail.scss

@@ -1,3 +1,4 @@
 @import '../../../../../../client/scss/settings';
 @import '../../../../../../client/scss/tools';
+@import '../../../../../../client/scss/components/forms/input-base';
 @import '../../../../../../client/src/components/Draftail/Draftail';

+ 1 - 1
wagtail/admin/templates/wagtailadmin/account/password_reset/form.html

@@ -30,7 +30,7 @@
 
                 {% block extra_fields %}
                     {% for field_name, field in form.extra_fields %}
-                        <li class="full">
+                        <li>
                             {{ field.label_tag }}
                             <div class="field iconfield">
                                 {{ field }}

+ 3 - 3
wagtail/admin/templates/wagtailadmin/login.html

@@ -32,7 +32,7 @@
                 <div class="fields-wrapper">
                     <ul class="fields">
                         {% block fields %}
-                            <li class="full">
+                            <li>
                                 <div class="field iconfield">
                                     {{ form.username.label_tag }}
                                     <div class="input icon-user">
@@ -40,7 +40,7 @@
                                     </div>
                                 </div>
                             </li>
-                            <li class="full">
+                            <li>
                                 <div class="field iconfield">
                                     {{ form.password.label_tag }}
                                     <div class="input icon-password">
@@ -51,7 +51,7 @@
 
                             {% block extra_fields %}
                                 {% for field_name, field in form.extra_fields %}
-                                    <li class="full">
+                                    <li>
                                         {{ field.label_tag }}
                                         <div class="field iconfield">
                                             {{ field }}

+ 1 - 1
wagtail/admin/templates/wagtailadmin/pages/confirm_delete.html

@@ -74,7 +74,7 @@
                         This action will delete total <b>{{ total_pages }}</b> pages.
                     {% endblocktrans %}
                 </p>
-                <label class="no-float w-font-normal" for="id_confirm_site_name">
+                <label class="w-label-3" for="id_confirm_site_name">
                     {% blocktrans trimmed %}
                         Please type <b>{{ wagtail_site_name }}</b> to confirm.
                     {% endblocktrans %}

+ 1 - 1
wagtail/admin/templates/wagtailadmin/pages/confirm_unpublish.html

@@ -27,7 +27,7 @@
                             <div class="field-content">
                                 <div class="input">
                                     <input id="id_include_descendants" name="include_descendants" type="checkbox">
-                                    <label for="id_include_descendants" class="plain-checkbox-label">
+                                    <label for="id_include_descendants" class="w-label-3">
                                         {% if translation_descendant_count %}
                                             {% if translation_descendant_count == 1 %}
                                                 {% blocktrans trimmed count counter=live_descendant_count %}

+ 1 - 1
wagtail/admin/templates/wagtailadmin/panels/help_panel.html

@@ -1,6 +1,6 @@
 <fieldset>
     {% if self.heading %}
-        <legend>{{ self.heading }}</legend>
+        <legend class="w-sr-only">{{ self.heading }}</legend>
     {% endif %}
     <div class="{{ self.classname }}">{{ self.content|safe }}</div>
 </fieldset>

+ 0 - 1
wagtail/admin/templates/wagtailadmin/shared/collection_chooser.html

@@ -14,7 +14,6 @@
                         </option>
                     {% endfor %}
                 </select>
-                <span></span>
             </div>
         </div>
     </div>

+ 0 - 2
wagtail/admin/templates/wagtailadmin/shared/field.html

@@ -10,8 +10,6 @@
                 {{ field|render_with_errors }}
             {% endblock %}
 
-            {# This span only used on rare occasions by certain types of input #}
-            <span></span>
         </div>
         {% if show_help_text|default_if_none:True and field.help_text %}
             <p class="help">{{ field.help_text }}</p>

+ 0 - 2
wagtail/admin/templates/wagtailadmin/shared/side_panels/preview.html

@@ -52,8 +52,6 @@
                                 <option value="{{ internal_name }}"{% if internal_name == object.default_preview_mode %} selected{% endif %}>{{ display_name }}</option>
                             {% endfor %}
                         </select>
-                        <span>
-                        </span>
                     </div>
                 </div>
             {% endif %}

+ 4 - 1
wagtail/admin/templates/wagtailadmin/widgets/switch.html

@@ -1,4 +1,7 @@
+{% load wagtailadmin_tags %}
 <label class="switch">
     {% include "django/forms/widgets/input.html" %}
-    <span class="switch__toggle"></span>
+    <span class="switch__toggle">
+        {% icon name="tick" class_name="switch__tick" %}
+    </span>
 </label>

+ 3 - 3
wagtail/contrib/forms/templates/wagtailforms/panels/form_responses_panel.html

@@ -2,9 +2,9 @@
 {% trans "Total submissions" as total %}
 {% trans "Latest submission" as latest %}
 <fieldset>
-    <legend>{{ self.heading }}</legend>
+    <legend class="w-sr-only">{{ self.heading }}</legend>
     <ul class="fields">
-        <li class="full">
+        <li>
             <div class="field">
                 <label class="label">{{ total }}</label>
                 <div class="field-content">
@@ -14,7 +14,7 @@
                 </div>
             </div>
         </li>
-        <li class="full">
+        <li>
             <div class="field">
                 <label class="label">{{ latest }}</label>
                 <div class="field-content">

+ 0 - 1
wagtail/contrib/modeladmin/templates/modeladmin/includes/search_form.html

@@ -9,7 +9,6 @@
                         <div class="input">
                             {% icon name="search" %}
                             <input id="id_q" name="{{ search_var }}" value="{{ view.query }}" placeholder="{% blocktrans trimmed with view.verbose_name_plural|lower as name %}Search {{ name }}{% endblocktrans %}" type="text">
-                            <span></span>
                         </div>
                     </div>
                 </div>

+ 1 - 1
wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/includes/searchpromotion_form.html

@@ -7,7 +7,7 @@
     </ul>
 
     <fieldset>
-        <legend>{% trans "Promoted search result" %}</legend>
+        <legend class="w-sr-only">{% trans "Promoted search result" %}</legend>
         <ul class="fields">
             <li class="model_choice_field">
                 {% include "wagtailadmin/shared/field.html" with field=form.page only %}

+ 0 - 1
wagtail/contrib/settings/templates/wagtailsettings/edit.html

@@ -14,7 +14,6 @@
                     </label>
                     <div class="input">
                         {{ site_switcher.site }}
-                        <span></span>
                     </div>
                 </form>
             </div>

+ 1 - 1
wagtail/images/templates/wagtailimages/images/edit.html

@@ -79,7 +79,7 @@
 
                 <div class="row">
                     <div class="col8 divider-after">
-                        <h2 class="label no-float">{% trans "Focal point" %} <span class="w-font-normal">{% trans "(optional)" %}</span></h2>
+                        <h2 class="w-label-3">{% trans "Focal point" %} <span class="w-font-normal">{% trans "(optional)" %}</span></h2>
                         <p>{% trans "To define this image's most important region, drag a box over the image above." %} {% if image.has_focal_point %}({% trans "Current focal point shown" %}){% endif %}</p>
 
                         <button class="button button-secondary no remove-focal-point" type="button">{% trans "Remove focal area" %}</button>

+ 1 - 3
wagtail/images/templates/wagtailimages/images/index.html

@@ -67,7 +67,6 @@
                                                 <option value="{{ ordering }}" {% if current_ordering == ordering %}selected="selected"{% endif %}>{{ ordering_text }}</option>
                                             {% endfor %}
                                         </select>
-                                        <span></span>
                                     </div>
                                 </div>
                             </div>
@@ -82,7 +81,6 @@
                                                 <option value="{{ value }}" {% if entries_per_page == value %}selected="selected"{% endif %}>{{ value }}</option>
                                             {% endfor %}
                                         </select>
-                                        <span></span>
                                     </div>
                                 </div>
                             </div>
@@ -92,7 +90,7 @@
                 {% if popular_tags %}
                     <li>
                         <fieldset class="tagfilter">
-                            <legend>{% trans 'Popular Tags:' %}</legend>
+                            <legend class="w-sr-only">{% trans 'Popular Tags:' %}</legend>
                             {% for tag in popular_tags %}
                                 {% if tag.name != current_tag %}
                                     <a class="button button-small button-secondary bicolor button--icon" href="{% url 'wagtailimages:index' %}{% querystring tag=tag.name %}">{% icon name="tag" wrapped=1 %}{{ tag.name }}</a>

+ 11 - 11
wagtail/test/demosite/models.py

@@ -180,7 +180,7 @@ class HomePageRelatedLink(Orderable, AbstractRelatedLink):
 
 
 HomePage.content_panels = Page.content_panels + [
-    FieldPanel("body", classname="full"),
+    FieldPanel("body"),
     InlinePanel("carousel_items", label="Carousel items"),
     InlinePanel("related_links", label="Related links"),
 ]
@@ -230,9 +230,9 @@ class StandardPageRelatedLink(Orderable, AbstractRelatedLink):
 
 
 StandardPage.content_panels = Page.content_panels + [
-    FieldPanel("intro", classname="full"),
+    FieldPanel("intro"),
     InlinePanel("carousel_items", label="Carousel items"),
-    FieldPanel("body", classname="full"),
+    FieldPanel("body"),
     InlinePanel("related_links", label="Related links"),
 ]
 
@@ -274,7 +274,7 @@ class StandardIndexPageRelatedLink(Orderable, AbstractRelatedLink):
 
 
 StandardIndexPage.content_panels = Page.content_panels + [
-    FieldPanel("intro", classname="full"),
+    FieldPanel("intro"),
     InlinePanel("related_links", label="Related links"),
 ]
 
@@ -345,7 +345,7 @@ class BlogEntryPageTag(TaggedItemBase):
 
 BlogEntryPage.content_panels = Page.content_panels + [
     FieldPanel("date"),
-    FieldPanel("body", classname="full"),
+    FieldPanel("body"),
     InlinePanel("carousel_items", label="Carousel items"),
     InlinePanel("related_links", label="Related links"),
 ]
@@ -407,7 +407,7 @@ class BlogIndexPageRelatedLink(Orderable, AbstractRelatedLink):
 
 
 BlogIndexPage.content_panels = Page.content_panels + [
-    FieldPanel("intro", classname="full"),
+    FieldPanel("intro"),
     InlinePanel("related_links", label="Related links"),
 ]
 
@@ -521,7 +521,7 @@ EventPage.content_panels = Page.content_panels + [
     FieldPanel("cost"),
     FieldPanel("signup_link"),
     InlinePanel("carousel_items", label="Carousel items"),
-    FieldPanel("body", classname="full"),
+    FieldPanel("body"),
     InlinePanel("speakers", label="Speakers"),
     InlinePanel("related_links", label="Related links"),
 ]
@@ -569,7 +569,7 @@ class EventIndexPageRelatedLink(Orderable, AbstractRelatedLink):
 
 
 EventIndexPage.content_panels = Page.content_panels + [
-    FieldPanel("intro", classname="full"),
+    FieldPanel("intro"),
     InlinePanel("related_links", label="Related links"),
 ]
 
@@ -627,8 +627,8 @@ class PersonPageRelatedLink(Orderable, AbstractRelatedLink):
 PersonPage.content_panels = Page.content_panels + [
     FieldPanel("first_name"),
     FieldPanel("last_name"),
-    FieldPanel("intro", classname="full"),
-    FieldPanel("biography", classname="full"),
+    FieldPanel("intro"),
+    FieldPanel("biography"),
     FieldPanel("image"),
     MultiFieldPanel(ContactFieldsMixin.panels, "Contact"),
     InlinePanel("related_links", label="Related links"),
@@ -668,7 +668,7 @@ class ContactPage(Page, ContactFieldsMixin):
 
 
 ContactPage.content_panels = Page.content_panels + [
-    FieldPanel("body", classname="full"),
+    FieldPanel("body"),
     MultiFieldPanel(ContactFieldsMixin.panels, "Contact"),
 ]
 

+ 24 - 24
wagtail/test/testapp/models.py

@@ -386,7 +386,7 @@ class EventPage(Page):
         FieldPanel("cost"),
         FieldPanel("signup_link"),
         InlinePanel("carousel_items", label="Carousel items"),
-        FieldPanel("body", classname="full"),
+        FieldPanel("body"),
         InlinePanel("speakers", label="Speakers", heading="Speaker lineup"),
         InlinePanel("related_links", label="Related links"),
         FieldPanel("categories"),
@@ -525,7 +525,7 @@ class EventIndex(Page):
 
     content_panels = [
         FieldPanel("title", classname="full title"),
-        FieldPanel("intro", classname="full"),
+        FieldPanel("intro"),
     ]
 
 
@@ -551,9 +551,9 @@ class FormPage(AbstractEmailForm):
         InlinePanel("form_fields", label="Form fields"),
         MultiFieldPanel(
             [
-                FieldPanel("to_address", classname="full"),
-                FieldPanel("from_address", classname="full"),
-                FieldPanel("subject", classname="full"),
+                FieldPanel("to_address"),
+                FieldPanel("from_address"),
+                FieldPanel("subject"),
             ],
             "Email",
         ),
@@ -577,9 +577,9 @@ class JadeFormPage(AbstractEmailForm):
         InlinePanel("form_fields", label="Form fields"),
         MultiFieldPanel(
             [
-                FieldPanel("to_address", classname="full"),
-                FieldPanel("from_address", classname="full"),
-                FieldPanel("subject", classname="full"),
+                FieldPanel("to_address"),
+                FieldPanel("from_address"),
+                FieldPanel("subject"),
             ],
             "Email",
         ),
@@ -626,9 +626,9 @@ class FormPageWithRedirect(AbstractEmailForm):
         InlinePanel("form_fields", label="Form fields"),
         MultiFieldPanel(
             [
-                FieldPanel("to_address", classname="full"),
-                FieldPanel("from_address", classname="full"),
-                FieldPanel("subject", classname="full"),
+                FieldPanel("to_address"),
+                FieldPanel("from_address"),
+                FieldPanel("subject"),
             ],
             "Email",
         ),
@@ -706,14 +706,14 @@ class FormPageWithCustomSubmission(AbstractEmailForm):
 
     content_panels = [
         FieldPanel("title", classname="full title"),
-        FieldPanel("intro", classname="full"),
+        FieldPanel("intro"),
         InlinePanel("custom_form_fields", label="Form fields"),
-        FieldPanel("thank_you_text", classname="full"),
+        FieldPanel("thank_you_text"),
         MultiFieldPanel(
             [
-                FieldPanel("to_address", classname="full"),
-                FieldPanel("from_address", classname="full"),
-                FieldPanel("subject", classname="full"),
+                FieldPanel("to_address"),
+                FieldPanel("from_address"),
+                FieldPanel("subject"),
             ],
             "Email",
         ),
@@ -777,14 +777,14 @@ class FormPageWithCustomSubmissionListView(AbstractEmailForm):
 
     content_panels = [
         FieldPanel("title", classname="full title"),
-        FieldPanel("intro", classname="full"),
+        FieldPanel("intro"),
         InlinePanel("form_fields", label="Form fields"),
-        FieldPanel("thank_you_text", classname="full"),
+        FieldPanel("thank_you_text"),
         MultiFieldPanel(
             [
-                FieldPanel("to_address", classname="full"),
-                FieldPanel("from_address", classname="full"),
-                FieldPanel("subject", classname="full"),
+                FieldPanel("to_address"),
+                FieldPanel("from_address"),
+                FieldPanel("subject"),
             ],
             "Email",
         ),
@@ -852,9 +852,9 @@ class FormPageWithCustomFormBuilder(AbstractEmailForm):
         InlinePanel("form_fields", label="Form fields"),
         MultiFieldPanel(
             [
-                FieldPanel("to_address", classname="full"),
-                FieldPanel("from_address", classname="full"),
-                FieldPanel("subject", classname="full"),
+                FieldPanel("to_address"),
+                FieldPanel("from_address"),
+                FieldPanel("subject"),
             ],
             "Email",
         ),

+ 3 - 3
wagtail/users/templates/wagtailusers/groups/includes/formatted_permissions.html

@@ -1,7 +1,7 @@
 {% load i18n %}
 
 <fieldset>
-    <legend class="visuallyhidden">{% trans "Permissions" %}</legend>
+    <legend class="w-sr-only">{% trans "Permissions" %}</legend>
     <h2>{% trans "Object permissions" %}</h2>
     <table class="listing">
         <col />
@@ -48,7 +48,7 @@
                         <td>
                             {% if content_perms_dict.custom %}
                                 <fieldset class="custom-permissions">
-                                    <legend>{% trans "Custom permissions" %}</legend>
+                                    <legend class="w-sr-only">{% trans "Custom permissions" %}</legend>
                                     {% for custom_perm in content_perms_dict.custom %}
                                         <label class="custom-permissions-item">
                                             <input type="checkbox" name="permissions" value="{{ custom_perm.perm.id }}" {% if custom_perm.selected %}checked{% endif %}>
@@ -77,7 +77,7 @@
         <tbody>
             {% for perm_tuple in other_perms %}
                 <tr>
-                    <td class="title"><label for="{{ perm_tuple.1.id_for_label }}" class="plain-checkbox-label">{{ perm_tuple.0.name }}</label></td>
+                    <td class="title"><label for="{{ perm_tuple.1.id_for_label }}" class="w-label-3">{{ perm_tuple.0.name }}</label></td>
                     <td>
                         {{ perm_tuple.1.tag }}
                     </td>