feat: Add dialog component - #4904
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4904 +/- ##
=======================================
Coverage 97.66% 97.67%
=======================================
Files 959 963 +4
Lines 31345 31421 +76
Branches 11579 11604 +25
=======================================
+ Hits 30614 30689 +75
- Misses 724 725 +1
Partials 7 7 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
4fb0a5e to
f87b9bc
Compare
f87b9bc to
5f24213
Compare
5f24213 to
2133113
Compare
2133113 to
e62996c
Compare
e62996c to
4cd8d21
Compare
4cd8d21 to
97f9d8a
Compare
|
|
||
| export namespace DialogProps { | ||
| export interface DismissDetail { | ||
| reason: string; |
There was a problem hiding this comment.
Do we call this field "reason" in some other components? E.g. in the Drawer a similar prop is called "method".
Why does it have a string type and not a union of possible values?
There was a problem hiding this comment.
Also take a look at how we name the values in other components - e.g. should we use "closeButton" or "close-button" (I'd argue we also need to call it "dismiss-button" to match the terminology used in the component).
There was a problem hiding this comment.
Thinking some more about dialog dismissal - is there any good reason to prevent dialog from closing on-escape, while keeping the dismiss button? If we don't have any use cases - let's remove the property, too.
If in the future we allow hiding the dismiss button - then we should disable the on-escape dismissal, too - relying on consumers to provide it if needed.
There was a problem hiding this comment.
The DismissDetails with reason as a strign is similar to the API in modal
components/src/modal/interfaces.ts
Line 114 in e404a45
closeButton and keyboard is also similar to the modal. I think adding the reason is beneficial if customers need to control the closing behavior when it is triggered by escape.
There was a problem hiding this comment.
The reason is a string (like Modal) instead of a union. The detail is an output type we can't widen later, so a union would lock the members and we couldn't add a future dismiss reason without a breaking change. string keeps it forward compatible. New reasons can be added later, with the current values (closeButton, escape) documented in the JSDoc if needed.
That said, I'm also fine dropping reason for now since we don't have a consumer for it yet. Adding a detail property later is non breaking, so we lose nothing by waiting and adding it when a real use case defines the shape. Happy to go either way.
There was a problem hiding this comment.
Thanks, I did not realise we use the same API in the modal already - that is a good call out. We can do the same for consistency in this case, but I'd still wait for the use cases. When dismiss button is not optional - the reason prop should not be needed.
| @@ -125,6 +125,7 @@ const tokens: StyleDictionary.ColorsDictionary = { | |||
| colorBackgroundAlertSuccess: '{colorBackgroundStatusSuccess}', | |||
| colorBackgroundAlertWarning: '{colorBackgroundStatusWarning}', | |||
| colorBackgroundDialog: '{colorBackgroundStatusInfo}', | |||
There was a problem hiding this comment.
Kept the existing public colorBackgroundDialog unchanged and added a private colorBackgroundDialogDefault token for the new Dialog component.
|
|
||
| const dismissDialog = () => { | ||
| setOpen(false); | ||
| window.setTimeout(() => focusTargetRef.current?.focus(), 0); |
There was a problem hiding this comment.
Can we avoid having setTimeout here?
What if the original target element is available, but the consumer intent is to move the focus elsewhere - will then both elements be focused in a close sequence? Can this trigger extra announcement by the screen reader?
There was a problem hiding this comment.
Yes, we don’t need setTimeout. I updated the example to move focus when Dialog transitions from open to closed. Our Focus management principles recommend returning focus to the trigger when it is still available. If it no longer exists, the builder should move focus programmatically to a logical fallback, usually the next focusable element in the DOM order. This example covers the latter case and does not override an available trigger. If a customer intentionally overrides restoration while the original trigger still exists, both elements could receive focus in sequence and cause an additional announcement as you mentioned.
Description
Adds an inline, non-modal Dialog component for in-context prompts, authorizations, and feedback. Dialog supports header actions, content, and footer slots, keeps the surrounding page interactive, manages initial and restored focus, and supports dismissal through the close button and Escape.
Related links, issue #, if available: 6f6tUHjL27wB - doc
How has this been tested?
Review checklist
The following items are to be evaluated by the author(s) and the reviewer(s).
Correctness
CONTRIBUTING.md.CONTRIBUTING.md.Security
checkSafeUrlfunction.Testing
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.