Improved accessibility (#118):
* channel configuration: adding title to inputs. * channel configuration: `aria-hidden="true"` on icons for add and remove row buttons.
This commit is contained in:
parent
944bdcebb7
commit
b673a49af6
@ -135,6 +135,7 @@ export function tplChannelConfiguration (el: ChannelConfigurationElement): Templ
|
|||||||
</livechat-configuration-section-header>
|
</livechat-configuration-section-header>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<textarea
|
<textarea
|
||||||
|
.title=${ptTr(LOC_LIVECHAT_CONFIGURATION_CHANNEL_TERMS_LABEL) as any}
|
||||||
name="terms"
|
name="terms"
|
||||||
id="peertube-livechat-terms"
|
id="peertube-livechat-terms"
|
||||||
.value=${el.channelConfiguration?.configuration.terms ?? ''}
|
.value=${el.channelConfiguration?.configuration.terms ?? ''}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
// This content comes from the file assets/images/plus-square.svg, from the Feather icons set https://feathericons.com/
|
// This content comes from the file assets/images/plus-square.svg, from the Feather icons set https://feathericons.com/
|
||||||
export const AddSVG: string =
|
export const AddSVG: string =
|
||||||
`<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
|
`<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
|
||||||
|
aria-hidden="true"
|
||||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||||
stroke-linejoin="round" class="feather feather-plus-square">
|
stroke-linejoin="round" class="feather feather-plus-square">
|
||||||
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
||||||
@ -15,6 +16,7 @@ export const AddSVG: string =
|
|||||||
// This content comes from the file assets/images/x-square.svg, from the Feather icons set https://feathericons.com/
|
// This content comes from the file assets/images/x-square.svg, from the Feather icons set https://feathericons.com/
|
||||||
export const RemoveSVG: string =
|
export const RemoveSVG: string =
|
||||||
`<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
|
`<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
|
||||||
|
aria-hidden="true"
|
||||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||||
stroke-linejoin="round" class="feather feather-x-square">
|
stroke-linejoin="round" class="feather feather-x-square">
|
||||||
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
||||||
|
@ -47,11 +47,11 @@ interface CellDataSchema {
|
|||||||
minlength?: number
|
minlength?: number
|
||||||
maxlength?: number
|
maxlength?: number
|
||||||
size?: number
|
size?: number
|
||||||
label?: TemplateResult | string
|
|
||||||
options?: { [key: string]: string }
|
options?: { [key: string]: string }
|
||||||
datalist?: DynamicTableAcceptedTypes[]
|
datalist?: DynamicTableAcceptedTypes[]
|
||||||
separator?: string
|
separator?: string
|
||||||
inputType?: DynamicTableAcceptedInputTypes
|
inputType?: DynamicTableAcceptedInputTypes
|
||||||
|
inputTitle?: string
|
||||||
default?: DynamicTableAcceptedTypes
|
default?: DynamicTableAcceptedTypes
|
||||||
colClassList?: string[] // CSS classes to add to the <td> element.
|
colClassList?: string[] // CSS classes to add to the <td> element.
|
||||||
}
|
}
|
||||||
@ -295,6 +295,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
const inputId =
|
const inputId =
|
||||||
`peertube-livechat-${this.formName.replace(/_/g, '-')}-${propertyName.toString().replace(/_/g, '-')}-${rowId}`
|
`peertube-livechat-${this.formName.replace(/_/g, '-')}-${propertyName.toString().replace(/_/g, '-')}-${rowId}`
|
||||||
|
|
||||||
|
const inputTitle: DirectiveResult | undefined = propertySchema.inputTitle ?? this.header[propertyName]?.colName
|
||||||
const feedback = this._renderFeedback(inputId, propertyName, originalIndex)
|
const feedback = this._renderFeedback(inputId, propertyName, originalIndex)
|
||||||
|
|
||||||
switch (propertySchema.default?.constructor) {
|
switch (propertySchema.default?.constructor) {
|
||||||
@ -320,6 +321,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
formElement = html`${this._renderInput(rowId,
|
formElement = html`${this._renderInput(rowId,
|
||||||
inputId,
|
inputId,
|
||||||
inputName,
|
inputName,
|
||||||
|
inputTitle,
|
||||||
propertyName,
|
propertyName,
|
||||||
propertySchema,
|
propertySchema,
|
||||||
propertyValue as string,
|
propertyValue as string,
|
||||||
@ -332,6 +334,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
formElement = html`${this._renderTextarea(rowId,
|
formElement = html`${this._renderTextarea(rowId,
|
||||||
inputId,
|
inputId,
|
||||||
inputName,
|
inputName,
|
||||||
|
inputTitle,
|
||||||
propertyName,
|
propertyName,
|
||||||
propertySchema,
|
propertySchema,
|
||||||
propertyValue as string,
|
propertyValue as string,
|
||||||
@ -344,6 +347,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
formElement = html`${this._renderSelect(rowId,
|
formElement = html`${this._renderSelect(rowId,
|
||||||
inputId,
|
inputId,
|
||||||
inputName,
|
inputName,
|
||||||
|
inputTitle,
|
||||||
propertyName,
|
propertyName,
|
||||||
propertySchema,
|
propertySchema,
|
||||||
propertyValue as string,
|
propertyValue as string,
|
||||||
@ -356,6 +360,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
formElement = html`${this._renderImageFileInput(rowId,
|
formElement = html`${this._renderImageFileInput(rowId,
|
||||||
inputId,
|
inputId,
|
||||||
inputName,
|
inputName,
|
||||||
|
inputTitle,
|
||||||
propertyName,
|
propertyName,
|
||||||
propertySchema,
|
propertySchema,
|
||||||
propertyValue?.toString(),
|
propertyValue?.toString(),
|
||||||
@ -376,6 +381,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
formElement = html`${this._renderInput(rowId,
|
formElement = html`${this._renderInput(rowId,
|
||||||
inputId,
|
inputId,
|
||||||
inputName,
|
inputName,
|
||||||
|
inputTitle,
|
||||||
propertyName,
|
propertyName,
|
||||||
propertySchema,
|
propertySchema,
|
||||||
(propertyValue as Date).toISOString(),
|
(propertyValue as Date).toISOString(),
|
||||||
@ -394,6 +400,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
formElement = html`${this._renderInput(rowId,
|
formElement = html`${this._renderInput(rowId,
|
||||||
inputId,
|
inputId,
|
||||||
inputName,
|
inputName,
|
||||||
|
inputTitle,
|
||||||
propertyName,
|
propertyName,
|
||||||
propertySchema,
|
propertySchema,
|
||||||
propertyValue as string,
|
propertyValue as string,
|
||||||
@ -411,6 +418,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
formElement = html`${this._renderCheckbox(rowId,
|
formElement = html`${this._renderCheckbox(rowId,
|
||||||
inputId,
|
inputId,
|
||||||
inputName,
|
inputName,
|
||||||
|
inputTitle,
|
||||||
propertyName,
|
propertyName,
|
||||||
propertySchema,
|
propertySchema,
|
||||||
propertyValue as boolean,
|
propertyValue as boolean,
|
||||||
@ -446,6 +454,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
formElement = html`${this._renderInput(rowId,
|
formElement = html`${this._renderInput(rowId,
|
||||||
inputId,
|
inputId,
|
||||||
inputName,
|
inputName,
|
||||||
|
inputTitle,
|
||||||
propertyName,
|
propertyName,
|
||||||
propertySchema,
|
propertySchema,
|
||||||
(propertyValue)?.join(propertySchema.separator ?? ',') ??
|
(propertyValue)?.join(propertySchema.separator ?? ',') ??
|
||||||
@ -461,6 +470,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
formElement = html`${this._renderTextarea(rowId,
|
formElement = html`${this._renderTextarea(rowId,
|
||||||
inputId,
|
inputId,
|
||||||
inputName,
|
inputName,
|
||||||
|
inputTitle,
|
||||||
propertyName,
|
propertyName,
|
||||||
propertySchema,
|
propertySchema,
|
||||||
(propertyValue)?.join(propertySchema.separator ?? ',') ??
|
(propertyValue)?.join(propertySchema.separator ?? ',') ??
|
||||||
@ -476,6 +486,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
formElement = html`${this._renderTagsInput(rowId,
|
formElement = html`${this._renderTagsInput(rowId,
|
||||||
inputId,
|
inputId,
|
||||||
inputName,
|
inputName,
|
||||||
|
inputTitle,
|
||||||
propertyName,
|
propertyName,
|
||||||
propertySchema,
|
propertySchema,
|
||||||
propertyValue,
|
propertyValue,
|
||||||
@ -501,6 +512,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
_renderInput = (rowId: number,
|
_renderInput = (rowId: number,
|
||||||
inputId: string,
|
inputId: string,
|
||||||
inputName: string,
|
inputName: string,
|
||||||
|
inputTitle: string | DirectiveResult | undefined,
|
||||||
propertyName: string,
|
propertyName: string,
|
||||||
propertySchema: CellDataSchema,
|
propertySchema: CellDataSchema,
|
||||||
propertyValue: string,
|
propertyValue: string,
|
||||||
@ -515,6 +527,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
id=${inputId}
|
id=${inputId}
|
||||||
|
title=${ifDefined(inputTitle)}
|
||||||
aria-describedby="${inputId}-feedback"
|
aria-describedby="${inputId}-feedback"
|
||||||
list=${ifDefined(propertySchema.datalist ? inputId + '-datalist' : undefined)}
|
list=${ifDefined(propertySchema.datalist ? inputId + '-datalist' : undefined)}
|
||||||
min=${ifDefined(propertySchema.min)}
|
min=${ifDefined(propertySchema.min)}
|
||||||
@ -534,6 +547,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
_renderTagsInput = (rowId: number,
|
_renderTagsInput = (rowId: number,
|
||||||
inputId: string,
|
inputId: string,
|
||||||
inputName: string,
|
inputName: string,
|
||||||
|
inputTitle: string | DirectiveResult | undefined,
|
||||||
propertyName: string,
|
propertyName: string,
|
||||||
propertySchema: CellDataSchema,
|
propertySchema: CellDataSchema,
|
||||||
propertyValue: Array<string | number>,
|
propertyValue: Array<string | number>,
|
||||||
@ -547,7 +561,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
id=${inputId}
|
id=${inputId}
|
||||||
.inputPlaceholder=${propertySchema.label as any}
|
.inputTitle=${inputTitle as any}
|
||||||
aria-describedby="${inputId}-feedback"
|
aria-describedby="${inputId}-feedback"
|
||||||
.min=${propertySchema.min}
|
.min=${propertySchema.min}
|
||||||
.max=${propertySchema.max}
|
.max=${propertySchema.max}
|
||||||
@ -563,6 +577,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
_renderTextarea = (rowId: number,
|
_renderTextarea = (rowId: number,
|
||||||
inputId: string,
|
inputId: string,
|
||||||
inputName: string,
|
inputName: string,
|
||||||
|
inputTitle: string | DirectiveResult | undefined,
|
||||||
propertyName: string,
|
propertyName: string,
|
||||||
propertySchema: CellDataSchema,
|
propertySchema: CellDataSchema,
|
||||||
propertyValue: string,
|
propertyValue: string,
|
||||||
@ -576,6 +591,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
id=${inputId}
|
id=${inputId}
|
||||||
|
title=${ifDefined(inputTitle)}
|
||||||
aria-describedby="${inputId}-feedback"
|
aria-describedby="${inputId}-feedback"
|
||||||
min=${ifDefined(propertySchema.min)}
|
min=${ifDefined(propertySchema.min)}
|
||||||
max=${ifDefined(propertySchema.max)}
|
max=${ifDefined(propertySchema.max)}
|
||||||
@ -588,6 +604,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
_renderCheckbox = (rowId: number,
|
_renderCheckbox = (rowId: number,
|
||||||
inputId: string,
|
inputId: string,
|
||||||
inputName: string,
|
inputName: string,
|
||||||
|
inputTitle: string | DirectiveResult | undefined,
|
||||||
propertyName: string,
|
propertyName: string,
|
||||||
propertySchema: CellDataSchema,
|
propertySchema: CellDataSchema,
|
||||||
propertyValue: boolean,
|
propertyValue: boolean,
|
||||||
@ -602,6 +619,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
id=${inputId}
|
id=${inputId}
|
||||||
|
title=${ifDefined(inputTitle)}
|
||||||
aria-describedby="${inputId}-feedback"
|
aria-describedby="${inputId}-feedback"
|
||||||
@change=${(event: Event) => this._updatePropertyFromValue(event, propertyName, propertySchema, rowId)}
|
@change=${(event: Event) => this._updatePropertyFromValue(event, propertyName, propertySchema, rowId)}
|
||||||
value="1"
|
value="1"
|
||||||
@ -611,6 +629,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
_renderSelect = (rowId: number,
|
_renderSelect = (rowId: number,
|
||||||
inputId: string,
|
inputId: string,
|
||||||
inputName: string,
|
inputName: string,
|
||||||
|
inputTitle: string | DirectiveResult | undefined,
|
||||||
propertyName: string,
|
propertyName: string,
|
||||||
propertySchema: CellDataSchema,
|
propertySchema: CellDataSchema,
|
||||||
propertyValue: string,
|
propertyValue: string,
|
||||||
@ -623,11 +642,12 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
id=${inputId}
|
id=${inputId}
|
||||||
|
title=${ifDefined(inputTitle)}
|
||||||
aria-describedby="${inputId}-feedback"
|
aria-describedby="${inputId}-feedback"
|
||||||
aria-label=${inputName}
|
aria-label=${inputName}
|
||||||
@change=${(event: Event) => this._updatePropertyFromValue(event, propertyName, propertySchema, rowId)}
|
@change=${(event: Event) => this._updatePropertyFromValue(event, propertyName, propertySchema, rowId)}
|
||||||
>
|
>
|
||||||
<option ?selected=${!propertyValue}>${propertySchema.label ?? 'Choose your option'}</option>
|
<option ?selected=${!propertyValue}>${inputTitle ?? ''}</option>
|
||||||
${Object.entries(propertySchema.options ?? {})
|
${Object.entries(propertySchema.options ?? {})
|
||||||
?.map(([value, name]) =>
|
?.map(([value, name]) =>
|
||||||
html`<option ?selected=${propertyValue === value} value=${value}>${name}</option>`
|
html`<option ?selected=${propertyValue === value} value=${value}>${name}</option>`
|
||||||
@ -638,6 +658,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
_renderImageFileInput = (rowId: number,
|
_renderImageFileInput = (rowId: number,
|
||||||
inputId: string,
|
inputId: string,
|
||||||
inputName: string,
|
inputName: string,
|
||||||
|
inputTitle: string | DirectiveResult | undefined,
|
||||||
propertyName: string,
|
propertyName: string,
|
||||||
propertySchema: CellDataSchema,
|
propertySchema: CellDataSchema,
|
||||||
propertyValue: string,
|
propertyValue: string,
|
||||||
@ -647,6 +668,7 @@ export class DynamicTableFormElement extends LivechatElement {
|
|||||||
.name=${inputName}
|
.name=${inputName}
|
||||||
class=${classMap(this._getInputValidationClass(propertyName, originalIndex))}
|
class=${classMap(this._getInputValidationClass(propertyName, originalIndex))}
|
||||||
id=${inputId}
|
id=${inputId}
|
||||||
|
.inputTitle=${inputTitle as any}
|
||||||
aria-describedby="${inputId}-feedback"
|
aria-describedby="${inputId}-feedback"
|
||||||
@change=${(event: Event) => this._updatePropertyFromValue(event, propertyName, propertySchema, rowId)}
|
@change=${(event: Event) => this._updatePropertyFromValue(event, propertyName, propertySchema, rowId)}
|
||||||
.value=${propertyValue}
|
.value=${propertyValue}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
// SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
|
// SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import { LivechatElement } from './livechat'
|
import { LivechatElement } from './livechat'
|
||||||
import { html } from 'lit'
|
import { html } from 'lit'
|
||||||
|
import type { DirectiveResult } from 'lit/directive'
|
||||||
import { customElement, property } from 'lit/decorators.js'
|
import { customElement, property } from 'lit/decorators.js'
|
||||||
|
import { ifDefined } from 'lit/directives/if-defined.js'
|
||||||
/**
|
/**
|
||||||
* Special element to upload image files.
|
* Special element to upload image files.
|
||||||
* If no current value, displays an input type="file" field.
|
* If no current value, displays an input type="file" field.
|
||||||
@ -29,13 +29,16 @@ export class ImageFileInputElement extends LivechatElement {
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public maxSize?: number
|
public maxSize?: number
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
public inputTitle?: string | DirectiveResult
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public accept: string[] = ['image/jpg', 'image/png', 'image/gif']
|
public accept: string[] = ['image/jpg', 'image/png', 'image/gif']
|
||||||
|
|
||||||
protected override render = (): unknown => {
|
protected override render = (): unknown => {
|
||||||
return html`
|
return html`
|
||||||
${this.value
|
${this.value
|
||||||
? html`<img src=${this.value} @click=${(ev: Event) => {
|
? html`<img src=${this.value} alt=${ifDefined(this.inputTitle)} @click=${(ev: Event) => {
|
||||||
ev.preventDefault()
|
ev.preventDefault()
|
||||||
const upload: HTMLInputElement | null | undefined = this.parentElement?.querySelector('input[type="file"]')
|
const upload: HTMLInputElement | null | undefined = this.parentElement?.querySelector('input[type="file"]')
|
||||||
upload?.click()
|
upload?.click()
|
||||||
@ -44,6 +47,7 @@ export class ImageFileInputElement extends LivechatElement {
|
|||||||
}
|
}
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
|
title=${ifDefined(this.inputTitle)}
|
||||||
accept="${this.accept.join(',')}"
|
accept="${this.accept.join(',')}"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
style=${this.value ? 'display: none;' : ''}
|
style=${this.value ? 'display: none;' : ''}
|
||||||
|
@ -12,6 +12,7 @@ import { ifDefined } from 'lit/directives/if-defined.js'
|
|||||||
import { classMap } from 'lit/directives/class-map.js'
|
import { classMap } from 'lit/directives/class-map.js'
|
||||||
import { animate, fadeOut, fadeIn } from '@lit-labs/motion'
|
import { animate, fadeOut, fadeIn } from '@lit-labs/motion'
|
||||||
import { repeat } from 'lit/directives/repeat.js'
|
import { repeat } from 'lit/directives/repeat.js'
|
||||||
|
import type { DirectiveResult } from 'lit/directive'
|
||||||
|
|
||||||
// FIXME: find a better way to store this image.
|
// FIXME: find a better way to store this image.
|
||||||
// This content comes from the file assets/images/copy.svg, after svgo cleaning.
|
// This content comes from the file assets/images/copy.svg, after svgo cleaning.
|
||||||
@ -48,7 +49,7 @@ export class TagsInputElement extends LivechatElement {
|
|||||||
private _inputValue?: string = ''
|
private _inputValue?: string = ''
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public inputPlaceholder?: string = ''
|
public inputTitle?: string | DirectiveResult = ''
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public datalist?: string[]
|
public datalist?: string[]
|
||||||
@ -166,7 +167,7 @@ export class TagsInputElement extends LivechatElement {
|
|||||||
@input=${(e: InputEvent) => this._handleInputEvent(e)}
|
@input=${(e: InputEvent) => this._handleInputEvent(e)}
|
||||||
@change=${(e: Event) => e.stopPropagation()}
|
@change=${(e: Event) => e.stopPropagation()}
|
||||||
.value=${this._inputValue ?? ''}
|
.value=${this._inputValue ?? ''}
|
||||||
placeholder=${ifDefined(this.inputPlaceholder)} />
|
title=${ifDefined(this.inputTitle)} />
|
||||||
${(this.datalist)
|
${(this.datalist)
|
||||||
? html`<datalist id="${this.id ?? 'tags-input'}-datalist">
|
? html`<datalist id="${this.id ?? 'tags-input'}-datalist">
|
||||||
${(this.datalist ?? []).map((value) => html`<option value=${value}>`)}
|
${(this.datalist ?? []).map((value) => html`<option value=${value}>`)}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user