diff --git a/.changeset/green-shoes-press.md b/.changeset/green-shoes-press.md new file mode 100644 index 000000000..22fcb538a --- /dev/null +++ b/.changeset/green-shoes-press.md @@ -0,0 +1,5 @@ +--- +'@cloudfour/patterns': minor +--- + +Add support for Jetpack Form Block diff --git a/src/components/checkbox/checkbox.scss b/src/components/checkbox/checkbox.scss index 2a0e8a402..8481407df 100644 --- a/src/components/checkbox/checkbox.scss +++ b/src/components/checkbox/checkbox.scss @@ -1,175 +1,5 @@ -@use '../../compiled/tokens/scss/color'; -@use '../../compiled/tokens/scss/ease'; -@use '../../compiled/tokens/scss/size'; -@use '../../compiled/tokens/scss/transition'; -@use '../../mixins/focus'; -@use '../../mixins/theme'; - -/** - * Themed properties - */ - -@include theme.props { - --theme-color-text-checkbox-checked-hover: var( - --theme-color-text-checkbox-hover - ); - --theme-color-text-checkbox-disabled: #{color.$base-gray-dark}; - --theme-color-text-checkbox-hover: #{color.$brand-primary}; -} - -@include theme.props(dark) { - --theme-color-text-checkbox-checked-hover: #{color.$brand-primary-darker}; - --theme-color-text-checkbox-disabled: #{color.$text-light}; - --theme-color-text-checkbox-hover: #{color.$text-dark}; -} - -/** - * 1. This `@supports` query prevents IE11 (and older browsers) from applying - * these styles, falling back to the native checkbox appearance. - * 2. Modern browsers let us apply wholly custom styles to certain elements, - * but only when `appearance` is set to `none`. Because this property is not - * a finalized standard, vendor prefixes are still required. - * 3. Some browsers will squish the checkbox in flex containers, which we never, - * ever want. - * 4. Without this, checkboxes appear too small unless hard-pixel sizes are - * used (ew). - */ +@use '../../mixins/toggle-input'; .c-checkbox { - @supports (-moz-appearance: none) or (-webkit-appearance: none) or - (appearance: none) { - /* 1 */ - -moz-appearance: none; /* stylelint-disable-line property-no-vendor-prefix */ - -webkit-appearance: none; /* stylelint-disable-line property-no-vendor-prefix */ - appearance: none; /* 2 */ - background-color: color.$text-light; - block-size: size.$square-toggle-medium; - border: size.$edge-control solid currentColor; - border-radius: size.$border-radius-medium; - color: color.$text-dark; - cursor: pointer; - flex: none; /* 3 */ - font: inherit; /* 4 */ - inline-size: size.$square-toggle-medium; - padding: 0; - position: relative; - transition-duration: transition.$quick; - transition-property: background-color, border-color, color; - transition-timing-function: ease.$out; - vertical-align: middle; - - /** - * State: Focused - * - * We use `focus-visible` here because checkboxes do not inherently require - * keyboard interactions. - */ - - @include focus.focus-visible { - box-shadow: 0 0 0 size.$edge-large color.$brand-primary-lighter; - } - - /** - * We add the check mark via a pseudo element so we can easily apply - * transitions to it without requiring separate elements. - * - * 1. The icon looks kind of claustrophobic if it runs right up to the - * element edge, so we re-use the border size as an inset value. This - * appears much more balanced! - * 2. Starting state of animation. - */ - - &::after { - background-image: svg-load( - 'icons/check.svg', - stroke=color.$text-light-emphasis - ); - background-position: center; - background-repeat: no-repeat; - background-size: contain; - content: ''; - inset: size.$edge-control; /* 1 */ - opacity: 0; /* 2 */ - position: absolute; - transform: scale(0); /* 2 */ - transition-duration: transition.$quick; - transition-property: opacity, transform; - transition-timing-function: ease.$out; - } - - /** - * State: Hover - */ - - &:hover { - background-color: color.$text-light-emphasis; - color: var(--theme-color-text-checkbox-hover); - } - - /** - * State: Checked - */ - - &:checked { - background-color: currentColor; - - /** - * End state of animation - */ - - &::after { - opacity: 1; - transform: scale(1); - } - - &:hover { - color: var(--theme-color-text-checkbox-checked-hover); - } - } - - /** - * State: Disabled - * - * 1. We want the checkbox to appear "read-only." A transparent background - * and dashed line help symbolize a lack of interactivity. - * 2. Same color used for disabled `c-input` borders. - */ - - &:disabled { - background-color: transparent; /* 1 */ - border-style: dashed; /* 1 */ - color: var(--theme-color-text-checkbox-disabled); /* 2 */ - cursor: not-allowed; - - &::after { - /** - * Inline SVGs aren't aware of custom properties, so we have to do a bit - * of theming trickery here - */ - - @include theme.styles { - background-image: svg-load( - 'icons/check.svg', - stroke=color.$base-gray-dark - ); - } - - @include theme.styles(dark) { - background-image: svg-load( - 'icons/check.svg', - stroke=color.$text-light - ); - } - } - - /** - * We can forego the border entirely for a disabled checkmark, as the hit - * area is unimportant. - */ - - &:checked { - border-color: transparent; - } - } - } + @include toggle-input.checkbox; } diff --git a/src/components/input/input.scss b/src/components/input/input.scss index 35a2d4187..8a26bd40f 100644 --- a/src/components/input/input.scss +++ b/src/components/input/input.scss @@ -1,164 +1,5 @@ -@use 'sass:math'; -@use '../../compiled/tokens/scss/color'; -@use '../../compiled/tokens/scss/ease'; -@use '../../compiled/tokens/scss/size'; -@use '../../compiled/tokens/scss/transition'; -@use '../../mixins/theme'; - -/** - * Themed properties - */ - -@include theme.props { - --theme-color-background-input-disabled: #{color.$base-gray-light}; - --theme-color-border-input-disabled: #{color.$base-gray}; - --theme-color-border-input-hover: #{color.$brand-primary}; -} - -@include theme.props(dark) { - --theme-color-background-input-disabled: #{color.$brand-primary-lighter}; - --theme-color-border-input-disabled: #{color.$brand-primary-dark}; - --theme-color-border-input-hover: currentColor; -} - -/** - * 1. Browsers apply certain default styles unless appearance is set to `none`. - * Unfortunately Chrome, Safari and Mozilla all still rely on the - * vendor-prefixed version of this property at the time of this writing. - * 2. Input heights vary between different types in certain browsers unless a - * height is explicitly set. - * 3. Non-normal line heights break placeholder text alignment in Safari. - * 4. Safari will not style disabled inputs with readable text unless we set - * this property in addition to `color`. Unfortunately this also resets the - * appearance of `::placeholder`, which we'll style later on. - */ +@use '../../mixins/input'; .c-input { - -moz-appearance: none; /* stylelint-disable-line property-no-vendor-prefix */ - -webkit-appearance: none; /* stylelint-disable-line property-no-vendor-prefix */ - appearance: none; /* 1 */ - background-color: color.$text-light; - block-size: size.$height-control-default; /* 2 */ - border: size.$edge-control solid currentColor; - border-radius: size.$border-radius-medium; - color: color.$text-dark; - display: block; - font: inherit; - font-style: normal; - inline-size: 100%; - line-height: normal; /* 3 */ - outline: none; - padding: size.$padding-control-vertical size.$spacing-control-text-inset; - -webkit-text-fill-color: color.$text-dark; /* 4 */ - transition-duration: transition.$quick; - transition-property: background-color, border-color; - transition-timing-function: ease.$out; - vertical-align: middle; - - /** - * For certain single-line input types, using `text-indent` instead of - * `padding-left` gives a more natural and intuitive appearance when text - * content overflows. - * - * We do not apply this for search inputs because Safari gets weird about - * search input padding. - */ - - &[type='email'], - &[type='text'] { - padding-inline-start: 0; - text-indent: size.$spacing-control-text-inset; - } - - /** - * For textareas with rows, overrides static default height - */ - - &[rows] { - block-size: auto; - } - - /** - * Progressively-enhanced styles; `is-elastic` is added by JavaScript - */ - - &.is-elastic { - resize: none; - } - - /** - * Multi-line types should be taller - */ - - @at-root textarea#{&} { - block-size: size.$height-control-multiline; - } - - /** - * Types that disclose additional options should have an icon - * - * 1. Setting the background size to `100%` avoids a strange background shift - * bug on hover in Chrome but has no visible effect in other browsers as - * long as the image is an SVG that does not preserve its aspect ratio. - * 2. Firefox misaligns inner options when padding is applied, but all modern - * browsers seem to align selects predictably even when there is no - * vertical padding. We still keep a small amount of padding because - * Firefox's inner dotted outline looks gross when it runs into the outer - * border, and existing hacks around this visibly degrade text rendering. - * 3. Prevents option text from overlapping icon. - */ - - @at-root select#{&} { - background-image: svg-load('icons/caret-down.svg', fill=color.$text-dark); - background-position: right size.$spacing-control-icon-inset center; - background-repeat: no-repeat; - background-size: size.$square-control-icon 100%; /* 1 */ - padding-block: math.div(size.$padding-control-vertical, 2); /* 2 */ - padding-inline-end: size.$spacing-control-icon-inset + - size.$square-control-icon; /* 3 */ - } - - &:hover:not(:disabled):not([readonly]) { - background-color: color.$text-light-emphasis; - border-color: var(--theme-color-border-input-hover); - } - - /** - * We use plain ol' `focus` rather than `focus-visible` because text inputs - * are almost always in a state of keyboard interaction, making the difference - * (if any) minimal. - */ - - &:focus { - background-color: #fff; - box-shadow: 0 0 0 size.$edge-large color.$brand-primary-lighter; - } - - &[readonly]:not(:disabled) { - background-color: transparent; - border-color: transparent; - color: inherit; - } - - &:disabled { - background-color: var(--theme-color-background-input-disabled); - border-color: var(--theme-color-border-input-disabled); - cursor: not-allowed; - } - - /** - * 1. We set `-webkit-text-fill-color` on the root element so that Safari - * would respect our disabled text color. But that also resets the - * `::placeholder` color, so we have to specify our own so it will be - * distinct from a normal value while maintaining reasonable high color - * contrast. - * 2. Firefox uses `opacity` instead of a lightened text color, appearing - * lighter than other browsers unless we reset it here. - */ - - &::placeholder { - color: color.$text-dark-muted; /* 1 */ - opacity: 1; /* 2 */ - -webkit-text-fill-color: color.$text-dark-muted; /* 1 */ - } + @include input.default; } diff --git a/src/mixins/_input.scss b/src/mixins/_input.scss new file mode 100644 index 000000000..3b4f1f134 --- /dev/null +++ b/src/mixins/_input.scss @@ -0,0 +1,171 @@ +@use 'sass:math'; +@use '../compiled/tokens/scss/color'; +@use '../compiled/tokens/scss/ease'; +@use '../compiled/tokens/scss/size'; +@use '../compiled/tokens/scss/transition'; +@use './theme'; + +/// Required themed properties (Default) +@include theme.props { + --theme-color-background-input-disabled: #{color.$base-gray-light}; + --theme-color-border-input-disabled: #{color.$base-gray}; + --theme-color-border-input-hover: #{color.$brand-primary}; +} + +/// Required themed properties (Dark) +@include theme.props(dark) { + --theme-color-background-input-disabled: #{color.$brand-primary-lighter}; + --theme-color-border-input-disabled: #{color.$brand-primary-dark}; + --theme-color-border-input-hover: currentColor; +} + +/// Base input styles +/// +/// 1. Browsers apply certain default styles unless appearance is set to `none`. +/// Unfortunately Chrome, Safari and Mozilla all still rely on the +/// vendor-prefixed version of this property at the time of this writing. +/// 2. Input heights vary between different types in certain browsers unless a +/// height is explicitly set. +/// 3. Non-normal line heights break placeholder text alignment in Safari. +/// 4. Safari will not style disabled inputs with readable text unless we set +/// this property in addition to `color`. Unfortunately this also resets the +/// appearance of `::placeholder`, which we'll style later on. +@mixin base { + // stylelint-disable-next-line property-no-vendor-prefix + -moz-appearance: none; + // stylelint-disable-next-line property-no-vendor-prefix + -webkit-appearance: none; + appearance: none; // 1 + background-color: color.$text-light; + block-size: size.$height-control-default; // 2 + border: size.$edge-control solid currentColor; + border-radius: size.$border-radius-medium; + color: color.$text-dark; + display: block; + font: inherit; + font-style: normal; + inline-size: 100%; + line-height: normal; // 3 + outline: none; + padding: size.$padding-control-vertical size.$spacing-control-text-inset; + -webkit-text-fill-color: color.$text-dark; // 4 + transition-duration: transition.$quick; + transition-property: background-color, border-color; + transition-timing-function: ease.$out; + vertical-align: middle; +} + +/// Single-line input styles (text, email, etc.) +/// +/// For certain single-line input types, using `text-indent` instead of +/// `padding-left` gives a more natural and intuitive appearance when text +/// content overflows. +/// +/// It is not recommended to use this for search inputs because Safari gets +/// weird about search input padding. +@mixin single-line { + padding-inline-start: 0; + text-indent: size.$spacing-control-text-inset; +} + +/// Multi-line input styles (textarea) +@mixin multi-line { + block-size: size.$height-control-multiline; + + // Let the browser determine the height of the textarea based on its content + // when it is not explicitly set. + &[rows] { + block-size: auto; + } + + // Prevent resizing if elastic JavaScript behavior is applied + &.is-elastic { + resize: none; + } +} + +/// Types that disclose additional options should have an icon +/// +/// 1. Setting the background size to `100%` avoids a strange background shift +/// bug on hover in Chrome but has no visible effect in other browsers as +/// long as the image is an SVG that does not preserve its aspect ratio. +/// 2. Firefox misaligns inner options when padding is applied, but all modern +/// browsers seem to align selects predictably even when there is no +/// vertical padding. We still keep a small amount of padding because +/// Firefox's inner dotted outline looks gross when it runs into the outer +/// border, and existing hacks around this visibly degrade text rendering. +/// 3. Prevents option text from overlapping icon. +@mixin icon-affordance( + $icon-url: svg-load('icons/caret-down.svg', fill=color.$text-dark) +) { + @if $icon-url { + background-image: $icon-url; + } + + background-position: right size.$spacing-control-icon-inset center; + background-repeat: no-repeat; + background-size: size.$square-control-icon 100%; // 1 + padding-block: math.div(size.$padding-control-vertical, 2); // 2 + padding-inline-end: size.$spacing-control-icon-inset size.$square-control-icon; // 3 +} + +/// Various input and interaction states +@mixin states { + &:hover:not(:disabled):not([readonly]) { + background-color: color.$text-light-emphasis; + border-color: var(--theme-color-border-input-hover); + } + + /// We use plain ol' `focus` rather than `focus-visible` because text inputs + /// are almost always in a state of keyboard interaction, making the difference + /// (if any) minimal. + &:focus { + background-color: #fff; + box-shadow: 0 0 0 size.$edge-large color.$brand-primary-lighter; + } + + &[readonly]:not(:disabled) { + background-color: transparent; + border-color: transparent; + color: inherit; + } + + &:disabled { + background-color: var(--theme-color-background-input-disabled); + border-color: var(--theme-color-border-input-disabled); + cursor: not-allowed; + } + + /// 1. We set `-webkit-text-fill-color` on the root element so that Safari + /// would respect our disabled text color. But that also resets the + /// `::placeholder` color, so we have to specify our own so it will be + /// distinct from a normal value while maintaining reasonable high color + /// contrast. + /// 2. Firefox uses `opacity` instead of a lightened text color, appearing + /// lighter than other browsers unless we reset it here. + &::placeholder { + color: color.$text-dark-muted; // 1 + opacity: 1; // 2 + -webkit-text-fill-color: color.$text-dark-muted; // 1 + } +} + +/// All default input styles in one convenient mixin! +@mixin default { + @include base; + + @include states; + + &[type='email'], + &[type='text'] { + @include single-line; + } + + @at-root textarea#{&} { + @include multi-line; + } + + @at-root select#{&} { + @include icon-affordance; + } +} diff --git a/src/mixins/_toggle-input.scss b/src/mixins/_toggle-input.scss new file mode 100644 index 000000000..04c6302b2 --- /dev/null +++ b/src/mixins/_toggle-input.scss @@ -0,0 +1,149 @@ +@use '../compiled/tokens/scss/color'; +@use '../compiled/tokens/scss/ease'; +@use '../compiled/tokens/scss/size'; +@use '../compiled/tokens/scss/transition'; +@use './focus'; +@use './theme'; + +@include theme.props { + --theme-color-text-checkbox-checked-hover: var( + --theme-color-text-checkbox-hover + ); + --theme-color-text-checkbox-disabled: #{color.$base-gray-dark}; + --theme-color-text-checkbox-hover: #{color.$brand-primary}; +} + +@include theme.props(dark) { + --theme-color-text-checkbox-checked-hover: #{color.$brand-primary-darker}; + --theme-color-text-checkbox-disabled: #{color.$text-light}; + --theme-color-text-checkbox-hover: #{color.$text-dark}; +} + +/// Checkbox styles +/// +/// 1. This `@supports` query prevents IE11 (and older browsers) from applying +/// these styles, falling back to the native checkbox appearance. +/// 2. Modern browsers let us apply wholly custom styles to certain elements, +/// but only when `appearance` is set to `none`. Because this property is not +/// a finalized standard, vendor prefixes are still required. +/// 3. Some browsers will squish the checkbox in flex containers, which we +/// never, ever want. +/// 4. Without this, checkboxes appear too small unless hard-pixel sizes are +/// used (ew). +@mixin checkbox { + @supports (-moz-appearance: none) or (-webkit-appearance: none) or + (appearance: none) { + // 1 + // stylelint-disable-next-line property-no-vendor-prefix + -moz-appearance: none; + // stylelint-disable-next-line property-no-vendor-prefix + -webkit-appearance: none; + appearance: none; // 2 + background-color: color.$text-light; + block-size: size.$square-toggle-medium; + border: size.$edge-control solid currentColor; + border-radius: size.$border-radius-medium; + color: color.$text-dark; + cursor: pointer; + flex: none; // 3 + font: inherit; // 4 + inline-size: size.$square-toggle-medium; + padding: 0; + position: relative; + transition-duration: transition.$quick; + transition-property: background-color, border-color, color; + transition-timing-function: ease.$out; + vertical-align: middle; + + /// State: Focused + /// + /// We use `focus-visible` here because checkboxes do not inherently require + /// keyboard interactions. + @include focus.focus-visible { + box-shadow: 0 0 0 size.$edge-large color.$brand-primary-lighter; + } + + /// We add the check mark via a pseudo element so we can easily apply + /// transitions to it without requiring separate elements. + /// + /// 1. The icon looks kind of claustrophobic if it runs right up to the + /// element edge, so we re-use the border size as an inset value. This + /// appears much more balanced! + /// 2. Starting state of animation. + &::after { + background-image: svg-load( + 'icons/check.svg', + stroke=color.$text-light-emphasis + ); + background-position: center; + background-repeat: no-repeat; + background-size: contain; + content: ''; + inset: size.$edge-control; // 1 + opacity: 0; // 2 + position: absolute; + transform: scale(0); // 2 + transition-duration: transition.$quick; + transition-property: opacity, transform; + transition-timing-function: ease.$out; + } + + /// State: Hover + &:hover { + background-color: color.$text-light-emphasis; + color: var(--theme-color-text-checkbox-hover); + } + + /// State: Checked + &:checked { + background-color: currentColor; + + /// End state of animation + &::after { + opacity: 1; + transform: scale(1); + } + + &:hover { + color: var(--theme-color-text-checkbox-checked-hover); + } + } + + /// State: Disabled + /// + /// 1. We want the checkbox to appear "read-only." A transparent background + /// and dashed line help symbolize a lack of interactivity. + /// 2. Same color used for disabled `c-input` borders. + + &:disabled { + background-color: transparent; // 1 + border-style: dashed; // 1 + color: var(--theme-color-text-checkbox-disabled); // 2 + cursor: not-allowed; + + &::after { + /// Inline SVGs aren't aware of custom properties, so we have to do a + /// bit of theming trickery here + @include theme.styles { + background-image: svg-load( + 'icons/check.svg', + stroke=color.$base-gray-dark + ); + } + + @include theme.styles(dark) { + background-image: svg-load( + 'icons/check.svg', + stroke=color.$text-light + ); + } + } + + /// We can forego the border entirely for a disabled checkmark, as the hit + /// area is unimportant. + &:checked { + border-color: transparent; + } + } + } +} diff --git a/src/vendor/wordpress/demo/contact-form/form.twig b/src/vendor/wordpress/demo/contact-form/form.twig new file mode 100644 index 000000000..2ab7b82e3 --- /dev/null +++ b/src/vendor/wordpress/demo/contact-form/form.twig @@ -0,0 +1,117 @@ +{% embed '@cloudfour/objects/container/container.twig' with { + class: 'o-container--prose o-container--pad', +} only %} + {% block content %} + {# Markup generated in a local WordPress instance with Jetpack 1.19 on March 14, 2023 #} +