Skip to content

Commit

Permalink
Merge branch 'trunk' into fix/toolbar-button-disabled
Browse files Browse the repository at this point in the history
  • Loading branch information
mirka authored Jul 3, 2024
2 parents 0836192 + 89bfae4 commit 8472e7a
Show file tree
Hide file tree
Showing 24 changed files with 212 additions and 31 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ module.exports = {
'no-restricted-syntax': [
'error',
...restrictedSyntax,
...restrictedSyntaxComponents,
{
selector:
':matches(Literal[value=/--wp-admin-theme-/],TemplateElement[value.cooked=/--wp-admin-theme-/])',
Expand Down
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -134,19 +134,19 @@ describe( 'BlockSwitcher', () => {
expect( items[ 1 ] ).toHaveTextContent( headingBlockType.title );
} );

test( 'should render disabled block switcher when we have a single selected block without styles and we cannot remove it', () => {
test( 'should render accessibly disabled block switcher when we have a single selected block without styles and we cannot remove it', () => {
useSelect.mockImplementation( () => ( {
blocks: [ headingBlock1 ],
icon: copy,
hasBlockStyles: false,
canRemove: false,
} ) );
render( <BlockSwitcher clientIds={ [ headingBlock1.clientId ] } /> );
expect(
screen.getByRole( 'button', {
name: 'Block Name',
} )
).toBeDisabled();
const blockSwitcher = screen.getByRole( 'button', {
name: 'Block Name',
} );
expect( blockSwitcher ).toBeEnabled();
expect( blockSwitcher ).toHaveAttribute( 'aria-disabled', 'true' );
} );

test( 'should render message for no available transforms', async () => {
Expand Down
17 changes: 13 additions & 4 deletions packages/block-editor/src/components/child-layout-control/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
Flex,
FlexItem,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { __, _x } from '@wordpress/i18n';
import { useEffect } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';

Expand Down Expand Up @@ -142,17 +142,26 @@ function FlexControls( {
<ToggleGroupControlOption
key="fit"
value="fit"
label={ __( 'Fit' ) }
label={ _x(
'Fit',
'Intrinsic block width in flex layout'
) }
/>
<ToggleGroupControlOption
key="fill"
value="fill"
label={ __( 'Fill' ) }
label={ _x(
'Grow',
'Block with expanding width in flex layout'
) }
/>
<ToggleGroupControlOption
key="fixed"
value="fixed"
label={ __( 'Fixed' ) }
label={ _x(
'Fixed',
'Block with fixed width in flex layout'
) }
/>
</ToggleGroupControl>
{ selfStretch === 'fixed' && (
Expand Down
2 changes: 2 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- `UnitControl`: Fix colors when disabled. ([#62970](https://github.com/WordPress/gutenberg/pull/62970))
- `useUpdateEffect`: Correctly track mounted state in strict mode. ([#62974](https://github.com/WordPress/gutenberg/pull/62974))
- `UnitControl`: Fix an issue where keyboard shortcuts unintentionally shift focus on Windows OS. ([#62988](https://github.com/WordPress/gutenberg/pull/62988))
- Fix inaccessibly disabled `Button`s ([#62306](https://github.com/WordPress/gutenberg/pull/62306)).

### Enhancements

Expand All @@ -15,6 +16,7 @@
### Internal

- `CustomSelectControlV2`: prevent keyboard event propagation in legacy wrapper. ([#62907](https://github.com/WordPress/gutenberg/pull/62907))
- `CustomSelectControlV2`: expose legacy wrapper through private APIs. ([#62936](https://github.com/WordPress/gutenberg/pull/62936))
- `CustomSelectControlV2`: fix item styles ([#62825](https://github.com/WordPress/gutenberg/pull/62825))
- `CustomSelectControlV2`: add root element wrapper. ([#62803](https://github.com/WordPress/gutenberg/pull/62803))
- `CustomSelectControlV2`: tweak item inline padding based on size ([#62850](https://github.com/WordPress/gutenberg/pull/62850)).
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/autocomplete/autocompleter-ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ function ListBox( {
id={ `components-autocomplete-item-${ instanceId }-${ option.key }` }
role="option"
aria-selected={ index === selectedIndex }
__experimentalIsFocusable
disabled={ option.isDisabled }
className={ clsx(
'components-autocomplete__result',
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/button/stories/e2e/index.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const VariantStates: StoryFn< typeof Button > = (
key={ variant ?? 'undefined' }
>
<Button { ...props } variant={ variant } />
{ /* eslint-disable-next-line no-restricted-syntax */ }
<Button { ...props } variant={ variant } disabled />
<Button
{ ...props }
Expand Down
6 changes: 6 additions & 0 deletions packages/components/src/button/test/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ describe( 'Button', () => {
} );

it( 'should add a disabled prop to the button', () => {
// eslint-disable-next-line no-restricted-syntax
render( <Button disabled /> );

expect( screen.getByRole( 'button' ) ).toBeDisabled();
Expand Down Expand Up @@ -536,6 +537,7 @@ describe( 'Button', () => {

it( 'should become a button again when disabled is supplied', () => {
// @ts-expect-error - a button should not have `href`
// eslint-disable-next-line no-restricted-syntax
render( <Button href="https://wordpress.org/" disabled /> );

expect( screen.getByRole( 'button' ) ).toBeVisible();
Expand Down Expand Up @@ -624,8 +626,12 @@ describe( 'Button', () => {
<Button href="foo" />
{ /* @ts-expect-error - `target` requires `href` */ }
<Button target="foo" />

{ /* eslint-disable no-restricted-syntax */ }
{ /* @ts-expect-error - `disabled` is only for buttons */ }
<Button href="foo" disabled />
{ /* eslint-enable no-restricted-syntax */ }

<Button href="foo" type="image/png" />
{ /* @ts-expect-error - if button, type must be submit/reset/button */ }
<Button type="image/png" />
Expand Down
2 changes: 2 additions & 0 deletions packages/components/src/combobox-control/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,8 @@ function ComboboxControl( props: ComboboxControlProps ) {
<Button
className="components-combobox-control__reset"
icon={ closeSmall }
// Disable reason: Focus returns to input field when reset is clicked.
// eslint-disable-next-line no-restricted-syntax
disabled={ ! value }
onClick={ handleOnReset }
label={ __( 'Reset' ) }
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/dropdown-menu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ function UnconnectedDropdownMenu( dropdownMenuProps: DropdownMenuProps ) {
? control.role
: 'menuitem'
}
__experimentalIsFocusable
disabled={ control.isDisabled }
>
{ control.title }
Expand Down
2 changes: 2 additions & 0 deletions packages/components/src/form-token-field/token.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ export default function Token( {
className="components-form-token-field__remove-token"
icon={ closeSmall }
onClick={ ! disabled ? onClick : undefined }
// Disable reason: Even when FormTokenField itself is accessibly disabled, token reset buttons shouldn't be in the tab sequence.
// eslint-disable-next-line no-restricted-syntax
disabled={ disabled }
label={ messages.remove }
aria-describedby={ `components-form-token-field__token-text-${ instanceId }` }
Expand Down
2 changes: 2 additions & 0 deletions packages/components/src/private-apis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
useCompositeStore as useCompositeStoreV2,
} from './composite/v2';
import { default as CustomSelectControl } from './custom-select-control';
import { default as CustomSelectControlV2Legacy } from './custom-select-control-v2/legacy-component';
import { positionToPlacement as __experimentalPopoverLegacyPositionToPlacement } from './popover/utils';
import { createPrivateSlotFill } from './slot-fill';
import {
Expand All @@ -39,6 +40,7 @@ lock( privateApis, {
CompositeItemV2,
CompositeRowV2,
useCompositeStoreV2,
CustomSelectControlV2Legacy,
CustomSelectControl,
__experimentalPopoverLegacyPositionToPlacement,
createPrivateSlotFill,
Expand Down
2 changes: 2 additions & 0 deletions packages/components/src/range-control/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,8 @@ function UnforwardedRangeControl(
<ActionRightWrapper>
<Button
className="components-range-control__reset"
// If the RangeControl itself is disabled, the reset button shouldn't be in the tab sequence.
__experimentalIsFocusable={ ! disabled }
disabled={ disabled || value === undefined }
variant="secondary"
size="small"
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/toolbar/toolbar-button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ function UnforwardedToolbarButton(
className
) }
isPressed={ isActive }
__experimentalIsFocusable
data-toolbar-item
{ ...extraProps }
{ ...restProps }
Expand Down
4 changes: 4 additions & 0 deletions packages/dataviews/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### New features

- Added a new `DataForm` component to render controls from a given configuration (fields, form), and data.

## 2.2.0 (2024-06-26)

## 2.1.0 (2024-06-15)
Expand Down
106 changes: 106 additions & 0 deletions packages/dataviews/src/dataform.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/**
* External dependencies
*/
import type { Dispatch, SetStateAction } from 'react';

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { TextControl } from '@wordpress/components';
import { useCallback, useMemo } from '@wordpress/element';

/**
* Internal dependencies
*/
import type { Form, Field, NormalizedField } from './types';
import { normalizeFields } from './normalize-fields';

type DataFormProps< Item > = {
data: Item;
fields: Field< Item >[];
form: Form;
onChange: Dispatch< SetStateAction< Item > >;
};

type DataFormControlProps< Item > = {
data: Item;
field: NormalizedField< Item >;
onChange: Dispatch< SetStateAction< Item > >;
};

function DataFormTextControl< Item >( {
data,
field,
onChange,
}: DataFormControlProps< Item > ) {
const { id, header, placeholder } = field;
const value = field.getValue( { item: data } );

const onChangeControl = useCallback(
( newValue: string ) =>
onChange( ( prevItem: Item ) => ( {
...prevItem,
[ id ]: newValue,
} ) ),
[ id, onChange ]
);

return (
<TextControl
label={ header }
placeholder={ placeholder }
value={ value }
onChange={ onChangeControl }
/>
);
}

const controls: {
[ key: string ]: < Item >(
props: DataFormControlProps< Item >
) => JSX.Element;
} = {
text: DataFormTextControl,
};

function getControlForField< Item >( field: NormalizedField< Item > ) {
if ( ! field.type ) {
return null;
}

if ( ! Object.keys( controls ).includes( field.type ) ) {
return null;
}

return controls[ field.type ];
}

export default function DataForm< Item >( {
data,
fields,
form,
onChange,
}: DataFormProps< Item > ) {
const visibleFields = useMemo(
() =>
normalizeFields(
fields.filter(
( { id } ) => !! form.visibleFields?.includes( id )
)
),
[ fields, form.visibleFields ]
);

return visibleFields.map( ( field ) => {
const DataFormControl = getControlForField( field );
return DataFormControl ? (
<DataFormControl
key={ field.id }
data={ data }
field={ field }
onChange={ onChange }
/>
) : null;
} );
}
1 change: 1 addition & 0 deletions packages/dataviews/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { default as DataViews } from './dataviews';
export { VIEW_LAYOUTS } from './layouts';
export { filterSortAndPaginate } from './filter-and-sort-data-view';
export type * from './types';
export { default as DataForm } from './dataform';
19 changes: 19 additions & 0 deletions packages/dataviews/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,17 @@ export type Operator =

export type ItemRecord = Record< string, unknown >;

export type FieldType = 'text';

/**
* A dataview field for a specific property of a data type.
*/
export type Field< Item > = {
/**
* Type of the fields.
*/
type?: FieldType;

/**
* The unique identifier of the field.
*/
Expand All @@ -58,6 +65,11 @@ export type Field< Item > = {
*/
header?: string;

/**
* Placeholder for the field.
*/
placeholder?: string;

/**
* Callback used to render the field. Defaults to `field.getValue`.
*/
Expand Down Expand Up @@ -131,6 +143,13 @@ export type Fields< Item > = Field< Item >[];

export type Data< Item > = Item[];

/**
* The form configuration.
*/
export type Form = {
visibleFields?: string[];
};

/**
* The filters applied to the dataset.
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/dependency-extraction-webpack-plugin/lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ function defaultRequestToExternalModule( request ) {
function defaultRequestToHandle( request ) {
switch ( request ) {
case '@babel/runtime/regenerator':
return 'wp-polyfill';
return 'regenerator-runtime';

case 'lodash-es':
return 'lodash';
Expand Down
1 change: 1 addition & 0 deletions packages/editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"@wordpress/compose": "file:../compose",
"@wordpress/core-data": "file:../core-data",
"@wordpress/data": "file:../data",
"@wordpress/dataviews": "file:../dataviews",
"@wordpress/date": "file:../date",
"@wordpress/deprecated": "file:../deprecated",
"@wordpress/dom": "file:../dom",
Expand Down
Loading

0 comments on commit 8472e7a

Please sign in to comment.