diff --git a/component/src/views/chat/input/buttons/buttonAccessility.ts b/component/src/views/chat/input/buttons/buttonAccessility.ts new file mode 100644 index 000000000..0e6b71fb0 --- /dev/null +++ b/component/src/views/chat/input/buttons/buttonAccessility.ts @@ -0,0 +1,27 @@ +export class ButtonAccessibility { + public static addAttributes(button: HTMLElement) { + button.role = 'button'; + button.setAttribute('tabindex', '0'); + } + + public static addAriaBusy(button: HTMLElement) { + button.setAttribute('aria-busy', 'true'); + } + + public static removeAriaBusy(button: HTMLElement) { + button.removeAttribute('aria-busy'); + } + + public static addAriaDisabled(button: HTMLElement) { + button.setAttribute('aria-disabled', 'true'); + } + + public static removeAriaDisabled(button: HTMLElement) { + button.removeAttribute('aria-disabled'); + } + + public static removeAriaAttributes(button: HTMLElement) { + ButtonAccessibility.removeAriaBusy(button); + ButtonAccessibility.removeAriaDisabled(button); + } +} diff --git a/component/src/views/chat/input/buttons/camera/cameraButton.ts b/component/src/views/chat/input/buttons/camera/cameraButton.ts index 4ccc4e220..be9b82026 100644 --- a/component/src/views/chat/input/buttons/camera/cameraButton.ts +++ b/component/src/views/chat/input/buttons/camera/cameraButton.ts @@ -6,6 +6,7 @@ import {CameraModal} from '../../fileAttachments/modal/cameraModal'; import {SVGIconUtils} from '../../../../../utils/svg/svgIconUtils'; import {CAMERA_ICON_STRING} from '../../../../../icons/cameraIcon'; import {ServiceIO} from '../../../../../services/serviceIO'; +import {ButtonAccessibility} from '../buttonAccessility'; import {CameraFiles} from '../../../../../types/camera'; import {CustomStyle} from '../../../../../types/styles'; import {InputButton} from '../inputButton'; @@ -37,8 +38,7 @@ export class CameraButton extends InputButton { private static createButtonElement() { const buttonElement = document.createElement('div'); buttonElement.classList.add('input-button'); - buttonElement.role = 'button'; - buttonElement.setAttribute('tabindex', '0'); + ButtonAccessibility.addAttributes(buttonElement); return buttonElement; } diff --git a/component/src/views/chat/input/buttons/microphone/microphoneButton.ts b/component/src/views/chat/input/buttons/microphone/microphoneButton.ts index aee95663a..c94716b6e 100644 --- a/component/src/views/chat/input/buttons/microphone/microphoneButton.ts +++ b/component/src/views/chat/input/buttons/microphone/microphoneButton.ts @@ -4,6 +4,7 @@ import {CustomButtonInnerElements} from '../customButtonInnerElements'; import {SVGIconUtils} from '../../../../../utils/svg/svgIconUtils'; import {MicrophoneStyles} from '../../../../../types/microphone'; import {ButtonStyles} from '../../../../../types/button'; +import {ButtonAccessibility} from '../buttonAccessility'; import {InputButton} from '../inputButton'; // commandMode is used for speech to text @@ -43,8 +44,7 @@ export class MicrophoneButton extends InputButton { const buttonElement = document.createElement('div'); buttonElement.id = 'microphone-button'; buttonElement.classList.add('input-button'); - buttonElement.role = 'button'; - buttonElement.setAttribute('tabindex', '0'); + ButtonAccessibility.addAttributes(buttonElement); return buttonElement; } diff --git a/component/src/views/chat/input/buttons/submit/submitButton.ts b/component/src/views/chat/input/buttons/submit/submitButton.ts index 188659ae2..3e5dde645 100644 --- a/component/src/views/chat/input/buttons/submit/submitButton.ts +++ b/component/src/views/chat/input/buttons/submit/submitButton.ts @@ -13,6 +13,7 @@ import {MicrophoneButton} from '../microphone/microphoneButton'; import {ServiceIO} from '../../../../../services/serviceIO'; import {UserContent} from '../../../../../types/messages'; import {Legacy} from '../../../../../utils/legacy/legacy'; +import {ButtonAccessibility} from '../buttonAccessility'; import {Response} from '../../../../../types/response'; import {TextInputEl} from '../../textInput/textInput'; import {Signals} from '../../../../../types/handler'; @@ -95,8 +96,7 @@ export class SubmitButton extends InputButton { private static createButtonContainerElement() { const buttonElement = document.createElement('div'); buttonElement.classList.add('input-button'); - buttonElement.role = 'button'; - buttonElement.setAttribute('tabindex', '0'); + ButtonAccessibility.addAttributes(buttonElement); return buttonElement; } @@ -222,8 +222,7 @@ export class SubmitButton extends InputButton { private changeToStopIcon() { if (this._serviceIO.websocket) return; // stop not used for streaming messages in websocket this.elementRef.classList.remove(SubmitButton.LOADING_CLASS, SubmitButton.DISABLED_CLASS, SubmitButton.SUBMIT_CLASS); - this.elementRef.removeAttribute('aria-busy'); - this.elementRef.removeAttribute('aria-disabled'); + ButtonAccessibility.removeAriaAttributes(this.elementRef); this.elementRef.replaceChildren(this._innerElements.stop); this.reapplyStateStyle('stop', ['loading', 'submit']); this.elementRef.onclick = this.stopStream.bind(this); @@ -234,9 +233,9 @@ export class SubmitButton extends InputButton { if (this._serviceIO.websocket) return; if (!this._isSVGLoadingIconOverriden) this.elementRef.replaceChildren(this._innerElements.loading); this.elementRef.classList.remove(SubmitButton.SUBMIT_CLASS, SubmitButton.DISABLED_CLASS); - this.elementRef.removeAttribute('aria-disabled'); + ButtonAccessibility.removeAriaDisabled(this.elementRef); this.elementRef.classList.add(SubmitButton.LOADING_CLASS); - this.elementRef.setAttribute('aria-busy', 'true'); + ButtonAccessibility.addAriaBusy(this.elementRef); this.reapplyStateStyle('loading', ['submit']); this.elementRef.onclick = () => {}; this.status.requestInProgress = true; @@ -247,8 +246,7 @@ export class SubmitButton extends InputButton { public changeToSubmitIcon() { if (this.elementRef.classList.contains(SubmitButton.SUBMIT_CLASS)) return; this.elementRef.classList.remove(SubmitButton.LOADING_CLASS, SubmitButton.DISABLED_CLASS); - this.elementRef.removeAttribute('aria-busy'); - this.elementRef.removeAttribute('aria-disabled'); + ButtonAccessibility.removeAriaAttributes(this.elementRef); this.elementRef.classList.add(SubmitButton.SUBMIT_CLASS); this.elementRef.replaceChildren(this._innerElements.submit); SubmitButtonStateStyle.resetSubmit(this, this.status.loadingActive); @@ -266,9 +264,9 @@ export class SubmitButton extends InputButton { this.changeToSubmitIcon(); } else if (!this.elementRef.classList.contains(SubmitButton.DISABLED_CLASS)) { this.elementRef.classList.remove(SubmitButton.LOADING_CLASS, SubmitButton.SUBMIT_CLASS); - this.elementRef.removeAttribute('aria-busy'); + ButtonAccessibility.removeAriaBusy(this.elementRef); this.elementRef.classList.add(SubmitButton.DISABLED_CLASS); - this.elementRef.setAttribute('aria-disabled', 'true'); + ButtonAccessibility.addAriaDisabled(this.elementRef); this.elementRef.replaceChildren(this._innerElements.disabled); this.reapplyStateStyle('disabled', ['submit']); this.elementRef.onclick = () => {}; diff --git a/component/src/views/chat/input/buttons/uploadFile/uploadFileButton.ts b/component/src/views/chat/input/buttons/uploadFile/uploadFileButton.ts index 0231ee622..9cdc968e5 100644 --- a/component/src/views/chat/input/buttons/uploadFile/uploadFileButton.ts +++ b/component/src/views/chat/input/buttons/uploadFile/uploadFileButton.ts @@ -5,6 +5,7 @@ import {CustomButtonInnerElements} from '../customButtonInnerElements'; import {FileAttachments} from '../../fileAttachments/fileAttachments'; import {SVGIconUtils} from '../../../../../utils/svg/svgIconUtils'; import {FileServiceIO} from '../../../../../services/serviceIO'; +import {ButtonAccessibility} from '../buttonAccessility'; import {Modal} from '../../fileAttachments/modal/modal'; import {InputButton} from '../inputButton'; @@ -61,8 +62,7 @@ export class UploadFileButton extends InputButton { private static createButtonElement() { const buttonElement = document.createElement('div'); buttonElement.classList.add('input-button', 'upload-file-button'); - buttonElement.role = 'button'; - buttonElement.setAttribute('tabindex', '0'); + ButtonAccessibility.addAttributes(buttonElement); return buttonElement; } diff --git a/component/src/views/chat/input/fileAttachments/modal/modal.ts b/component/src/views/chat/input/fileAttachments/modal/modal.ts index 694f802a6..607ff36d2 100644 --- a/component/src/views/chat/input/fileAttachments/modal/modal.ts +++ b/component/src/views/chat/input/fileAttachments/modal/modal.ts @@ -1,4 +1,5 @@ import {KEYBOARD_KEY} from '../../../../../utils/buttons/keyboardKeys'; +import {ButtonAccessibility} from '../../buttons/buttonAccessility'; import {SVGIconUtils} from '../../../../../utils/svg/svgIconUtils'; import {FileServiceIO} from '../../../../../services/serviceIO'; import {CustomStyle} from '../../../../../types/styles'; @@ -59,8 +60,11 @@ export class Modal { return backgroundPanel; } - addButtons(...buttons: HTMLElement[]) { - buttons.forEach((button) => this._buttonPanel.appendChild(button)); + public addButtons(...buttons: HTMLElement[]) { + buttons.forEach((button) => { + ButtonAccessibility.addAttributes(button); + this._buttonPanel.appendChild(button); + }); } private static createTextButton(text: string) {