Skip to content

Commit

Permalink
follow up
Browse files Browse the repository at this point in the history
  • Loading branch information
ntsekouras committed Jun 16, 2021
1 parent 69574e6 commit 51dd550
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 69 deletions.
2 changes: 1 addition & 1 deletion packages/components/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export { default as RangeControl } from './range-control';
export { default as ResizableBox } from './resizable-box';
export { default as ResponsiveWrapper } from './responsive-wrapper';
export { default as SandBox } from './sandbox';
export { default as __experimentalSegmentedControl } from './segmented-control';
export { SegmentedControl as __experimentalSegmentedControl } from './segmented-control';
export { default as SelectControl } from './select-control';
export { default as Snackbar } from './snackbar';
export { default as SnackbarList } from './snackbar/list';
Expand Down
44 changes: 25 additions & 19 deletions packages/components/src/segmented-control/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,15 @@
import { cx } from 'emotion';
// eslint-disable-next-line no-restricted-imports
import { RadioGroup, useRadioState } from 'reakit';
import useResizeAware from 'react-resize-aware';

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { useRef } from '@wordpress/element';
import { useMergeRefs, useResizeObserver } from '@wordpress/compose';
import { useRef, useMemo } from '@wordpress/element';
import { useMergeRefs } from '@wordpress/compose';

/**
* Internal dependencies
*/
/**
* Internal dependencies
*/
Expand All @@ -24,25 +22,30 @@ import * as styles from './styles';
import { useUpdateEffect } from '../utils/hooks';
import Backdrop from './segmented-control-backdrop';
import Button from './segmented-control-button';
import type { SegmentedControlProps } from './types';

function SegmentControl( props: any, forwardedRef: any ) {
const noop = () => {};

/**
* @param {import('./types').SegmentedControlProps} props
* @param {import('react').Ref<any>} forwardedRef
*/
function SegmentControl( props, forwardedRef ) {
const {
className,
baseId,
isAdaptiveWidth = false,
isBlock = false,
id,
label = __( 'SegmentControl' ),
label,
options = [],
onChange = () => {},
onChange = noop,
size = 'medium',
value,
...otherProps
} = useContextSystem( props, 'SegmentedControl' );

const containerRef = useRef();
const [ resizeListener, sizes ] = useResizeObserver();
const [ resizeListener, sizes ] = useResizeAware();

const radio = useRadioState( {
baseId: baseId || id,
Expand All @@ -62,29 +65,32 @@ function SegmentControl( props: any, forwardedRef: any ) {
}
}, [ value ] );

const classes = cx(
styles.SegmentedControl,
isBlock && styles.block,
styles[ size ],
className
const classes = useMemo(
() =>
cx(
styles.SegmentedControl,
isBlock && styles.block,
styles[ size ],
className
),
[ className, size ]
);
const mergedRefs = useMergeRefs( [ containerRef, forwardedRef ] );
return (
<RadioGroup
{ ...radio }
aria-label={ label }
as={ View }
className={ classes }
{ ...otherProps }
ref={ mergedRefs }
ref={ useMergeRefs( [ containerRef, forwardedRef ] ) }
>
{ resizeListener }
<Backdrop
{ ...radio }
containerRef={ containerRef }
containerWidth={ sizes.width }
/>
{ options.map( ( option, index: number ) => {
{ options.map( ( option: any, index: number ) => {
const showSeparator = getShowSeparator( radio, index );
return (
<Button
Expand All @@ -100,7 +106,7 @@ function SegmentControl( props: any, forwardedRef: any ) {
);
}

function getShowSeparator( radio, index: number ) {
function getShowSeparator( radio: any, index: number ) {
const { currentId, items } = radio;
const isLast = index === items.length - 1;
const isActive = items[ index ]?.id === currentId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import { useState, useEffect, memo } from '@wordpress/element';
/**
* Internal dependencies
*/
import type { SegmentedControlBackdropProps } from './types';
import { BackdropView } from './styles';
import { CONFIG, COLORS } from '../utils';

function SegmentedControlBackdrop( { containerRef, containerWidth, state } ) {
function SegmentedControlBackdrop( props: SegmentedControlBackdropProps ) {
const { containerRef, containerWidth, state } = props;
const [ left, setLeft ] = useState( 0 );
const [ width, setWidth ] = useState( 0 );
const [ canAnimate, setCanAnimate ] = useState( false );
Expand Down Expand Up @@ -44,10 +45,9 @@ function SegmentedControlBackdrop( { containerRef, containerWidth, state } ) {
return (
<BackdropView
role="presentation"
{ ...ui.$( 'SegmentedControlBackdrop' ) }
style={ {
transform: `translateX(${ left }px)`,
transition: canAnimate ? null : 'none',
transition: canAnimate ? undefined : 'none',
width,
} }
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,37 +13,32 @@ import { memo } from '@wordpress/element';
/**
* Internal dependencies
*/
import * as styles from './styles';
import { CONFIG, COLORS } from '../utils';

const {
import {
ButtonContentView,
ButtonView,
LabelPlaceholderView,
LabelView,
SeparatorView,
} = styles;
} from './styles';
// eslint-disable-next-line no-duplicate-imports
import * as styles from './styles';
import type { SegmentedControlButtonProps } from './types';

function SegmentedControlButton( {
className,
forwardedRef,
isBlock = false,
label,
showSeparator,
value,
...props
} ) {
function SegmentedControlButton( allProps: SegmentedControlButtonProps ) {
const {
className,
forwardedRef,
isBlock = false,
label,
showSeparator,
value,
...props
} = allProps;
const isActive = props.state === value;

const labelViewClasses = cx( isBlock && styles.labelBlock );
const classes = cx( isActive && styles.buttonActive, className );

return (
<LabelView
className={ labelViewClasses }
data-active={ isActive }
{ ...ui.$( 'SegmentedControlButtonLabel' ) }
>
<LabelView className={ labelViewClasses } data-active={ isActive }>
<Radio
{ ...props }
as={ ButtonView }
Expand All @@ -52,15 +47,8 @@ function SegmentedControlButton( {
ref={ forwardedRef }
value={ value }
>
<ButtonContentView
{ ...ui.$( 'SegmentedControlButtonContent' ) }
>
{ label }
</ButtonContentView>
<LabelPlaceholderView
aria-hidden
{ ...ui.$( 'SegmentedControlButtonContentPlaceholder' ) }
>
<ButtonContentView>{ label }</ButtonContentView>
<LabelPlaceholderView aria-hidden>
{ label }
</LabelPlaceholderView>
</Radio>
Expand All @@ -69,16 +57,9 @@ function SegmentedControlButton( {
);
}

const SegmentedControlSeparator = memo( ( { isActive } ) => {
const SegmentedControlSeparator = memo( ( { isActive: boolean } ) => {
const classes = cx( isActive && styles.separatorActive );

return (
<SeparatorView
aria-hidden
className={ classes }
{ ...ui.$( 'SegmentedControlButtonSeparator' ) }
/>
);
return <SeparatorView aria-hidden className={ classes } />;
} );

export default memo( SegmentedControlButton );
4 changes: 2 additions & 2 deletions packages/components/src/segmented-control/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const ButtonView = styled.button`
background: transparent;
border: none;
border-radius: ${ CONFIG.controlBorderRadius };
color: ${ CONFIG.controlTextActiveColor }; // ui.color.text
color: ${ CONFIG.controlTextActiveColor };
cursor: pointer;
display: flex;
height: 100%;
Expand All @@ -77,7 +77,7 @@ export const ButtonView = styled.button`
padding: 0 12px;
position: relative;
text-align: center;
transition: background-color ${ CONFIG.transitionDurationFast } linear,
transition: background ${ CONFIG.transitionDurationFast } linear,
color ${ CONFIG.transitionDurationFast } linear, font-weight 60ms linear;
user-select: none;
width: 100%;
Expand Down
55 changes: 52 additions & 3 deletions packages/components/src/segmented-control/types.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,37 @@
/**
* External dependencies
*/
// eslint-disable-next-line no-restricted-imports
import type { Ref, RefObject } from 'react';

/**
* Internal dependencies
*/
import type { FormElementProps, SizeRangeDefault } from '../utils/types';
import type { PolymorphicComponent } from '../ui/context';

export declare type SegmentedControlProps = Omit<
/**
* Option to render within `SegmentedControl`.
*
* @example
* ```jsx
* const option = { id: 'elsa', value: 'elsa', label: 'Elsa' };
* ```
*/
export type SegmentedControlOption = {
id: string | number;
value: string | number;
label: string;
};

export type SegmentedControlProps = Omit<
FormElementProps< any >,
'defaultValue'
> & {
/**
* Label for the form element.
*/
label: string;
/**
* ID that will serve as a base for all the items IDs.
*
Expand Down Expand Up @@ -39,7 +63,7 @@ export declare type SegmentedControlProps = Omit<
* const Heroes = <SegmentedControl options={options} />
* ```
*/
options?: Array< unknown >;
options?: Array< SegmentedControlOption >;
/**
* Callback when a segment is selected.
*/
Expand All @@ -50,6 +74,10 @@ export declare type SegmentedControlProps = Omit<
* @default 'medium'
*/
size?: SizeRangeDefault;
/**
* The value of `SegmentedControl`
*/
value?: string | number;
};

/**
Expand All @@ -60,7 +88,28 @@ export declare type SegmentedControlProps = Omit<
* <SegmentedControl options={[...]} />
* ```
*/
export declare const SegmentedControl: PolymorphicComponent<
export type SegmentedControl = PolymorphicComponent<
'input',
SegmentedControlProps
>;

export type SegmentedControlButtonProps = {
className?: string;
forwardedRef?: Ref< any >;
/**
* Renders `SegmentedControl` is a (CSS) block element.
*
* @default false
*/
isBlock?: boolean;
label: string;
showSeparator?: boolean;
value?: string | number;
state?: any;
};

export type SegmentedControlBackdropProps = {
containerRef: RefObject< any >;
containerWidth?: number | null;
state?: any;
};
3 changes: 2 additions & 1 deletion packages/components/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
{ "path": "../is-shallow-equal" },
{ "path": "../primitives" },
{ "path": "../react-i18n" },
{ "path": "../warning" }
{ "path": "../warning" },
{ "path": "../compose" }
],
"include": [
"src/__next/**/*",
Expand Down

0 comments on commit 51dd550

Please sign in to comment.