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

Foundation: update templates for structure and consistency #6286

Closed
wants to merge 5 commits into from

Conversation

bheston
Copy link
Collaborator

@bheston bheston commented Aug 16, 2022

Pull Request

📖 Description

As part of the next major release of fast-foundation, we wanted to do a complete review of the component templates and align the structure and naming as much as possible.

This PR unifies the naming and cleans up some test styles, especially around the recent update to the start and end slots.

Before on the left, update on the right. "C" = class, "P" = part, "R" = role, "S" = slot. 💔 = potentially style-breaking.

Simple containers

Accordion (migrated to #6796)

  • Remove unused <template> wrapper

Accordion

Complex containers

Breadcrumb (migrated to #6797)

  • Add "start" and "end" slots

Breadcrumb

Dialog

  • 💔 Flatten "positioning-region" element to host

Dialog

Disclosure

  • Update to use "start" and "end" helpers
  • 💔 Rename “disclosure” to “details”
  • 💔 Rename “invoker” to “summary”
  • 💔 Rename “disclosure-content” to “content”
  • Add part to "details", "summary", and "content"

Disclosure

Radio group

  • 💔 Rename “positioning-region” to “control”
  • 💔 Remove “horizontal” or “vertical” class, use attribute on host instead

Radio group

Toolbar

  • 💔 Rename “positioning-region” to “control”

Toolbar

Inputs

Number field (migrated to #6798)

  • 💔 Rename “control” to “field”
  • 💔 Rename “root” to “control”
  • 💔 Rename “controls” to “step-buttons”
  • 💔 Rename “step-up-glyph” to “step-up-icon”
  • 💔 Rename “step-down-glyph” to “step-down-icon”

Number field

Search (migrated to #6798)

  • 💔 Rename “control” to “field”
  • 💔 Rename “root” to “control”
  • 💔 Remove “input-wrapper”
  • 💔 Rename “clear-glyph” to “clear-icon”

Search

Switch (migrated to #6798)

  • 💔 Rename “switch” to “control”
  • 💔 Rename "switch" slot to "thumb"
  • Add default "thumb" with class and part

Switch

Text area (migrated to #6798)

  • 💔 Rename “control” to “field”
  • Add wrapper element “control”
  • Add "start" and "end" slots

Text area

Text field (migrated to #6798)

  • 💔 Rename “control” to “field”
  • 💔 Rename “root” to “control”

Text field

Start, content, end pattern

Badge (migrated to #6797)

  • Add "start" and "end" slots
  • 💔 Rename “control” to “content”

Badge

Breadcrumb item (migrated to #6797)

  • 💔 Flatten “listitem” div to template

Breadcrumb item

Tab

  • Wrap default slot in “content”

Tab

Items with children

Accordion item (migrated to #6796)

  • 💔 Rename “icon” to “expand-collapse-icon”
  • 💔 Move “start”, "end", and "expand-collapse-icon" inside “button”
  • 💔 Rename "region" class and part to "panel"

Accordion item

Combobox

  • 💔 Rename “indicator” to “open-close-icon” (slot and wrapper)
  • 💔 Move “open-close-icon” outside of “control” slot
  • 💔 Move “end” slot before “open-close-icon”
  • 💔 Rename "selected-value" to "field"
  • 💔 Rename "control" slot to "field"

Combobox

Horizontal scroll (migrated to #6921)

  • 💔 Rename "content-container" to "content"
  • 💔 Rename "scroll-prev" to "scroll-previous"
  • 💔 Remove "scroll-action" containers
  • Add default flipper content with parts

Horizontal scroll

Menu item

  • 💔 Remove “input-container”
  • 💔 Rename “checkbox” to “checkbox-indicator”
  • 💔 Rename “radio” to “radio-indicator”
  • 💔 Remove “expand-collapse-glyph-container”
  • 💔 Rename “expand-collapse” to “submenu-icon”
  • 💔 Rename “expand-collapse-indicator” to “submenu-icon”

Menu item

Select

  • 💔 Align to ARIA spec
  • 💔 Rename “indicator” to “open-close-icon” (slot and wrapper)
  • 💔 Remove “control” container
  • 💔 Move “open-close-icon” outside of “control” container
  • 💔 Add "button" element inside "button-container"
  • 💔 Move "start" and “end” slots into "button"
  • Add "listbox-container" slot

Select

Tree item

  • 💔 Remove “positioning-region” element
  • 💔 Rename “content-region” to “control”
  • 💔 Rename “expand-collapse-glyph” to “expand-collapse-icon”
  • Add “content” wrapper around default slot

Tree item

Everything else

Avatar

  • 💔 Remove "backplate" container
  • Add "content" wrapper around default slot

Avatar

Progress (migrated to #6799)

  • 💔 Rename "progress" container to "determinate" and "indeterminate"
  • 💔 Change “determinate” div to slot
  • 💔 Remove “indeterminateIndicator2” option

Progress

Progress ring (migrated to #6799)

  • 💔 Follow Progress structure

Progress ring

Slider (migrated to #6800)

  • 💔 Rename “track-container” part to “track”
  • Add default "thumb" with class and part
  • 💔 Remove duplicate class (orientation) on root template element

Slider

Slider label (migrated to #6800)

  • 💔 Flatten “container” and “root”
  • 💔 Rename “label” to “content”
  • Add part to "mark" and "content"

Slider label

👩‍💻 Reviewer Notes

Review the Storybook site, or the illustrations of the components before and after, compared to the changes in code.

📑 Test Plan

Tested via comparison against proposal and in Storybook.

✅ Checklist

General

  • I have included a change request file using $ yarn change
  • I have added tests for my changes.
  • I have tested my changes.
  • I have updated the project documentation to reflect my changes.
  • I have read the CONTRIBUTING documentation and followed the standards for this project.

Component-specific

  • I have added a new component
  • I have modified an existing component

@EisenbergEffect
Copy link
Contributor

I don't have strong opinions on how these should be structured. That's more the area of @chrisdholt. I'll just review the code itself independent of those decisions.

@@ -7,31 +7,29 @@ import type { FASTDialog } from "./dialog.js";
*/
export function dialogTemplate(): ElementViewTemplate<FASTDialog> {
return html<FASTDialog>`
<div class="positioning-region" part="positioning-region">
Copy link
Member

Choose a reason for hiding this comment

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

This is one I'll need to pull down and play with to put it through it's paces, but moving that to the host here should work for all considerations I can think of.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It worked for the ones I considered as well. There's a note in the spec about why it was structured that way, but I couldn't find a way it didn't work like this.

Comment on lines 33 to 72
<div part="input-container" class="input-container">
<span part="checkbox" class="checkbox">
<slot name="checkbox-indicator">
${options.checkboxIndicator || ""}
</slot>
</span>
</div>
<span part="checkbox-indicator" class="checkbox-indicator">
<slot name="checkbox-indicator">
${options.checkboxIndicator || checkboxIndicator}
</slot>
</span>
`
)}
${when(
x => x.role === MenuItemRole.menuitemradio,
html<FASTMenuItem>`
<div part="input-container" class="input-container">
<span part="radio" class="radio">
<slot name="radio-indicator">
${options.radioIndicator || ""}
</slot>
</span>
</div>
<span part="radio-indicator" class="radio-indicator">
<slot name="radio-indicator">
${options.radioIndicator || radioIndicator}
</slot>
</span>
Copy link
Member

Choose a reason for hiding this comment

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

These are both typically in the same spot because an item is either a menuitem, menuitemcheckbox, or menuitemradio, so I'm wondering if we can simplify this with something that serves a single indicator but sets the class and part based on its role. So a single conditional check with the part/class set based on the role. Thoughts? I think it simplifies the template and still accomplishes the same thing.

Copy link
Member

Choose a reason for hiding this comment

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

Actually, I think we may only need one of these and I think it should likely still be called checked-indicator.

While I know that the initial fast-components made these look like a checkbox and an radio, the actual indicator represents the checked state of either an element with one of the checkable roles. I'd like to dig in here, because I think this can simplify and while someone may choose to make it look like one or the other, that's also primarily state based that can be handled in styles or using a when directive from the view to manage sending alternative svg's here. In other implementations, it may be the same SVG, but the behavior only allows single selection.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

See my comment on progress for one potential way to slim down this block by removing the slot. I don't see a case for individual components to slot in a custom indicator here.

I do think it's beneficial to be able to provide the icons individually, the same icon if that's what your design called for, but I think it's good UX to have different icons. I'd hate to see the css get messier to accommodate a minor reduction.

Copy link
Member

Choose a reason for hiding this comment

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

Again, I don't think that is prohibited by having a singular slot. These could be handled in configuration using a when directive without needing to hoist that requirement to all implementations. If the goal is whether we can accomplish what you've stated above I think we should use the most concise method of addressing that. I commented below but the removal of slots in general is a non-starter. The options don't replace it, they provide a method of configuring a global default. That helps for "menu" but if I need to configure something else there in a one-off scenario, the slot is still massively more useful.

Copy link
Contributor

Choose a reason for hiding this comment

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

A couple of thoughts here.

  • Let's decouple the icons as mentioned above.
  • Should we make raio/checkbox support an option and only compose those in if present? We could make this really simple. See the label options sampele above.

If we keep radio/checkbox in by default, I think we should remove the use of the double when and instead just render a property that returns a template based on a single condition check. That will be slightly better in terms of performance.

Copy link
Member

Choose a reason for hiding this comment

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

Yes ^ - My big question here is whether the better ergonomic is baking the conditional rendering in or letting that be handled by the person implementing. On one hand, in the case I don't need two I need to pass the same thing twice. Alternatively, if I have two different SVG's I can handle my own when, right? Does one match our composition value more than the other?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'd love to find a way to slim down the template here if that's what @EisenbergEffect's last comment suggests. I'm not sure I am seeing the exact change though.

From a component framework perspective, the person authoring the component doesn't know if someone is going to use checkbox or radio or not. Since the component supports this to fully support the ARIA spec it should also have a clear way to have two different indicators. This should be easy without having to worry about it for each menu you implement.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've consolidated this to a single conditional using the pattern from Flipper.

I understand that someone may not always need checked functionality, and the only feasible solution I see for that is using the template builder to exclude it. For now we have that role capability built in.

From a visual perspective, it's bad usability for two things that operate differently to have the same look, so I can't in good conscience agree with a solution where the easy default is to treat them the same. The fact that they both relate to the checked state is not the sole decision or the ARIA spec could have omitted the two roles and encouraged people to implement radio functionality in code.

This is at least better than what we had, and if we want to consider changing this, though my vote is not to, we should pull it into a new issue.

Comment on lines 68 to 63
${when(
x => x.hasSubmenu,
html<FASTMenuItem>`
<div
part="expand-collapse-glyph-container"
class="expand-collapse-glyph-container"
>
<span part="expand-collapse" class="expand-collapse">
<slot name="expand-collapse-indicator">
${options.expandCollapseGlyph || ""}
</slot>
</span>
</div>
<span part="submenu-icon" class="submenu-icon">
<slot name="submenu-icon">
${options.submenuIcon || submenuIcon}
</slot>
</span>
Copy link
Member

Choose a reason for hiding this comment

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

@EisenbergEffect do you think this and the below code snippet might be a good candidate for one of the new conditional directives?

Copy link
Member

Choose a reason for hiding this comment

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

Note that the expanded check changes with the menu updates i have in the RFC for removing anchored region...

Copy link
Contributor

Choose a reason for hiding this comment

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

It's actually simpler than that I think. We don't need render to do this. Instead, we can have a single computed property that based on the conditions returns just one template. That will be cheaper than multiple when instances.

@bheston
Copy link
Collaborator Author

bheston commented Aug 17, 2022

Related to #5806

x.orientation === Orientation.horizontal ? "horizontal" : "vertical"}"
part="positioning-region"
>
<div class="radiogroup" part="radiogroup">
Copy link
Member

Choose a reason for hiding this comment

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

Larger question here is whether it's worth keeping the attribute for horizontal and vertical. If we decide to keep it there is an argument for keeping a class here out of convenience. If we opt for removal then the primary method of adding would require extending the class (which I don't think is the worst thing). Given that there isn't a functional purpose, I'd be for removing the attribute from here as vertical and horizontal is primarily a visual consideration which would track similar to appearances on other controls.

Copy link
Contributor

Choose a reason for hiding this comment

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

If we remove this, should we have the CLI set up the default by adding this back in? I saw a customer just the other day indicating that this was important. So, if we remove it from the base, I'm thinking it might be nice to add it via the CLI.

Copy link
Member

Choose a reason for hiding this comment

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

Yes - And on this, the confusion I believe is that the attribute exists on the Foundation component but then no styling is delivered. I'd propose that vertical in this case is largely a design consideration. There's no functional requirement for it and no impact to AT currently by it existing. One could add an attribute for it by extending the component (what we should do in the CLI), perhaps they want to use data- instead to just apply the visual style. I think the attribute can be removed from Foundation but it's a good example on how to extend and a pattern we value, so a good fit for the CLI implementation. Open here, but I do think that it's confusing to have this in Foundation when it only serves a visual purpose. That follows along with not baking semantics on appearances into foundation.

Copy link
Collaborator

@radium-v radium-v Aug 18, 2022

Choose a reason for hiding this comment

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

The aria-orientation attribute is an inherited property for the radiogroup role. A note for the attribute indicates that ARIA 1.1 changed the default value from being horizontal to undefined: https://w3c.github.io/aria/#radiogroup:~:text=In%20ARIA%201.1%2C%20the%20default,ambiguous%20(e.g.%2C%20radiogroup).

Copy link
Member

Choose a reason for hiding this comment

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

It can still be passed to the host where the role is, we just don't need to actually use it within the class or template, so I'm not sure it needs to be enumerated.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The goal in removing it was bringing the selectors closer together. There have been some specificity issues, though this may not be one of them. Since there was no functional changes based on the orientation, using the attribute in the selector seemed like a good way to simplify the overall component. I suppose that could be said for all class selectors, though we've decided they are worth the overhead for internal styling convenience. By that logic, perhaps it's best to leave this here.

@bheston bheston force-pushed the users/bheston/foundation-template-update branch from c9b7754 to e938afc Compare January 30, 2023 23:47
@github-actions
Copy link

Azure Static Web Apps: Your stage site is ready! Visit it here: https://purple-ocean-0b7ce3410-6286.centralus.azurestaticapps.net

@bheston bheston force-pushed the users/bheston/foundation-template-update branch from e938afc to a8f1189 Compare January 31, 2023 00:58
@github-actions
Copy link

Azure Static Web Apps: Your stage site is ready! Visit it here: https://purple-ocean-0b7ce3410-6286.centralus.azurestaticapps.net

Comment on lines 30 to 39
${startSlotTemplate(options)}
<span class="heading-content" part="heading-content">
<slot name="heading"></slot>
</span>
${endSlotTemplate(options)}
<span class="expand-collapse-icon" part="expand-collapse-icon" aria-hidden="true">
<slot name="expand-collapse-icon">
${staticallyCompose(options.expandCollapseIcon)}
</slot>
<span>
Copy link
Member

Choose a reason for hiding this comment

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

Revisiting this and I don't think we want these within the button itself because it will group all content as part of the label. While I can definitely see a case for the expand-collapse-icon, moving the others in could actually generate some new a11y issues for folks under the assumption that the only slotted content here is icons (which I don't think would be an accurate assumption).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This might be a case of an ambiguous definition in the ARIA spec. At https://w3c.github.io/aria-practices/#accordion, under "Roles, States, and Properties" bullet 2.2 says "The button element is the only element inside the heading element." Agreed that if slotted content is something else like a Menu Button with interactions for the section it might confuse what is announced as the title. I believe this is true for the start and end slot placement in other components as well, though maybe less likely that we expect content other than icons. Do we have any general guidance re: a11y on slotted content?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I tested this on Anchor, for instance with a Badge, and it reads the badge content the same in both cases. In some cases that may make sense, like announcing something as "New". If they are Buttons instead, focus goes to the accordion button, then tab to start, end, then the next accordion item, which seems like the flow I expect.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Note that this change (at least currently) is only the sequence of items, not the hierarchy. This should not have any a11y impact that I know of, it only seeks to align the named intent of the "start" and "end" slots with their document order to minimize the need to resequence with css.

Copy link
Member

Choose a reason for hiding this comment

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

I think the intent with not including these as part of the button was that there may be scenarios where people may place other interactive elements within these slots and placing those inside the button would create a problem there. I think this is a hierarchy change because these are moving to be nested within the button, which means anything projected into the slot is a child of the button now instead.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Uh, looks like I didn't look at the diff correctly. Of course those elements moved.

I looked back at the spec, and I don't see a way to make both of the following statements true given the additional elements we have. I agree that the previous hierarchy (I've shifted the sequence) is best.

The button element is the only element inside the heading element.
That is, if there are other visually persistent elements, they are not included inside the heading element.

</slot>
${endSlotTemplate(options)}
<div class="open-close-icon" part="open-close-icon" aria-hidden="true">
Copy link
Member

Choose a reason for hiding this comment

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

this is a nit but I'd suggest a span here as the element is intended to be inline.

Copy link
Member

@chrisdholt chrisdholt Feb 11, 2023

Choose a reason for hiding this comment

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

@bheston I need to pull down and test a couple things here on the a11y end of things. I think it's fine but need to validate the tree with certain slotted items.

@bheston bheston force-pushed the users/bheston/foundation-template-update branch from a8f1189 to b6f6978 Compare February 14, 2023 19:55
@github-actions
Copy link

Azure Static Web Apps: Your stage site is ready! Visit it here: https://purple-ocean-0b7ce3410-6286.centralus.azurestaticapps.net

@bheston bheston force-pushed the users/bheston/foundation-template-update branch from b6f6978 to 93448bb Compare April 25, 2023 23:38
@github-actions
Copy link

Azure Static Web Apps: Your stage site is ready! Visit it here: https://purple-ocean-0b7ce3410-6286.centralus.azurestaticapps.net

@bheston bheston force-pushed the users/bheston/foundation-template-update branch from 4b1b416 to 8acc662 Compare May 22, 2023 21:07
@janechu
Copy link
Collaborator

janechu commented Jun 14, 2024

Closing this due to the sheer number of conflicts and this also seems like it might break downstream CSS for consumers.

@janechu janechu closed this Jun 14, 2024
@janechu janechu deleted the users/bheston/foundation-template-update branch June 14, 2024 16:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:fast-foundation Pertains to fast-foundation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants