Skip to content
This repository was archived by the owner on Sep 20, 2024. It is now read-only.

Conversation

@TylerAPfledderer
Copy link
Collaborator

Pull request checklist

Please check if your PR fulfills the following requirements:

  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been reviewed and added / updated if needed (for bug fixes
    /start features)

Pull request type

Please check the type of change your PR introduces:

  • Bugfix
  • Feature
  • Code style update (formatting, renaming)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • Documentation content changes
  • Other (please describe):

What is the current behavior?

Closes #195

What is the new behavior?

  • Create LiveRegion class which sets up region, establishes the aria options, and destroys the region on component unmount.
  • Create composable to supply the logic to the component

Does this introduce a breaking change?

  • Yes
  • No

Other information

@vercel
Copy link

vercel bot commented Oct 20, 2022

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated
chakra-ui-vue-next ✅ Ready (Inspect) Visit Preview Oct 27, 2022 at 9:13PM (UTC)
chakra-ui-vue-next-playground ✅ Ready (Inspect) Visit Preview Oct 27, 2022 at 9:13PM (UTC)

* Indicates what types of changes should be presented to the user.
* @default "all"
*/
"aria-relevant"?:
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In the React package, there is the React.AriaAttributes type signature that is used to retrieve the types for the aria-relevant and aria-atomic attributes, instead of hard coding them here.

Is their a Vue version of this signature??

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah I see. I don't think there is such a type in Vue.js. all of them usually fall under the HTMLAttributes type exported from Vue.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Whoops! Forgot about that. 😅

Comment on lines +57 to +100
export class LiveRegion {
region: HTMLElement | null
options: Required<LiveRegionOptions>
parentNode: HTMLElement

constructor(options?: LiveRegionOptions) {
this.options = getOptions(options) as any
this.region = getRegion(this.options)
this.parentNode = this.options.parentNode
if (this.region) {
this.parentNode.appendChild(this.region)
}
}

/**
* Message provided to the region to be read out by the Screen Reader.
*
* Message can be supplied on trigger of some event (i.e. button click)
*/
public speak(message: string) {
this.clear()
if (this.region) {
this.region.innerText = message
}
}

/**
* Removes the region.
*/
public destroy() {
if (this.region) {
this.region.parentNode?.removeChild(this.region)
}
}

/**
* Clears the inner text of the region
*/
public clear() {
if (this.region) {
this.region.innerText = ""
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Hi @TylerAPfledderer

Can't this class be a component instead? It seem that it only creates/appends attributes to certain elements, which seems better as a component to me.

Also, using methods such as removeChild should only be done when there is no other solution, otherwise it's a bit of an anti-pattern in Vue. So i'd say that if we have the choice let's create a component.

Comment on lines +130 to +148
function setup(region: HTMLElement, options: Required<LiveRegionOptions>) {
region.id = options.id || "chakra-live-region"
region.className = "__chakra-live-region"
region.setAttribute("aria-live", options["aria-live"])
region.setAttribute("role", options.role)
region.setAttribute("aria-relevant", options["aria-relevant"])
region.setAttribute("aria-atomic", String(options["aria-atomic"]))
Object.assign(region.style, {
border: "0px",
clip: "rect(0px, 0px, 0px, 0px)",
height: "1px",
width: "1px",
margin: "-1px",
padding: "0px",
overflow: "hidden",
whiteSpace: "nowrap",
position: "absolute",
})
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems better to me to pass a Ref instead of an HTMLElement might be better for reactivity.

Also, this setup function also looks like it can also just be a component

Comment on lines +8 to +14
export function useLiveRegion(options?: LiveRegionOptions) {
const liveRegion = reactive(() => new LiveRegion(options))

watchEffect((cleanup) => cleanup(() => liveRegion().destroy()))

return liveRegion()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

After thinking about it, seem better to have a CLiveRegion component instead of a hook imo.

All the options passed can basically be props and the rest of the code would be much simpler and more aligned with the Vue philosophy.
It will also allow to remove some of the code. I think that eventhough we need to be as close to the React package, there are some things that need to be done differently due to the different philosophy between React and Vue.

What is your opinion about this @codebender828 , @TylerAPfledderer ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@Shyrro @codebender828 for context and my understanding of LiveRegion, it is a class because the hook triggers an instance which renders an element out of view of the visual user; a hidden portal of sorts specific to the use of a acreen reader. Then you pull methods (events) from the instance through the hook, to apply to what triggers are used in a given component.

The developer can certainly access the other data to make their own reason, but it did not seem to be intended by default for someone to have to make an element just for a screen reader to readout a simple message on change from some event.

I would not mind converting to a component, with composables to house the props that can be exported separately, but then the question would be how this new component is to be implemented in the environment.

I'm primarily thinking about how the speak method is currently executed versus an alternative approach.

Copy link
Contributor

Choose a reason for hiding this comment

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

Tbh if you want to access methods of the components or other data you can expose them through the expose method of your component. They'll then be available through template refs

And for the fact the the component is outside the screen it doesn't really matter if you wrap it in a Teleport or CPortal

It just feels the "Vue way" so to say. Also, when manipulating the DOM directly through document.createElement etc, basically nothing is tracked so you're instance doesn't have any reactivity whatsoever.

I might be wrong about this since this is a special hook, but it just feels more natural in Vue to have in this case a logical component instead of a hook.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Understood! I'll take a look at expose.

I'll play around with it, because you could probably argue the same case against direct DOM manipulation in React here with the reactivity, so maybe I can ask one of the React folks on the reason for this approach. 🤔

Better for me to know at least so I can get a better idea on differences! 😄

Copy link
Contributor

Choose a reason for hiding this comment

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

Let me know if u need any more clarification on what i'm saying or any more explanation on this approach.

We can even discuss it in a call, might be easier ☺️

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

Labels

☄️ core team This issue/pull request has been opened by a Vue core team member status: work in progress 🐜 Someone is working on this type: feature or enhancement ⚡️ New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add c-live-region component

3 participants