diff --git a/examples/index.html b/examples/index.html index 13d91ba..886af5c 100644 --- a/examples/index.html +++ b/examples/index.html @@ -200,6 +200,14 @@

Localised Dates

+

With Aria Hidden

+ + + diff --git a/src/relative-time-element.ts b/src/relative-time-element.ts index 068183d..80dc977 100644 --- a/src/relative-time-element.ts +++ b/src/relative-time-element.ts @@ -112,6 +112,7 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor 'datetime', 'lang', 'title', + 'aria-hidden', ] } @@ -201,6 +202,17 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor return `${this.prefix} ${formatter.format(date)}`.trim() } + #updateRenderRootContent(content: string | null): void { + if (this.hasAttribute('aria-hidden') && this.getAttribute('aria-hidden') === 'true') { + const span = document.createElement('span') + span.setAttribute('aria-hidden', 'true') + span.textContent = content + ;(this.#renderRoot as Element).replaceChildren(span) + } else { + this.#renderRoot.textContent = content + } + } + #onRelativeTimeUpdated: ((event: RelativeTimeUpdatedEvent) => void) | null = null get onRelativeTimeUpdated() { return this.#onRelativeTimeUpdated @@ -459,10 +471,10 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor } if (newText) { - this.#renderRoot.textContent = newText + this.#updateRenderRootContent(newText) } else if (this.shadowRoot === this.#renderRoot && this.textContent) { // Ensure invalid dates fall back to lightDOM text content - this.#renderRoot.textContent = this.textContent + this.#updateRenderRootContent(this.textContent) } if (newText !== oldText || newTitle !== oldTitle) { diff --git a/test/relative-time.js b/test/relative-time.js index 0d13096..de5c102 100644 --- a/test/relative-time.js +++ b/test/relative-time.js @@ -130,6 +130,7 @@ suite('relative-time', function () { ...Object.getOwnPropertyNames(HTMLElement.prototype), ] const observedAttributes = new Set(RelativeTimeElement.observedAttributes) + observedAttributes.delete('aria-hidden') // Standard HTML attribute, no need for custom getter for (const member of members) observedAttributes.delete(member) assert.empty([...observedAttributes], 'observedAttributes that arent class members') }) @@ -1872,6 +1873,40 @@ suite('relative-time', function () { } }) + suite('[aria-hidden]', async () => { + test('[aria-hidden="true"] applies to shadow root', async () => { + const now = new Date().toISOString() + const time = document.createElement('relative-time') + time.setAttribute('datetime', now) + time.setAttribute('aria-hidden', 'true') + await Promise.resolve() + + const span = time.shadowRoot.querySelector('span') + assert.equal(span.getAttribute('aria-hidden'), 'true') + }) + + test('[aria-hidden="false"] applies to shadow root', async () => { + const now = new Date().toISOString() + const time = document.createElement('relative-time') + time.setAttribute('datetime', now) + time.setAttribute('aria-hidden', 'false') + await Promise.resolve() + + assert.isNull(time.shadowRoot.querySelector('[aria-hidden]'), 'Expected no aria-hidden to be present') + assert.isNull(time.shadowRoot.querySelector('span'), 'Expected no span to be present') + }) + + test('no aria-hidden applies to shadow root', async () => { + const now = new Date().toISOString() + const time = document.createElement('relative-time') + time.setAttribute('datetime', now) + await Promise.resolve() + + assert.isNull(time.shadowRoot.querySelector('[aria-hidden]'), 'Expected no aria-hidden to be present') + assert.isNull(time.shadowRoot.querySelector('span'), 'Expected no span to be present') + }) + }) + suite('legacy formats', function () { const referenceDate = '2022-10-24T14:46:00.000Z' const tests = new Set([