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:
Chi-Hsuan Huang 2022-02-23 09:35:50 +08:00 committed by GitHub
parent 1c2bc9843c
commit f052c3fed1
17 changed files with 450 additions and 393 deletions

View File

@ -1,5 +1,7 @@
# Unreleased
- Replace deprecated wp.compose.withState with wp.element.useState. #8338
# 9.0.0
- Update line-height of SelectControl label to avoid truncated descenders in some typefaces and zoom levels. #8186

View File

@ -2,13 +2,12 @@
* External dependencies
*/
import moment from 'moment';
import { withState } from '@wordpress/compose';
import { DatePicker, H, Section } from '@woocommerce/components';
import { createElement } from '@wordpress/element';
import { useState } from '@wordpress/element';
const dateFormat = 'MM/DD/YYYY';
const DatePickerExample = withState( {
const DatePickerExample = () => {
const [ state, setState ] = useState( {
after: null,
afterText: '',
before: null,
@ -16,9 +15,12 @@ const DatePickerExample = withState( {
afterError: null,
beforeError: null,
focusedInput: 'startDate',
} )( ( { after, afterText, afterError, setState } ) => {
} );
const { after, afterText, afterError } = state;
function onDatePickerUpdate( { date, text, error } ) {
setState( {
...state,
after: date,
afterText: text,
afterError: error,
@ -40,7 +42,7 @@ const DatePickerExample = withState( {
</Section>
</div>
);
} );
};
export const Basic = () => <DatePickerExample />;

View File

@ -2,13 +2,13 @@
* External dependencies
*/
import moment from 'moment';
import { withState } from '@wordpress/compose';
import { DateRange, H, Section } from '@woocommerce/components';
import { createElement, Fragment } from '@wordpress/element';
import { useState } from '@wordpress/element';
const dateFormat = 'MM/DD/YYYY';
const DateRangeExample = withState( {
const DateRangeExample = () => {
const [ state, setState ] = useState( {
after: null,
afterText: '',
before: null,
@ -16,9 +16,15 @@ const DateRangeExample = withState( {
afterError: null,
beforeError: null,
focusedInput: 'startDate',
} )( ( { after, afterText, before, beforeText, focusedInput, setState } ) => {
} );
const { after, afterText, before, beforeText, focusedInput } = state;
function onRangeUpdate( update ) {
setState( update );
setState( {
...state,
...update,
} );
}
return (
@ -40,7 +46,7 @@ const DateRangeExample = withState( {
</Section>
</>
);
} );
};
export const Basic = () => <DateRangeExample />;

View File

@ -1,16 +1,17 @@
/**
* External dependencies
*/
import { withState } from '@wordpress/compose';
import { Fragment } from '@wordpress/element';
import { Fragment, useState } from '@wordpress/element';
import { Icon } from '@wordpress/icons';
import CrossSmall from 'gridicons/dist/cross-small';
import { EllipsisMenu, MenuItem, MenuTitle } from '@woocommerce/components';
const ExampleEllipsisMenu = withState( {
const ExampleEllipsisMenu = () => {
const [ { showCustomers, showOrders }, setState ] = useState( {
showCustomers: true,
showOrders: true,
} )( ( { setState, showCustomers, showOrders } ) => (
} );
return (
<EllipsisMenu
label="Choose which analytics to display"
renderContent={ ( { onToggle } ) => (
@ -21,7 +22,10 @@ const ExampleEllipsisMenu = withState( {
isClickable
checked={ showCustomers }
onInvoke={ () =>
setState( { showCustomers: ! showCustomers } )
setState( {
showOrders,
showCustomers: ! showCustomers,
} )
}
>
Show Customers
@ -30,7 +34,12 @@ const ExampleEllipsisMenu = withState( {
isCheckbox
isClickable
checked={ showOrders }
onInvoke={ () => setState( { showOrders: ! showOrders } ) }
onInvoke={ () =>
setState( {
showCustomers,
showOrders: ! showOrders,
} )
}
>
Show Orders
</MenuItem>
@ -41,7 +50,8 @@ const ExampleEllipsisMenu = withState( {
</Fragment>
) }
/>
) );
);
};
export const Basic = () => <ExampleEllipsisMenu />;

View File

@ -1,17 +1,19 @@
/**
* External dependencies
*/
import { withState } from '@wordpress/compose';
import { useState } from '@wordpress/element';
import { ImageUpload } from '@woocommerce/components';
const ImageUploadExample = withState( {
image: null,
} )( ( { setState, logo } ) => (
const ImageUploadExample = () => {
const [ image, setImage ] = useState( null );
return (
<ImageUpload
image={ logo }
onChange={ ( image ) => setState( { logo: image } ) }
image={ image }
onChange={ ( _image ) => setImage( _image ) }
/>
) );
);
};
export const Basic = () => <ImageUploadExample />;

View File

@ -8,8 +8,13 @@ import {
TextControl,
withSpokenMessages,
} from '@wordpress/components';
import { createElement, Component, Fragment } from '@wordpress/element';
import { compose, withInstanceId, withState } from '@wordpress/compose';
import {
createElement,
Fragment,
useState,
useEffect,
} from '@wordpress/element';
import { compose, withInstanceId } from '@wordpress/compose';
import { escapeRegExp, findIndex } from 'lodash';
import NoticeOutlineIcon from 'gridicons/dist/notice-outline';
import PropTypes from 'prop-types';
@ -43,28 +48,33 @@ const defaultMessages = {
/**
* Component to display a searchable, selectable list of items.
*
* @param {Object} props
*/
export class SearchListControl extends Component {
constructor() {
super( ...arguments );
export const SearchListControl = ( props ) => {
const [ searchValue, setSearchValue ] = useState( props.search || '' );
const {
isSingle,
isLoading,
onChange,
selected,
instanceId,
messages: propsMessages,
isCompact,
debouncedSpeak,
onSearch,
className = '',
} = props;
this.onSelect = this.onSelect.bind( this );
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 );
}
const messages = { ...defaultMessages, ...propsMessages };
componentDidUpdate( prevProps ) {
const { onSearch, search } = this.props;
if ( search !== prevProps.search && typeof onSearch === 'function' ) {
onSearch( search );
}
useEffect( () => {
if ( typeof onSearch === 'function' ) {
onSearch( searchValue );
}
}, [ onSearch, searchValue ] );
onRemove( id ) {
const { isSingle, onChange, selected } = this.props;
const onRemove = ( id ) => {
return () => {
if ( isSingle ) {
onChange( [] );
@ -75,13 +85,12 @@ export class SearchListControl extends Component {
...selected.slice( i + 1 ),
] );
};
}
};
onSelect( item ) {
const { isSingle, onChange, selected } = this.props;
const onSelect = ( item ) => {
return () => {
if ( this.isSelected( item ) ) {
this.onRemove( item.id )();
if ( isSelected( item ) ) {
onRemove( item.id )();
return;
}
if ( isSingle ) {
@ -90,39 +99,32 @@ export class SearchListControl extends Component {
onChange( [ ...selected, item ] );
}
};
}
};
onClear() {
this.props.onChange( [] );
}
const isSelected = ( item ) =>
findIndex( selected, { id: item.id } ) !== -1;
isSelected( item ) {
return findIndex( this.props.selected, { id: item.id } ) !== -1;
}
getFilteredList( list, search ) {
const { isHierarchical } = this.props;
const getFilteredList = ( list, search ) => {
const { isHierarchical } = props;
if ( ! search ) {
return isHierarchical ? buildTermsTree( list ) : list;
}
const messages = { ...defaultMessages, ...this.props.messages };
const re = new RegExp( escapeRegExp( search ), 'i' );
this.props.debouncedSpeak( messages.updated );
debouncedSpeak( messages.updated );
const filteredList = list
.map( ( item ) => ( re.test( item.name ) ? item : false ) )
.filter( Boolean );
return isHierarchical
? buildTermsTree( filteredList, list )
: filteredList;
}
};
defaultRenderItem( args ) {
const defaultRenderItem = ( args ) => {
return <SearchListItem { ...args } />;
}
};
renderList( list, depth = 0 ) {
const { isSingle, search, instanceId } = this.props;
const renderItem = this.props.renderItem || this.defaultRenderItem;
const renderList = ( list, depth = 0 ) => {
const renderItem = props.renderItem || defaultRenderItem;
if ( ! list ) {
return null;
}
@ -132,23 +134,20 @@ export class SearchListControl extends Component {
<li>
{ renderItem( {
item,
isSelected: this.isSelected( item ),
onSelect: this.onSelect,
isSelected: isSelected( item ),
onSelect,
isSingle,
search,
search: searchValue,
depth,
controlId: instanceId,
} ) }
</li>
{ this.renderList( item.children, depth + 1 ) }
{ renderList( item.children, depth + 1 ) }
</Fragment>
) );
}
renderListSection() {
const { isLoading, search } = this.props;
const messages = { ...defaultMessages, ...this.props.messages };
};
const renderListSection = () => {
if ( isLoading ) {
return (
<div className="woocommerce-search-list__list is-loading">
@ -156,7 +155,7 @@ export class SearchListControl extends Component {
</div>
);
}
const list = this.getFilteredList( this.props.list, search );
const list = getFilteredList( props.list, searchValue );
if ( ! list.length ) {
return (
@ -169,9 +168,9 @@ export class SearchListControl extends Component {
/>
</span>
<span className="woocommerce-search-list__not-found-text">
{ search
{ searchValue
? // eslint-disable-next-line @wordpress/valid-sprintf
sprintf( messages.noResults, search )
sprintf( messages.noResults, searchValue )
: messages.noItems }
</span>
</div>
@ -180,15 +179,12 @@ export class SearchListControl extends Component {
return (
<ul className="woocommerce-search-list__list">
{ this.renderList( list ) }
{ renderList( list ) }
</ul>
);
}
renderSelectedSection() {
const { isLoading, isSingle, selected } = this.props;
const messages = { ...defaultMessages, ...this.props.messages };
};
const renderSelectedSection = () => {
if ( isLoading || isSingle || ! selected ) {
return null;
}
@ -202,7 +198,7 @@ export class SearchListControl extends Component {
<Button
isLink
isDestructive
onClick={ this.onClear }
onClick={ onChange( [] ) }
aria-label={ messages.clear }
>
{ __( 'Clear all', 'woocommerce-admin' ) }
@ -216,7 +212,7 @@ export class SearchListControl extends Component {
<Tag
label={ item.name }
id={ item.id }
remove={ this.onRemove }
remove={ onRemove }
/>
</li>
) ) }
@ -224,11 +220,7 @@ export class SearchListControl extends Component {
) : null }
</div>
);
}
render() {
const { className = '', isCompact, search, setState } = this.props;
const messages = { ...defaultMessages, ...this.props.messages };
};
return (
<div
@ -236,22 +228,21 @@ export class SearchListControl extends Component {
'is-compact': isCompact,
} ) }
>
{ this.renderSelectedSection() }
{ renderSelectedSection() }
<div className="woocommerce-search-list__search">
<TextControl
label={ messages.search }
type="search"
value={ search }
onChange={ ( value ) => setState( { search: value } ) }
value={ searchValue }
onChange={ ( value ) => setSearchValue( value ) }
/>
</div>
{ this.renderListSection() }
{ renderListSection() }
</div>
);
}
}
};
SearchListControl.propTypes = {
/**
@ -334,19 +325,12 @@ SearchListControl.propTypes = {
* The list of currently selected items.
*/
selected: PropTypes.array.isRequired,
// from withState
search: PropTypes.string,
setState: PropTypes.func,
// from withSpokenMessages
debouncedSpeak: PropTypes.func,
// from withInstanceId
instanceId: PropTypes.number,
};
export default compose( [
withState( {
search: '',
} ),
withSpokenMessages,
withInstanceId,
] )( SearchListControl );
export default compose( [ withSpokenMessages, withInstanceId ] )(
SearchListControl
);

View File

@ -3,13 +3,12 @@
*/
import { boolean } from '@storybook/addon-knobs';
import { SearchListControl } from '@woocommerce/components';
import { withState } from '@wordpress/compose';
import { createElement } from '@wordpress/element';
import { useState } 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 isCompact = boolean( 'Compact', false );
const isSingle = boolean( 'Single', false );
@ -30,7 +29,7 @@ const SearchListControlExample = withState( {
return (
<div>
<button onClick={ () => setState( { loading: ! loading } ) }>
<button onClick={ () => setLoading( ! loading ) }>
Toggle loading state
</button>
<SearchListControl
@ -38,12 +37,12 @@ const SearchListControlExample = withState( {
isCompact={ isCompact }
isLoading={ loading }
selected={ selected }
onChange={ ( items ) => setState( { selected: items } ) }
onChange={ ( items ) => setSelected( items ) }
isSingle={ isSingle }
/>
</div>
);
} );
};
export const Basic = () => <SearchListControlExample />;

View File

@ -1,7 +1,7 @@
/**
* External dependencies
*/
import { render } from '@testing-library/react';
import { render, fireEvent } from '@testing-library/react';
import { noop } from 'lodash';
import { createElement } from '@wordpress/element';
@ -174,4 +174,24 @@ describe( 'SearchListControl', () => {
);
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 );
} );
} );

View File

@ -1,13 +1,14 @@
/**
* External dependencies
*/
import { withState } from '@wordpress/compose';
import { H, Search, Section } from '@woocommerce/components';
import { useState } from '@wordpress/element';
const SearchExample = withState( {
selected: [],
inlineSelected: [],
} )( ( { selected, inlineSelected, setState } ) => (
const SearchExample = () => {
const [ selected, setSelected ] = useState( [] );
const [ inlineSelected, setInlineSelect ] = useState( [] );
return (
<div>
<H>Tags Below Input</H>
<Section component={ false }>
@ -15,7 +16,7 @@ const SearchExample = withState( {
type="products"
placeholder="Search for a product"
selected={ selected }
onChange={ ( items ) => setState( { selected: items } ) }
onChange={ ( items ) => setSelected( items ) }
/>
</Section>
<H>Tags Inline with Input</H>
@ -24,12 +25,13 @@ const SearchExample = withState( {
type="products"
placeholder="Search for a product"
selected={ inlineSelected }
onChange={ ( items ) => setState( { inlineSelected: items } ) }
onChange={ ( items ) => setInlineSelect( items ) }
inlineTags
/>
</Section>
</div>
) );
);
};
export const Basic = () => <SearchExample />;

View File

@ -1,14 +1,15 @@
/**
* External dependencies
*/
import { withState } from '@wordpress/compose';
import { SegmentedSelection } from '@woocommerce/components';
import { useState } from '@wordpress/element';
const name = 'number';
const SegmentedSelectionExample = withState( {
selected: 'two',
} )( ( { selected, setState } ) => (
const SegmentedSelectionExample = () => {
const [ selected, setSelected ] = useState( 'two' );
return (
<SegmentedSelection
options={ [
{ value: 'one', label: 'One' },
@ -18,10 +19,11 @@ const SegmentedSelectionExample = withState( {
] }
selected={ selected }
legend="Select a number"
onSelect={ ( data ) => setState( { selected: data[ name ] } ) }
onSelect={ ( data ) => setSelected( data[ name ] ) }
name={ name }
/>
) );
);
};
export const Basic = () => <SegmentedSelectionExample />;

View File

@ -2,11 +2,7 @@
* External dependencies
*/
import { SelectControl } from '@woocommerce/components';
/**
* External dependencies
*/
import { withState } from '@wordpress/compose';
import { useState } from '@wordpress/element';
const options = [
{
@ -52,7 +48,8 @@ const options = [
},
];
const SelectControlExample = withState( {
const SelectControlExample = () => {
const [ state, setState ] = useState( {
simpleSelected: [],
simpleMultipleSelected: [],
singleSelected: [],
@ -60,8 +57,9 @@ const SelectControlExample = withState( {
multipleSelected: [],
inlineSelected: [],
allOptionsIncludingSelected: options[ options.length - 1 ].key,
} )(
( {
} );
const {
simpleSelected,
simpleMultipleSelected,
singleSelected,
@ -69,13 +67,14 @@ const SelectControlExample = withState( {
multipleSelected,
inlineSelected,
allOptionsIncludingSelected,
setState,
} ) => (
} = state;
return (
<div>
<SelectControl
label="Simple single value"
onChange={ ( selected ) =>
setState( { simpleSelected: selected } )
setState( { ...state, simpleSelected: selected } )
}
options={ options }
placeholder="Start typing to filter options..."
@ -86,7 +85,7 @@ const SelectControlExample = withState( {
label="Multiple values"
multiple
onChange={ ( selected ) =>
setState( { simpleMultipleSelected: selected } )
setState( { ...state, simpleMultipleSelected: selected } )
}
options={ options }
placeholder="Start typing to filter options..."
@ -96,7 +95,10 @@ const SelectControlExample = withState( {
<SelectControl
label="Show all options with default selected"
onChange={ ( selected ) =>
setState( { allOptionsIncludingSelected: selected } )
setState( {
...state,
allOptionsIncludingSelected: selected,
} )
}
options={ options }
placeholder="Start typing to filter options..."
@ -110,7 +112,7 @@ const SelectControlExample = withState( {
label="Single value searchable"
isSearchable
onChange={ ( selected ) =>
setState( { singleSelected: selected } )
setState( { ...state, singleSelected: selected } )
}
options={ options }
placeholder="Start typing to filter options..."
@ -121,7 +123,7 @@ const SelectControlExample = withState( {
label="Single value searchable with options on refocus"
isSearchable
onChange={ ( selected ) =>
setState( { singleSelectedShowAll: selected } )
setState( { ...state, singleSelectedShowAll: selected } )
}
options={ options }
placeholder="Start typing to filter options..."
@ -135,7 +137,7 @@ const SelectControlExample = withState( {
multiple
inlineTags
onChange={ ( selected ) =>
setState( { inlineSelected: selected } )
setState( { ...state, inlineSelected: selected } )
}
options={ options }
placeholder="Start typing to filter options..."
@ -148,7 +150,7 @@ const SelectControlExample = withState( {
label="Hidden options before search"
multiple
onChange={ ( selected ) =>
setState( { multipleSelected: selected } )
setState( { ...state, multipleSelected: selected } )
}
options={ options }
placeholder="Start typing to filter options..."
@ -156,8 +158,8 @@ const SelectControlExample = withState( {
showClearButton
/>
</div>
)
);
);
};
export const Basic = () => <SelectControlExample />;

View File

@ -1,15 +1,17 @@
/**
* External dependencies
*/
import { withState } from '@wordpress/compose';
import { Stepper } from '@woocommerce/components';
import { createElement } from '@wordpress/element';
import { useState } from '@wordpress/element';
const BasicExamples = withState( {
const BasicExamples = () => {
const [ state, setState ] = useState( {
currentStep: 'first',
isComplete: false,
isPending: false,
} )( ( { currentStep, isComplete, isPending, setState } ) => {
} );
const { currentStep, isComplete, isPending } = state;
const goToStep = ( key ) => {
setState( { currentStep: key } );
};
@ -56,7 +58,11 @@ const BasicExamples = withState( {
{ isComplete ? (
<button
onClick={ () =>
setState( { currentStep: 'first', isComplete: false } )
setState( {
...state,
currentStep: 'first',
isComplete: false,
} )
}
>
Reset
@ -66,6 +72,7 @@ const BasicExamples = withState( {
<button
onClick={ () =>
setState( {
...state,
currentStep: steps[ currentIndex - 1 ].key,
} )
}
@ -76,6 +83,7 @@ const BasicExamples = withState( {
<button
onClick={ () =>
setState( {
...state,
currentStep: steps[ currentIndex + 1 ].key,
} )
}
@ -84,13 +92,17 @@ const BasicExamples = withState( {
Next step
</button>
<button
onClick={ () => setState( { isComplete: true } ) }
onClick={ () =>
setState( { ...state, isComplete: true } )
}
disabled={ currentIndex !== steps.length - 1 }
>
Complete
</button>
<button
onClick={ () => setState( { isPending: ! isPending } ) }
onClick={ () =>
setState( { ...state, isPending: ! isPending } )
}
>
Toggle Spinner
</button>
@ -113,7 +125,7 @@ const BasicExamples = withState( {
/>
</div>
);
} );
};
export const Examples = () => <BasicExamples />;

View File

@ -2,22 +2,20 @@
* External dependencies
*/
import { TableCard } from '@woocommerce/components';
/**
* External dependencies
*/
import { withState } from '@wordpress/compose';
import { useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import { headers, rows, summary } from './index';
const TableCardExample = withState( {
const TableCardExample = () => {
const [ { query }, setState ] = useState( {
query: {
paged: 1,
},
} )( ( { query, setState } ) => (
} );
return (
<TableCard
title="Revenue last week"
rows={ rows }
@ -33,7 +31,8 @@ const TableCardExample = withState( {
totalRows={ 10 }
summary={ summary }
/>
) );
);
};
export const Basic = () => <TableCardExample />;

View File

@ -2,13 +2,13 @@
* External dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { createElement, Fragment } from '@wordpress/element';
import { createElement, Fragment, useState } from '@wordpress/element';
import classnames from 'classnames';
import { Button, Popover } from '@wordpress/components';
import { Icon, cancelCircleFilled } from '@wordpress/icons';
import { decodeEntities } from '@wordpress/html-entities';
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"
@ -17,26 +17,24 @@ import { withState, withInstanceId } from '@wordpress/compose';
* @param {Object} props
* @param {number|string} props.id
* @param {string}props.instanceId
* @param {boolean} props.isVisible
* @param {string} props.label
* @param {Object} props.popoverContents
* @param {Function} props.remove
* @param {string} props.screenReaderLabel
* @param {Function} props.setState
* @param {string} props.className
* @return {Object} -
*/
const Tag = ( {
id,
instanceId,
isVisible,
label,
popoverContents,
remove,
screenReaderLabel,
setState,
className,
} ) => {
const [ isVisible, setIsVisible ] = useState( false );
screenReaderLabel = screenReaderLabel || label;
if ( ! label ) {
// A null label probably means something went wrong
@ -61,7 +59,7 @@ const Tag = ( {
<Button
className="woocommerce-tag__text"
id={ labelId }
onClick={ () => setState( () => ( { isVisible: true } ) ) }
onClick={ () => setIsVisible( true ) }
>
{ labelTextNode }
</Button>
@ -71,9 +69,7 @@ const Tag = ( {
</span>
) }
{ popoverContents && isVisible && (
<Popover
onClose={ () => setState( () => ( { isVisible: false } ) ) }
>
<Popover onClose={ () => setIsVisible( false ) }>
{ popoverContents }
</Popover>
) }
@ -122,6 +118,4 @@ Tag.propTypes = {
screenReaderLabel: PropTypes.string,
};
export default withState( {
isVisible: false,
} )( withInstanceId( Tag ) );
export default withInstanceId( Tag );

View File

@ -1,7 +1,7 @@
/**
* External dependencies
*/
import { render } from '@testing-library/react';
import { render, fireEvent } from '@testing-library/react';
import { createElement } from '@wordpress/element';
/**
@ -35,4 +35,26 @@ describe( 'Tag', () => {
);
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();
} );
} );

View File

@ -2,44 +2,47 @@
* External dependencies
*/
import { TextControlWithAffixes } from '@woocommerce/components';
import { useState } from '@wordpress/element';
/**
* External dependencies
*/
import { withState } from '@wordpress/compose';
const Examples = withState( {
const Examples = () => {
const [ state, setState ] = useState( {
first: '',
second: '',
third: '',
fourth: '',
fifth: '',
} )( ( { first, second, third, fourth, fifth, setState } ) => (
} );
const { first, second, third, fourth, fifth } = state;
const partialUpdate = ( partial ) => {
setState( { ...state, ...partial } );
};
return (
<div>
<TextControlWithAffixes
label="Text field without affixes"
value={ first }
placeholder="Placeholder"
onChange={ ( value ) => setState( { first: value } ) }
onChange={ ( value ) => partialUpdate( { first: value } ) }
/>
<TextControlWithAffixes
label="Disabled text field without affixes"
value={ first }
placeholder="Placeholder"
onChange={ ( value ) => setState( { first: value } ) }
onChange={ ( value ) => partialUpdate( { first: value } ) }
disabled
/>
<TextControlWithAffixes
prefix="$"
label="Text field with a prefix"
value={ second }
onChange={ ( value ) => setState( { second: value } ) }
onChange={ ( value ) => partialUpdate( { second: value } ) }
/>
<TextControlWithAffixes
prefix="$"
label="Disabled text field with a prefix"
value={ second }
onChange={ ( value ) => setState( { second: value } ) }
onChange={ ( value ) => partialUpdate( { second: value } ) }
disabled
/>
<TextControlWithAffixes
@ -47,46 +50,47 @@ const Examples = withState( {
suffix="Suffix"
label="Text field with both affixes"
value={ third }
onChange={ ( value ) => setState( { third: value } ) }
onChange={ ( value ) => partialUpdate( { third: value } ) }
/>
<TextControlWithAffixes
prefix="Prefix"
suffix="Suffix"
label="Disabled text field with both affixes"
value={ third }
onChange={ ( value ) => setState( { third: value } ) }
onChange={ ( value ) => partialUpdate( { third: value } ) }
disabled
/>
<TextControlWithAffixes
suffix="%"
label="Text field with a suffix"
value={ fourth }
onChange={ ( value ) => setState( { fourth: value } ) }
onChange={ ( value ) => partialUpdate( { fourth: value } ) }
/>
<TextControlWithAffixes
suffix="%"
label="Disabled text field with a suffix"
value={ fourth }
onChange={ ( value ) => setState( { fourth: value } ) }
onChange={ ( value ) => partialUpdate( { fourth: value } ) }
disabled
/>
<TextControlWithAffixes
prefix="$"
label="Text field with prefix and help text"
value={ fifth }
onChange={ ( value ) => setState( { fifth: value } ) }
onChange={ ( value ) => partialUpdate( { fifth: value } ) }
help="This is some help text."
/>
<TextControlWithAffixes
prefix="$"
label="Disabled text field with prefix and help text"
value={ fifth }
onChange={ ( value ) => setState( { fifth: value } ) }
onChange={ ( value ) => partialUpdate( { fifth: value } ) }
help="This is some help text."
disabled
/>
</div>
) );
);
};
export const Basic = () => <Examples />;

View File

@ -2,29 +2,24 @@
* External dependencies
*/
import { TextControl } from '@woocommerce/components';
import { createElement } from '@wordpress/element';
import { useState } from '@wordpress/element';
/**
* External dependencies
*/
import { withState } from '@wordpress/compose';
const Example = () => {
const [ value, setValue ] = useState( '' );
const Example = withState( {
value: '',
} )( ( { setState, value } ) => {
return (
<div>
<TextControl
name="text-control"
label="Enter text here"
onChange={ ( newValue ) => setState( { value: newValue } ) }
onChange={ ( newValue ) => setValue( newValue ) }
value={ value }
/>
<br />
<TextControl label="Disabled field" disabled value="" />
</div>
);
} );
};
export const Basic = () => <Example />;