Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ Introduce new sections and organize content to help visitors (and search engines

- **Name:** core/heading
- **Category:** text
- **Supports:** __unstablePasteTextInline, align (full, wide), anchor, className, color (background, gradients, link, text), interactivity (clientNavigation), spacing (margin, padding), splitting, typography (fitText, fontSize, lineHeight, textAlign)
- **Supports:** __unstablePasteTextInline, align (full, wide), anchor, background (backgroundClip, backgroundImage, gradient), className, color (background, gradients, link, text), interactivity (clientNavigation), spacing (margin, padding), splitting, typography (fitText, fontSize, lineHeight, textAlign)
- **Attributes:** content, level, levelOptions, placeholder

## Home Link
Expand Down Expand Up @@ -606,7 +606,7 @@ Start with the basic building block of all narrative. ([Source](https://github.c

- **Name:** core/paragraph
- **Category:** text
- **Supports:** __unstablePasteTextInline, align (full, wide), anchor, color (background, gradients, link, text), interactivity (clientNavigation), spacing (margin, padding), splitting, typography (fitText, fontSize, lineHeight, textAlign, textColumns, textIndent), ~~className~~
- **Supports:** __unstablePasteTextInline, align (full, wide), anchor, background (backgroundClip, gradient), color (background, gradients, link, text), interactivity (clientNavigation), spacing (margin, padding), splitting, typography (fitText, fontSize, lineHeight, textAlign, textColumns, textIndent), ~~className~~
- **Attributes:** content, direction, dropCap, placeholder

## Pattern Placeholder
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import {
Dropdown,
Button,
__experimentalDropdownContentWrapper as DropdownContentWrapper,
__experimentalHStack as HStack,
__experimentalVStack as VStack,
FlexBlock,
} from '@wordpress/components';
import { useState } from '@wordpress/element';

/**
* External dependencies
*/
import clsx from 'clsx';

export const ALL_BACKGROUND_CLIP_VALUES = [
'border-box',
'padding-box',
'content-box',
'text',
];

const BACKGROUND_CLIP_OPTIONS = [
{
label: __( 'Border box' ),
value: 'border-box',
},
{
label: __( 'Padding box' ),
value: 'padding-box',
},
{
label: __( 'Content box' ),
value: 'content-box',
},
{
label: __( 'Text' ),
value: 'text',
},
];

const BACKGROUND_POPOVER_PROPS = {
placement: 'left-start',
offset: 36,
shift: true,
className: 'block-editor-background-clip-control__popover',
};

function BackgroundClipPreview( { value } ) {
const isText = value === 'text';

return (
<span
aria-hidden="true"
className={ clsx( 'block-editor-background-clip-control__preview', {
'is-text': isText,
'is-padding-box': value === 'padding-box',
'is-content-box': value === 'content-box',
} ) }
>
{ isText && 'Ab' }
</span>
);
}

function BackgroundClipOption( { label, value, isActive, onSelect } ) {
return (
<button
role="option"
aria-label={ label }
aria-selected={ isActive }
className={ clsx( 'block-editor-background-clip-control__option', {
'is-active': isActive,
} ) }
onClick={ onSelect }
>
<BackgroundClipPreview value={ value } />
<span className="block-editor-background-clip-control__option-label">
{ label }
</span>
</button>
);
}

function BackgroundClipToggle( { value, toggleProps } ) {
const activeOption = BACKGROUND_CLIP_OPTIONS.find(
( option ) => option.value === value
);
const label = activeOption ? activeOption.label : __( 'Border box' );

return (
<Button __next40pxDefaultSize { ...toggleProps }>
<HStack className="block-editor-background-clip-control__toggle-inner">
<BackgroundClipPreview value={ value || 'border-box' } />
<FlexBlock>{ label }</FlexBlock>
</HStack>
</Button>
);
}

export default function BackgroundClipControl( {
value,
onChange,
allowedValues,
} ) {
const [ isOpen, setIsOpen ] = useState( false );

const options = allowedValues
? BACKGROUND_CLIP_OPTIONS.filter( ( opt ) =>
allowedValues.includes( opt.value )
)
: BACKGROUND_CLIP_OPTIONS;

return (
<div
className={ clsx(
'block-editor-background-clip-control__container',
{
'is-open': isOpen,
}
) }
>
<Dropdown
popoverProps={ BACKGROUND_POPOVER_PROPS }
renderToggle={ ( { onToggle, isOpen: dropdownIsOpen } ) => {
return (
<BackgroundClipToggle
value={ value }
toggleProps={ {
onClick: () => {
onToggle();
setIsOpen( ! dropdownIsOpen );
},
className:
'block-editor-background-clip-control__dropdown-toggle',
'aria-expanded': dropdownIsOpen,
'aria-label': __( 'Background clip options' ),
} }
/>
);
} }
onClose={ () => setIsOpen( false ) }
renderContent={ () => (
<DropdownContentWrapper
className="block-editor-background-clip-control__dropdown-content-wrapper"
paddingSize="medium"
>
<VStack spacing={ 2 }>
<span className="block-editor-background-clip-control__popover-title">
{ __( 'Background clip' ) }
</span>
<div
role="listbox"
className="block-editor-background-clip-control__options"
aria-label={ __( 'Background clip' ) }
>
{ options.map( ( option ) => (
<BackgroundClipOption
key={ option.value }
label={ option.label }
value={ option.value }
isActive={ value === option.value }
onSelect={ () =>
onChange(
value === option.value
? undefined
: option.value
)
}
/>
) ) }
</div>
</VStack>
</DropdownContentWrapper>
) }
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
@use "@wordpress/base-styles/variables" as *;
@use "@wordpress/base-styles/colors" as *;

.block-editor-background-clip-control__container {
position: relative;

&.is-open {
background-color: $gray-100;
}

.components-dropdown {
display: block;
}
}

.block-editor-background-clip-control__dropdown-toggle {
cursor: pointer;
background: transparent;
border: none;
height: $button-size-next-default-40px;
width: 100%;
padding-left: $grid-unit-15;
padding-right: $grid-unit-15;
color: $gray-900;

&:hover {
color: var(--wp-admin-theme-color);
}

&:focus {
box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
}
}

// Popover content
.block-editor-background-clip-control__dropdown-content-wrapper {
min-width: 260px;
}

.block-editor-background-clip-control__popover-title {
font-size: 11px;
font-weight: 500;
text-transform: uppercase;
color: $gray-700;
}

.block-editor-background-clip-control__options {
display: grid;
grid-template-columns: 1fr 1fr;
gap: $grid-unit-10;
}

.block-editor-background-clip-control__option {
appearance: none;
background: $gray-100;
color: $gray-900;
border: $border-width solid $gray-200;
border-radius: $radius-small;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: $grid-unit-10;
padding: $grid-unit-15;
box-sizing: border-box;

@media not (prefers-reduced-motion) {
transition:
border-color 0.1s ease,
background-color 0.1s ease;
}

&:hover {
background-color: $gray-200;
border-color: $gray-400;
}

&:focus-visible {
outline: none;
box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
}

&.is-active {
background-color: $white;
border-color: var(--wp-admin-theme-color);
box-shadow: inset 0 0 0 $border-width var(--wp-admin-theme-color);
}
}

.block-editor-background-clip-control__option-label {
font-size: 12px;
line-height: 1;
}

// Preview swatch shared styles
.block-editor-background-clip-control__preview {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 2px;
box-sizing: border-box;

// Background gradient as the "fill" that gets clipped.
background: linear-gradient(135deg, var(--wp-admin-theme-color) 0%, var(--wp-admin-theme-color-darker-20, #{$gray-700}) 100%);

// Default: border-box — fill extends to border edge.
// Show a dashed border to indicate the border area is included.
border: 3px dashed rgba(0, 0, 0, 0.15);
background-clip: border-box;

&.is-padding-box {
// Fill clips to inside the border — border area is empty.
border: 3px dashed $gray-400;
background-clip: padding-box;
}

&.is-content-box {
// Fill clips to content only — padding and border are empty.
border: 3px dashed $gray-400;
padding: 4px;
background-clip: content-box;
}

&.is-text {
font-size: 18px;
font-weight: 800;
line-height: 1;
color: transparent;
border: none;
padding: 0;
-webkit-background-clip: text;
background-clip: text;
}
}

// Smaller preview in the toggle button row.
.block-editor-background-clip-control__toggle-inner {
height: 100%;

.block-editor-background-clip-control__preview {
width: 20px;
height: 20px;
border-width: 2px;
flex-shrink: 0;

&.is-content-box {
padding: 2px;
border-width: 2px;
}

&.is-text {
font-size: 11px;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function StyleInspectorSlots( {
/>
<InspectorControls.Slot
group="background"
label={ __( 'Background image' ) }
label={ __( 'Background' ) }
className="background-block-support-panel__inner-wrapper"
/>
<InspectorControls.Slot
Expand Down
Loading
Loading