WIP accessibility of widgets:

- fixed fallback-order for aria-attributes (done now in connected callback and not updated, which was not reliable in the order called)
- aria-label set by (in order of priority): ariaLabel, label, placeholder, statustext
- aria-description set by (----- " -----): ariaDescription, helpText, statustext (if not already used for -label)
- following widget work now (incl. focus by click on label): et2-textbox, et2-date*, et2-url*, et2-select*
This commit is contained in:
ralf 2024-04-26 12:04:37 +02:00
parent e1d4c61e9d
commit e9d366aa98
3 changed files with 22 additions and 15 deletions

View File

@ -28,7 +28,7 @@ export const ButtonMixin = <T extends Constructor>(superclass : T) => class exte
cancel: /cancel(&|\]|$)/, cancel: /cancel(&|\]|$)/,
delete: /delete(&|\]|$)/, delete: /delete(&|\]|$)/,
discard: /discard(&|\]|$)/, discard: /discard(&|\]|$)/,
edit: /edit(&|\[\]|$)/, edit: /edit(&|\[|\]|$)/,
next: /(next|continue)(&|\]|$)/, next: /(next|continue)(&|\]|$)/,
finish: /finish(&|\]|$)/, finish: /finish(&|\]|$)/,
back: /(back|previous)(&|\]|$)/, back: /(back|previous)(&|\]|$)/,
@ -426,4 +426,12 @@ export const ButtonMixin = <T extends Constructor>(superclass : T) => class exte
// array. // array.
return null; return null;
} }
/**
* Reimplemented to pass aria-attributes to button
*/
getInputNode()
{
return this.shadowRoot.querySelector('button');
}
} }

View File

@ -216,6 +216,17 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
}); });
this.addEventListener("focus", this.et2HandleFocus); this.addEventListener("focus", this.et2HandleFocus);
this.addEventListener("blur", this.et2HandleBlur); this.addEventListener("blur", this.et2HandleBlur);
// set aria-label and -description fallbacks (done here and not in updated to ensure reliable fallback order)
if (!this.ariaLabel) this.ariaLabel = this.label || this.placeholder || this.statustext;
if (!this.ariaDescription) this.ariaDescription = this.helpText || (this.statustext !== this.ariaLabel ? this.statustext : '');
// pass them on to input-node, if we have one / this.getInputNode() returns one
const input = this.getInputNode();
if (input)
{
input.ariaLabel = this.ariaLabel;
input.ariaDescription = this.ariaDescription;
}
} }
disconnectedCallback() disconnectedCallback()
@ -253,20 +264,6 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
// Base off this.value, not this.getValue(), to ignore readonly // Base off this.value, not this.getValue(), to ignore readonly
this.classList.toggle("hasValue", !(this.value == null || this.value == "")); this.classList.toggle("hasValue", !(this.value == null || this.value == ""));
} }
if (changedProperties.has('ariaLabel') || changedProperties.has('ariaDescription') ||
changedProperties.has("statustext") || changedProperties.has('helpText'))
{
const input = this.getInputNode();
if (input && (changedProperties.has('ariaLabel') || changedProperties.has("statustext")))
{
input.ariaLabel = this.ariaLabel || this.statustext;
}
if (input && (changedProperties.has('ariaDescription') || changedProperties.has('helpText')))
{
input.ariaDescription = this.ariaDescription || this.helpText;
}
}
} }
/** /**

View File

@ -1046,6 +1046,8 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
exportparts="form-control-label, prefix, tags, display-input, expand-icon, combobox, combobox:base, listbox, option" exportparts="form-control-label, prefix, tags, display-input, expand-icon, combobox, combobox:base, listbox, option"
label=${this.label} label=${this.label}
placeholder=${this.placeholder || (this.multiple && this.emptyLabel ? this.emptyLabel : "")} placeholder=${this.placeholder || (this.multiple && this.emptyLabel ? this.emptyLabel : "")}
aria-label=${this.ariaLabel}
aria-description=${this.ariaDesciption}
?multiple=${this.multiple} ?multiple=${this.multiple}
?disabled=${this.disabled || this.readonly} ?disabled=${this.disabled || this.readonly}
?clearable=${this.clearable} ?clearable=${this.clearable}