Skip to content

Commit

Permalink
Draft combined border controls components
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronrobertshaw committed Jan 18, 2022
1 parent 5bad8e8 commit a650d77
Show file tree
Hide file tree
Showing 52 changed files with 2,565 additions and 24 deletions.
42 changes: 42 additions & 0 deletions docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,48 @@
"markdown_source": "../packages/components/src/base-field/README.md",
"parent": "components"
},
{
"title": "BorderBoxControl",
"slug": "border-box-control",
"markdown_source": "../packages/components/src/border-box-control/border-box-control/README.md",
"parent": "components"
},
{
"title": "BorderVisualizer",
"slug": "border-visualizer",
"markdown_source": "../packages/components/src/border-box-control/border-visualizer/README.md",
"parent": "components"
},
{
"title": "LinkedButton",
"slug": "linked-button",
"markdown_source": "../packages/components/src/border-box-control/linked-button/README.md",
"parent": "components"
},
{
"title": "SplitBorderControl",
"slug": "split-border-control",
"markdown_source": "../packages/components/src/border-box-control/split-border-control/README.md",
"parent": "components"
},
{
"title": "BorderControl",
"slug": "border-control",
"markdown_source": "../packages/components/src/border-control/border-control/README.md",
"parent": "components"
},
{
"title": "BorderDropdown",
"slug": "border-dropdown",
"markdown_source": "../packages/components/src/border-control/border-dropdown/README.md",
"parent": "components"
},
{
"title": "BorderStyleControl",
"slug": "border-style-control",
"markdown_source": "../packages/components/src/border-control/border-style-control/README.md",
"parent": "components"
},
{
"title": "BoxControl",
"slug": "box-control",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# BorderBoxControl

<div class="callout callout-alert">
This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes.
</div>
<br />

## Development guidelines
## Usage
## Props
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import LinkedButton from '../linked-button';
import SplitBorderControl from '../split-border-control';
import { BorderControl } from '../../border-control';
import { HStack } from '../../h-stack';
import { StyledLabel } from '../../base-control/styles/base-control-styles';
import { View } from '../../view';
import { VisuallyHidden } from '../../visually-hidden';
import { contextConnect, WordPressComponentProps } from '../../ui/context';
import { useBorderBoxControl } from './hook';

import type { BorderBoxControlProps, BorderLabelProps } from '../types';

const BorderLabel = ( props: BorderLabelProps ) => {
const { label, hideLabelFromVision } = props;

if ( ! label ) {
return null;
}

return hideLabelFromVision ? (
<VisuallyHidden as="label">{ label }</VisuallyHidden>
) : (
<StyledLabel>{ label }</StyledLabel>
);
};

const BorderBoxControl = (
props: WordPressComponentProps< BorderBoxControlProps, 'div' >,
forwardedRef: React.Ref< any >
) => {
const {
className,
colors,
hasMixedBorders,
hideLabelFromVision,
isLinked,
label,
linkedControlClassName,
linkedValue,
onLinkedChange,
onSplitChange,
splitValue,
toggleLinked,
__experimentalHasMultipleOrigins,
__experimentalIsRenderedInSidebar,
...otherProps
} = useBorderBoxControl( props );

return (
<View className={ className } { ...otherProps } ref={ forwardedRef }>
<BorderLabel
label={ label }
hideLabelFromVision={ hideLabelFromVision }
/>
<HStack alignment={ 'start' } expanded={ true } spacing={ 3 }>
{ isLinked ? (
<BorderControl
className={ linkedControlClassName }
colors={ colors }
onChange={ onLinkedChange }
placeholder={
hasMixedBorders ? __( 'Mixed' ) : undefined
}
shouldSanitizeBorder={ false } // This component will handle that.
value={ linkedValue }
withSlider={ true }
width={ '110px' }
__experimentalHasMultipleOrigins={
__experimentalHasMultipleOrigins
}
__experimentalIsRenderedInSidebar={
__experimentalIsRenderedInSidebar
}
/>
) : (
<SplitBorderControl
colors={ colors }
onChange={ onSplitChange }
value={ splitValue }
__experimentalHasMultipleOrigins={
__experimentalHasMultipleOrigins
}
__experimentalIsRenderedInSidebar={
__experimentalIsRenderedInSidebar
}
/>
) }
<LinkedButton onClick={ toggleLinked } isLinked={ isLinked } />
</HStack>
</View>
);
};

const ConnectedBorderBoxControl = contextConnect(
BorderBoxControl,
'BorderBoxControl'
);

export default ConnectedBorderBoxControl;
119 changes: 119 additions & 0 deletions packages/components/src/border-box-control/border-box-control/hook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/**
* WordPress dependencies
*/
import { useMemo, useState } from '@wordpress/element';

/**
* Internal dependencies
*/
import * as styles from '../styles';
import {
getBorderDiff,
getCommonBorder,
getSplitBorders,
hasMixedBorders,
hasSplitBorders,
isCompleteBorder,
isEmptyBorder,
} from '../utils';
import { useContextSystem, WordPressComponentProps } from '../../ui/context';
import { useCx } from '../../utils/hooks/use-cx';

import type { Border } from '../../border-control/types';
import type { Borders, BorderSide, BorderBoxControlProps } from '../types';

export function useBorderBoxControl(
props: WordPressComponentProps< BorderBoxControlProps, 'div' >
) {
const { className, onChange, value, ...otherProps } = useContextSystem(
props,
'BorderBoxControl'
);

const mixedBorders = hasMixedBorders( value );
const splitBorders = hasSplitBorders( value );

const linkedValue = splitBorders
? getCommonBorder( value as Borders | undefined )
: ( value as Border );

const splitValue = splitBorders
? ( value as Borders )
: getSplitBorders( value as Border | undefined );

const [ isLinked, setIsLinked ] = useState( ! mixedBorders );
const toggleLinked = () => setIsLinked( ! isLinked );

const onLinkedChange = ( newBorder: Border | undefined ) => {
if ( ! newBorder ) {
return onChange( undefined );
}

// If we have all props defined on the new border apply it.
if ( ! mixedBorders || isCompleteBorder( newBorder ) ) {
return onChange(
isEmptyBorder( newBorder ) ? undefined : newBorder
);
}

// If we had mixed borders we might have had some shared border props
// that we need to maintain. For example; we could have mixed borders
// with all the same color but different widths. Then from the linked
// control we change the color. We should keep the separate widths.
const changes = getBorderDiff(
linkedValue as Border,
newBorder as Border
);
const updatedBorders = {
top: { ...( value as Borders )?.top, ...changes },
right: { ...( value as Borders )?.right, ...changes },
bottom: { ...( value as Borders )?.bottom, ...changes },
left: { ...( value as Borders )?.left, ...changes },
};

if ( hasMixedBorders( updatedBorders ) ) {
return onChange( updatedBorders );
}

const filteredResult = isEmptyBorder( updatedBorders.top )
? undefined
: updatedBorders.top;

onChange( filteredResult );
};

const onSplitChange = (
newBorder: Border | undefined,
side: BorderSide
) => {
const updatedBorders = { ...splitValue, [ side ]: newBorder };

if ( hasMixedBorders( updatedBorders ) ) {
onChange( updatedBorders );
} else {
onChange( newBorder );
}
};

const cx = useCx();
const classes = useMemo( () => {
return cx( styles.BorderBoxControl, className );
}, [ className ] );

const linkedControlClassName = useMemo( () => {
return cx( styles.LinkedBorderControl );
}, [] );

return {
...otherProps,
className: classes,
hasMixedBorders: mixedBorders,
isLinked,
linkedControlClassName,
onLinkedChange,
onSplitChange,
toggleLinked,
linkedValue,
splitValue,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as BorderBoxControl } from './component';
export { useBorderBoxControl } from './hook';
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# BorderVisualizer

<div class="callout callout-alert">
This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes.
</div>
<br />

## Development guidelines
## Usage
## Props
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { View } from '../../view';
import { contextConnect, WordPressComponentProps } from '../../ui/context';
import { getClampedWidthBorderStyle } from '../utils';
import { useBorderVisualizer } from './hook';

import type { BorderVisualizerProps } from '../types';

const BorderVisualizer = (
props: WordPressComponentProps< BorderVisualizerProps, 'div' >,
forwardedRef: React.Ref< any >
) => {
const { value, ...otherProps } = useBorderVisualizer( props );
const styles = {
borderTop: getClampedWidthBorderStyle( value?.top ),
borderRight: getClampedWidthBorderStyle( value?.right ),
borderBottom: getClampedWidthBorderStyle( value?.bottom ),
borderLeft: getClampedWidthBorderStyle( value?.left ),
};

return <View { ...otherProps } ref={ forwardedRef } style={ styles } />;
};

const ConnectedBorderVisualizer = contextConnect(
BorderVisualizer,
'BorderVisualizer'
);
export default ConnectedBorderVisualizer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* WordPress dependencies
*/
import { useMemo } from '@wordpress/element';

/**
* Internal dependencies
*/
import * as styles from '../styles';
import { useContextSystem, WordPressComponentProps } from '../../ui/context';
import { useCx } from '../../utils/hooks/use-cx';

import type { BorderVisualizerProps } from '../types';

export function useBorderVisualizer(
props: WordPressComponentProps< BorderVisualizerProps, 'div' >
) {
const { className, ...otherProps } = useContextSystem(
props,
'BorderVisualizer'
);

// Generate class names.
const cx = useCx();
const classes = useMemo( () => {
return cx( styles.BorderVisualizer, className );
}, [ className ] );

return { ...otherProps, className: classes };
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './component';
2 changes: 2 additions & 0 deletions packages/components/src/border-box-control/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as BorderBoxControl } from './border-box-control/component';
export { useBorderBoxControl } from './border-box-control/hook';
10 changes: 10 additions & 0 deletions packages/components/src/border-box-control/linked-button/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# LinkedButton

<div class="callout callout-alert">
This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes.
</div>
<br />

## Development guidelines
## Usage
## Props
Loading

0 comments on commit a650d77

Please sign in to comment.