Skip to content

Conversation

@nicolethoen
Copy link
Contributor

@nicolethoen nicolethoen commented Apr 28, 2020

Summary of changes:

To Modal component

  • Uses pf-c-modal-box__title in the modal header if title is provided.
  • Make title prop optional.
  • Add aria-label prop for use if title is not provided.
  • Add noPadding prop to place Modal children in the ModalContent rather than a ModalBody
  • Add 'Modal with wizard' and 'No title' example to docs

To Wizard component

  • Only display wizard header if a title is provided.
  • Added hideClose prop to allow user to hide the close button on wizard header.
  • remove wizard's inPage prop.
  • Update wizard examples. Add in page example showing wizard header with no close button. Add - Wizard in modal example.
  • implemented Wizard's height prop.

Above changes address Core updates:
patternfly/patternfly#2969
patternfly/patternfly#2964

What: Closes #3668

Breaking changes

  • Modal: Remove hideTitle prop. To hide the Modal header, do not pass a title prop, a description prop, or a header prop. If there is no title or header passed, please provide an aria-label prop to the Modal component to make it accessible.
  • Wizard: Remove inPage prop. By default the Wizard will be displayed in page, filling its parent container. If the consumer passes a managed isOpen flag, then the Wizard will be displayed in a modal.

@patternfly-build
Copy link
Collaborator

patternfly-build commented Apr 28, 2020

Copy link
Member

@dlabrecq dlabrecq left a comment

Choose a reason for hiding this comment

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

You can see the adverse effect of the wizard changes in our examples

Screen Shot 2020-04-28 at 10 21 23 AM

Comment on lines -48 to -50
isOpen?: boolean;
/** True to show the wizard without the modal */
isInPage?: boolean;
Copy link
Member

@dlabrecq dlabrecq Apr 28, 2020

Choose a reason for hiding this comment

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

I don't understand why isOpen was removed? Are all wizards now being placed within a modal?

@nicolethoen
Copy link
Contributor Author

@dlabrecq
Yeah, this is a breaking change PR for sure.
The wizard is just a regular component now, filling its parent element. So the steps scroll in the examples for Wizard.

To see the Wizard component in a Modal, there is now an example in the Modal component examples. I could conceivably add it to the wizard examples as well.

The issue I addressed wanted to decouple the Wizard with the Modal component so that it wasn't a second modal implementation.

@nicolethoen
Copy link
Contributor Author

nicolethoen commented Apr 28, 2020

@tlabaj
I added a variant to the Modal so that it can now house a Wizard - you can see it in the examples.
Do we want a variant to the Wizard that puts it in a modal? Do we want variants going both directions?
Easy enough to add. If I add it, do we want it to be in a modal by default? If it is by default - are these changes necessary?

Copy link
Contributor

@redallen redallen left a comment

Choose a reason for hiding this comment

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

I'm liking where this is going~! You can create a wizard.css file with a rule like

.ws-react-c-wizard {
  min-height: 400px;
}

and just import it in Wizard.md to fix the height of the examples in the preview :)

this.descriptionId = `pf-wizard-description-${newId}`;
}

this.state = {
Copy link
Contributor

Choose a reason for hiding this comment

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

If all you're doing is setting state, you don't need a constructor and can just set the class member state.

@redallen
Copy link
Contributor

As for the API, I'm fine with whatever we choose since there aren't that many products using a Wizard:

image

My 2 cents are that we should create a wrapper WizardModal component and export that. I could more easily write codemods for that.

@mcoker
Copy link
Contributor

mcoker commented Apr 28, 2020

This looks great @nicolethoen! A couple of things. In the example where we show the wizard in a modal

  • the large modal size variation is preferred for a wizard in a modal. Can we update the example to use size={ModalVariant.large}?
  • In a modal, the wizard header should be present. That will also introduce a close button.
  • Is disableFocusTrap={true} required with isBasic if there isn't a close button? If I don't add that to the examples, I get an error "You can't have a focus-trap without at least one focusable element". I wonder if we need to call any of that out in the docs?

You can see examples of the size variation and wizard header in the core docs under demos -> wizard - http://patternfly-v4.surge.sh/documentation/core/demos/wizard

@nicolethoen
Copy link
Contributor Author

  • In a modal, the wizard header should be present. That will also introduce a close button.
  • Is disableFocusTrap={true} required with isBasic if there isn't a close button? If I don't add that to the examples, I get an error "You can't have a focus-trap without at least one focusable element". I wonder if we need to call any of that out in the docs?

These are the sorts of things that would actually be solved much easier with a WizardModal wrapper. Because the Wizard needs to know it's in a modal to have these features work correctly. It cannot remain parent agnostic. I will begin implementing a WizardModal component as Zac recommended.

@tlabaj tlabaj added the Breaking change 💥 this change requires a major release and has API changes. label Apr 28, 2020
@nicolethoen nicolethoen force-pushed the wizard_modal_changes branch from 92ade72 to 72d3427 Compare April 29, 2020 12:46
@nicolethoen
Copy link
Contributor Author

  • In a modal, the wizard header should be present. That will also introduce a close button.
  • Is disableFocusTrap={true} required with isBasic if there isn't a close button? If I don't add that to the examples, I get an error "You can't have a focus-trap without at least one focusable element". I wonder if we need to call any of that out in the docs?

These are the sorts of things that would actually be solved much easier with a WizardModal wrapper. Because the Wizard needs to know it's in a modal to have these features work correctly. It cannot remain parent agnostic. I will begin implementing a WizardModal component as Zac recommended.

So, I think I was able to get it to work. If the consumer provides a Title, the WizardHeader will appear. So a Wizard with a Title placed in a Modal with the isBasic flag works like an old Wizard :)

@karelhala
Copy link
Contributor

As an app developer, I wouldn't think to look at the modal component for wizard examples. The previous wizard examples had shown how to launch the wizard.

The wizard component was from the start fundamentally wrong, it's not specific usecase only to modals. It should be a component that can be placed wherever you want and be free with it. Why not placing the wizard component in dropdown? It might sound strange, but the useage of it can be actually pretty nice. As for the demo, the wizard page demo could have an example in modal since that's one usecase, but I wouldn't limit the wizard component to modals only.

I think this is great direction with the wizard compoent, thank you @nicolethoen for taking care of it!

{children}
</ModalBoxBody>
{modalBoxFooter}
{!isBasic && showClose && <ModalBoxCloseButton onClose={onClose} />}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we remove this isBasic prop and unify all these elements into one component?

const ModalBody = () => {
  onst modalBoxHeader = header ? (
    <div className={css(titleStyles.title)}>{header}</div>
  ) : (
    <ModalBoxHeader hideTitle={hideTitle}> {title} </ModalBoxHeader>
  );

  const modalBoxFooter = footer ? (
    <ModalBoxFooter>{footer}</ModalBoxFooter>
  ) : (
    actions.length > 0 && <ModalBoxFooter>{actions}</ModalBoxFooter>
  );
  return <Fragment>
    {showClose && <ModalBoxCloseButton onClose={onClose} />}
    {modalBoxHeader}
    {description && <ModalBoxDescription id={id}>{description}</ModalBoxDescription>}
    <ModalBoxBody {...props} {...(!description && { id })}>
          {children}
        </ModalBoxBody>
    {modalBoxFooter}
</Fragment>
}

This way we won't have a ton of ifs in this component and it can just have children as with any other component.

If we don't want to break backwards compatibility that much we could add prop called bodyWrapper to Modal where you'd by default use ModalBody component, if you'd don't want to use you could pass in null or w/e. The bodyWrapper prop could be either null, string, number, function or node.

@karelhala
Copy link
Contributor

I've had discussion with a few folks about this PR, I really want it to be part of PF, because it can be great example of how to write and export componets as building blocks. However this can eventually be hard to migrate to as we usually have a lot of other things to do instead just fixing breaking changes from component libray.

This PR fixes the linked issue in elegant way, but it will introduce a breaking change and would require from app developers to fix this. There can be another approach to this, it will bloat the PR, but I think it'll help us in the long run:

  • Add new component exported as Wizard that will be just a wrapper that passes down all props except isModal. Based on this prop it'll use Wizard in modal (current way) or modal in page without modal at all (new and proposed way)
  • It would be also beneficial to export a few new components as proposed in the original issue. App devs can then combine these components toger as they choose and as they want.
    • WizardHeader
    • WizardStepper
    • WizardBody
    • WizardInPage - combination of WizardHeader, WizardStepper and WizardBody. This component can by default have these 3 components used trough render funcion so consumers can override these part with their own. Meaning if I don't want to use WizardStepper and I want to implement my own I can do that easilly by adding wizardStepper={(...props) => <div>My awesome stepper</div>}.

@nicolethoen the work you've done here is awesome, it actually led me to these ideas and proposals, without this change we'd probably won't know what would be the ideal outcome of original issue. But I feel like this is the right path. I'd be more than happy to implement it as well, because this might be interesting addition. That being said if you'd need any more information or didn't understood anything, don't hesitate to ask. I'll monitor this PR and try help you as much as I could so we can have this change un in the wilderness soon.

@nicolethoen nicolethoen force-pushed the wizard_modal_changes branch from 72d3427 to 2bd7bfe Compare May 1, 2020 16:19
/** Simple text content of the Modal Header, also used for aria-label on the body */
title: string;
/** Flag to hide the title */
hideTitle?: boolean;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This looks great! Can you please add all the breaking changes to the bottom of your PR? in this form:

## Breaking changes
- Your list of changes.
- You can use MD

}
```

```js title=No-title
Copy link
Collaborator

Choose a reason for hiding this comment

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

the no header and no title examples seem identical?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Lol, yep. That's evident of me experiencing tunnel vision.

}
```

```js title=With-wizard
Copy link
Collaborator

Choose a reason for hiding this comment

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

The Escape button does not seem to be working to close the wizard.

@nicolethoen nicolethoen force-pushed the wizard_modal_changes branch from 7dae4e1 to 3df306c Compare May 4, 2020 16:11
@codecov-io
Copy link

Codecov Report

Merging #4140 into v4 will decrease coverage by 0.79%.
The diff coverage is 73.68%.

Impacted file tree graph

@@            Coverage Diff             @@
##               v4    #4140      +/-   ##
==========================================
- Coverage   58.73%   57.94%   -0.80%     
==========================================
  Files         396      390       -6     
  Lines        6007     5963      -44     
  Branches     2350     2334      -16     
==========================================
- Hits         3528     3455      -73     
- Misses       2022     2060      +38     
+ Partials      457      448       -9     
Flag Coverage Δ
#patternfly4 57.94% <73.68%> (-0.80%) ⬇️
Impacted Files Coverage Δ
...tension/src/components/CatalogTile/CatalogTile.tsx 79.16% <ø> (ø)
packages/react-core/src/helpers/util.ts 46.66% <ø> (ø)
...es/react-table/src/components/Table/RowWrapper.tsx 67.85% <ø> (-1.11%) ⬇️
...src/components/Table/utils/decorators/cellWidth.ts 100.00% <ø> (ø)
...-table/src/components/Table/utils/transformers.tsx 100.00% <ø> (ø)
...kages/react-core/src/components/Modal/ModalBox.tsx 55.55% <33.33%> (-11.12%) ⬇️
...eact-core/src/components/Toolbar/ToolbarFilter.tsx 8.00% <50.00%> (ø)
.../react-core/src/components/Toolbar/ToolbarItem.tsx 60.00% <50.00%> (ø)
...core/src/components/Toolbar/ToolbarToggleGroup.tsx 23.52% <50.00%> (ø)
...ckages/react-core/src/components/Wizard/Wizard.tsx 44.52% <53.84%> (-1.37%) ⬇️
... and 23 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2ed8b95...44dbf15. Read the comment docs.

<div className={css(titleStyles.title)}>{header}</div>
) : (
<ModalBoxHeader hideTitle={hideTitle}> {title} </ModalBoxHeader>
title && <div className={css(styles.modalBoxTitle)}>{title}</div>
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it might be good to keep the ModalBoxHeader and just update it. This way, existing consumers won't be too broken

@nicolethoen nicolethoen force-pushed the wizard_modal_changes branch from 44dbf15 to 4fa074a Compare May 4, 2020 19:01
Copy link
Collaborator

@jschuler jschuler left a comment

Choose a reason for hiding this comment

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

LGTM!

Copy link
Contributor

@redallen redallen left a comment

Choose a reason for hiding this comment

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

This API is a crowd pleaser!

@redallen redallen dismissed dlabrecq’s stale review May 4, 2020 19:58

Examples had min-height added.

target.appendChild(this.container);
}
this.toggleSiblingsFromScreenReaders(true);
const target = (typeof document !== 'undefined' && document.body) || null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Creative way to write a ternary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

lol I guess I too quickly borrowed the logic from a different part of the code :P

/** Variant of the modal */
variant?: 'small' | 'large' | 'default';
/** Flag indicating if modal content should have no padding*/
noPadding?: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if this prop name is too generic and might overlap or be confusing with other props we could introduce into the modal, like one that removes all padding from the modal, or just the padding from the <ModalBoxBody> element. I have seen potential use cases for the former.

Technically this prop removes the <ModalBoxBody> element all together.

Here is what it looks like now with regular modal content and noPadding

Screen Shot 2020-05-04 at 3 46 26 PM

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hm... would it makes sense to have it be called noModalBoxBody? Would that make sense to a consumer? Could something like removeBody make more sense?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, noModalBoxBody definitely isn't as easy of a name, though it's a more accurate description of what it does. Or maybe noModalBoxBodyWrapper since you can still pass content and it puts it where the body would go. noModalBoxBody and removeBody could be confused with the modal having no body content. At any rate, I think as long as we document it, any of those names seem OK to me. I'm interested in others' thoughts.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I could go with noModalBoxBodyWrapper... it's a mouthful.
@tlabaj @jschuler @dlabrecq any thoughts?

@mcoker
Copy link
Contributor

mcoker commented May 4, 2020

Should we remove the description prop from wizard examples that don't also have a title, since description will only show up if you have a title?

Copy link
Contributor

@mcoker mcoker left a comment

Choose a reason for hiding this comment

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

Looks good to me! Thanks for all of your hard work on this @nicolethoen!

Copy link
Contributor

@karelhala karelhala left a comment

Choose a reason for hiding this comment

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

Looking good! I am wondering if we could also somehow export helper functions this.goToStepById, this.goToStepByName, this.onNext and this.onBack. No need to be part of this PR at all! But it would make the further usage of smaller building blocks much easier.

Copy link
Contributor

@redallen redallen left a comment

Choose a reason for hiding this comment

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

I love seeing more lines removed than added :)

Thanks for the refactor @nicolethoen !

@redallen redallen merged commit a6f4431 into patternfly:v4 May 5, 2020
@patternfly-build
Copy link
Collaborator

Your changes have been released in:

  • @patternfly/react-catalog-view-extension@4.2.18
  • @patternfly/react-core@4.9.12
  • @patternfly/react-docs@5.2.22
  • @patternfly/react-inline-edit-extension@4.3.18
  • demo-app-ts@4.6.15
  • @patternfly/react-integration@4.6.5
  • @patternfly/react-table@4.3.18
  • @patternfly/react-topology@4.2.18
  • @patternfly/react-virtualized-extension@4.2.18

Thanks for your contribution! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Breaking change 💥 this change requires a major release and has API changes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wizard: The wizard is another implementation of modal

9 participants