Skip to content

Commit

Permalink
Stepper: add header position
Browse files Browse the repository at this point in the history
  • Loading branch information
TikouWeb committed Aug 13, 2024
1 parent 0d55658 commit e69e01e
Show file tree
Hide file tree
Showing 64 changed files with 6,264 additions and 1,337 deletions.
8 changes: 8 additions & 0 deletions components/doc/common/apidoc/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -47308,6 +47308,14 @@
"default": "0",
"description": "Active step index of stepper."
},
{
"name": "headerPosition",
"optional": true,
"readonly": false,
"type": "\"left\" | \"top\" | \"bottom\" | \"right\"",
"default": "",
"description": "Position of the stepper panel header relative to the step number."
},
{
"name": "linear",
"optional": true,
Expand Down
154 changes: 154 additions & 0 deletions components/doc/stepper/headerdoc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import { DocSectionCode } from '@/components/doc/common/docsectioncode';
import { DocSectionText } from '@/components/doc/common/docsectiontext';
import { Button } from '@/components/lib/button/Button';
import { Stepper } from '@/components/lib/stepper/Stepper';
import { StepperPanel } from '@/components/lib/stepperpanel/StepperPanel';
import { useRef } from 'react';

export function HeaderDoc(props) {
const stepperRef = useRef([]);

const code = {
basic: `
<h5>Position top</h5>
<Stepper ref={(ref) => (stepperRef.current[2] = ref)} headerPosition="top">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
<h5>Position right</h5>
<Stepper ref={(ref) => (stepperRef.current[0] = ref)} headerPosition="right">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
<h5>Position left</h5>
<Stepper ref={(ref) => (stepperRef.current[1] = ref)} headerPosition="left">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
<h5>Position bottom</h5>
<Stepper ref={(ref) => (stepperRef.current[2] = ref)} headerPosition="bottom">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
`,
javascript: `
import { useRef } from 'react';
import { Stepper } from 'primereact/stepper';
import { StepperPanel } from 'primereact/stepperpanel';
import { Button } from 'primereact/button';
export default function BasicDemo() {
const stepperRef = useRef(null);
return (
<h5>Position top</h5>
<Stepper ref={(ref) => (stepperRef.current[2] = ref)} headerPosition="top">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
<h5>Position right</h5>
<Stepper ref={(ref) => (stepperRef.current[0] = ref)} headerPosition="right">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
<h5>Position left</h5>
<Stepper ref={(ref) => (stepperRef.current[1] = ref)} headerPosition="left">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
<h5>Position bottom</h5>
<Stepper ref={(ref) => (stepperRef.current[2] = ref)} headerPosition="bottom">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
);
}
`,
typescript: `
import { useRef } from 'react';
import { Stepper } from 'primereact/stepper';
import { StepperPanel } from 'primereact/stepperpanel';
import { Button } from 'primereact/button';
export default function BasicDemo() {
const stepperRef = useRef(null);
return (
<h5>Position top</h5>
<Stepper ref={(ref) => (stepperRef.current[2] = ref)} headerPosition="top">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
<h5>Position right</h5>
<Stepper ref={(ref) => (stepperRef.current[0] = ref)} headerPosition="right">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
<h5>Position left</h5>
<Stepper ref={(ref) => (stepperRef.current[1] = ref)} headerPosition="left">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
<h5>Position bottom</h5>
<Stepper ref={(ref) => (stepperRef.current[2] = ref)} headerPosition="bottom">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
);
}
`
};

return (
<>
<DocSectionText {...props}>
<p>
Header position of the stepper can be customized using the <i>headerPosition</i> property. Default value is <i>right</i>.
</p>
</DocSectionText>
<div className="card flex flex-column justify-content-center">
<h5>Position top</h5>
<Stepper ref={(ref) => (stepperRef.current[0] = ref)} headerPosition="top">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
<h5>Position right</h5>
<Stepper ref={(ref) => (stepperRef.current[1] = ref)} headerPosition="right">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
<h5>Position left</h5>
<Stepper ref={(ref) => (stepperRef.current[2] = ref)} headerPosition="left">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
<h5>Position bottom</h5>
<Stepper ref={(ref) => (stepperRef.current[3] = ref)} headerPosition="bottom">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
<div className="flex pt-4 justify-content-between">
<Button label="Back" severity="secondary" icon="pi pi-arrow-left" onClick={() => stepperRef.current.forEach((ref) => ref.prevCallback())} />
<Button label="Next" icon="pi pi-arrow-right" iconPos="right" onClick={() => stepperRef.current.forEach((ref) => ref.nextCallback())} />
</div>
</div>
<DocSectionCode code={code} />
</>
);
}
2 changes: 1 addition & 1 deletion components/lib/stepper/Stepper.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export const Stepper = React.memo(
return stepperPanels().map((step, index) => {
const panelProps = mergeProps(
{
className: classNames(cx('stepper.header', { isStepActive, isItemDisabled, step, index })),
className: classNames(cx('stepper.header', { isStepActive, isItemDisabled, step, index, headerPosition: props.headerPosition, orientation: props.orientation })),
'aria-current': isStepActive(index) && 'step',
role: 'presentation',
'data-p-highlight': isStepActive(index),
Expand Down
138 changes: 138 additions & 0 deletions components/lib/stepper/Stepper.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import '@testing-library/jest-dom';
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { snapshot } from '../../test';
import { PrimeReactProvider } from '../api/Api';
import { Stepper } from './Stepper';
import { StepperPanel } from '../stepperpanel/StepperPanel';

function assertSelectedStep(expectedIndex) {
const selectedStep = screen.getByRole('presentation', { current: 'step' });
const expectedStep = screen.getByRole('list').children.item(expectedIndex);

expect(expectedStep).toEqual(selectedStep);
}

describe('Stepper', () => {
snapshot(
<PrimeReactProvider>
<Stepper />
</PrimeReactProvider>,
'default'
);
snapshot(
<Stepper>
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>,
'panels'
);
snapshot(
<Stepper orientation="vertical">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>,
'vertical'
);
snapshot(
<Stepper headerPosition="top">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
</Stepper>,
'header position top'
);
snapshot(
<Stepper headerPosition="right">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
</Stepper>,
'header position right'
);
snapshot(
<Stepper headerPosition="bottom">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
</Stepper>,
'header position bottom'
);
snapshot(
<Stepper headerPosition="left">
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
</Stepper>,
'header position left'
);

test('Step should have aria step when selected', async () => {
render(
<Stepper>
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
);

await userEvent.click(screen.getByRole('tab', { name: '3 Header III' }));
assertSelectedStep(2);
});

test('Control active step from outside', async () => {
render(
<Stepper activeStep={3}>
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
<StepperPanel header="Header IV"></StepperPanel>
<StepperPanel header="Header VI"></StepperPanel>
</Stepper>
);

assertSelectedStep(3);
});

test('Changing step should trigger onChangeStep callback', async () => {
const onChangeStep = jest.fn();

render(
<Stepper onChangeStep={onChangeStep}>
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
);

await userEvent.click(screen.getByRole('tab', { name: '2 Header II' }));
expect(onChangeStep).toHaveBeenCalledTimes(1);

await userEvent.click(screen.getByRole('tab', { name: '3 Header III' }));
expect(onChangeStep).toHaveBeenCalledTimes(2);
});

test('Change steps with buttons', async () => {
const stepperRef = React.createRef(null);
const onChangeStep = jest.fn();

render(
<div>
<Stepper ref={stepperRef} onChangeStep={onChangeStep}>
<StepperPanel header="Header I"></StepperPanel>
<StepperPanel header="Header II"></StepperPanel>
<StepperPanel header="Header III"></StepperPanel>
</Stepper>
<button onClick={() => stepperRef.current.nextCallback()}>Next</button>
<button onClick={() => stepperRef.current.previousCallback()}>Previous</button>
</div>
);

const nextButton = screen.getByRole('button', { name: 'Next' });

await userEvent.click(nextButton);

expect(onChangeStep).toHaveBeenCalledTimes(1);

assertSelectedStep(1);
});
});
Loading

0 comments on commit e69e01e

Please sign in to comment.