Skip to content

Commit

Permalink
Box Control: Add Runtime Check & Conditional Types for presets and …
Browse files Browse the repository at this point in the history
…`presetKey` Props (WordPress#68385)

* feat: Improve developer experience for presets

* fix: change Warning error message

* fix: Enforce runtime check for presets, and presetKey

* doc: Add log for runtime check

* doc: Add in unreleased section

---

Co-authored-by: im3dabasia <[email protected]>
Co-authored-by: ciampo <[email protected]>
  • Loading branch information
3 people authored Jan 22, 2025
1 parent d7593ae commit b771bdd
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 13 deletions.
4 changes: 4 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Internal

- `BoxControl`: Add runtime check for presets and presetKey ([#68385](https://github.com/WordPress/gutenberg/pull/68385)).

## 29.2.0 (2025-01-15)

### Internal
Expand Down
9 changes: 9 additions & 0 deletions packages/components/src/box-control/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { useInstanceId } from '@wordpress/compose';
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import warning from '@wordpress/warning';

/**
* Internal dependencies
Expand Down Expand Up @@ -166,6 +167,14 @@ function BoxControl( {
} );
const sidesToRender = getAllowedSides( sides );

if ( ( presets && ! presetKey ) || ( ! presets && presetKey ) ) {
const definedProp = presets ? 'presets' : 'presetKey';
const missingProp = presets ? 'presetKey' : 'presets';
warning(
`wp.components.BoxControl: the '${ missingProp }' prop is required when the '${ definedProp }' prop is defined.`
);
}

return (
<Grid
id={ id }
Expand Down
11 changes: 9 additions & 2 deletions packages/components/src/box-control/test/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,15 @@ import { useState } from '@wordpress/element';
import BoxControl from '..';
import type { BoxControlProps, BoxControlValue } from '../types';

// Since `BoxControlProps` is a the result of type unions, we need to use
// a distributive version of the standard `Omit` utility.
// See https://stackoverflow.com/a/57103940
type DistributiveOmit< T, K extends keyof any > = T extends any
? Omit< T, K >
: never;

const ControlledBoxControl = (
extraProps: Omit< BoxControlProps, 'onChange' >
extraProps: DistributiveOmit< BoxControlProps, 'onChange' >
) => {
const [ state, setState ] = useState< BoxControlValue >();

Expand All @@ -33,7 +40,7 @@ const ControlledBoxControl = (
const UncontrolledBoxControl = ( {
onChange = () => {},
...props
}: Omit< BoxControlProps, 'onChange' > & {
}: DistributiveOmit< BoxControlProps, 'onChange' > & {
onChange?: BoxControlProps[ 'onChange' ];
} ) => <BoxControl __next40pxDefaultSize onChange={ onChange } { ...props } />;

Expand Down
37 changes: 26 additions & 11 deletions packages/components/src/box-control/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,32 @@ export type BoxControlProps = Pick< UnitControlProps, 'units' > &
* @default false
*/
__next40pxDefaultSize?: boolean;
/**
* Available presets to pick from.
*/
presets?: Preset[];
/**
* The key of the preset to apply.
* If you provide a list of presets, you must provide a preset key to use.
* The format of preset selected values is going to be `var:preset|${ presetKey }|${ presetSlug }`
*/
presetKey?: string;
};
} & (
| {
/**
* Available presets to pick from.
*/
presets?: never;
/**
* The key of the preset to apply.
* If you provide a list of presets, you must provide a preset key to use.
* The format of preset selected values is going to be `var:preset|${ presetKey }|${ presetSlug }`
*/
presetKey?: never;
}
| {
/**
* Available presets to pick from.
*/
presets: Preset[];
/**
* The key of the preset to apply.
* If you provide a list of presets, you must provide a preset key to use.
* The format of preset selected values is going to be `var:preset|${ presetKey }|${ presetSlug }`
*/
presetKey: string;
}
);

export type BoxControlInputControlProps = UnitControlPassthroughProps & {
onChange?: ( nextValues: BoxControlValue ) => void;
Expand Down

0 comments on commit b771bdd

Please sign in to comment.