From e763b1325d98f75caef616959e17278bdb2fca48 Mon Sep 17 00:00:00 2001 From: Xiangyu Shen Date: Fri, 9 Dec 2022 09:57:50 -0500 Subject: [PATCH] chore(Wizard): Convert examples to typescript (#8287) * chore(Wizard): Convert examples to typescript * Fix import statements * Requested changes for cleanup * Integrate FinishedStep and SampleForm into examples directly * Remove unused onExpand function * Fix useEffect not defined * Import CogsIcon * a11y fixes for FinishedStep and SampleForm conversions * a11y fixes * Bug Fixes * Fixed incorrect Radio button state setting * Revert Progressive Steps example change * Fix Validate on Button Press for Wizard * Fix import in example * Remove unnecessary step state --- .../Wizard/examples/FinishedStep.js | 70 -- .../components/Wizard/examples/SampleForm.js | 59 -- .../src/components/Wizard/examples/Wizard.md | 705 +----------------- .../examples/WizardAnchorsForNavItems.tsx | 42 ++ .../Wizard/examples/WizardBasic.tsx | 14 + .../examples/WizardBasicWithDisabledSteps.tsx | 14 + .../WizardEnabledOnFormValidation.tsx | 139 ++++ .../Wizard/examples/WizardExpandableSteps.tsx | 34 + .../Wizard/examples/WizardFinished.tsx | 90 +++ .../Wizard/examples/WizardGetCurrentStep.tsx | 33 + .../Wizard/examples/WizardInModal.tsx | 32 + .../WizardIncrementallyEnabledSteps.tsx | 61 ++ .../examples/WizardValidateOnButtonPress.tsx | 204 +++++ .../Wizard/examples/WizardWithDrawer.tsx | 126 ++++ 14 files changed, 803 insertions(+), 820 deletions(-) delete mode 100644 packages/react-core/src/components/Wizard/examples/FinishedStep.js delete mode 100644 packages/react-core/src/components/Wizard/examples/SampleForm.js create mode 100644 packages/react-core/src/components/Wizard/examples/WizardAnchorsForNavItems.tsx create mode 100644 packages/react-core/src/components/Wizard/examples/WizardBasic.tsx create mode 100644 packages/react-core/src/components/Wizard/examples/WizardBasicWithDisabledSteps.tsx create mode 100644 packages/react-core/src/components/Wizard/examples/WizardEnabledOnFormValidation.tsx create mode 100644 packages/react-core/src/components/Wizard/examples/WizardExpandableSteps.tsx create mode 100644 packages/react-core/src/components/Wizard/examples/WizardFinished.tsx create mode 100644 packages/react-core/src/components/Wizard/examples/WizardGetCurrentStep.tsx create mode 100644 packages/react-core/src/components/Wizard/examples/WizardInModal.tsx create mode 100644 packages/react-core/src/components/Wizard/examples/WizardIncrementallyEnabledSteps.tsx create mode 100644 packages/react-core/src/components/Wizard/examples/WizardValidateOnButtonPress.tsx create mode 100644 packages/react-core/src/components/Wizard/examples/WizardWithDrawer.tsx diff --git a/packages/react-core/src/components/Wizard/examples/FinishedStep.js b/packages/react-core/src/components/Wizard/examples/FinishedStep.js deleted file mode 100644 index 6adfd128f09..00000000000 --- a/packages/react-core/src/components/Wizard/examples/FinishedStep.js +++ /dev/null @@ -1,70 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { - EmptyState, - EmptyStateIcon, - EmptyStateBody, - EmptyStateSecondaryActions, - Title, - Progress, - Button -} from '@patternfly/react-core'; -// eslint-disable-next-line patternfly-react/import-tokens-icons -import { CogsIcon } from '@patternfly/react-icons'; - -const propTypes = { - onClose: PropTypes.func.isRequired -}; - -class FinishedStep extends React.Component { - constructor(props) { - super(props); - this.state = { percent: 0 }; - } - - tick() { - if (this.state.percent < 100) { - this.setState(prevState => ({ - percent: prevState.percent + 20 - })); - } - } - - componentDidMount() { - this.interval = setInterval(() => this.tick(), 1000); - } - - componentWillUnmount() { - clearInterval(this.interval); - } - - render() { - const { percent } = this.state; - return ( -
- - - - {percent === 100 ? 'Validation complete' : 'Validating credentials'} - - - - - - Description can be used to further elaborate on the validation step, or give the user a better idea of how - long the process will take. - - - - - -
- ); - } -} - -FinishedStep.propTypes = propTypes; - -export default FinishedStep; diff --git a/packages/react-core/src/components/Wizard/examples/SampleForm.js b/packages/react-core/src/components/Wizard/examples/SampleForm.js deleted file mode 100644 index 9992752f404..00000000000 --- a/packages/react-core/src/components/Wizard/examples/SampleForm.js +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { Form, FormGroup, TextInput } from '@patternfly/react-core'; - -const propTypes = { - formValue: PropTypes.string, - isFormValid: PropTypes.bool, - onChange: PropTypes.func -}; - -const defaultProps = { - formValue: '', - isFormValid: false, - onChange: () => undefined -}; - -class SampleForm extends React.Component { - static propTypes = propTypes; - static defaultProps = defaultProps; - - state = { - value: this.props.formValue, - isValid: this.props.isFormValid - }; - - handleTextInputChange = value => { - const isValid = /^\d+$/.test(value); - this.setState({ value, isValid }); - this.props.onChange && this.props.onChange(isValid, value); - }; - - render() { - const { value, isValid } = this.state; - const validated = isValid ? 'default' : 'error'; - - return ( -
- - - -
- ); - } -} - -export default SampleForm; diff --git a/packages/react-core/src/components/Wizard/examples/Wizard.md b/packages/react-core/src/components/Wizard/examples/Wizard.md index 75ee563df68..56cc069554c 100644 --- a/packages/react-core/src/components/Wizard/examples/Wizard.md +++ b/packages/react-core/src/components/Wizard/examples/Wizard.md @@ -8,11 +8,11 @@ ouia: true --- import { Button, Drawer, DrawerActions, DrawerCloseButton, DrawerColorVariant, -DrawerContent, DrawerContentBody, DrawerHead, DrawerPanelContent, DrawerSection, Wizard, WizardFooter, WizardContextConsumer, ModalVariant, Alert, EmptyState, EmptyStateIcon, EmptyStateBody, EmptyStateSecondaryActions, Title, Progress } from '@patternfly/react-core'; +DrawerContent, DrawerContentBody, DrawerHead, DrawerPanelContent, DrawerSection, Wizard, WizardFooter, WizardContextConsumer, ModalVariant, Alert, EmptyState, EmptyStateIcon, EmptyStateBody, EmptyStateSecondaryActions, Title, Progress, Form, FormGroup, TextInput } from '@patternfly/react-core'; import ExternalLinkAltIcon from '@patternfly/react-icons/dist/esm/icons/external-link-alt-icon'; import SlackHashIcon from '@patternfly/react-icons/dist/esm/icons/slack-hash-icon'; -import FinishedStep from './FinishedStep'; -import SampleForm from './SampleForm'; +import CogsIcon from '@patternfly/react-icons/dist/esm/icons/cogs-icon'; + If you seek a wizard solution that allows for more composition, see the [React next](/components/wizard/react-next) tab. @@ -20,374 +20,37 @@ If you seek a wizard solution that allows for more composition, see the [React n ### Basic -```js -import React from 'react'; -import { Button, Wizard } from '@patternfly/react-core'; - -class SimpleWizard extends React.Component { - constructor(props) { - super(props); - } - - render() { - const steps = [ - { name: 'First step', component:

Step 1 content

}, - { name: 'Second step', component:

Step 2 content

}, - { name: 'Third step', component:

Step 3 content

}, - { name: 'Fourth step', component:

Step 4 content

}, - { name: 'Review', component:

Review step content

, nextButtonText: 'Finish' } - ]; - const title = 'Basic wizard'; - return ; - } -} +```ts file="./WizardBasic.tsx" ``` ### Basic with disabled steps -```js -import React from 'react'; -import { Button, Wizard } from '@patternfly/react-core'; - -class SimpleWizard extends React.Component { - constructor(props) { - super(props); - } - - render() { - const steps = [ - { name: 'First step', component:

Step 1 content

}, - { name: 'Second step', component:

Step 2 content

, isDisabled: true }, - { name: 'Third step', component:

Step 3 content

}, - { name: 'Fourth step', component:

Step 4 content

, isDisabled: true }, - { name: 'Review', component:

Review step content

, nextButtonText: 'Finish' } - ]; - const title = 'Basic wizard'; - return ; - } -} +```ts file="./WizardBasicWithDisabledSteps.tsx" ``` ### Anchors for nav items -```js -import React from 'react'; -import { Button, Wizard } from '@patternfly/react-core'; -import ExternalLinkAltIcon from '@patternfly/react-icons/dist/esm/icons/external-link-alt-icon'; -import SlackHashIcon from '@patternfly/react-icons/dist/esm/icons/slack-hash-icon'; - -class WizardWithNavAnchors extends React.Component { - constructor(props) { - super(props); - } - - render() { - const steps = [ - { - name: ( -
- PF3 -
- ), - component:

Step 1: Read about PF3

, - stepNavItemProps: { navItemComponent: 'a', href: 'https://www.patternfly.org/v3/', target: '_blank' } - }, - { - name: ( -
- PF4 -
- ), - component:

Step 2: Read about PF4

, - stepNavItemProps: { navItemComponent: 'a', href: 'https://www.patternfly.org/v4/', target: '_blank' } - }, - { - name: ( -
- Join us on slack -
- ), - component: ( - - ), - stepNavItemProps: { navItemComponent: 'a', href: 'https://patternfly.slack.com/', target: '_blank' } - } - ]; - const title = 'Anchor link wizard'; - return ; - } -} +```ts file="./WizardAnchorsForNavItems.tsx" ``` ### Incrementally enabled steps -```js -import React from 'react'; -import { Button, Wizard } from '@patternfly/react-core'; - -class IncrementallyEnabledStepsWizard extends React.Component { - constructor(props) { - super(props); - this.state = { - stepIdReached: 1 - }; - this.onNext = ({ id }) => { - const [, orderIndex] = id.split('-'); - - this.setState({ - stepIdReached: this.state.stepIdReached < orderIndex ? orderIndex : this.state.stepIdReached - }); - }; - this.closeWizard = () => { - console.log('close wizard'); - }; - } - - render() { - const { stepIdReached } = this.state; - - const steps = [ - { id: 'incrementallyEnabled-1', name: 'First step', component:

Step 1 content

}, - { - id: 'incrementallyEnabled-2', - name: 'Second step', - component:

Step 2 content

, - canJumpTo: stepIdReached >= 2 - }, - { - id: 'incrementallyEnabled-3', - name: 'Third step', - component:

Step 3 content

, - canJumpTo: stepIdReached >= 3 - }, - { - id: 'incrementallyEnabled-4', - name: 'Fourth step', - component:

Step 4 content

, - canJumpTo: stepIdReached >= 4 - }, - { - id: 'incrementallyEnabled-5', - name: 'Review', - component:

Review step content

, - nextButtonText: 'Finish', - canJumpTo: stepIdReached >= 5 - } - ]; - const title = 'Incrementally enabled wizard'; - return ( - - ); - } -} +```ts file="./WizardIncrementallyEnabledSteps.tsx" ``` ### Expandable steps -```js -import React from 'react'; -import { Button, Wizard } from '@patternfly/react-core'; - -class SimpleWizard extends React.Component { - constructor(props) { - super(props); - } - - render() { - const steps = [ - { - name: 'First step', - steps: [ - { name: 'Substep A', component:

Substep A content

}, - { name: 'Substep B', component:

Substep B content

} - ] - }, - { name: 'Second step', component:

Step 2 content

}, - { - name: 'Third step', - steps: [ - { name: 'Substep C', component:

Substep C content

}, - { name: 'Substep D', component:

Substep D content

} - ] - }, - { name: 'Fourth step', component:

Step 4 content

}, - { name: 'Review', component:

Review step content

, nextButtonText: 'Finish' } - ]; - const title = 'Expandable wizard'; - return ( - - ); - } -} +```ts file="./WizardExpandableSteps.tsx" ``` ### Finished -```js -import React from 'react'; -import { Button, Wizard } from '@patternfly/react-core'; -import FinishedStep from './examples/FinishedStep'; - -class FinishedStepWizard extends React.Component { - constructor(props) { - super(props); - - this.closeWizard = () => { - console.log('close wizard'); - }; - } - - render() { - const steps = [ - { name: 'First step', component:

Step 1 content

}, - { name: 'Second step', component:

Step 2 content

}, - { name: 'Third step', component:

Step 3 content

}, - { name: 'Fourth step', component:

Step 4 content

}, - { name: 'Review', component:

Review step content

, nextButtonText: 'Finish' }, - { name: 'Finish', component: , isFinishedStep: true } - ]; - const title = 'Finished wizard'; - return ( - - ); - } -} +```ts file="./WizardFinished.tsx" ``` ### Enabled on form validation -```js -import React from 'react'; -import { Button, Wizard, Form, FormGroup, TextInput } from '@patternfly/react-core'; -import SampleForm from './examples/SampleForm'; - -class ValidationWizard extends React.Component { - constructor(props) { - super(props); - this.state = { - isFormValid: false, - formValue: 'Thirty', - allStepsValid: false, - stepIdReached: 1 - }; - - this.closeWizard = () => { - console.log('close wizard'); - }; - - this.onFormChange = (isValid, value) => { - this.setState( - { - isFormValid: isValid, - formValue: value - }, - this.areAllStepsValid - ); - }; - - this.areAllStepsValid = () => { - this.setState({ - allStepsValid: this.state.isFormValid - }); - }; - - this.onNext = ({ id, name }, { prevId, prevName }) => { - console.log(`current id: ${id}, current name: ${name}, previous id: ${prevId}, previous name: ${prevName}`); - const [, orderIndex] = id.split('-'); - - this.setState({ - stepIdReached: this.state.stepIdReached < orderIndex ? orderIndex : this.state.stepIdReached - }); - this.areAllStepsValid(); - }; - - this.onBack = ({ id, name }, { prevId, prevName }) => { - console.log(`current id: ${id}, current name: ${name}, previous id: ${prevId}, previous name: ${prevName}`); - this.areAllStepsValid(); - }; - - this.onGoToStep = ({ id, name }, { prevId, prevName }) => { - console.log(`current id: ${id}, current name: ${name}, previous id: ${prevId}, previous name: ${prevName}`); - }; - - this.onSave = () => { - console.log('Saved and closed the wizard'); - this.setState({ - isOpen: false - }); - }; - } - - render() { - const { isFormValid, formValue, allStepsValid, stepIdReached } = this.state; - - const steps = [ - { id: 'validated-1', name: 'Information', component:

Step 1 content

}, - { - name: 'Configuration', - steps: [ - { - id: 'validated-2', - name: 'Substep A with validation', - component: , - enableNext: isFormValid, - canJumpTo: stepIdReached >= 2 - }, - { id: 'validated-3', name: 'Substep B', component:

Substep B

, canJumpTo: stepIdReached >= 3 } - ] - }, - { - id: 'validated-4', - name: 'Additional', - component:

Step 3 content

, - enableNext: allStepsValid, - canJumpTo: stepIdReached >= 4 - }, - { - id: 'validated-5', - name: 'Review', - component:

Step 4 content

, - nextButtonText: 'Close', - canJumpTo: stepIdReached >= 5 - } - ]; - const title = 'Enabled on form validation wizard'; - return ( - - ); - } -} +```ts file="./WizardEnabledOnFormValidation.tsx" ``` ### Validate on button press @@ -407,104 +70,7 @@ interface WizardContext { } ``` -```js -import React from 'react'; -import { Button, Wizard, WizardFooter, WizardContextConsumer, Alert } from '@patternfly/react-core'; -import SampleForm from './examples/SampleForm'; -import FinishedStep from './examples/FinishedStep'; - -class ValidateButtonPressWizard extends React.Component { - constructor(props) { - super(props); - this.state = { - stepsValid: 0 - }; - - this.closeWizard = () => { - console.log('close wizard'); - }; - - this.validateLastStep = onNext => { - const { stepsValid } = this.state; - if (stepsValid !== 1) { - this.setState({ - stepsValid: 1 - }); - } else { - onNext(); - } - }; - } - - render() { - const { stepsValid } = this.state; - - const steps = [ - { name: 'First step', component:

Step 1 content

}, - { name: 'Second step', component:

Step 2 content

}, - { - name: 'Final Step', - component: ( - <> - {stepsValid === 1 && ( -
- -
- )} - - - ) - }, - { name: 'Finish', component: , isFinishedStep: true } - ]; - - const CustomFooter = ( - - - {({ activeStep, goToStepByName, goToStepById, onNext, onBack, onClose }) => { - if (activeStep.name !== 'Final Step') { - return ( - <> - - - - - ); - } - // Final step buttons - return ( - <> - - - - ); - }} - - - ); - const title = 'Validate on button press wizard'; - return ( - - ); - } -} +```ts file="./WizardValidateOnButtonPress.tsx" ``` ### Progressive steps @@ -512,8 +78,6 @@ class ValidateButtonPressWizard extends React.Component { ```js import React from 'react'; import { Button, Radio, Wizard, WizardFooter, WizardContextConsumer, Alert } from '@patternfly/react-core'; -import SampleForm from './examples/SampleForm'; -import FinishedStep from './examples/FinishedStep'; class ProgressiveWizard extends React.Component { constructor(props) { @@ -642,7 +206,6 @@ class ProgressiveWizard extends React.Component { } }; } - render() { const { stepsValid, @@ -654,7 +217,6 @@ class ProgressiveWizard extends React.Component { showOptionsStep, showReviewStep } = this.state; - const getStartedStep = { name: 'Get started', component: ( @@ -678,7 +240,6 @@ class ProgressiveWizard extends React.Component { ) }; - const createStep = { name: 'Create options', component: ( @@ -702,7 +263,6 @@ class ProgressiveWizard extends React.Component { ) }; - const updateStep = { name: 'Update options', component: ( @@ -726,7 +286,6 @@ class ProgressiveWizard extends React.Component { ) }; - const optionsStep = { name: showCreateStep ? `${createStepRadio} Options` : `${updateStepRadio} Options`, steps: [ @@ -744,7 +303,6 @@ class ProgressiveWizard extends React.Component { } ] }; - const reviewStep = { name: 'Review', component: ( @@ -754,7 +312,6 @@ class ProgressiveWizard extends React.Component { ) }; - const steps = [ getStartedStep, ...(showCreateStep ? [createStep] : []), @@ -762,7 +319,6 @@ class ProgressiveWizard extends React.Component { ...(showOptionsStep ? [optionsStep] : []), ...(showReviewStep ? [reviewStep] : []) ]; - const CustomFooter = ( @@ -806,248 +362,15 @@ class ProgressiveWizard extends React.Component { ### Get current step -```js -import React from 'react'; -import { Button, Wizard } from '@patternfly/react-core'; - -class GetCurrentStepWizard extends React.Component { - constructor(props) { - super(props); - this.state = { - step: 1 - }; - this.onCurrentStepChanged = ({ id }) => { - this.setState({ - step: id - }); - }; - this.closeWizard = () => { - console.log('close wizard'); - }; - } - - render() { - const steps = [ - { id: 1, name: 'First step', component:

Step 1 content

}, - { id: 2, name: 'Second step', component:

Step 2 content

}, - { id: 3, name: 'Third step', component:

Step 3 content

}, - { id: 4, name: 'Fourth step', component:

Step 4 content

}, - { id: 5, name: 'Review', component:

Review step content

, nextButtonText: 'Finish' } - ]; - const title = 'Get current step wizard'; - return ( - - ); - } -} +```ts file="./WizardGetCurrentStep.tsx" ``` ### Wizard in modal -```js -import React from 'react'; -import { Button, Wizard } from '@patternfly/react-core'; - -class WizardInModal extends React.Component { - constructor(props) { - super(props); - this.state = { - isOpen: false - }; - this.handleModalToggle = () => { - this.setState(({ isOpen }) => ({ - isOpen: !isOpen - })); - }; - } - - render() { - const { isOpen } = this.state; - - const steps = [ - { name: 'First step', component:

Step 1 content

}, - { name: 'Second step', component:

Step 2 content

}, - { name: 'Third step', component:

Step 3 content

}, - { name: 'Fourth step', component:

Step 4 content

}, - { name: 'Review', component:

Review step content

, nextButtonText: 'Finish' } - ]; - const title = 'Wizard in modal'; - return ( - - - - - ); - } -} +```ts file="./WizardInModal.tsx" ``` ### Wizard with drawer -```js -import React from 'react'; -import { - Button, - DrawerActions, - DrawerCloseButton, - DrawerHead, - DrawerPanelContent, - Text, - TextContent, - Wizard -} from '@patternfly/react-core'; - -class WizardWithDrawer extends React.Component { - constructor(props) { - super(props); - this.state = { - isOpen: false, - isDrawerExpanded: false, - sectionGray: false, - panelGray: true, - contentGray: false - }; - - this.drawerRef = React.createRef(); - - this.onExpand = () => { - this.drawerRef.current && this.drawerRef.current.focus(); - }; - - this.onOpenClick = () => { - this.setState({ - isDrawerExpanded: true - }); - }; - - this.onCloseClick = () => { - this.setState({ - isDrawerExpanded: false - }); - }; - } - - render() { - const { isDrawerExpanded } = this.state; - - const panel1Content = ( - - - - drawer-panel-1 content - - - - - - - ); - - const panel2Content = ( - - - - drawer-panel-2 content - - - - - - - ); - - const panel3Content = ( - - - - drawer-panel-3 content - - - - - - - ); - - const drawerToggleButton = ( - - ); - - const steps = [ - { - name: 'Information', - component:

Information step content

, - drawerPanelContent: panel1Content, - drawerToggleButton: drawerToggleButton - }, - { - name: 'Configuration', - steps: [ - { - name: 'Substep A', - component:

Substep A content

, - drawerPanelContent: panel2Content, - drawerToggleButton: drawerToggleButton - }, - { - name: 'Substep B', - component:

Substep B content

, - drawerPanelContent: panel2Content, - drawerToggleButton: drawerToggleButton - }, - { - name: 'Substep C', - component:

Substep C content

, - drawerPanelContent: panel2Content, - drawerToggleButton: drawerToggleButton - } - ] - }, - { - name: 'Additional', - component:

Additional step content

, - drawerPanelContent: panel3Content, - drawerToggleButton: drawerToggleButton - }, - { - name: 'Review', - component:

Review step content

, - nextButtonText: 'Finish' - } - ]; - - const title = 'Wizard with drawer'; - - return ( - - - - ); - } -} +```ts file="./WizardWithDrawer.tsx" ``` diff --git a/packages/react-core/src/components/Wizard/examples/WizardAnchorsForNavItems.tsx b/packages/react-core/src/components/Wizard/examples/WizardAnchorsForNavItems.tsx new file mode 100644 index 00000000000..6c26cd8e937 --- /dev/null +++ b/packages/react-core/src/components/Wizard/examples/WizardAnchorsForNavItems.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { Button, Wizard } from '@patternfly/react-core'; +import ExternalLinkAltIcon from '@patternfly/react-icons/dist/esm/icons/external-link-alt-icon'; +import SlackHashIcon from '@patternfly/react-icons/dist/esm/icons/slack-hash-icon'; + +export const WizardWithNavAnchors: React.FunctionComponent = () => { + const steps = [ + { + name: ( +
+ PF3 +
+ ), + component:

Step 1: Read about PF3

, + stepNavItemProps: { navItemComponent: 'a', href: 'https://www.patternfly.org/v3/', target: '_blank' } + }, + { + name: ( +
+ PF4 +
+ ), + component:

Step 2: Read about PF4

, + stepNavItemProps: { navItemComponent: 'a', href: 'https://www.patternfly.org/v4/', target: '_blank' } + }, + { + name: ( +
+ Join us on slack +
+ ), + component: ( + + ), + stepNavItemProps: { navItemComponent: 'a', href: 'https://patternfly.slack.com/', target: '_blank' } + } + ]; + const title = 'Anchor link wizard example'; + return ; +}; diff --git a/packages/react-core/src/components/Wizard/examples/WizardBasic.tsx b/packages/react-core/src/components/Wizard/examples/WizardBasic.tsx new file mode 100644 index 00000000000..71eca4176f5 --- /dev/null +++ b/packages/react-core/src/components/Wizard/examples/WizardBasic.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { Wizard } from '@patternfly/react-core'; + +export const WizardBasic: React.FunctionComponent = () => { + const steps = [ + { name: 'First step', component:

Step 1 content

}, + { name: 'Second step', component:

Step 2 content

}, + { name: 'Third step', component:

Step 3 content

}, + { name: 'Fourth step', component:

Step 4 content

}, + { name: 'Review', component:

Review step content

, nextButtonText: 'Finish' } + ]; + const title = 'Basic wizard example'; + return ; +}; diff --git a/packages/react-core/src/components/Wizard/examples/WizardBasicWithDisabledSteps.tsx b/packages/react-core/src/components/Wizard/examples/WizardBasicWithDisabledSteps.tsx new file mode 100644 index 00000000000..46b92e151e9 --- /dev/null +++ b/packages/react-core/src/components/Wizard/examples/WizardBasicWithDisabledSteps.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { Wizard } from '@patternfly/react-core'; + +export const WizardBasicWithDisabledSteps: React.FunctionComponent = () => { + const steps = [ + { name: 'First step', component:

Step 1 content

}, + { name: 'Second step', component:

Step 2 content

, isDisabled: true }, + { name: 'Third step', component:

Step 3 content

}, + { name: 'Fourth step', component:

Step 4 content

, isDisabled: true }, + { name: 'Review', component:

Review step content

, nextButtonText: 'Finish' } + ]; + const title = 'Basic wizard with disabled steps example'; + return ; +}; diff --git a/packages/react-core/src/components/Wizard/examples/WizardEnabledOnFormValidation.tsx b/packages/react-core/src/components/Wizard/examples/WizardEnabledOnFormValidation.tsx new file mode 100644 index 00000000000..9121779a59e --- /dev/null +++ b/packages/react-core/src/components/Wizard/examples/WizardEnabledOnFormValidation.tsx @@ -0,0 +1,139 @@ +import React from 'react'; +import { Form, FormGroup, TextInput, Wizard, WizardStep } from '@patternfly/react-core'; +interface PrevStepInfo { + prevId?: string | number; + prevName: React.ReactNode; +} + +interface sampleFormProps { + formValue: string; + isFormValid: boolean; + onChange?: (isValid: boolean, value: string) => void; +} + +const SampleForm: React.FunctionComponent = (props: sampleFormProps) => { + const [value, setValue] = React.useState(props.formValue); + const [isValid, setIsValid] = React.useState(props.isFormValid); + + const handleTextInputChange = (value: string) => { + const valid = /^\d+$/.test(value); + setValue(value); + setIsValid(valid); + props.onChange && props.onChange(valid, value); + }; + + const validated = isValid ? 'default' : 'error'; + + return ( +
+ + + +
+ ); +}; + +export const WizardFormValidation: React.FunctionComponent = () => { + const [isFormValid, setIsFormValid] = React.useState(false); + const [formValue, setFormValue] = React.useState('Thirty'); + const [allStepsValid, setAllStepsValid] = React.useState(false); + const [stepIdReached, setStepIdReached] = React.useState(1); + + React.useEffect(() => { + setAllStepsValid(isFormValid); + }, [isFormValid, stepIdReached]); + + const closeWizard = () => { + // eslint-disable-next-line no-console + console.log('close wizard'); + }; + + const onFormChange = (isValid: boolean, value: string) => { + setIsFormValid(isValid); + setFormValue(value); + }; + + const areAllStepsValid = () => { + setAllStepsValid(isFormValid); + }; + + const onNext = ({ id, name }: WizardStep, { prevId, prevName }: PrevStepInfo) => { + // eslint-disable-next-line no-console + console.log(`current id: ${id}, current name: ${name}, previous id: ${prevId}, previous name: ${prevName}`); + if (id) { + if (typeof id === 'string') { + const [, orderIndex] = id.split('-'); + id = parseInt(orderIndex); + } + setStepIdReached(stepIdReached < id ? id : stepIdReached); + } + }; + + const onBack = ({ id, name }: WizardStep, { prevId, prevName }: PrevStepInfo) => { + // eslint-disable-next-line no-console + console.log(`current id: ${id}, current name: ${name}, previous id: ${prevId}, previous name: ${prevName}`); + areAllStepsValid(); + }; + + const onGoToStep = ({ id, name }: WizardStep, { prevId, prevName }: PrevStepInfo) => { + // eslint-disable-next-line no-console + console.log(`current id: ${id}, current name: ${name}, previous id: ${prevId}, previous name: ${prevName}`); + }; + + const steps = [ + { id: 'validated-1', name: 'Information', component:

Step 1 content

}, + { + name: 'Configuration', + steps: [ + { + id: 'validated-2', + name: 'Substep A with validation', + component: , + enableNext: isFormValid, + canJumpTo: stepIdReached >= 2 + }, + { id: 'validated-3', name: 'Substep B', component:

Substep B

, canJumpTo: stepIdReached >= 3 } + ] + }, + { + id: 'validated-4', + name: 'Additional', + component:

Step 3 content

, + enableNext: allStepsValid, + canJumpTo: stepIdReached >= 4 + }, + { + id: 'validated-5', + name: 'Review', + component:

Step 4 content

, + nextButtonText: 'Finish', + canJumpTo: stepIdReached >= 5 + } + ]; + const title = 'Wizard enabled on form validation example'; + return ( + + ); +}; diff --git a/packages/react-core/src/components/Wizard/examples/WizardExpandableSteps.tsx b/packages/react-core/src/components/Wizard/examples/WizardExpandableSteps.tsx new file mode 100644 index 00000000000..5400820f6fe --- /dev/null +++ b/packages/react-core/src/components/Wizard/examples/WizardExpandableSteps.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { Wizard } from '@patternfly/react-core'; + +export const WizardExpandableSteps: React.FunctionComponent = () => { + const steps = [ + { + name: 'First step', + steps: [ + { name: 'Substep A', component:

Substep A content

}, + { name: 'Substep B', component:

Substep B content

} + ] + }, + { name: 'Second step', component:

Step 2 content

}, + { + name: 'Third step', + steps: [ + { name: 'Substep C', component:

Substep C content

}, + { name: 'Substep D', component:

Substep D content

} + ] + }, + { name: 'Fourth step', component:

Step 4 content

}, + { name: 'Review', component:

Review step content

, nextButtonText: 'Finish' } + ]; + const title = 'Expandable wizard example'; + return ( + + ); +}; diff --git a/packages/react-core/src/components/Wizard/examples/WizardFinished.tsx b/packages/react-core/src/components/Wizard/examples/WizardFinished.tsx new file mode 100644 index 00000000000..072d1098f46 --- /dev/null +++ b/packages/react-core/src/components/Wizard/examples/WizardFinished.tsx @@ -0,0 +1,90 @@ +import React from 'react'; +import { + EmptyState, + EmptyStateIcon, + EmptyStateBody, + EmptyStateSecondaryActions, + Title, + Progress, + Button, + Wizard +} from '@patternfly/react-core'; +// eslint-disable-next-line patternfly-react/import-tokens-icons +import { CogsIcon } from '@patternfly/react-icons'; + +interface finishedProps { + onClose: () => void; +} + +const FinishedStep: React.FunctionComponent = (props: finishedProps) => { + const [percent, setPercent] = React.useState(0); + + const tick = () => { + setPercent(prevPercent => { + if (prevPercent < 100) { + return prevPercent + 20; + } else { + return prevPercent; + } + }); + }; + + React.useEffect(() => { + const interval = setInterval(() => tick(), 1000); + + if (percent >= 100) { + clearInterval(interval); + } + + return () => clearInterval(interval); + }, [percent]); + + return ( +
+ + + + {percent === 100 ? 'Validation complete' : 'Validating credentials'} + + + + + + Description can be used to further elaborate on the validation step, or give the user a better idea of how + long the process will take. + + + + + +
+ ); +}; + +export const WizardFinished: React.FunctionComponent = () => { + const closeWizard = () => { + // eslint-disable-next-line no-console + console.log('close wizard'); + }; + + const steps = [ + { name: 'First step', component:

Step 1 content

}, + { name: 'Second step', component:

Step 2 content

}, + { name: 'Third step', component:

Step 3 content

}, + { name: 'Fourth step', component:

Step 4 content

}, + { name: 'Review', component:

Review step content

, nextButtonText: 'Finish' }, + { name: 'Finish', component: , isFinishedStep: true } + ]; + const title = 'Finished wizard example'; + return ( + + ); +}; diff --git a/packages/react-core/src/components/Wizard/examples/WizardGetCurrentStep.tsx b/packages/react-core/src/components/Wizard/examples/WizardGetCurrentStep.tsx new file mode 100644 index 00000000000..f41edaa0f34 --- /dev/null +++ b/packages/react-core/src/components/Wizard/examples/WizardGetCurrentStep.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { Wizard, WizardStep } from '@patternfly/react-core'; + +export const WizardGetCurrentStep: React.FunctionComponent = () => { + const onCurrentStepChanged = ({ id }: WizardStep) => { + // eslint-disable-next-line no-console + console.log(id); + }; + const closeWizard = () => { + // eslint-disable-next-line no-console + console.log('close wizard'); + }; + + const steps = [ + { id: 1, name: 'First step', component:

Step 1 content

}, + { id: 2, name: 'Second step', component:

Step 2 content

}, + { id: 3, name: 'Third step', component:

Step 3 content

}, + { id: 4, name: 'Fourth step', component:

Step 4 content

}, + { id: 5, name: 'Review', component:

Review step content

, nextButtonText: 'Finish' } + ]; + const title = 'Get current step wizard example'; + return ( + + ); +}; diff --git a/packages/react-core/src/components/Wizard/examples/WizardInModal.tsx b/packages/react-core/src/components/Wizard/examples/WizardInModal.tsx new file mode 100644 index 00000000000..98695bf6521 --- /dev/null +++ b/packages/react-core/src/components/Wizard/examples/WizardInModal.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { Button, Wizard } from '@patternfly/react-core'; + +export const WizardInModal: React.FunctionComponent = () => { + const [isOpen, setIsOpen] = React.useState(false); + const handleModalToggle = () => { + setIsOpen(!isOpen); + }; + const steps = [ + { name: 'First step', component:

Step 1 content

}, + { name: 'Second step', component:

Step 2 content

}, + { name: 'Third step', component:

Step 3 content

}, + { name: 'Fourth step', component:

Step 4 content

}, + { name: 'Review', component:

Review step content

, nextButtonText: 'Finish' } + ]; + const title = 'Wizard in modal example'; + return ( + + + + + ); +}; diff --git a/packages/react-core/src/components/Wizard/examples/WizardIncrementallyEnabledSteps.tsx b/packages/react-core/src/components/Wizard/examples/WizardIncrementallyEnabledSteps.tsx new file mode 100644 index 00000000000..f769c9d7455 --- /dev/null +++ b/packages/react-core/src/components/Wizard/examples/WizardIncrementallyEnabledSteps.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { Wizard, WizardStep } from '@patternfly/react-core'; + +export const WizardIncrementallyEnabledSteps: React.FunctionComponent = () => { + const [stepIdReached, setStepIdReached] = React.useState(1); + + const onNext = ({ id }: WizardStep) => { + if (id) { + if (typeof id === 'string') { + const [, orderIndex] = id.split('-'); + id = parseInt(orderIndex); + } + setStepIdReached(stepIdReached < id ? id : stepIdReached); + } + }; + + const closeWizard = () => { + // eslint-disable-next-line no-console + console.log('close wizard'); + }; + + const steps = [ + { id: 'incrementallyEnabled-1', name: 'First step', component:

Step 1 content

}, + { + id: 'incrementallyEnabled-2', + name: 'Second step', + component:

Step 2 content

, + canJumpTo: stepIdReached >= 2 + }, + { + id: 'incrementallyEnabled-3', + name: 'Third step', + component:

Step 3 content

, + canJumpTo: stepIdReached >= 3 + }, + { + id: 'incrementallyEnabled-4', + name: 'Fourth step', + component:

Step 4 content

, + canJumpTo: stepIdReached >= 4 + }, + { + id: 'incrementallyEnabled-5', + name: 'Review', + component:

Review step content

, + nextButtonText: 'Finish', + canJumpTo: stepIdReached >= 5 + } + ]; + const title = 'Incrementally enabled wizard example'; + return ( + + ); +}; diff --git a/packages/react-core/src/components/Wizard/examples/WizardValidateOnButtonPress.tsx b/packages/react-core/src/components/Wizard/examples/WizardValidateOnButtonPress.tsx new file mode 100644 index 00000000000..d13172d8f61 --- /dev/null +++ b/packages/react-core/src/components/Wizard/examples/WizardValidateOnButtonPress.tsx @@ -0,0 +1,204 @@ +import React from 'react'; +import { + EmptyState, + EmptyStateIcon, + EmptyStateBody, + EmptyStateSecondaryActions, + Title, + Form, + FormGroup, + TextInput, + Progress, + Button, + Wizard, + WizardFooter, + WizardContextConsumer, + Alert +} from '@patternfly/react-core'; +// eslint-disable-next-line patternfly-react/import-tokens-icons +import { CogsIcon } from '@patternfly/react-icons'; + +interface finishedProps { + onClose: () => void; +} + +const FinishedStep: React.FunctionComponent = (props: finishedProps) => { + const [percent, setPercent] = React.useState(0); + + const tick = () => { + setPercent(prevPercent => { + if (prevPercent < 100) { + return prevPercent + 20; + } else { + return prevPercent; + } + }); + }; + + React.useEffect(() => { + const interval = setInterval(() => tick(), 1000); + + if (percent >= 100) { + clearInterval(interval); + } + + return () => clearInterval(interval); + }, [percent]); + + return ( +
+ + + + {percent === 100 ? 'Validation complete' : 'Validating credentials'} + + + + + + Description can be used to further elaborate on the validation step, or give the user a better idea of how + long the process will take. + + + + + +
+ ); +}; + +interface sampleFormProps { + formValue: string; + isFormValid: boolean; + onChange?: (isValid: boolean, value: string) => void; +} + +const SampleForm: React.FunctionComponent = (props: sampleFormProps) => { + const [value, setValue] = React.useState(props.formValue); + const [isValid, setIsValid] = React.useState(props.isFormValid); + + const handleTextInputChange = (value: string) => { + const valid = /^\d+$/.test(value); + setValue(value); + setIsValid(valid); + props.onChange && props.onChange(valid, value); + }; + + const validated = isValid ? 'default' : 'error'; + + return ( +
+ + + +
+ ); +}; + +export const WizardValidateButtonPress: React.FunctionComponent = () => { + const [isFormValid, setIsFormValid] = React.useState(false); + const [formValue, setFormValue] = React.useState('Validating on button press'); + const [stepsValid, setStepsValid] = React.useState(0); + const [errorText, setErrorText] = React.useState(false); + + const closeWizard = () => { + // eslint-disable-next-line no-console + console.log('close wizard'); + }; + + const onFormChange = (isValid: boolean, value: string) => { + setIsFormValid(isValid); + setFormValue(value); + }; + + const validateLastStep: (onNext: () => void) => void = onNext => { + if (stepsValid !== 1 && !isFormValid) { + setErrorText(true); + } else { + setStepsValid(1); + setErrorText(false); + onNext(); + } + }; + + const steps = [ + { name: 'First step', component:

Step 1 content

}, + { name: 'Second step', component:

Step 2 content

}, + { + name: 'Final Step', + component: ( + <> + {errorText && ( +
+ +
+ )} + + + ) + }, + { name: 'Finish', component: , isFinishedStep: true } + ]; + + const CustomFooter = ( + + + {({ activeStep, goToStepByName, onNext, onBack, onClose }) => { + if (activeStep.name !== 'Final Step') { + return ( + <> + + + + + ); + } + // Final step buttons + return ( + <> + + + + ); + }} + + + ); + + const title = 'Validate on button press wizard example'; + return ( + + ); +}; diff --git a/packages/react-core/src/components/Wizard/examples/WizardWithDrawer.tsx b/packages/react-core/src/components/Wizard/examples/WizardWithDrawer.tsx new file mode 100644 index 00000000000..9a1e134fa9b --- /dev/null +++ b/packages/react-core/src/components/Wizard/examples/WizardWithDrawer.tsx @@ -0,0 +1,126 @@ +import React from 'react'; +import { + Button, + DrawerActions, + DrawerCloseButton, + DrawerColorVariant, + DrawerHead, + DrawerPanelContent, + Wizard +} from '@patternfly/react-core'; + +export const WizardWithDrawer: React.FunctionComponent = () => { + const [isDrawerExpanded, setIsDrawerExpanded] = React.useState(false); + + const drawerRef = React.useRef(null); + + const onOpenClick = () => { + setIsDrawerExpanded(true); + }; + + const onCloseClick = () => { + setIsDrawerExpanded(false); + }; + + const panel1Content = ( + + + + drawer-panel-1 content + + + + + + + ); + + const panel2Content = ( + + + + drawer-panel-2 content + + + + + + + ); + + const panel3Content = ( + + + + drawer-panel-3 content + + + + + + + ); + + const drawerToggleButton = ( + + ); + + const steps = [ + { + name: 'Information', + component:

Information step content

, + drawerPanelContent: panel1Content, + drawerToggleButton + }, + { + name: 'Configuration', + steps: [ + { + name: 'Substep A', + component:

Substep A content

, + drawerPanelContent: panel2Content, + drawerToggleButton + }, + { + name: 'Substep B', + component:

Substep B content

, + drawerPanelContent: panel2Content, + drawerToggleButton + }, + { + name: 'Substep C', + component:

Substep C content

, + drawerPanelContent: panel2Content, + drawerToggleButton + } + ] + }, + { + name: 'Additional', + component:

Additional step content

, + drawerPanelContent: panel3Content, + drawerToggleButton + }, + { + name: 'Review', + component:

Review step content

, + nextButtonText: 'Finish' + } + ]; + + const title = 'Wizard with drawer example'; + + return ( + + + + ); +};