diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index abdb1dc8110570..e1f944005aca22 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -24,6 +24,7 @@ - `SlotFill`: updated to satisfy `react/exhaustive-deps` eslint rule ([#44403](https://github.com/WordPress/gutenberg/pull/44403)) - `Context`: updated to ignore `react/exhaustive-deps` eslint rule ([#45044](https://github.com/WordPress/gutenberg/pull/45044)) - `Button`: Refactor Storybook to controls and align docs ([#44105](https://github.com/WordPress/gutenberg/pull/44105)). +- `BorderBoxControl`: Convert stories to TypeScript and use Controls ([#45002](https://github.com/WordPress/gutenberg/pull/45002)). ## 21.3.0 (2022-10-19) diff --git a/packages/components/src/border-box-control/border-box-control/component.tsx b/packages/components/src/border-box-control/border-box-control/component.tsx index c25e572f40e89c..4918abafebfce3 100644 --- a/packages/components/src/border-box-control/border-box-control/component.tsx +++ b/packages/components/src/border-box-control/border-box-control/component.tsx @@ -37,8 +37,8 @@ const BorderLabel = ( props: LabelProps ) => { ); }; -const BorderBoxControl = ( - props: WordPressComponentProps< BorderBoxControlProps, 'div' >, +const UnconnectedBorderBoxControl = ( + props: WordPressComponentProps< BorderBoxControlProps, 'div', false >, forwardedRef: React.ForwardedRef< any > ) => { const { @@ -153,9 +153,58 @@ const BorderBoxControl = ( ); }; -const ConnectedBorderBoxControl = contextConnect( - BorderBoxControl, +/** + * The `BorderBoxControl` effectively has two view states. The first, a "linked" + * view, allows configuration of a flat border via a single `BorderControl`. + * The second, a "split" view, contains a `BorderControl` for each side + * as well as a visualizer for the currently selected borders. Each view also + * contains a button to toggle between the two. + * + * When switching from the "split" view to "linked", if the individual side + * borders are not consistent, the "linked" view will display any border + * properties selections that are consistent while showing a mixed state for + * those that aren't. For example, if all borders had the same color and style + * but different widths, then the border dropdown in the "linked" view's + * `BorderControl` would show that consistent color and style but the "linked" + * view's width input would show "Mixed" placeholder text. + * + * ```jsx + * import { __experimentalBorderBoxControl as BorderBoxControl } from '@wordpress/components'; + * import { __ } from '@wordpress/i18n'; + * + * const colors = [ + * { name: 'Blue 20', color: '#72aee6' }, + * // ... + * ]; + * + * const MyBorderBoxControl = () => { + * const defaultBorder = { + * color: '#72aee6', + * style: 'dashed', + * width: '1px', + * }; + * const [ borders, setBorders ] = useState( { + * top: defaultBorder, + * right: defaultBorder, + * bottom: defaultBorder, + * left: defaultBorder, + * } ); + * const onChange = ( newBorders ) => setBorders( newBorders ); + * + * return ( + * + * ); + * }; + * ``` + */ +export const BorderBoxControl = contextConnect( + UnconnectedBorderBoxControl, 'BorderBoxControl' ); -export default ConnectedBorderBoxControl; +export default BorderBoxControl; diff --git a/packages/components/src/border-box-control/stories/index.js b/packages/components/src/border-box-control/stories/index.js deleted file mode 100644 index 158f07f16fbea9..00000000000000 --- a/packages/components/src/border-box-control/stories/index.js +++ /dev/null @@ -1,106 +0,0 @@ -/** - * External dependencies - */ -import styled from '@emotion/styled'; - -/** - * WordPress dependencies - */ -import { useEffect, useState } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import Button from '../../button'; -import Popover from '../../popover'; -import { BorderBoxControl } from '../'; -import { Provider as SlotFillProvider } from '../../slot-fill'; - -// Available border colors. -const colors = [ - { name: 'Gray 0', color: '#f6f7f7' }, - { name: 'Gray 5', color: '#dcdcde' }, - { name: 'Gray 20', color: '#a7aaad' }, - { name: 'Gray 70', color: '#3c434a' }, - { name: 'Gray 100', color: '#101517' }, - { name: 'Blue 20', color: '#72aee6' }, - { name: 'Blue 40', color: '#3582c4' }, - { name: 'Blue 70', color: '#0a4b78' }, - { name: 'Red 40', color: '#e65054' }, - { name: 'Red 70', color: '#8a2424' }, - { name: 'Green 10', color: '#68de7c' }, - { name: 'Green 40', color: '#00a32a' }, - { name: 'Green 60', color: '#007017' }, - { name: 'Yellow 10', color: '#f2d675' }, - { name: 'Yellow 40', color: '#bd8600' }, -]; - -export default { - title: 'Components (Experimental)/BorderBoxControl', - component: BorderBoxControl, - parameters: { - knobs: { disable: false }, - }, -}; - -const _default = ( props ) => { - const { defaultBorder } = props; - const [ borders, setBorders ] = useState( defaultBorder ); - - useEffect( () => setBorders( defaultBorder ), [ defaultBorder ] ); - - return ( - - - setBorders( newBorders ) } - value={ borders } - { ...props } - /> - - - - The BorderBoxControl is intended to be used within a component - that will provide reset controls. The button below is only for - convenience. - - - - - ); -}; - -export const Default = _default.bind( {} ); -Default.args = { - disableCustomColors: false, - enableAlpha: true, - enableStyle: true, - defaultBorder: { - color: '#72aee6', - style: 'dashed', - width: '1px', - }, - size: 'default', - popoverPlacement: 'right-start', -}; - -const WrapperView = styled.div` - max-width: 248px; - padding: 16px; -`; - -const Separator = styled.hr` - margin-top: 100px; - border-color: #ddd; - border-style: solid; - border-bottom: none; -`; - -const HelpText = styled.p` - color: #aaa; - font-size: 0.9em; -`; diff --git a/packages/components/src/border-box-control/stories/index.tsx b/packages/components/src/border-box-control/stories/index.tsx new file mode 100644 index 00000000000000..4e0cb56379ccf2 --- /dev/null +++ b/packages/components/src/border-box-control/stories/index.tsx @@ -0,0 +1,92 @@ +/** + * External dependencies + */ +import type { ComponentMeta, ComponentStory } from '@storybook/react'; +import type { ComponentProps } from 'react'; + +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import Button from '../../button'; +import Popover from '../../popover'; +import { BorderBoxControl } from '../'; +import { Provider as SlotFillProvider } from '../../slot-fill'; + +const meta: ComponentMeta< typeof BorderBoxControl > = { + title: 'Components (Experimental)/BorderBoxControl', + component: BorderBoxControl, + argTypes: { + onChange: { action: 'onChange' }, + value: { control: { type: null } }, + }, + parameters: { + controls: { expanded: true }, + docs: { source: { state: 'open' } }, + }, +}; +export default meta; + +// Available border colors. +const colors = [ + { name: 'Blue 20', color: '#72aee6' }, + { name: 'Blue 40', color: '#3582c4' }, + { name: 'Red 40', color: '#e65054' }, + { name: 'Red 70', color: '#8a2424' }, + { name: 'Yellow 10', color: '#f2d675' }, + { name: 'Yellow 40', color: '#bd8600' }, +]; + +const Template: ComponentStory< typeof BorderBoxControl > = ( props ) => { + const { onChange, ...otherProps } = props; + const [ borders, setBorders ] = useState< typeof props[ 'value' ] >(); + + const onChangeMerged: ComponentProps< + typeof BorderBoxControl + >[ 'onChange' ] = ( newBorders ) => { + setBorders( newBorders ); + onChange( newBorders ); + }; + + return ( + +
+ +
+
+

+ The BorderBoxControl is intended to be used within a component + that will provide reset controls. The button below is only for + convenience. +

+ + { /* @ts-expect-error Ignore until Popover.Slot is converted to TS */ } + +
+ ); +}; +export const Default = Template.bind( {} ); +Default.args = { + colors, + label: 'Borders', +}; diff --git a/packages/components/src/border-control/stories/index.tsx b/packages/components/src/border-control/stories/index.tsx index 59aa440591b7f3..33f28cb9bd4351 100644 --- a/packages/components/src/border-control/stories/index.tsx +++ b/packages/components/src/border-control/stories/index.tsx @@ -36,12 +36,12 @@ export default meta; // Available border colors. const colors = [ - { name: 'Blue', color: '#72aee6' }, - { name: 'Red', color: '#e65054' }, - { name: 'Yellow', color: '#f2d675' }, - { name: 'Blue', color: '#72aee6' }, - { name: 'Red', color: '#e65054' }, - { name: 'Yellow', color: '#f2d675' }, + { name: 'Blue 20', color: '#72aee6' }, + { name: 'Blue 40', color: '#3582c4' }, + { name: 'Red 40', color: '#e65054' }, + { name: 'Red 70', color: '#8a2424' }, + { name: 'Yellow 10', color: '#f2d675' }, + { name: 'Yellow 40', color: '#bd8600' }, ]; // Multiple origin colors. @@ -91,7 +91,7 @@ const Template: ComponentStory< typeof BorderControl > = ( { { ...props } /> - { /* @ts-expect-error Ignore until Popover is converted to TS */ } + { /* @ts-expect-error Ignore until Popover.Slot is converted to TS */ } );