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

Update ways of configuring menu attributes #650

Merged
merged 4 commits into from Feb 12, 2024

Conversation

romaricpascal
Copy link
Member

@romaricpascal romaricpascal commented Jan 26, 2024

Prevent the attributes set through menuAttributes from overriding any of the attributes set internally:

  • id and role are dropped to limit risks to accessibility
  • className and class are appended to the class attribute of the menu so it keeps the classes computed by the component

In addition to the update to menuAttributes, the PR also adds a menuClasses. Even if it doubles with with menuAttributes.(class|className), it provides a API with a name consistent with inputClasses and hintClasses from #649 .

@romaricpascal romaricpascal force-pushed the menu-attributes-update branch 4 times, most recently from de4763e to 7cfc175 Compare January 26, 2024 16:56
@@ -57,6 +57,10 @@
.custom-hint-class {
box-shadow: inset 0 0 0 5px #44952e;
}

.custom-menu-class {
box-shadow: 0 3px 0 0 #fd0, 3px 3px 0 0 #fd0, -3px 3px 0 0 #fd0;
Copy link
Member Author

Choose a reason for hiding this comment

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

Bit wordy, but extends the yellow focus border to wrap around the menu, not just the input, for a nice visual change.

src/autocomplete.js Outdated Show resolved Hide resolved
@romaricpascal romaricpascal marked this pull request as ready for review January 26, 2024 16:57
@romaricpascal romaricpascal added this to the Next milestone Jan 26, 2024
const menuIsVisible = menuOpen || showNoOptionsFound
const menuModifierVisibility = `${menuClassName}--${(menuIsVisible) ? 'visible' : 'hidden'}`

const safeMenuAttributes = sanitiseMenuAttributes(menuAttributes || {})
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 lots of new sanitisation code, can we overwrite role/id instead?

menuAttributes.id = id
menuAttributes.role = role

Copy link
Member Author

Choose a reason for hiding this comment

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

That's a good idea for avoiding to delete the id and the role, didn't think of that. We could do the same with class and className (we'd need to set both, but I don't think that's a massive issue. Could try setting one to null depending on how things work with React/Preact).

I'd still be keen to clone the object to avoid modifying the prop we're given, or do you think it's over the top?

Copy link
Contributor

Choose a reason for hiding this comment

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

With object spread?

We had {...menuAttributes} on line 538 previously:

https://github.com/alphagov/accessible-autocomplete/blob/40350ae89328e813cc9437e4aac8d52ef813dd4a/src/autocomplete.js#L538C11-L538C30

Are you thinking to overwrite role/id with {...menuAttributes, id, role} instead?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, just with an object spread, so that when we set the id or role, it doesn't leak the modifications to the object that was passed as props directly. Thinking this'll end up with something like:

// Compute the menu classes from the array
// including `menuAttributes.class` and `menuAttributes.className`
const menuClasses = ...

const computedMenuAttributes = {
  ...menuAttributes,
  // Override the attributes the component computes
  id: `${id}__listbox`,
  role: 'listbox',
  className: menuClasses.join(' ')
}

// Figure a way to delete the `class` property
delete computedMenuAttributes.class

// Then in the JSX, leaving the handler here for consistency with the other elements
// whose handlers are set  in JSX. But could equaly go in `computedMenuAttributes` as well.
<ul 
	onMouseLeave={(event) => this.handleListMouseLeave(event)}
	{...computedMenuAttributes} >

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated with something of the shape I described. Moved onMouseLeave in the computedAttributes to make the JSX on one line in the end.

src/autocomplete.js Outdated Show resolved Hide resolved
@romaricpascal romaricpascal force-pushed the styling-props branch 2 times, most recently from b972a2d to d1967d5 Compare January 29, 2024 09:55
in anticipation of pushing optional values to the array before it's joined in the JSX
id: `${id}__listbox`,
role: 'listbox',
className: menuClassList.join(' '),
onMouseLeave: this.handleListMouseLeave
Copy link
Member Author

Choose a reason for hiding this comment

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

Removed the wrapping arrow function, as the handler is bound in the constructor already, so that'll save re-creating listeners each time the menu is re-rendered.

Copy link
Contributor

Choose a reason for hiding this comment

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

Shall we do the same to handleInputClick?

README.md Outdated Show resolved Hide resolved
Base automatically changed from styling-props to main January 30, 2024 16:52
README.md Outdated
Comment on lines 214 to 216
> This option will not override the attributes computed by the component
> - `id` and `role` are dropped to limit risks to accessibility
> - `className` and `class` are appended to the `class` attribute of the menu so it keeps the classes computed by the component
Copy link
Contributor

Choose a reason for hiding this comment

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

I've had a go at re-wording this to include all three id, role and onMouseLeave

Good to explain and link to menuClasses too? Don't worry about explaining the class/className difference since we haven't already done so in the dropdownArrow docs

Suggested change
> This option will not override the attributes computed by the component
> - `id` and `role` are dropped to limit risks to accessibility
> - `className` and `class` are appended to the `class` attribute of the menu so it keeps the classes computed by the component
> To maintain assistive technology support, menu attributes `id`, `role` and `onMouseLeave` cannot be overridden using `menuAttributes`. Setting `className` will append to the component default and [`menuClasses`](#menuClasses) values.

Comment on lines 505 to 507
if (menuAttributes?.className) {
menuClassList.push(menuAttributes.className)
}

if (menuAttributes?.class) {
menuClassList.push(menuAttributes.class)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like class takes precedence in Preact, rather than allowing both?

Suggested change
if (menuAttributes?.className) {
menuClassList.push(menuAttributes.className)
}
if (menuAttributes?.class) {
menuClassList.push(menuAttributes.class)
}
if (menuAttributes?.class || menuAttributes?.className) {
menuClassList.push(menuAttributes?.class || menuAttributes?.className)
}

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, that's a good shout. I'll amend 😊

Copy link
Member Author

Choose a reason for hiding this comment

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

Added extra test cases while I was at it.

@romaricpascal
Copy link
Member Author

@colinrotherham Things should be all tidy. The first force-push has the interesting changes, the second being just the tidy up of a stray comma that standard wasn't happy with 😬

README.md Outdated

Type: `string | null`

Adds custom html classes to the menu elements.
Copy link
Contributor

Choose a reason for hiding this comment

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

We just say "menu" elsewhere but should we fix elements → element, or be specific like menuAttributes?

Suggested change
Adds custom html classes to the menu elements.
Adds custom html classes to the generated `ul` menu element.

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated both here and for menuAttributes 😊

Copy link
Contributor

Choose a reason for hiding this comment

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

Even better, thank you

@romaricpascal romaricpascal merged commit 9079e77 into main Feb 12, 2024
3 checks passed
@romaricpascal romaricpascal deleted the menu-attributes-update branch February 12, 2024 10:46
@romaricpascal romaricpascal mentioned this pull request Apr 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done 🏁
Development

Successfully merging this pull request may close these issues.

None yet

2 participants