: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @param {string|Object} blockType Block name or Block Type object.
* @return {boolean} Whether there is support.
function hasPositionSupport(blockType) {
const support = (0,external_wp_blocks_namespaceObject.getBlockSupport)(blockType, POSITION_SUPPORT_KEY);
* Checks if there is a current value in the position block support attributes.
* @param {Object} props Block props.
* @return {boolean} Whether or not the block has a position value set.
function hasPositionValue(props) {
return props.attributes.style?.position?.type !== undefined;
* Checks if the block is currently set to a sticky or fixed position.
* This check is helpful for determining how to position block toolbars or other elements.
* @param {Object} attributes Block attributes.
* @return {boolean} Whether or not the block is set to a sticky or fixed position.
function hasStickyOrFixedPositionValue(attributes) {
const positionType = attributes?.style?.position?.type;
return positionType === 'sticky' || positionType === 'fixed';
* Resets the position block support attributes. This can be used when disabling
* the position support controls for a block via a `ToolsPanel`.
* @param {Object} props Block props.
* @param {Object} props.attributes Block's attributes.
* @param {Object} props.setAttributes Function to set block's attributes.
style: cleanEmptyObject({
* Custom hook that checks if position settings have been disabled.
* @param {string} name The name of the block.
* @return {boolean} Whether padding setting is disabled.
function useIsPositionDisabled({
const [allowFixed, allowSticky] = use_settings_useSettings('position.fixed', 'position.sticky');
const isDisabled = !allowFixed && !allowSticky;
return !hasPositionSupport(blockName) || isDisabled;
* Position controls rendered in an inspector control panel.
* @return {Element} Position panel.
function PositionPanelPure({
const allowFixed = hasFixedPositionSupport(blockName);
const allowSticky = hasStickyPositionSupport(blockName);
const value = style?.position?.type;
} = (0,external_wp_data_namespaceObject.useSelect)(select => {
const parents = getBlockParents(clientId);
firstParentClientId: parents[parents.length - 1]
const blockInformation = useBlockDisplayInformation(firstParentClientId);
const stickyHelpText = allowSticky && value === STICKY_OPTION.value && blockInformation ? (0,external_wp_i18n_namespaceObject.sprintf)( /* translators: %s: the name of the parent block. */
(0,external_wp_i18n_namespaceObject.__)('The block will stick to the scrollable area of the parent %s block.'), blockInformation.title) : null;
const options = (0,external_wp_element_namespaceObject.useMemo)(() => {
const availableOptions = [DEFAULT_OPTION];
// Display options if they are allowed, or if a block already has a valid value set.
// This allows for a block to be switched off from a position type that is not allowed.
if (allowSticky || value === STICKY_OPTION.value) {
availableOptions.push(STICKY_OPTION);
if (allowFixed || value === FIXED_OPTION.value) {
availableOptions.push(FIXED_OPTION);
}, [allowFixed, allowSticky, value]);
const onChangeType = next => {
// For now, use a hard-coded `0px` value for the position.
// `0px` is preferred over `0` as it can be used in `calc()` functions.
// In the future, it could be useful to allow for an offset value.
const placementValue = '0px';
top: next === 'sticky' || next === 'fixed' ? placementValue : undefined
style: utils_cleanEmptyObject(newStyle)
const selectedOption = value ? options.find(option => option.value === value) || DEFAULT_OPTION : DEFAULT_OPTION;
// Only display position controls if there is at least one option to choose from.
return external_wp_element_namespaceObject.Platform.select({
web: options.length > 1 ? /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(inspector_controls, {
children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.BaseControl, {
className: "block-editor-hooks__position-selection",
__nextHasNoMarginBottom: true,
children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(CustomSelectControl, {
__next40pxDefaultSize: true,
className: "block-editor-hooks__position-selection__select-control",
label: (0,external_wp_i18n_namespaceObject.__)('Position'),
hideLabelFromVision: true,
describedBy: (0,external_wp_i18n_namespaceObject.sprintf)(
// translators: %s: Currently selected position.
(0,external_wp_i18n_namespaceObject.__)('Currently selected position: %s'), selectedOption.name),
__experimentalShowSelectedHint: true,
onChangeType(selectedItem.value);
/* harmony default export */ const position = ({
edit: function Edit(props) {
const isPositionDisabled = useIsPositionDisabled(props);
if (isPositionDisabled) {
return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(PositionPanelPure, {
useBlockProps: position_useBlockProps,
attributeKeys: ['style'],
return (0,external_wp_blocks_namespaceObject.hasBlockSupport)(name, POSITION_SUPPORT_KEY);
function position_useBlockProps({
const hasPositionBlockSupport = (0,external_wp_blocks_namespaceObject.hasBlockSupport)(name, POSITION_SUPPORT_KEY);
const isPositionDisabled = useIsPositionDisabled({
const allowPositionStyles = hasPositionBlockSupport && !isPositionDisabled;
const id = (0,external_wp_compose_namespaceObject.useInstanceId)(position_useBlockProps);
// Higher specificity to override defaults in editor UI.
const positionSelector = `.wp-container-${id}.wp-container-${id}`;
// Get CSS string for the current position values.
if (allowPositionStyles) {
selector: positionSelector,
// Attach a `wp-container-` id-based class name.
const className = dist_clsx({
[`wp-container-${id}`]: allowPositionStyles && !!css,
// Only attach a container class if there is generated CSS to be attached.
[`is-position-${style?.position?.type}`]: allowPositionStyles && !!css && !!style?.position?.type
;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/global-styles/use-global-styles-output.js
// Elements that rely on class names in their selectors.
const ELEMENT_CLASS_NAMES = {
button: 'wp-element-button',
caption: 'wp-element-caption'
// List of block support features that can have their related styles
// generated under their own feature level selector rather than the block's.
const BLOCK_SUPPORT_FEATURE_LEVEL_SELECTORS = {
__experimentalBorder: 'border',
kebabCase: use_global_styles_output_kebabCase
} = unlock(external_wp_components_namespaceObject.privateApis);
function compileStyleValue(uncompiledValue) {
const VARIABLE_REFERENCE_PREFIX = 'var:';
const VARIABLE_PATH_SEPARATOR_TOKEN_ATTRIBUTE = '|';
const VARIABLE_PATH_SEPARATOR_TOKEN_STYLE = '--';
if (uncompiledValue?.startsWith?.(VARIABLE_REFERENCE_PREFIX)) {
const variable = uncompiledValue.slice(VARIABLE_REFERENCE_PREFIX.length).split(VARIABLE_PATH_SEPARATOR_TOKEN_ATTRIBUTE).join(VARIABLE_PATH_SEPARATOR_TOKEN_STYLE);
return `var(--wp--${variable})`;
* Transform given preset tree into a set of style declarations.
* @param {Object} blockPresets
* @param {Object} mergedSettings Merged theme.json settings.
* @return {Array<Object>} An array of style declarations.
function getPresetsDeclarations(blockPresets = {}, mergedSettings) {
return PRESET_METADATA.reduce((declarations, {
const presetByOrigin = getValueFromObjectPath(blockPresets, path, []);
['default', 'theme', 'custom'].forEach(origin => {
if (presetByOrigin[origin]) {
presetByOrigin[origin].forEach(value => {
if (valueKey && !valueFunc) {
declarations.push(`--wp--preset--${cssVarInfix}--${use_global_styles_output_kebabCase(value.slug)}: ${value[valueKey]}`);
} else if (valueFunc && typeof valueFunc === 'function') {
declarations.push(`--wp--preset--${cssVarInfix}--${use_global_styles_output_kebabCase(value.slug)}: ${valueFunc(value, mergedSettings)}`);
* Transform given preset tree into a set of preset class declarations.
* @param {?string} blockSelector
* @param {Object} blockPresets
* @return {string} CSS declarations for the preset classes.
function getPresetsClasses(blockSelector = '*', blockPresets = {}) {
return PRESET_METADATA.reduce((declarations, {
const presetByOrigin = getValueFromObjectPath(blockPresets, path, []);
['default', 'theme', 'custom'].forEach(origin => {
if (presetByOrigin[origin]) {
presetByOrigin[origin].forEach(({
const classSelectorToUse = `.has-${use_global_styles_output_kebabCase(slug)}-${classSuffix}`;
const selectorToUse = blockSelector.split(',') // Selector can be "h1, h2, h3"
.map(selector => `${selector}${classSelectorToUse}`).join(',');
const value = `var(--wp--preset--${cssVarInfix}--${use_global_styles_output_kebabCase(slug)})`;
declarations += `${selectorToUse}{${propertyName}: ${value} !important;}`;
function getPresetsSvgFilters(blockPresets = {}) {
return PRESET_METADATA.filter(
// Duotone are the only type of filters for now.
metadata => metadata.path.at(-1) === 'duotone').flatMap(metadata => {
const presetByOrigin = getValueFromObjectPath(blockPresets, metadata.path, {});
return ['default', 'theme'].filter(origin => presetByOrigin[origin]).flatMap(origin => presetByOrigin[origin].map(preset => getDuotoneFilter(`wp-duotone-${preset.slug}`, preset.colors))).join('');
function flattenTree(input = {}, prefix, token) {
Object.keys(input).forEach(key => {
const newKey = prefix + use_global_styles_output_kebabCase(key.replace('/', '-'));
const newLeaf = input[key];
if (newLeaf instanceof Object) {
const newPrefix = newKey + token;
result = [...result, ...flattenTree(newLeaf, newPrefix, token)];
result.push(`${newKey}: ${newLeaf}`);
* Gets variation selector string from feature selector.
* @param {string} featureSelector The feature selector.
* @param {string} styleVariationSelector The style variation selector.
* @return {string} Combined selector string.
function concatFeatureVariationSelectorString(featureSelector, styleVariationSelector) {
const featureSelectors = featureSelector.split(',');
const combinedSelectors = [];
featureSelectors.forEach(selector => {
combinedSelectors.push(`${styleVariationSelector.trim()}${selector.trim()}`);
return combinedSelectors.join(', ');
* Generate style declarations for a block's custom feature and subfeature
* NOTE: The passed `styles` object will be mutated by this function.
* @param {Object} selectors Custom selectors object for a block.
* @param {Object} styles A block's styles object.
* @return {Object} Style declarations.
const getFeatureDeclarations = (selectors, styles) => {
Object.entries(selectors).forEach(([feature, selector]) => {
// We're only processing features/subfeatures that have styles.
if (feature === 'root' || !styles?.[feature]) {
const isShorthand = typeof selector === 'string';
// If we have a selector object instead of shorthand process it.
Object.entries(selector).forEach(([subfeature, subfeatureSelector]) => {
// Don't process root feature selector yet or any
// subfeature that doesn't have a style.
if (subfeature === 'root' || !styles?.[feature][subfeature]) {
// Create a temporary styles object and build
// declarations for subfeature.
const subfeatureStyles = {
[subfeature]: styles[feature][subfeature]
const newDeclarations = getStylesDeclarations(subfeatureStyles);
// Merge new declarations in with any others that
// share the same selector.
declarations[subfeatureSelector] = [...(declarations[subfeatureSelector] || []), ...newDeclarations];
// Remove the subfeature's style now it will be
// included under its own selector not the block's.
delete styles[feature][subfeature];
// Now subfeatures have been processed and removed, we can
// process root, or shorthand, feature selectors.
if (isShorthand || selector.root) {
const featureSelector = isShorthand ? selector : selector.root;
// Create temporary style object and build declarations for feature.
[feature]: styles[feature]
const newDeclarations = getStylesDeclarations(featureStyles);
// Merge new declarations with any others that share the selector.
declarations[featureSelector] = [...(declarations[featureSelector] || []), ...newDeclarations];
// Remove the feature from the block's styles now as it will be
// included under its own selector not the block's.
* Transform given style tree into a set of style declarations.
* @param {Object} blockStyles Block styles.
* @param {string} selector The selector these declarations should attach to.
* @param {boolean} useRootPaddingAlign Whether to use CSS custom properties in root selector.
* @param {Object} tree A theme.json tree containing layout definitions.
* @param {boolean} disableRootPadding Whether to force disable the root padding styles.
* @return {Array} An array of style declarations.
function getStylesDeclarations(blockStyles = {}, selector = '', useRootPaddingAlign, tree = {}, disableRootPadding = false) {
const isRoot = ROOT_BLOCK_SELECTOR === selector;
const output = Object.entries(external_wp_blocks_namespaceObject.__EXPERIMENTAL_STYLE_PROPERTY).reduce((declarations, [key, {
if (rootOnly && !isRoot) {
const pathToValue = value;
if (pathToValue[0] === 'elements' || useEngine) {
const styleValue = getValueFromObjectPath(blockStyles, pathToValue);
// Root-level padding styles don't currently support strings with CSS shorthand values.
// This may change: https://github.com/WordPress/gutenberg/issues/40132.
if (key === '--wp--style--root--padding' && (typeof styleValue === 'string' || !useRootPaddingAlign)) {
if (properties && typeof styleValue !== 'string') {
Object.entries(properties).forEach(entry => {
const [name, prop] = entry;
if (!getValueFromObjectPath(styleValue, [prop], false)) {
// Do not create a declaration
// for sub-properties that don't have any value.
const cssProperty = name.startsWith('--') ? name : use_global_styles_output_kebabCase(name);
declarations.push(`${cssProperty}: ${compileStyleValue(getValueFromObjectPath(styleValue, [prop]))}`);