Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 56 additions & 46 deletions packages/react-core/src/components/Pagination/OptionsToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,25 @@ import { DropdownToggle } from '../Dropdown';
export interface OptionsToggleProps extends React.HTMLProps<HTMLDivElement> {
/** The type or title of the items being paginated */
itemsTitle?: string;
/** Accessible label for the Options Toggle */
/** Accessible label for the options toggle */
optionsToggle?: string;
/** The Title of the Pagination Options Menu */
/** The title of the pagination options menu */
itemsPerPageTitle?: string;
/** The first index of the items being paginated */
firstIndex?: number;
/** The last index of the items being paginated */
lastIndex?: number;
/** The total number of items being paginated */
itemCount?: number;
/** Id added to the title of the Pagination Options Menu */
/** Id added to the title of the pagination options menu */
widgetId?: string;
/** showToggle */
showToggle?: boolean;
/** Event function that fires when user clicks the Options Menu toggle */
/** Event function that fires when user clicks the options menu toggle */
onToggle?: (isOpen: boolean) => void;
/** Flag indicating if the Options Menu dropdown is open or not */
/** Flag indicating if the options menu dropdown is open or not */
isOpen?: boolean;
/** Flag indicating if the Options Menu is disabled */
/** Flag indicating if the options menu is disabled */
isDisabled?: boolean;
/** */
parentRef?: HTMLElement;
Expand All @@ -37,12 +37,16 @@ export interface OptionsToggleProps extends React.HTMLProps<HTMLDivElement> {
onEnter?: () => void;
/** Label for the English word "of" */
ofWord?: string;
/** Component to be used for wrapping the toggle contents. Use 'button' when you want
* all of the toggle text to be clickable.
*/
perPageComponent?: 'div' | 'button';
}

let toggleId = 0;
export const OptionsToggle: React.FunctionComponent<OptionsToggleProps> = ({
itemsTitle = 'items',
optionsToggle = 'Items per page',
optionsToggle,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
itemsPerPageTitle = 'Items per page',
ofWord = 'of',
Expand All @@ -57,43 +61,49 @@ export const OptionsToggle: React.FunctionComponent<OptionsToggleProps> = ({
isDisabled = false,
parentRef = null,
toggleTemplate: ToggleTemplate,
onEnter = null
}: OptionsToggleProps) => (
<div
className={css(
styles.optionsMenuToggle,
isDisabled && styles.modifiers.disabled,
styles.modifiers.plain,
styles.modifiers.text
)}
>
{showToggle && (
<React.Fragment>
<span className={css(styles.optionsMenuToggleText)}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Products could be applying custom styles here . This would be a breaking change.

{typeof ToggleTemplate === 'string' ? (
fillTemplate(ToggleTemplate, { firstIndex, lastIndex, ofWord, itemCount, itemsTitle })
) : (
<ToggleTemplate
firstIndex={firstIndex}
lastIndex={lastIndex}
ofWord={ofWord}
itemCount={itemCount}
itemsTitle={itemsTitle}
/>
)}
</span>
<DropdownToggle
onEnter={onEnter}
aria-label={optionsToggle}
onToggle={onToggle}
isDisabled={isDisabled || (itemCount && itemCount <= 0)}
isOpen={isOpen}
id={`${widgetId}-toggle-${toggleId++}`}
className={styles.optionsMenuToggleButton}
parentRef={parentRef}
></DropdownToggle>
</React.Fragment>
)}
</div>
);
onEnter = null,
perPageComponent = 'div'
}: OptionsToggleProps) => {
const isDiv = perPageComponent === 'div';
const toggleClasses = css(
styles.optionsMenuToggle,
isDisabled && styles.modifiers.disabled,
styles.modifiers.plain,
styles.modifiers.text
);

const template =
typeof ToggleTemplate === 'string' ? (
fillTemplate(ToggleTemplate, { firstIndex, lastIndex, ofWord, itemCount, itemsTitle })
) : (
<ToggleTemplate
firstIndex={firstIndex}
lastIndex={lastIndex}
ofWord={ofWord}
itemCount={itemCount}
itemsTitle={itemsTitle}
/>
);

const dropdown = showToggle && (
<React.Fragment>
{isDiv && <span className={css(styles.optionsMenuToggleText)}>{template}</span>}
<DropdownToggle
onEnter={onEnter}
aria-label={isDiv ? optionsToggle || 'Items per page' : optionsToggle}
onToggle={onToggle}
isDisabled={isDisabled || (itemCount && itemCount <= 0)}
isOpen={isOpen}
id={`${widgetId}-toggle-${toggleId++}`}
className={isDiv ? styles.optionsMenuToggleButton : toggleClasses}
parentRef={parentRef}
aria-haspopup="listbox"
>
{!isDiv && template}
</DropdownToggle>
</React.Fragment>
);

return isDiv ? <div className={toggleClasses}>{dropdown}</div> : dropdown;
};
OptionsToggle.displayName = 'OptionsToggle';
17 changes: 12 additions & 5 deletions packages/react-core/src/components/Pagination/Pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ export interface PaginationTitles {
pages?: string;
/** The type or title of the items being paginated */
items?: string;
/** The Title of the Pagination Options Menu */
/** The title of the pagination options menu */
itemsPerPage?: string;
/** The suffix to be displayed after each option on the Options Menu dropdown */
/** The suffix to be displayed after each option on the options menu dropdown */
perPageSuffix?: string;
/** Accessible label for the button which moves to the first page */
toFirstPage?: string;
Expand All @@ -60,7 +60,7 @@ export interface PaginationTitles {
toLastPage?: string;
/** Accessible label for the button which moves to the next page */
toNextPage?: string;
/** Accessible label for the Options Toggle */
/** Accessible label for the options toggle */
optionsToggle?: string;
/** Accessible label for the input displaying the current page */
currPage?: string;
Expand Down Expand Up @@ -141,6 +141,10 @@ export interface PaginationProps extends React.HTMLProps<HTMLDivElement>, OUIAPr
onPageInput?: (event: React.SyntheticEvent<HTMLButtonElement>, page: number) => void;
/** Function called when user selects number of items per page. */
onPerPageSelect?: OnPerPageSelect;
/** Component to be used for wrapping the toggle contents. Use 'button' when you want
* all of the toggle text to be clickable.
*/
perPageComponent?: 'div' | 'button';
}

const handleInputWidth = (lastPage: number, node: HTMLDivElement) => {
Expand Down Expand Up @@ -177,7 +181,7 @@ export class Pagination extends React.Component<PaginationProps, { ouiaStateId:
toPreviousPage: 'Go to previous page',
toLastPage: 'Go to last page',
toNextPage: 'Go to next page',
optionsToggle: 'Items per page',
optionsToggle: '',
currPage: 'Current page',
paginationTitle: 'Pagination',
ofWord: 'of'
Expand All @@ -197,7 +201,8 @@ export class Pagination extends React.Component<PaginationProps, { ouiaStateId:
onNextClick: () => undefined,
onPageInput: () => undefined,
onLastClick: () => undefined,
ouiaSafe: true
ouiaSafe: true,
perPageComponent: 'div'
};

state = {
Expand Down Expand Up @@ -252,6 +257,7 @@ export class Pagination extends React.Component<PaginationProps, { ouiaStateId:
onLastClick,
ouiaId,
ouiaSafe,
perPageComponent,
...props
} = this.props;
const dropDirection = dropDirectionProp || (variant === 'bottom' && !isStatic ? 'up' : 'down');
Expand Down Expand Up @@ -335,6 +341,7 @@ export class Pagination extends React.Component<PaginationProps, { ouiaStateId:
widgetId={widgetId}
toggleTemplate={toggleTemplate}
isDisabled={isDisabled}
perPageComponent={perPageComponent}
/>
<Navigation
pagesTitle={titles.page}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@ import { ToggleTemplateProps, ToggleTemplate } from './ToggleTemplate';
import { PerPageOptions, OnPerPageSelect } from './Pagination';

export interface PaginationOptionsMenuProps extends React.HTMLProps<HTMLDivElement> {
/** Custom class name added to the Pagination Options Menu */
/** Custom class name added to the pagination options menu */
className?: string;
/** Id added to the title of the Pagination Options Menu */
/** Id added to the title of the Pagination options menu */
widgetId?: string;
/** Flag indicating if Pagination Options Menu is disabled */
/** Flag indicating if pagination options menu is disabled */
isDisabled?: boolean;
/** Menu will open up or open down from the Options menu toggle */
/** Menu will open up or open down from the options menu toggle */
dropDirection?: 'up' | 'down';
/** Array of titles and values which will be the options on the Options Menu dropdown */
/** Array of titles and values which will be the options on the options menu dropdown */
perPageOptions?: PerPageOptions[];
/** The Title of the Pagination Options Menu */
/** The title of the pagination options menu */
itemsPerPageTitle?: string;
/** Current page number */
page?: number;
/** The suffix to be displayed after each option on the Options Menu dropdown */
/** The suffix to be displayed after each option on the options menu dropdown */
perPageSuffix?: string;
/** The type or title of the items being paginated */
itemsTitle?: string;
/** The text to be displayed on the Options Toggle */
/** Accessible label for the options toggle */
optionsToggle?: string;
/** The total number of items being paginated */
itemCount?: number;
Expand All @@ -46,6 +46,10 @@ export interface PaginationOptionsMenuProps extends React.HTMLProps<HTMLDivEleme
onPerPageSelect?: OnPerPageSelect;
/** Label for the English word "of" */
ofWord?: string;
/** Component to be used for wrapping the toggle contents. Use 'button' when you want
* all of the toggle text to be clickable.
*/
perPageComponent?: 'div' | 'button';
}

interface PaginationOptionsMenuState {
Expand All @@ -63,15 +67,16 @@ export class PaginationOptionsMenu extends React.Component<PaginationOptionsMenu
perPageOptions: [] as PerPageOptions[],
itemsPerPageTitle: 'Items per page',
perPageSuffix: 'per page',
optionsToggle: 'Items per page',
optionsToggle: '',
ofWord: 'of',
perPage: 0,
firstIndex: 0,
lastIndex: 0,
defaultToFullPage: false,
itemsTitle: 'items',
toggleTemplate: ToggleTemplate,
onPerPageSelect: () => null as any
onPerPageSelect: () => null as any,
perPageComponent: 'div'
};

constructor(props: PaginationOptionsMenuProps) {
Expand Down Expand Up @@ -144,7 +149,8 @@ export class PaginationOptionsMenu extends React.Component<PaginationOptionsMenu
lastIndex,
itemCount,
itemsTitle,
ofWord
ofWord,
perPageComponent
} = this.props;
const { isOpen } = this.state;

Expand All @@ -153,7 +159,8 @@ export class PaginationOptionsMenu extends React.Component<PaginationOptionsMenu
value={{
id: widgetId,
onSelect: this.onSelect,
toggleIndicatorClass: styles.optionsMenuToggleButtonIcon,
toggleIndicatorClass:
perPageComponent === 'div' ? styles.optionsMenuToggleButtonIcon : styles.optionsMenuToggleIcon,
toggleTextClass: styles.optionsMenuToggleText,
menuClass: styles.optionsMenuMenu,
itemClass: styles.optionsMenuMenuItem,
Expand Down Expand Up @@ -184,6 +191,7 @@ export class PaginationOptionsMenu extends React.Component<PaginationOptionsMenu
toggleTemplate={toggleTemplate}
parentRef={this.parentRef.current}
isDisabled={isDisabled}
perPageComponent={perPageComponent}
/>
}
dropdownItems={this.renderItems()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ exports[`OptionsToggle should match snapshot (auto-generated) 1`] = `
/>
<button
aria-expanded="false"
aria-haspopup="listbox"
aria-label="'Select'"
class="pf-c-dropdown__toggle pf-c-options-menu__toggle-button"
data-ouia-component-id="OUIA-Generated-DropdownToggle-1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,7 @@ describe('Pagination', () => {

test('custom pagination toggle', () => {
const { asFragment } = render(
<Pagination
itemCount={40}
toggleTemplate={'${firstIndex} - ${lastIndex} - ${itemCount} - ${itemsTitle}'}
/>
<Pagination itemCount={40} toggleTemplate={'${firstIndex} - ${lastIndex} - ${itemCount} - ${itemsTitle}'} />
);
expect(asFragment()).toMatchSnapshot();
});
Expand Down Expand Up @@ -110,6 +107,11 @@ describe('Pagination', () => {
render(<Pagination toggleTemplate={'I am a string'} />);
expect(screen.getAllByText('I am a string')[0]).toBeInTheDocument();
});

test('should render correctly button variant', () => {
const { asFragment } = render(<Pagination perPageComponent="button" itemCount={20} />);
expect(asFragment()).toMatchSnapshot();
});
});

describe('API', () => {
Expand Down
Loading