Replace deprecated wp.compose.withState with wp.element.useState (https://github.com/woocommerce/woocommerce-admin/pull/8338)
* Update search-list-control * Update tag * Update stories * Add packages/components changelog
This commit is contained in:
parent
1c2bc9843c
commit
f052c3fed1
|
@ -1,5 +1,7 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- Replace deprecated wp.compose.withState with wp.element.useState. #8338
|
||||||
|
|
||||||
# 9.0.0
|
# 9.0.0
|
||||||
|
|
||||||
- Update line-height of SelectControl label to avoid truncated descenders in some typefaces and zoom levels. #8186
|
- Update line-height of SelectControl label to avoid truncated descenders in some typefaces and zoom levels. #8186
|
||||||
|
|
|
@ -2,23 +2,25 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { withState } from '@wordpress/compose';
|
|
||||||
import { DatePicker, H, Section } from '@woocommerce/components';
|
import { DatePicker, H, Section } from '@woocommerce/components';
|
||||||
import { createElement } from '@wordpress/element';
|
import { useState } from '@wordpress/element';
|
||||||
|
|
||||||
const dateFormat = 'MM/DD/YYYY';
|
const dateFormat = 'MM/DD/YYYY';
|
||||||
|
|
||||||
const DatePickerExample = withState( {
|
const DatePickerExample = () => {
|
||||||
after: null,
|
const [ state, setState ] = useState( {
|
||||||
afterText: '',
|
after: null,
|
||||||
before: null,
|
afterText: '',
|
||||||
beforeText: '',
|
before: null,
|
||||||
afterError: null,
|
beforeText: '',
|
||||||
beforeError: null,
|
afterError: null,
|
||||||
focusedInput: 'startDate',
|
beforeError: null,
|
||||||
} )( ( { after, afterText, afterError, setState } ) => {
|
focusedInput: 'startDate',
|
||||||
|
} );
|
||||||
|
const { after, afterText, afterError } = state;
|
||||||
|
|
||||||
function onDatePickerUpdate( { date, text, error } ) {
|
function onDatePickerUpdate( { date, text, error } ) {
|
||||||
setState( {
|
setState( {
|
||||||
|
...state,
|
||||||
after: date,
|
after: date,
|
||||||
afterText: text,
|
afterText: text,
|
||||||
afterError: error,
|
afterError: error,
|
||||||
|
@ -40,7 +42,7 @@ const DatePickerExample = withState( {
|
||||||
</Section>
|
</Section>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} );
|
};
|
||||||
|
|
||||||
export const Basic = () => <DatePickerExample />;
|
export const Basic = () => <DatePickerExample />;
|
||||||
|
|
||||||
|
|
|
@ -2,23 +2,29 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { withState } from '@wordpress/compose';
|
|
||||||
import { DateRange, H, Section } from '@woocommerce/components';
|
import { DateRange, H, Section } from '@woocommerce/components';
|
||||||
import { createElement, Fragment } from '@wordpress/element';
|
import { useState } from '@wordpress/element';
|
||||||
|
|
||||||
const dateFormat = 'MM/DD/YYYY';
|
const dateFormat = 'MM/DD/YYYY';
|
||||||
|
|
||||||
const DateRangeExample = withState( {
|
const DateRangeExample = () => {
|
||||||
after: null,
|
const [ state, setState ] = useState( {
|
||||||
afterText: '',
|
after: null,
|
||||||
before: null,
|
afterText: '',
|
||||||
beforeText: '',
|
before: null,
|
||||||
afterError: null,
|
beforeText: '',
|
||||||
beforeError: null,
|
afterError: null,
|
||||||
focusedInput: 'startDate',
|
beforeError: null,
|
||||||
} )( ( { after, afterText, before, beforeText, focusedInput, setState } ) => {
|
focusedInput: 'startDate',
|
||||||
|
} );
|
||||||
|
|
||||||
|
const { after, afterText, before, beforeText, focusedInput } = state;
|
||||||
|
|
||||||
function onRangeUpdate( update ) {
|
function onRangeUpdate( update ) {
|
||||||
setState( update );
|
setState( {
|
||||||
|
...state,
|
||||||
|
...update,
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -40,7 +46,7 @@ const DateRangeExample = withState( {
|
||||||
</Section>
|
</Section>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
} );
|
};
|
||||||
|
|
||||||
export const Basic = () => <DateRangeExample />;
|
export const Basic = () => <DateRangeExample />;
|
||||||
|
|
||||||
|
|
|
@ -1,47 +1,57 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { withState } from '@wordpress/compose';
|
import { Fragment, useState } from '@wordpress/element';
|
||||||
import { Fragment } from '@wordpress/element';
|
|
||||||
import { Icon } from '@wordpress/icons';
|
import { Icon } from '@wordpress/icons';
|
||||||
import CrossSmall from 'gridicons/dist/cross-small';
|
import CrossSmall from 'gridicons/dist/cross-small';
|
||||||
import { EllipsisMenu, MenuItem, MenuTitle } from '@woocommerce/components';
|
import { EllipsisMenu, MenuItem, MenuTitle } from '@woocommerce/components';
|
||||||
|
|
||||||
const ExampleEllipsisMenu = withState( {
|
const ExampleEllipsisMenu = () => {
|
||||||
showCustomers: true,
|
const [ { showCustomers, showOrders }, setState ] = useState( {
|
||||||
showOrders: true,
|
showCustomers: true,
|
||||||
} )( ( { setState, showCustomers, showOrders } ) => (
|
showOrders: true,
|
||||||
<EllipsisMenu
|
} );
|
||||||
label="Choose which analytics to display"
|
return (
|
||||||
renderContent={ ( { onToggle } ) => (
|
<EllipsisMenu
|
||||||
<Fragment>
|
label="Choose which analytics to display"
|
||||||
<MenuTitle>Display stats</MenuTitle>
|
renderContent={ ( { onToggle } ) => (
|
||||||
<MenuItem
|
<Fragment>
|
||||||
isCheckbox
|
<MenuTitle>Display stats</MenuTitle>
|
||||||
isClickable
|
<MenuItem
|
||||||
checked={ showCustomers }
|
isCheckbox
|
||||||
onInvoke={ () =>
|
isClickable
|
||||||
setState( { showCustomers: ! showCustomers } )
|
checked={ showCustomers }
|
||||||
}
|
onInvoke={ () =>
|
||||||
>
|
setState( {
|
||||||
Show Customers
|
showOrders,
|
||||||
</MenuItem>
|
showCustomers: ! showCustomers,
|
||||||
<MenuItem
|
} )
|
||||||
isCheckbox
|
}
|
||||||
isClickable
|
>
|
||||||
checked={ showOrders }
|
Show Customers
|
||||||
onInvoke={ () => setState( { showOrders: ! showOrders } ) }
|
</MenuItem>
|
||||||
>
|
<MenuItem
|
||||||
Show Orders
|
isCheckbox
|
||||||
</MenuItem>
|
isClickable
|
||||||
<MenuItem isClickable onInvoke={ onToggle }>
|
checked={ showOrders }
|
||||||
<Icon icon={ <CrossSmall /> } />
|
onInvoke={ () =>
|
||||||
Close Menu
|
setState( {
|
||||||
</MenuItem>
|
showCustomers,
|
||||||
</Fragment>
|
showOrders: ! showOrders,
|
||||||
) }
|
} )
|
||||||
/>
|
}
|
||||||
) );
|
>
|
||||||
|
Show Orders
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem isClickable onInvoke={ onToggle }>
|
||||||
|
<Icon icon={ <CrossSmall /> } />
|
||||||
|
Close Menu
|
||||||
|
</MenuItem>
|
||||||
|
</Fragment>
|
||||||
|
) }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const Basic = () => <ExampleEllipsisMenu />;
|
export const Basic = () => <ExampleEllipsisMenu />;
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { withState } from '@wordpress/compose';
|
import { useState } from '@wordpress/element';
|
||||||
import { ImageUpload } from '@woocommerce/components';
|
import { ImageUpload } from '@woocommerce/components';
|
||||||
|
|
||||||
const ImageUploadExample = withState( {
|
const ImageUploadExample = () => {
|
||||||
image: null,
|
const [ image, setImage ] = useState( null );
|
||||||
} )( ( { setState, logo } ) => (
|
|
||||||
<ImageUpload
|
return (
|
||||||
image={ logo }
|
<ImageUpload
|
||||||
onChange={ ( image ) => setState( { logo: image } ) }
|
image={ image }
|
||||||
/>
|
onChange={ ( _image ) => setImage( _image ) }
|
||||||
) );
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const Basic = () => <ImageUploadExample />;
|
export const Basic = () => <ImageUploadExample />;
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,13 @@ import {
|
||||||
TextControl,
|
TextControl,
|
||||||
withSpokenMessages,
|
withSpokenMessages,
|
||||||
} from '@wordpress/components';
|
} from '@wordpress/components';
|
||||||
import { createElement, Component, Fragment } from '@wordpress/element';
|
import {
|
||||||
import { compose, withInstanceId, withState } from '@wordpress/compose';
|
createElement,
|
||||||
|
Fragment,
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
} from '@wordpress/element';
|
||||||
|
import { compose, withInstanceId } from '@wordpress/compose';
|
||||||
import { escapeRegExp, findIndex } from 'lodash';
|
import { escapeRegExp, findIndex } from 'lodash';
|
||||||
import NoticeOutlineIcon from 'gridicons/dist/notice-outline';
|
import NoticeOutlineIcon from 'gridicons/dist/notice-outline';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
@ -43,28 +48,33 @@ const defaultMessages = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component to display a searchable, selectable list of items.
|
* Component to display a searchable, selectable list of items.
|
||||||
|
*
|
||||||
|
* @param {Object} props
|
||||||
*/
|
*/
|
||||||
export class SearchListControl extends Component {
|
export const SearchListControl = ( props ) => {
|
||||||
constructor() {
|
const [ searchValue, setSearchValue ] = useState( props.search || '' );
|
||||||
super( ...arguments );
|
const {
|
||||||
|
isSingle,
|
||||||
|
isLoading,
|
||||||
|
onChange,
|
||||||
|
selected,
|
||||||
|
instanceId,
|
||||||
|
messages: propsMessages,
|
||||||
|
isCompact,
|
||||||
|
debouncedSpeak,
|
||||||
|
onSearch,
|
||||||
|
className = '',
|
||||||
|
} = props;
|
||||||
|
|
||||||
this.onSelect = this.onSelect.bind( this );
|
const messages = { ...defaultMessages, ...propsMessages };
|
||||||
this.onRemove = this.onRemove.bind( this );
|
|
||||||
this.onClear = this.onClear.bind( this );
|
|
||||||
this.isSelected = this.isSelected.bind( this );
|
|
||||||
this.defaultRenderItem = this.defaultRenderItem.bind( this );
|
|
||||||
this.renderList = this.renderList.bind( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate( prevProps ) {
|
useEffect( () => {
|
||||||
const { onSearch, search } = this.props;
|
if ( typeof onSearch === 'function' ) {
|
||||||
if ( search !== prevProps.search && typeof onSearch === 'function' ) {
|
onSearch( searchValue );
|
||||||
onSearch( search );
|
|
||||||
}
|
}
|
||||||
}
|
}, [ onSearch, searchValue ] );
|
||||||
|
|
||||||
onRemove( id ) {
|
const onRemove = ( id ) => {
|
||||||
const { isSingle, onChange, selected } = this.props;
|
|
||||||
return () => {
|
return () => {
|
||||||
if ( isSingle ) {
|
if ( isSingle ) {
|
||||||
onChange( [] );
|
onChange( [] );
|
||||||
|
@ -75,13 +85,12 @@ export class SearchListControl extends Component {
|
||||||
...selected.slice( i + 1 ),
|
...selected.slice( i + 1 ),
|
||||||
] );
|
] );
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
onSelect( item ) {
|
const onSelect = ( item ) => {
|
||||||
const { isSingle, onChange, selected } = this.props;
|
|
||||||
return () => {
|
return () => {
|
||||||
if ( this.isSelected( item ) ) {
|
if ( isSelected( item ) ) {
|
||||||
this.onRemove( item.id )();
|
onRemove( item.id )();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ( isSingle ) {
|
if ( isSingle ) {
|
||||||
|
@ -90,39 +99,32 @@ export class SearchListControl extends Component {
|
||||||
onChange( [ ...selected, item ] );
|
onChange( [ ...selected, item ] );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
onClear() {
|
const isSelected = ( item ) =>
|
||||||
this.props.onChange( [] );
|
findIndex( selected, { id: item.id } ) !== -1;
|
||||||
}
|
|
||||||
|
|
||||||
isSelected( item ) {
|
const getFilteredList = ( list, search ) => {
|
||||||
return findIndex( this.props.selected, { id: item.id } ) !== -1;
|
const { isHierarchical } = props;
|
||||||
}
|
|
||||||
|
|
||||||
getFilteredList( list, search ) {
|
|
||||||
const { isHierarchical } = this.props;
|
|
||||||
if ( ! search ) {
|
if ( ! search ) {
|
||||||
return isHierarchical ? buildTermsTree( list ) : list;
|
return isHierarchical ? buildTermsTree( list ) : list;
|
||||||
}
|
}
|
||||||
const messages = { ...defaultMessages, ...this.props.messages };
|
|
||||||
const re = new RegExp( escapeRegExp( search ), 'i' );
|
const re = new RegExp( escapeRegExp( search ), 'i' );
|
||||||
this.props.debouncedSpeak( messages.updated );
|
debouncedSpeak( messages.updated );
|
||||||
const filteredList = list
|
const filteredList = list
|
||||||
.map( ( item ) => ( re.test( item.name ) ? item : false ) )
|
.map( ( item ) => ( re.test( item.name ) ? item : false ) )
|
||||||
.filter( Boolean );
|
.filter( Boolean );
|
||||||
return isHierarchical
|
return isHierarchical
|
||||||
? buildTermsTree( filteredList, list )
|
? buildTermsTree( filteredList, list )
|
||||||
: filteredList;
|
: filteredList;
|
||||||
}
|
};
|
||||||
|
|
||||||
defaultRenderItem( args ) {
|
const defaultRenderItem = ( args ) => {
|
||||||
return <SearchListItem { ...args } />;
|
return <SearchListItem { ...args } />;
|
||||||
}
|
};
|
||||||
|
|
||||||
renderList( list, depth = 0 ) {
|
const renderList = ( list, depth = 0 ) => {
|
||||||
const { isSingle, search, instanceId } = this.props;
|
const renderItem = props.renderItem || defaultRenderItem;
|
||||||
const renderItem = this.props.renderItem || this.defaultRenderItem;
|
|
||||||
if ( ! list ) {
|
if ( ! list ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -132,23 +134,20 @@ export class SearchListControl extends Component {
|
||||||
<li>
|
<li>
|
||||||
{ renderItem( {
|
{ renderItem( {
|
||||||
item,
|
item,
|
||||||
isSelected: this.isSelected( item ),
|
isSelected: isSelected( item ),
|
||||||
onSelect: this.onSelect,
|
onSelect,
|
||||||
isSingle,
|
isSingle,
|
||||||
search,
|
search: searchValue,
|
||||||
depth,
|
depth,
|
||||||
controlId: instanceId,
|
controlId: instanceId,
|
||||||
} ) }
|
} ) }
|
||||||
</li>
|
</li>
|
||||||
{ this.renderList( item.children, depth + 1 ) }
|
{ renderList( item.children, depth + 1 ) }
|
||||||
</Fragment>
|
</Fragment>
|
||||||
) );
|
) );
|
||||||
}
|
};
|
||||||
|
|
||||||
renderListSection() {
|
|
||||||
const { isLoading, search } = this.props;
|
|
||||||
const messages = { ...defaultMessages, ...this.props.messages };
|
|
||||||
|
|
||||||
|
const renderListSection = () => {
|
||||||
if ( isLoading ) {
|
if ( isLoading ) {
|
||||||
return (
|
return (
|
||||||
<div className="woocommerce-search-list__list is-loading">
|
<div className="woocommerce-search-list__list is-loading">
|
||||||
|
@ -156,7 +155,7 @@ export class SearchListControl extends Component {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const list = this.getFilteredList( this.props.list, search );
|
const list = getFilteredList( props.list, searchValue );
|
||||||
|
|
||||||
if ( ! list.length ) {
|
if ( ! list.length ) {
|
||||||
return (
|
return (
|
||||||
|
@ -169,9 +168,9 @@ export class SearchListControl extends Component {
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span className="woocommerce-search-list__not-found-text">
|
<span className="woocommerce-search-list__not-found-text">
|
||||||
{ search
|
{ searchValue
|
||||||
? // eslint-disable-next-line @wordpress/valid-sprintf
|
? // eslint-disable-next-line @wordpress/valid-sprintf
|
||||||
sprintf( messages.noResults, search )
|
sprintf( messages.noResults, searchValue )
|
||||||
: messages.noItems }
|
: messages.noItems }
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -180,15 +179,12 @@ export class SearchListControl extends Component {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul className="woocommerce-search-list__list">
|
<ul className="woocommerce-search-list__list">
|
||||||
{ this.renderList( list ) }
|
{ renderList( list ) }
|
||||||
</ul>
|
</ul>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
renderSelectedSection() {
|
|
||||||
const { isLoading, isSingle, selected } = this.props;
|
|
||||||
const messages = { ...defaultMessages, ...this.props.messages };
|
|
||||||
|
|
||||||
|
const renderSelectedSection = () => {
|
||||||
if ( isLoading || isSingle || ! selected ) {
|
if ( isLoading || isSingle || ! selected ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -202,7 +198,7 @@ export class SearchListControl extends Component {
|
||||||
<Button
|
<Button
|
||||||
isLink
|
isLink
|
||||||
isDestructive
|
isDestructive
|
||||||
onClick={ this.onClear }
|
onClick={ onChange( [] ) }
|
||||||
aria-label={ messages.clear }
|
aria-label={ messages.clear }
|
||||||
>
|
>
|
||||||
{ __( 'Clear all', 'woocommerce-admin' ) }
|
{ __( 'Clear all', 'woocommerce-admin' ) }
|
||||||
|
@ -216,7 +212,7 @@ export class SearchListControl extends Component {
|
||||||
<Tag
|
<Tag
|
||||||
label={ item.name }
|
label={ item.name }
|
||||||
id={ item.id }
|
id={ item.id }
|
||||||
remove={ this.onRemove }
|
remove={ onRemove }
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
) ) }
|
) ) }
|
||||||
|
@ -224,34 +220,29 @@ export class SearchListControl extends Component {
|
||||||
) : null }
|
) : null }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
const { className = '', isCompact, search, setState } = this.props;
|
<div
|
||||||
const messages = { ...defaultMessages, ...this.props.messages };
|
className={ classnames( 'woocommerce-search-list', className, {
|
||||||
|
'is-compact': isCompact,
|
||||||
|
} ) }
|
||||||
|
>
|
||||||
|
{ renderSelectedSection() }
|
||||||
|
|
||||||
return (
|
<div className="woocommerce-search-list__search">
|
||||||
<div
|
<TextControl
|
||||||
className={ classnames( 'woocommerce-search-list', className, {
|
label={ messages.search }
|
||||||
'is-compact': isCompact,
|
type="search"
|
||||||
} ) }
|
value={ searchValue }
|
||||||
>
|
onChange={ ( value ) => setSearchValue( value ) }
|
||||||
{ this.renderSelectedSection() }
|
/>
|
||||||
|
|
||||||
<div className="woocommerce-search-list__search">
|
|
||||||
<TextControl
|
|
||||||
label={ messages.search }
|
|
||||||
type="search"
|
|
||||||
value={ search }
|
|
||||||
onChange={ ( value ) => setState( { search: value } ) }
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{ this.renderListSection() }
|
|
||||||
</div>
|
</div>
|
||||||
);
|
|
||||||
}
|
{ renderListSection() }
|
||||||
}
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
SearchListControl.propTypes = {
|
SearchListControl.propTypes = {
|
||||||
/**
|
/**
|
||||||
|
@ -334,19 +325,12 @@ SearchListControl.propTypes = {
|
||||||
* The list of currently selected items.
|
* The list of currently selected items.
|
||||||
*/
|
*/
|
||||||
selected: PropTypes.array.isRequired,
|
selected: PropTypes.array.isRequired,
|
||||||
// from withState
|
|
||||||
search: PropTypes.string,
|
|
||||||
setState: PropTypes.func,
|
|
||||||
// from withSpokenMessages
|
// from withSpokenMessages
|
||||||
debouncedSpeak: PropTypes.func,
|
debouncedSpeak: PropTypes.func,
|
||||||
// from withInstanceId
|
// from withInstanceId
|
||||||
instanceId: PropTypes.number,
|
instanceId: PropTypes.number,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default compose( [
|
export default compose( [ withSpokenMessages, withInstanceId ] )(
|
||||||
withState( {
|
SearchListControl
|
||||||
search: '',
|
);
|
||||||
} ),
|
|
||||||
withSpokenMessages,
|
|
||||||
withInstanceId,
|
|
||||||
] )( SearchListControl );
|
|
||||||
|
|
|
@ -3,13 +3,12 @@
|
||||||
*/
|
*/
|
||||||
import { boolean } from '@storybook/addon-knobs';
|
import { boolean } from '@storybook/addon-knobs';
|
||||||
import { SearchListControl } from '@woocommerce/components';
|
import { SearchListControl } from '@woocommerce/components';
|
||||||
import { withState } from '@wordpress/compose';
|
import { useState } from '@wordpress/element';
|
||||||
import { createElement } from '@wordpress/element';
|
|
||||||
|
const SearchListControlExample = () => {
|
||||||
|
const [ selected, setSelected ] = useState( [] );
|
||||||
|
const [ loading, setLoading ] = useState( false );
|
||||||
|
|
||||||
const SearchListControlExample = withState( {
|
|
||||||
selected: [],
|
|
||||||
loading: false,
|
|
||||||
} )( ( { selected, loading, setState } ) => {
|
|
||||||
const showCount = boolean( 'Show count', false );
|
const showCount = boolean( 'Show count', false );
|
||||||
const isCompact = boolean( 'Compact', false );
|
const isCompact = boolean( 'Compact', false );
|
||||||
const isSingle = boolean( 'Single', false );
|
const isSingle = boolean( 'Single', false );
|
||||||
|
@ -30,7 +29,7 @@ const SearchListControlExample = withState( {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<button onClick={ () => setState( { loading: ! loading } ) }>
|
<button onClick={ () => setLoading( ! loading ) }>
|
||||||
Toggle loading state
|
Toggle loading state
|
||||||
</button>
|
</button>
|
||||||
<SearchListControl
|
<SearchListControl
|
||||||
|
@ -38,12 +37,12 @@ const SearchListControlExample = withState( {
|
||||||
isCompact={ isCompact }
|
isCompact={ isCompact }
|
||||||
isLoading={ loading }
|
isLoading={ loading }
|
||||||
selected={ selected }
|
selected={ selected }
|
||||||
onChange={ ( items ) => setState( { selected: items } ) }
|
onChange={ ( items ) => setSelected( items ) }
|
||||||
isSingle={ isSingle }
|
isSingle={ isSingle }
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} );
|
};
|
||||||
|
|
||||||
export const Basic = () => <SearchListControlExample />;
|
export const Basic = () => <SearchListControlExample />;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { render } from '@testing-library/react';
|
import { render, fireEvent } from '@testing-library/react';
|
||||||
import { noop } from 'lodash';
|
import { noop } from 'lodash';
|
||||||
import { createElement } from '@wordpress/element';
|
import { createElement } from '@wordpress/element';
|
||||||
|
|
||||||
|
@ -174,4 +174,24 @@ describe( 'SearchListControl', () => {
|
||||||
);
|
);
|
||||||
expect( component ).toMatchSnapshot();
|
expect( component ).toMatchSnapshot();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
test( 'should match options after changing search control', () => {
|
||||||
|
const { getByLabelText, getAllByText } = render(
|
||||||
|
<SearchListControl
|
||||||
|
instanceId={ 1 }
|
||||||
|
list={ list }
|
||||||
|
search=""
|
||||||
|
selected={ [] }
|
||||||
|
onChange={ noop }
|
||||||
|
debouncedSpeak={ noop }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.change( getByLabelText( 'Search for items' ), {
|
||||||
|
target: {
|
||||||
|
value: 'berry',
|
||||||
|
},
|
||||||
|
} );
|
||||||
|
expect( getAllByText( 'berry' ).length ).toBe( 2 );
|
||||||
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -1,35 +1,37 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { withState } from '@wordpress/compose';
|
|
||||||
import { H, Search, Section } from '@woocommerce/components';
|
import { H, Search, Section } from '@woocommerce/components';
|
||||||
|
import { useState } from '@wordpress/element';
|
||||||
|
|
||||||
const SearchExample = withState( {
|
const SearchExample = () => {
|
||||||
selected: [],
|
const [ selected, setSelected ] = useState( [] );
|
||||||
inlineSelected: [],
|
const [ inlineSelected, setInlineSelect ] = useState( [] );
|
||||||
} )( ( { selected, inlineSelected, setState } ) => (
|
|
||||||
<div>
|
return (
|
||||||
<H>Tags Below Input</H>
|
<div>
|
||||||
<Section component={ false }>
|
<H>Tags Below Input</H>
|
||||||
<Search
|
<Section component={ false }>
|
||||||
type="products"
|
<Search
|
||||||
placeholder="Search for a product"
|
type="products"
|
||||||
selected={ selected }
|
placeholder="Search for a product"
|
||||||
onChange={ ( items ) => setState( { selected: items } ) }
|
selected={ selected }
|
||||||
/>
|
onChange={ ( items ) => setSelected( items ) }
|
||||||
</Section>
|
/>
|
||||||
<H>Tags Inline with Input</H>
|
</Section>
|
||||||
<Section component={ false }>
|
<H>Tags Inline with Input</H>
|
||||||
<Search
|
<Section component={ false }>
|
||||||
type="products"
|
<Search
|
||||||
placeholder="Search for a product"
|
type="products"
|
||||||
selected={ inlineSelected }
|
placeholder="Search for a product"
|
||||||
onChange={ ( items ) => setState( { inlineSelected: items } ) }
|
selected={ inlineSelected }
|
||||||
inlineTags
|
onChange={ ( items ) => setInlineSelect( items ) }
|
||||||
/>
|
inlineTags
|
||||||
</Section>
|
/>
|
||||||
</div>
|
</Section>
|
||||||
) );
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const Basic = () => <SearchExample />;
|
export const Basic = () => <SearchExample />;
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,29 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { withState } from '@wordpress/compose';
|
|
||||||
import { SegmentedSelection } from '@woocommerce/components';
|
import { SegmentedSelection } from '@woocommerce/components';
|
||||||
|
import { useState } from '@wordpress/element';
|
||||||
|
|
||||||
const name = 'number';
|
const name = 'number';
|
||||||
|
|
||||||
const SegmentedSelectionExample = withState( {
|
const SegmentedSelectionExample = () => {
|
||||||
selected: 'two',
|
const [ selected, setSelected ] = useState( 'two' );
|
||||||
} )( ( { selected, setState } ) => (
|
|
||||||
<SegmentedSelection
|
return (
|
||||||
options={ [
|
<SegmentedSelection
|
||||||
{ value: 'one', label: 'One' },
|
options={ [
|
||||||
{ value: 'two', label: 'Two' },
|
{ value: 'one', label: 'One' },
|
||||||
{ value: 'three', label: 'Three' },
|
{ value: 'two', label: 'Two' },
|
||||||
{ value: 'four', label: 'Four' },
|
{ value: 'three', label: 'Three' },
|
||||||
] }
|
{ value: 'four', label: 'Four' },
|
||||||
selected={ selected }
|
] }
|
||||||
legend="Select a number"
|
selected={ selected }
|
||||||
onSelect={ ( data ) => setState( { selected: data[ name ] } ) }
|
legend="Select a number"
|
||||||
name={ name }
|
onSelect={ ( data ) => setSelected( data[ name ] ) }
|
||||||
/>
|
name={ name }
|
||||||
) );
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const Basic = () => <SegmentedSelectionExample />;
|
export const Basic = () => <SegmentedSelectionExample />;
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,7 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { SelectControl } from '@woocommerce/components';
|
import { SelectControl } from '@woocommerce/components';
|
||||||
|
import { useState } from '@wordpress/element';
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { withState } from '@wordpress/compose';
|
|
||||||
|
|
||||||
const options = [
|
const options = [
|
||||||
{
|
{
|
||||||
|
@ -52,16 +48,18 @@ const options = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const SelectControlExample = withState( {
|
const SelectControlExample = () => {
|
||||||
simpleSelected: [],
|
const [ state, setState ] = useState( {
|
||||||
simpleMultipleSelected: [],
|
simpleSelected: [],
|
||||||
singleSelected: [],
|
simpleMultipleSelected: [],
|
||||||
singleSelectedShowAll: [],
|
singleSelected: [],
|
||||||
multipleSelected: [],
|
singleSelectedShowAll: [],
|
||||||
inlineSelected: [],
|
multipleSelected: [],
|
||||||
allOptionsIncludingSelected: options[ options.length - 1 ].key,
|
inlineSelected: [],
|
||||||
} )(
|
allOptionsIncludingSelected: options[ options.length - 1 ].key,
|
||||||
( {
|
} );
|
||||||
|
|
||||||
|
const {
|
||||||
simpleSelected,
|
simpleSelected,
|
||||||
simpleMultipleSelected,
|
simpleMultipleSelected,
|
||||||
singleSelected,
|
singleSelected,
|
||||||
|
@ -69,13 +67,14 @@ const SelectControlExample = withState( {
|
||||||
multipleSelected,
|
multipleSelected,
|
||||||
inlineSelected,
|
inlineSelected,
|
||||||
allOptionsIncludingSelected,
|
allOptionsIncludingSelected,
|
||||||
setState,
|
} = state;
|
||||||
} ) => (
|
|
||||||
|
return (
|
||||||
<div>
|
<div>
|
||||||
<SelectControl
|
<SelectControl
|
||||||
label="Simple single value"
|
label="Simple single value"
|
||||||
onChange={ ( selected ) =>
|
onChange={ ( selected ) =>
|
||||||
setState( { simpleSelected: selected } )
|
setState( { ...state, simpleSelected: selected } )
|
||||||
}
|
}
|
||||||
options={ options }
|
options={ options }
|
||||||
placeholder="Start typing to filter options..."
|
placeholder="Start typing to filter options..."
|
||||||
|
@ -86,7 +85,7 @@ const SelectControlExample = withState( {
|
||||||
label="Multiple values"
|
label="Multiple values"
|
||||||
multiple
|
multiple
|
||||||
onChange={ ( selected ) =>
|
onChange={ ( selected ) =>
|
||||||
setState( { simpleMultipleSelected: selected } )
|
setState( { ...state, simpleMultipleSelected: selected } )
|
||||||
}
|
}
|
||||||
options={ options }
|
options={ options }
|
||||||
placeholder="Start typing to filter options..."
|
placeholder="Start typing to filter options..."
|
||||||
|
@ -96,7 +95,10 @@ const SelectControlExample = withState( {
|
||||||
<SelectControl
|
<SelectControl
|
||||||
label="Show all options with default selected"
|
label="Show all options with default selected"
|
||||||
onChange={ ( selected ) =>
|
onChange={ ( selected ) =>
|
||||||
setState( { allOptionsIncludingSelected: selected } )
|
setState( {
|
||||||
|
...state,
|
||||||
|
allOptionsIncludingSelected: selected,
|
||||||
|
} )
|
||||||
}
|
}
|
||||||
options={ options }
|
options={ options }
|
||||||
placeholder="Start typing to filter options..."
|
placeholder="Start typing to filter options..."
|
||||||
|
@ -110,7 +112,7 @@ const SelectControlExample = withState( {
|
||||||
label="Single value searchable"
|
label="Single value searchable"
|
||||||
isSearchable
|
isSearchable
|
||||||
onChange={ ( selected ) =>
|
onChange={ ( selected ) =>
|
||||||
setState( { singleSelected: selected } )
|
setState( { ...state, singleSelected: selected } )
|
||||||
}
|
}
|
||||||
options={ options }
|
options={ options }
|
||||||
placeholder="Start typing to filter options..."
|
placeholder="Start typing to filter options..."
|
||||||
|
@ -121,7 +123,7 @@ const SelectControlExample = withState( {
|
||||||
label="Single value searchable with options on refocus"
|
label="Single value searchable with options on refocus"
|
||||||
isSearchable
|
isSearchable
|
||||||
onChange={ ( selected ) =>
|
onChange={ ( selected ) =>
|
||||||
setState( { singleSelectedShowAll: selected } )
|
setState( { ...state, singleSelectedShowAll: selected } )
|
||||||
}
|
}
|
||||||
options={ options }
|
options={ options }
|
||||||
placeholder="Start typing to filter options..."
|
placeholder="Start typing to filter options..."
|
||||||
|
@ -135,7 +137,7 @@ const SelectControlExample = withState( {
|
||||||
multiple
|
multiple
|
||||||
inlineTags
|
inlineTags
|
||||||
onChange={ ( selected ) =>
|
onChange={ ( selected ) =>
|
||||||
setState( { inlineSelected: selected } )
|
setState( { ...state, inlineSelected: selected } )
|
||||||
}
|
}
|
||||||
options={ options }
|
options={ options }
|
||||||
placeholder="Start typing to filter options..."
|
placeholder="Start typing to filter options..."
|
||||||
|
@ -148,7 +150,7 @@ const SelectControlExample = withState( {
|
||||||
label="Hidden options before search"
|
label="Hidden options before search"
|
||||||
multiple
|
multiple
|
||||||
onChange={ ( selected ) =>
|
onChange={ ( selected ) =>
|
||||||
setState( { multipleSelected: selected } )
|
setState( { ...state, multipleSelected: selected } )
|
||||||
}
|
}
|
||||||
options={ options }
|
options={ options }
|
||||||
placeholder="Start typing to filter options..."
|
placeholder="Start typing to filter options..."
|
||||||
|
@ -156,8 +158,8 @@ const SelectControlExample = withState( {
|
||||||
showClearButton
|
showClearButton
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
|
|
||||||
export const Basic = () => <SelectControlExample />;
|
export const Basic = () => <SelectControlExample />;
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { withState } from '@wordpress/compose';
|
|
||||||
import { Stepper } from '@woocommerce/components';
|
import { Stepper } from '@woocommerce/components';
|
||||||
import { createElement } from '@wordpress/element';
|
import { useState } from '@wordpress/element';
|
||||||
|
|
||||||
|
const BasicExamples = () => {
|
||||||
|
const [ state, setState ] = useState( {
|
||||||
|
currentStep: 'first',
|
||||||
|
isComplete: false,
|
||||||
|
isPending: false,
|
||||||
|
} );
|
||||||
|
const { currentStep, isComplete, isPending } = state;
|
||||||
|
|
||||||
const BasicExamples = withState( {
|
|
||||||
currentStep: 'first',
|
|
||||||
isComplete: false,
|
|
||||||
isPending: false,
|
|
||||||
} )( ( { currentStep, isComplete, isPending, setState } ) => {
|
|
||||||
const goToStep = ( key ) => {
|
const goToStep = ( key ) => {
|
||||||
setState( { currentStep: key } );
|
setState( { currentStep: key } );
|
||||||
};
|
};
|
||||||
|
@ -56,7 +58,11 @@ const BasicExamples = withState( {
|
||||||
{ isComplete ? (
|
{ isComplete ? (
|
||||||
<button
|
<button
|
||||||
onClick={ () =>
|
onClick={ () =>
|
||||||
setState( { currentStep: 'first', isComplete: false } )
|
setState( {
|
||||||
|
...state,
|
||||||
|
currentStep: 'first',
|
||||||
|
isComplete: false,
|
||||||
|
} )
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Reset
|
Reset
|
||||||
|
@ -66,6 +72,7 @@ const BasicExamples = withState( {
|
||||||
<button
|
<button
|
||||||
onClick={ () =>
|
onClick={ () =>
|
||||||
setState( {
|
setState( {
|
||||||
|
...state,
|
||||||
currentStep: steps[ currentIndex - 1 ].key,
|
currentStep: steps[ currentIndex - 1 ].key,
|
||||||
} )
|
} )
|
||||||
}
|
}
|
||||||
|
@ -76,6 +83,7 @@ const BasicExamples = withState( {
|
||||||
<button
|
<button
|
||||||
onClick={ () =>
|
onClick={ () =>
|
||||||
setState( {
|
setState( {
|
||||||
|
...state,
|
||||||
currentStep: steps[ currentIndex + 1 ].key,
|
currentStep: steps[ currentIndex + 1 ].key,
|
||||||
} )
|
} )
|
||||||
}
|
}
|
||||||
|
@ -84,13 +92,17 @@ const BasicExamples = withState( {
|
||||||
Next step
|
Next step
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={ () => setState( { isComplete: true } ) }
|
onClick={ () =>
|
||||||
|
setState( { ...state, isComplete: true } )
|
||||||
|
}
|
||||||
disabled={ currentIndex !== steps.length - 1 }
|
disabled={ currentIndex !== steps.length - 1 }
|
||||||
>
|
>
|
||||||
Complete
|
Complete
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={ () => setState( { isPending: ! isPending } ) }
|
onClick={ () =>
|
||||||
|
setState( { ...state, isPending: ! isPending } )
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Toggle Spinner
|
Toggle Spinner
|
||||||
</button>
|
</button>
|
||||||
|
@ -113,7 +125,7 @@ const BasicExamples = withState( {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} );
|
};
|
||||||
|
|
||||||
export const Examples = () => <BasicExamples />;
|
export const Examples = () => <BasicExamples />;
|
||||||
|
|
||||||
|
|
|
@ -2,38 +2,37 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { TableCard } from '@woocommerce/components';
|
import { TableCard } from '@woocommerce/components';
|
||||||
|
import { useState } from '@wordpress/element';
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { withState } from '@wordpress/compose';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { headers, rows, summary } from './index';
|
import { headers, rows, summary } from './index';
|
||||||
|
|
||||||
const TableCardExample = withState( {
|
const TableCardExample = () => {
|
||||||
query: {
|
const [ { query }, setState ] = useState( {
|
||||||
paged: 1,
|
query: {
|
||||||
},
|
paged: 1,
|
||||||
} )( ( { query, setState } ) => (
|
},
|
||||||
<TableCard
|
} );
|
||||||
title="Revenue last week"
|
return (
|
||||||
rows={ rows }
|
<TableCard
|
||||||
headers={ headers }
|
title="Revenue last week"
|
||||||
onQueryChange={ ( param ) => ( value ) =>
|
rows={ rows }
|
||||||
setState( {
|
headers={ headers }
|
||||||
query: {
|
onQueryChange={ ( param ) => ( value ) =>
|
||||||
[ param ]: value,
|
setState( {
|
||||||
},
|
query: {
|
||||||
} ) }
|
[ param ]: value,
|
||||||
query={ query }
|
},
|
||||||
rowsPerPage={ 7 }
|
} ) }
|
||||||
totalRows={ 10 }
|
query={ query }
|
||||||
summary={ summary }
|
rowsPerPage={ 7 }
|
||||||
/>
|
totalRows={ 10 }
|
||||||
) );
|
summary={ summary }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const Basic = () => <TableCardExample />;
|
export const Basic = () => <TableCardExample />;
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { __, sprintf } from '@wordpress/i18n';
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
import { createElement, Fragment } from '@wordpress/element';
|
import { createElement, Fragment, useState } from '@wordpress/element';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { Button, Popover } from '@wordpress/components';
|
import { Button, Popover } from '@wordpress/components';
|
||||||
import { Icon, cancelCircleFilled } from '@wordpress/icons';
|
import { Icon, cancelCircleFilled } from '@wordpress/icons';
|
||||||
import { decodeEntities } from '@wordpress/html-entities';
|
import { decodeEntities } from '@wordpress/html-entities';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { withState, withInstanceId } from '@wordpress/compose';
|
import { withInstanceId } from '@wordpress/compose';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component can be used to show an item styled as a "tag", optionally with an `X` + "remove"
|
* This component can be used to show an item styled as a "tag", optionally with an `X` + "remove"
|
||||||
|
@ -17,26 +17,24 @@ import { withState, withInstanceId } from '@wordpress/compose';
|
||||||
* @param {Object} props
|
* @param {Object} props
|
||||||
* @param {number|string} props.id
|
* @param {number|string} props.id
|
||||||
* @param {string}props.instanceId
|
* @param {string}props.instanceId
|
||||||
* @param {boolean} props.isVisible
|
|
||||||
* @param {string} props.label
|
* @param {string} props.label
|
||||||
* @param {Object} props.popoverContents
|
* @param {Object} props.popoverContents
|
||||||
* @param {Function} props.remove
|
* @param {Function} props.remove
|
||||||
* @param {string} props.screenReaderLabel
|
* @param {string} props.screenReaderLabel
|
||||||
* @param {Function} props.setState
|
|
||||||
* @param {string} props.className
|
* @param {string} props.className
|
||||||
* @return {Object} -
|
* @return {Object} -
|
||||||
*/
|
*/
|
||||||
const Tag = ( {
|
const Tag = ( {
|
||||||
id,
|
id,
|
||||||
instanceId,
|
instanceId,
|
||||||
isVisible,
|
|
||||||
label,
|
label,
|
||||||
popoverContents,
|
popoverContents,
|
||||||
remove,
|
remove,
|
||||||
screenReaderLabel,
|
screenReaderLabel,
|
||||||
setState,
|
|
||||||
className,
|
className,
|
||||||
} ) => {
|
} ) => {
|
||||||
|
const [ isVisible, setIsVisible ] = useState( false );
|
||||||
|
|
||||||
screenReaderLabel = screenReaderLabel || label;
|
screenReaderLabel = screenReaderLabel || label;
|
||||||
if ( ! label ) {
|
if ( ! label ) {
|
||||||
// A null label probably means something went wrong
|
// A null label probably means something went wrong
|
||||||
|
@ -61,7 +59,7 @@ const Tag = ( {
|
||||||
<Button
|
<Button
|
||||||
className="woocommerce-tag__text"
|
className="woocommerce-tag__text"
|
||||||
id={ labelId }
|
id={ labelId }
|
||||||
onClick={ () => setState( () => ( { isVisible: true } ) ) }
|
onClick={ () => setIsVisible( true ) }
|
||||||
>
|
>
|
||||||
{ labelTextNode }
|
{ labelTextNode }
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -71,9 +69,7 @@ const Tag = ( {
|
||||||
</span>
|
</span>
|
||||||
) }
|
) }
|
||||||
{ popoverContents && isVisible && (
|
{ popoverContents && isVisible && (
|
||||||
<Popover
|
<Popover onClose={ () => setIsVisible( false ) }>
|
||||||
onClose={ () => setState( () => ( { isVisible: false } ) ) }
|
|
||||||
>
|
|
||||||
{ popoverContents }
|
{ popoverContents }
|
||||||
</Popover>
|
</Popover>
|
||||||
) }
|
) }
|
||||||
|
@ -122,6 +118,4 @@ Tag.propTypes = {
|
||||||
screenReaderLabel: PropTypes.string,
|
screenReaderLabel: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withState( {
|
export default withInstanceId( Tag );
|
||||||
isVisible: false,
|
|
||||||
} )( withInstanceId( Tag ) );
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { render } from '@testing-library/react';
|
import { render, fireEvent } from '@testing-library/react';
|
||||||
import { createElement } from '@wordpress/element';
|
import { createElement } from '@wordpress/element';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,4 +35,26 @@ describe( 'Tag', () => {
|
||||||
);
|
);
|
||||||
expect( component ).toMatchSnapshot();
|
expect( component ).toMatchSnapshot();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
test( 'Do not show popoverContents by default', () => {
|
||||||
|
const { queryByText } = render(
|
||||||
|
<Tag label="foo" popoverContents={ <p>This is a popover</p> } />
|
||||||
|
);
|
||||||
|
expect( queryByText( 'This is a popover' ) ).toBeNull();
|
||||||
|
} );
|
||||||
|
|
||||||
|
test( 'Show popoverContents after clicking the button', () => {
|
||||||
|
const { queryByText, queryByRole } = render(
|
||||||
|
<Tag
|
||||||
|
label="foo"
|
||||||
|
instanceId="1"
|
||||||
|
popoverContents={ <p>This is a popover</p> }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.click(
|
||||||
|
queryByRole( 'button', { id: 'woocommerce-tag__label-1' } )
|
||||||
|
);
|
||||||
|
expect( queryByText( 'This is a popover' ) ).toBeDefined();
|
||||||
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -2,91 +2,95 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { TextControlWithAffixes } from '@woocommerce/components';
|
import { TextControlWithAffixes } from '@woocommerce/components';
|
||||||
|
import { useState } from '@wordpress/element';
|
||||||
|
|
||||||
/**
|
const Examples = () => {
|
||||||
* External dependencies
|
const [ state, setState ] = useState( {
|
||||||
*/
|
first: '',
|
||||||
import { withState } from '@wordpress/compose';
|
second: '',
|
||||||
|
third: '',
|
||||||
|
fourth: '',
|
||||||
|
fifth: '',
|
||||||
|
} );
|
||||||
|
const { first, second, third, fourth, fifth } = state;
|
||||||
|
const partialUpdate = ( partial ) => {
|
||||||
|
setState( { ...state, ...partial } );
|
||||||
|
};
|
||||||
|
|
||||||
const Examples = withState( {
|
return (
|
||||||
first: '',
|
<div>
|
||||||
second: '',
|
<TextControlWithAffixes
|
||||||
third: '',
|
label="Text field without affixes"
|
||||||
fourth: '',
|
value={ first }
|
||||||
fifth: '',
|
placeholder="Placeholder"
|
||||||
} )( ( { first, second, third, fourth, fifth, setState } ) => (
|
onChange={ ( value ) => partialUpdate( { first: value } ) }
|
||||||
<div>
|
/>
|
||||||
<TextControlWithAffixes
|
<TextControlWithAffixes
|
||||||
label="Text field without affixes"
|
label="Disabled text field without affixes"
|
||||||
value={ first }
|
value={ first }
|
||||||
placeholder="Placeholder"
|
placeholder="Placeholder"
|
||||||
onChange={ ( value ) => setState( { first: value } ) }
|
onChange={ ( value ) => partialUpdate( { first: value } ) }
|
||||||
/>
|
disabled
|
||||||
<TextControlWithAffixes
|
/>
|
||||||
label="Disabled text field without affixes"
|
<TextControlWithAffixes
|
||||||
value={ first }
|
prefix="$"
|
||||||
placeholder="Placeholder"
|
label="Text field with a prefix"
|
||||||
onChange={ ( value ) => setState( { first: value } ) }
|
value={ second }
|
||||||
disabled
|
onChange={ ( value ) => partialUpdate( { second: value } ) }
|
||||||
/>
|
/>
|
||||||
<TextControlWithAffixes
|
<TextControlWithAffixes
|
||||||
prefix="$"
|
prefix="$"
|
||||||
label="Text field with a prefix"
|
label="Disabled text field with a prefix"
|
||||||
value={ second }
|
value={ second }
|
||||||
onChange={ ( value ) => setState( { second: value } ) }
|
onChange={ ( value ) => partialUpdate( { second: value } ) }
|
||||||
/>
|
disabled
|
||||||
<TextControlWithAffixes
|
/>
|
||||||
prefix="$"
|
<TextControlWithAffixes
|
||||||
label="Disabled text field with a prefix"
|
prefix="Prefix"
|
||||||
value={ second }
|
suffix="Suffix"
|
||||||
onChange={ ( value ) => setState( { second: value } ) }
|
label="Text field with both affixes"
|
||||||
disabled
|
value={ third }
|
||||||
/>
|
onChange={ ( value ) => partialUpdate( { third: value } ) }
|
||||||
<TextControlWithAffixes
|
/>
|
||||||
prefix="Prefix"
|
<TextControlWithAffixes
|
||||||
suffix="Suffix"
|
prefix="Prefix"
|
||||||
label="Text field with both affixes"
|
suffix="Suffix"
|
||||||
value={ third }
|
label="Disabled text field with both affixes"
|
||||||
onChange={ ( value ) => setState( { third: value } ) }
|
value={ third }
|
||||||
/>
|
onChange={ ( value ) => partialUpdate( { third: value } ) }
|
||||||
<TextControlWithAffixes
|
disabled
|
||||||
prefix="Prefix"
|
/>
|
||||||
suffix="Suffix"
|
<TextControlWithAffixes
|
||||||
label="Disabled text field with both affixes"
|
suffix="%"
|
||||||
value={ third }
|
label="Text field with a suffix"
|
||||||
onChange={ ( value ) => setState( { third: value } ) }
|
value={ fourth }
|
||||||
disabled
|
onChange={ ( value ) => partialUpdate( { fourth: value } ) }
|
||||||
/>
|
/>
|
||||||
<TextControlWithAffixes
|
<TextControlWithAffixes
|
||||||
suffix="%"
|
suffix="%"
|
||||||
label="Text field with a suffix"
|
label="Disabled text field with a suffix"
|
||||||
value={ fourth }
|
value={ fourth }
|
||||||
onChange={ ( value ) => setState( { fourth: value } ) }
|
onChange={ ( value ) => partialUpdate( { fourth: value } ) }
|
||||||
/>
|
disabled
|
||||||
<TextControlWithAffixes
|
/>
|
||||||
suffix="%"
|
<TextControlWithAffixes
|
||||||
label="Disabled text field with a suffix"
|
prefix="$"
|
||||||
value={ fourth }
|
label="Text field with prefix and help text"
|
||||||
onChange={ ( value ) => setState( { fourth: value } ) }
|
value={ fifth }
|
||||||
disabled
|
onChange={ ( value ) => partialUpdate( { fifth: value } ) }
|
||||||
/>
|
help="This is some help text."
|
||||||
<TextControlWithAffixes
|
/>
|
||||||
prefix="$"
|
<TextControlWithAffixes
|
||||||
label="Text field with prefix and help text"
|
prefix="$"
|
||||||
value={ fifth }
|
label="Disabled text field with prefix and help text"
|
||||||
onChange={ ( value ) => setState( { fifth: value } ) }
|
value={ fifth }
|
||||||
help="This is some help text."
|
onChange={ ( value ) => partialUpdate( { fifth: value } ) }
|
||||||
/>
|
help="This is some help text."
|
||||||
<TextControlWithAffixes
|
disabled
|
||||||
prefix="$"
|
/>
|
||||||
label="Disabled text field with prefix and help text"
|
</div>
|
||||||
value={ fifth }
|
);
|
||||||
onChange={ ( value ) => setState( { fifth: value } ) }
|
};
|
||||||
help="This is some help text."
|
|
||||||
disabled
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) );
|
|
||||||
|
|
||||||
export const Basic = () => <Examples />;
|
export const Basic = () => <Examples />;
|
||||||
|
|
||||||
|
|
|
@ -2,29 +2,24 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { TextControl } from '@woocommerce/components';
|
import { TextControl } from '@woocommerce/components';
|
||||||
import { createElement } from '@wordpress/element';
|
import { useState } from '@wordpress/element';
|
||||||
|
|
||||||
/**
|
const Example = () => {
|
||||||
* External dependencies
|
const [ value, setValue ] = useState( '' );
|
||||||
*/
|
|
||||||
import { withState } from '@wordpress/compose';
|
|
||||||
|
|
||||||
const Example = withState( {
|
|
||||||
value: '',
|
|
||||||
} )( ( { setState, value } ) => {
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<TextControl
|
<TextControl
|
||||||
name="text-control"
|
name="text-control"
|
||||||
label="Enter text here"
|
label="Enter text here"
|
||||||
onChange={ ( newValue ) => setState( { value: newValue } ) }
|
onChange={ ( newValue ) => setValue( newValue ) }
|
||||||
value={ value }
|
value={ value }
|
||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
<TextControl label="Disabled field" disabled value="" />
|
<TextControl label="Disabled field" disabled value="" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} );
|
};
|
||||||
|
|
||||||
export const Basic = () => <Example />;
|
export const Basic = () => <Example />;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue