Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Blue dialog code snippet #2923

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open

Conversation

laveshv
Copy link

@laveshv laveshv commented Oct 22, 2024

Description

Related links, issue #, if available: n/a

How has this been tested?

Review checklist

The following items are to be evaluated by the author(s) and the reviewer(s).

Correctness

  • Changes include appropriate documentation updates.
  • Changes are backward-compatible if not indicated, see CONTRIBUTING.md.
  • Changes do not include unsupported browser features, see CONTRIBUTING.md.
  • Changes were manually tested for accessibility, see accessibility guidelines.

Security

Testing

  • Changes are covered with new/existing unit tests?
  • Changes are covered with new/existing integration tests?

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@laveshv laveshv requested a review from a team as a code owner October 22, 2024 20:33
@laveshv laveshv requested review from YueyingLu and removed request for a team October 22, 2024 20:33
setShowDialog(false);
}

return showDialog ? (
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's not remove the dialog at all, we can console.log instead. I think overall the example here could be simpler.

Copy link
Author

Choose a reason for hiding this comment

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

Done in latest revision.

}

return showDialog ? (
<div className={styles['blue-dialog-box']}>
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see the a11y requirements being addressed.

Copy link
Author

Choose a reason for hiding this comment

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

I added some a11y specific code. Can you please review?

@cansuaa cansuaa changed the title Bluedialog Initial commit feat: Blue dialog code snippet Oct 24, 2024
Comment on lines 8 to 9
margin-block: 20px;
margin-inline: 20px;
border-block: 1px solid awsui.$color-border-status-info;
border-inline: 1px solid awsui.$color-border-status-info;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not just margin and border? Is margin even needed?

Copy link
Author

Choose a reason for hiding this comment

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

margin and border are disallowed in the lint settings -> https://github.com/cloudscape-design/components/blob/main/.stylelintrc#L59C39-L59C74

Actually, we can remove the margin. Just that it wasn't looking very good on my whole page. It was spreading on the whole page. So, I introduced it.

Comment on lines 34 to 33
padding-block: 10px;
padding-inline: 10px;
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here

Copy link
Author

Choose a reason for hiding this comment

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

role={'dialog'}
aria-labelledby="dialog-title"
aria-modal="false" // Maintains natural focus flow since it's an inline dialog
tabIndex={-1} // This allows the dialog to receive focus
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe the value should be 0 not -1

Copy link
Member

Choose a reason for hiding this comment

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

-1 means the dialog can only be focused programmatically which is good for one-time focus when it appears. I think making it user-focusable is not needed.

Copy link
Member

Choose a reason for hiding this comment

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

In either case, it would be great to show this focusing behaviour in action.

Copy link

codecov bot commented Oct 29, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 96.40%. Comparing base (b3e4bf7) to head (793d280).
Report is 8 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2923   +/-   ##
=======================================
  Coverage   96.40%   96.40%           
=======================================
  Files         784      784           
  Lines       22136    22138    +2     
  Branches     7190     7190           
=======================================
+ Hits        21341    21343    +2     
  Misses        788      788           
  Partials        7        7           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

aria-modal="false" // Maintains natural focus flow since it's an inline dialog
tabIndex={-1} // This allows the dialog to receive focus
>
<Form
Copy link
Member

Choose a reason for hiding this comment

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

Should we also use a semantic form element and support onSubmit?

Copy link
Author

Choose a reason for hiding this comment

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

Actually we can, but then I did not see the onSubmit event in the

component of clouscape, so wanted to navigate away from that practice. Also, it adds some over burden of styling that semantic element.


import styles from './styles.scss';

export default function Bluedialogbox() {
Copy link
Member

Choose a reason for hiding this comment

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

Should we separate page and component?

Say, we can have some BluedialogPage that renders the screenshot area maybe and some additional heading (needed for a11y static checks anyways) etc. and the Bluedialog component that can also take some onSubmit/onCancel props and maybe some other, showcasing the actual design of the component?

Copy link
Author

@laveshv laveshv Oct 29, 2024

Choose a reason for hiding this comment

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

Actually, the approach that we decided was that we will not create any built-in component for this request. This whole tasks would be to just create a code snippet that the users can copy and use, with minimum changes from their end.

Also, I think this folder, might not be the right place for this code. So, please feel free to suggest if there is a better place to put these files

Copy link
Contributor

@cansuaa cansuaa Nov 4, 2024

Choose a reason for hiding this comment

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

I believe Andrei's suggesting to do it this way so that customers would directly be able to copy the "component". Similarly the reason why he suggested to put the functions like onCancel outside of the "component"


useEffect(() => {
// Store the element that had focus before dialog opened
triggerRef.current = document.activeElement as HTMLElement;
Copy link
Member

Choose a reason for hiding this comment

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

If the dialog is opened programmatically this transition can be weird. Would it be better to handle the focus transition on the outside? If the parent component provides onSubmit/onCancel then the focus transition can be done as part of it:

function ParentComponent() {
  // ...
  
  function returnFocus() {
    sendButtonRef.current?.focus()
  }
  
  function onSubmit() {
    // submit
    returnFocus();
  }
  
  function onCancel() {
    // cancel
    returnFocus();
  }
  
  return (
    <div>
      // ...
      <Bluedialog onSubmit={onSubmit} onCancel={onCancel} />
    </div>
  );
}

Copy link
Author

Choose a reason for hiding this comment

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

Like I mentioned previously, this is just a code snippet. It is upto the individual users on how they want to use it.

@cansuaa cansuaa marked this pull request as draft October 29, 2024 14:11
@cansuaa cansuaa removed the request for review from YueyingLu October 29, 2024 14:11
@laveshv
Copy link
Author

laveshv commented Oct 30, 2024

I refactored this little code little bit. Converted BluedialogPage into a parent page and move all its code to child component dialog

@laveshv laveshv marked this pull request as ready for review October 30, 2024 21:13
@cansuaa cansuaa marked this pull request as draft November 4, 2024 13:42
@laveshv laveshv marked this pull request as ready for review December 20, 2024 01:46
@laveshv
Copy link
Author

laveshv commented Dec 20, 2024

Screenshot 2024-12-19 at 6 01 58 PM
Attching screenshot for reference

Comment on lines +13 to +18
const [feedbackOptions, setFeedbackOptions] = React.useState({
harmful: false,
incomplete: false,
inaccurate: false,
other: false,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of this you can have selectedFeedbackOption where you set the value to one of harmful, incomplete, etc. That way you won't need to spread objects during state setting below and it'll be easier to understand. What do you think?

Copy link
Author

Choose a reason for hiding this comment

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

I think this needs to be a multi select, where one or more options can be selected at a time. Hence, I chose to maintain a separate property for each option.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh right multi choice makes sense in this case.

Comment on lines +37 to +39
function submitData() {
onSubmit({ feedbackOptions, feedbackText });
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we could add validation here to ensure one of the checkboxes are selected before submission

Copy link
Author

Choose a reason for hiding this comment

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

I was not aware of this use case. Hence avoided it to leave it on the user's choice. I will implement it in the new revision.

Copy link
Author

@laveshv laveshv Jan 7, 2025

Choose a reason for hiding this comment

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

Actually, I am not sure how we want to handle it. This needs to be discussed if there can be a use case where we don't want to select any option, but just want to submit the 'Tell us more' section. Will implement it after discussion.

Copy link
Contributor

Choose a reason for hiding this comment

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

But "Tell us more" is optional. I believe at least one of the boxes should be checked but we can discuss it.

<div
className={styles['blue-dialog-box']}
role={'dialog'}
aria-labelledby="dialog-title"
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see a corresponding element to dialog-title? Instead we could use aria-label and set it to "Feedback dialog"?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, I think I forgot to edit it, from previous suggested change. Made the change in new revision.

tabIndex={-1} // This allows the dialog to receive focus
>
<Form>
<div className={styles['blue-dialog-box__content']}>
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Author

@laveshv laveshv Jan 6, 2025

Choose a reason for hiding this comment

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

I thought of using Box, but doesn't allow me add css class to it. It gives me more control to use div here. I also see this practice in other components as well.

<Form>
<div className={styles['blue-dialog-box__content']}>
<SpaceBetween direction="vertical" size="l">
<FormField label="What did you dislike about the response?">
Copy link
Contributor

Choose a reason for hiding this comment

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

We still need to show a dismiss button

Copy link
Author

Choose a reason for hiding this comment

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

Done in the new Revision. Thanks for pointing it out

Copy link
Author

@laveshv laveshv left a comment

Choose a reason for hiding this comment

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

Addressed comments on previous revision

<div
className={styles['blue-dialog-box']}
role={'dialog'}
aria-labelledby="feedback dialog"
Copy link
Contributor

Choose a reason for hiding this comment

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

feedback-dialog is not defined anywhere, could you replace this with aria-label?

Comment on lines +13 to +18
const [feedbackOptions, setFeedbackOptions] = React.useState({
harmful: false,
incomplete: false,
inaccurate: false,
other: false,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

Oh right multi choice makes sense in this case.


// Focus the dialog container when it opens
if (dialogRef.current) {
dialogRef.current.focus();
Copy link
Member

Choose a reason for hiding this comment

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

The dialog ref is not assigned anywhere so this code does nothing.


useEffect(() => {
// Store the element that had focus before dialog opened
triggerRef.current = document.activeElement as HTMLElement;
Copy link
Member

Choose a reason for hiding this comment

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

Would it make more sense to handle the focus management from the outside using the onSkip? Otherwise there are corner cases like if the trigger disappears after opening the dialog etc. that are not covered by this approach. Or, if the dialog opens after an async transition or automatically - the last focused element might not be related to the dialog at all.


.blue-dialog-box__footer {
border-block-start: 1px solid awsui.$color-border-divider-default;
padding-block: 10px;
Copy link
Member

Choose a reason for hiding this comment

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

can we use design tokens here?

border-block: 1px solid awsui.$color-border-status-info;
border-inline: 1px solid awsui.$color-border-status-info;
background-color: awsui.$color-background-status-info;
border-start-start-radius: 16px;
Copy link
Member

Choose a reason for hiding this comment

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

can we use $border-radius-container here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants