diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index b50a0f8badd07d..8b3e71a19469fe 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -28,6 +28,7 @@
- Update control labels to the new uppercase styles ([#42789](https://github.com/WordPress/gutenberg/pull/42789)).
- `UnitControl`: Update unit dropdown design for the large size variant ([#42000](https://github.com/WordPress/gutenberg/pull/42000)).
- `BaseControl`: Add `box-sizing` reset style ([#42889](https://github.com/WordPress/gutenberg/pull/42889)).
+- `ToggleGroupControl`, `RangeControl`, `FontSizePicker`: Add `__nextHasNoMarginBottom` prop for opting into the new margin-free styles ([#43062](https://github.com/WordPress/gutenberg/pull/43062)).
- `BoxControl`: Export `applyValueToSides` util function. ([#42733](https://github.com/WordPress/gutenberg/pull/42733/)).
- `AnglePickerControl`: Add `__nextHasNoMarginBottom` prop for opting into the new margin-free styles ([#43160](https://github.com/WordPress/gutenberg/pull/43160/)).
diff --git a/packages/components/src/font-size-picker/index.js b/packages/components/src/font-size-picker/index.js
index 18f5a4e9093cd2..2eefe8107d946e 100644
--- a/packages/components/src/font-size-picker/index.js
+++ b/packages/components/src/font-size-picker/index.js
@@ -1,3 +1,8 @@
+/**
+ * External dependencies
+ */
+import classNames from 'classnames';
+
/**
* WordPress dependencies
*/
@@ -26,9 +31,20 @@ import {
isSimpleCssValue,
CUSTOM_FONT_SIZE,
} from './utils';
+import { VStack } from '../v-stack';
+
+// This conditional is needed to maintain the spacing before the slider in the `withSlider` case.
+const MaybeVStack = ( { __nextHasNoMarginBottom, children } ) =>
+ ! __nextHasNoMarginBottom ? (
+ children
+ ) : (
+
+ );
function FontSizePicker(
{
+ /** Start opting into the new margin-free styles that will become the default in a future version. */
+ __nextHasNoMarginBottom = false,
fallbackFontSize,
fontSizes = [],
disableCustomFontSizes = false,
@@ -165,119 +181,133 @@ function FontSizePicker(
) }
-
- { !! fontSizes.length &&
- shouldUseSelectControl &&
- ! showCustomValueControl && (
-
+
+ { !! fontSizes.length &&
+ shouldUseSelectControl &&
+ ! showCustomValueControl && (
+
+ option.key === selectedOption.slug
+ ) }
+ onChange={ ( { selectedItem } ) => {
+ onChange(
+ hasUnits
+ ? selectedItem.size
+ : Number( selectedItem.size )
+ );
+ if (
+ selectedItem.key === CUSTOM_FONT_SIZE
+ ) {
+ setShowCustomValueControl( true );
+ }
+ } }
+ size={ size }
+ />
+ ) }
+ { ! shouldUseSelectControl && ! showCustomValueControl && (
+ option.key === selectedOption.slug
- ) }
- onChange={ ( { selectedItem } ) => {
+ value={ value }
+ onChange={ ( newValue ) => {
onChange(
- hasUnits
- ? selectedItem.size
- : Number( selectedItem.size )
+ hasUnits ? newValue : Number( newValue )
);
- if ( selectedItem.key === CUSTOM_FONT_SIZE ) {
- setShowCustomValueControl( true );
- }
} }
+ isBlock
size={ size }
- />
- ) }
- { ! shouldUseSelectControl && ! showCustomValueControl && (
- {
- onChange(
- hasUnits ? newValue : Number( newValue )
- );
- } }
- isBlock
- size={ size }
- >
- { options.map( ( option ) => (
-
- ) ) }
-
- ) }
- { ! withSlider &&
- ! disableCustomFontSizes &&
- showCustomValueControl && (
-
-
- {
- if (
- 0 === parseFloat( nextSize ) ||
- ! nextSize
- ) {
- onChange( undefined );
- } else {
- onChange(
- hasUnits
- ? nextSize
- : parseInt( nextSize, 10 )
- );
- }
- } }
- size={ size }
- units={ hasUnits ? units : [] }
+ { options.map( ( option ) => (
+
-
- { withReset && (
+ ) ) }
+
+ ) }
+ { ! withSlider &&
+ ! disableCustomFontSizes &&
+ showCustomValueControl && (
+
-
+ size={ size }
+ units={ hasUnits ? units : [] }
+ />
- ) }
-
- ) }
-
- { withSlider && (
- {
- onChange( hasUnits ? newValue + 'px' : newValue );
- } }
- min={ 12 }
- max={ 100 }
- />
- ) }
+ { withReset && (
+
+
+
+ ) }
+
+ ) }
+
+ { withSlider && (
+ {
+ onChange( hasUnits ? newValue + 'px' : newValue );
+ } }
+ min={ 12 }
+ max={ 100 }
+ />
+ ) }
+
);
}
diff --git a/packages/components/src/font-size-picker/stories/index.js b/packages/components/src/font-size-picker/stories/index.js
index 7f23a457992911..b86941e3d9836b 100644
--- a/packages/components/src/font-size-picker/stories/index.js
+++ b/packages/components/src/font-size-picker/stories/index.js
@@ -12,6 +12,7 @@ export default {
title: 'Components/FontSizePicker',
component: FontSizePicker,
argTypes: {
+ __nextHasNoMarginBottom: { control: { type: 'boolean' } },
initialValue: { table: { disable: true } }, // hide prop because it's not actually part of FontSizePicker
fallbackFontSize: {
description:
diff --git a/packages/components/src/font-size-picker/style.scss b/packages/components/src/font-size-picker/style.scss
index bf3965ab304cd3..90d7658330d04f 100644
--- a/packages/components/src/font-size-picker/style.scss
+++ b/packages/components/src/font-size-picker/style.scss
@@ -16,7 +16,10 @@
max-width: $sidebar-width - ( 2 * $grid-unit-20 );
align-items: center;
margin-top: $grid-unit-10;
- margin-bottom: $grid-unit-30;
+
+ &:not(.is-next-has-no-margin-bottom) {
+ margin-bottom: $grid-unit-30;
+ }
.components-unit-control-wrapper {
.components-input-control__label {
diff --git a/packages/components/src/range-control/index.tsx b/packages/components/src/range-control/index.tsx
index 3045b5c0283ddf..de3c60d9246273 100644
--- a/packages/components/src/range-control/index.tsx
+++ b/packages/components/src/range-control/index.tsx
@@ -49,6 +49,7 @@ function UnforwardedRangeControl< IconProps = unknown >(
forwardedRef: ForwardedRef< HTMLInputElement >
) {
const {
+ __nextHasNoMarginBottom = false,
afterIcon,
allowReset = false,
beforeIcon,
@@ -212,6 +213,7 @@ function UnforwardedRangeControl< IconProps = unknown >(
return (
(
) }
css( { color } );
-const wrapperMargin = ( { marks }: WrapperProps ) =>
- css( { marginBottom: marks ? 16 : undefined } );
+const wrapperMargin = ( { marks, __nextHasNoMarginBottom }: WrapperProps ) => {
+ if ( ! __nextHasNoMarginBottom ) {
+ return css( { marginBottom: marks ? 16 : undefined } );
+ }
+ return '';
+};
export const Wrapper = styled.div< WrapperProps >`
color: ${ COLORS.blue.medium.focus };
@@ -56,12 +60,14 @@ export const Wrapper = styled.div< WrapperProps >`
`;
export const BeforeIconWrapper = styled.span`
+ display: flex; // ensures the height isn't affected by line-height
margin-top: ${ railHeight }px;
${ rtl( { marginRight: 6 } ) }
`;
export const AfterIconWrapper = styled.span`
+ display: flex; // ensures the height isn't affected by line-height
margin-top: ${ railHeight }px;
${ rtl( { marginLeft: 6 } ) }
diff --git a/packages/components/src/range-control/types.ts b/packages/components/src/range-control/types.ts
index e59f240496c9d6..594ce7a77a4445 100644
--- a/packages/components/src/range-control/types.ts
+++ b/packages/components/src/range-control/types.ts
@@ -76,7 +76,7 @@ export type ControlledRangeValue = number | '' | null;
export type RangeControlProps< IconProps = unknown > = Pick<
BaseControlProps,
- 'hideLabelFromVision' | 'help'
+ 'hideLabelFromVision' | 'help' | '__nextHasNoMarginBottom'
> &
MarksProps & {
/**
@@ -243,7 +243,10 @@ export type InputRangeProps = {
value?: number | '';
};
-export type WrapperProps = {
+export type WrapperProps = Pick<
+ BaseControlProps,
+ '__nextHasNoMarginBottom'
+> & {
color?: CSSProperties[ 'color' ];
marks?: RangeMarks;
};
diff --git a/packages/components/src/toggle-group-control/stories/index.js b/packages/components/src/toggle-group-control/stories/index.js
index a16d094eae4cf8..13cb5829ea2577 100644
--- a/packages/components/src/toggle-group-control/stories/index.js
+++ b/packages/components/src/toggle-group-control/stories/index.js
@@ -18,6 +18,7 @@ import {
ToggleGroupControlOptionIcon,
} from '../index';
import { View } from '../../view';
+import { HStack } from '../../h-stack';
import Button from '../../button';
export default {
@@ -26,6 +27,7 @@ export default {
subcomponents: { ToggleGroupControlOption, ToggleGroupControlOptionIcon },
argTypes: {
__experimentalIsIconGroup: { control: { type: 'boolean' } },
+ __nextHasNoMarginBottom: { control: 'boolean' },
size: {
control: 'radio',
options: [ 'default', '__unstable-large' ],
@@ -187,7 +189,7 @@ export const WithReset = ( props ) => {
/>
) );
return (
-
+
{
-
+
);
};
WithReset.args = {
...Default.args,
+ __nextHasNoMarginBottom: true,
};
diff --git a/packages/components/src/toggle-group-control/toggle-group-control/component.tsx b/packages/components/src/toggle-group-control/toggle-group-control/component.tsx
index 09ef6ea6925d90..b17cadc6411c7d 100644
--- a/packages/components/src/toggle-group-control/toggle-group-control/component.tsx
+++ b/packages/components/src/toggle-group-control/toggle-group-control/component.tsx
@@ -40,6 +40,7 @@ function ToggleGroupControl(
forwardedRef: ForwardedRef< any >
) {
const {
+ __nextHasNoMarginBottom = false,
className,
isAdaptiveWidth = false,
isBlock = false,
@@ -93,7 +94,10 @@ function ToggleGroupControl(
[ className, cx, isBlock, __experimentalIsIconGroup, size ]
);
return (
-
+
diff --git a/packages/components/src/toggle-group-control/types.ts b/packages/components/src/toggle-group-control/types.ts
index 66ad2b56338ab0..f42ef84f83660b 100644
--- a/packages/components/src/toggle-group-control/types.ts
+++ b/packages/components/src/toggle-group-control/types.ts
@@ -8,6 +8,7 @@ import type { RadioStateReturn } from 'reakit';
/**
* Internal dependencies
*/
+import type { BaseControlProps } from '../base-control/types';
import type { FormElementProps } from '../utils/types';
export type ToggleGroupControlOptionBaseProps = {
@@ -74,59 +75,55 @@ export type WithToolTipProps = {
export type ToggleGroupControlProps = Omit<
FormElementProps< any >,
'defaultValue'
-> & {
- /**
- * Label for the form element.
- */
- label: string;
- /**
- * If true, the label will only be visible to screen readers.
- *
- * @default false
- */
- hideLabelFromVision?: boolean;
- /**
- * Determines if segments should be rendered with equal widths.
- *
- * @default false
- */
- isAdaptiveWidth?: boolean;
- /**
- * Renders `ToggleGroupControl` as a (CSS) block element.
- *
- * @default false
- */
- isBlock?: boolean;
- /**
- * Style for use with `ToggleGroupControlOptionIcon`s.
- *
- * @default false
- */
- __experimentalIsIconGroup?: boolean; // TODO: Refactor so this can be private
- /**
- * Callback when a segment is selected.
- */
- onChange?: ( value: ReactText | undefined ) => void;
- /**
- * The value of `ToggleGroupControl`
- */
- value?: ReactText;
- /**
- * React children
- */
- children: ReactNode;
- /**
- * If this property is added, a help text will be generated
- * using help property as the content.
- */
- help?: ReactNode;
- /**
- * The size variant of the control.
- *
- * @default 'default'
- */
- size?: 'default' | '__unstable-large';
-};
+> &
+ Pick< BaseControlProps, 'help' | '__nextHasNoMarginBottom' > & {
+ /**
+ * Label for the form element.
+ */
+ label: string;
+ /**
+ * If true, the label will only be visible to screen readers.
+ *
+ * @default false
+ */
+ hideLabelFromVision?: boolean;
+ /**
+ * Determines if segments should be rendered with equal widths.
+ *
+ * @default false
+ */
+ isAdaptiveWidth?: boolean;
+ /**
+ * Renders `ToggleGroupControl` as a (CSS) block element.
+ *
+ * @default false
+ */
+ isBlock?: boolean;
+ /**
+ * Style for use with `ToggleGroupControlOptionIcon`s.
+ *
+ * @default false
+ */
+ __experimentalIsIconGroup?: boolean; // TODO: Refactor so this can be private
+ /**
+ * Callback when a segment is selected.
+ */
+ onChange?: ( value: ReactText | undefined ) => void;
+ /**
+ * The value of `ToggleGroupControl`
+ */
+ value?: ReactText;
+ /**
+ * React children
+ */
+ children: ReactNode;
+ /**
+ * The size variant of the control.
+ *
+ * @default 'default'
+ */
+ size?: 'default' | '__unstable-large';
+ };
export type ToggleGroupControlContextProps = RadioStateReturn &
Pick< ToggleGroupControlProps, 'size' > & {