Skip to content

Commit 402f8af

Browse files
Merge branch 'main' into patch-1
2 parents 7caedfb + 96a93b0 commit 402f8af

6 files changed

Lines changed: 108 additions & 48 deletions

File tree

.github/workflows/test.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ jobs:
1818
uses: actions/setup-node@v3
1919
with:
2020
node-version: 22
21-
- name: npm install, build, and test
22-
run: |
23-
npm it
21+
- name: npm install
22+
run: npm install
23+
- name: Install Playwright browsers
24+
run: npx playwright install --with-deps chromium
25+
- name: Run tests
26+
run: npm test
2427
env:
2528
CI: true

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,20 @@ Lang is a [built-in global attribute](https://developer.mozilla.org/en-US/docs/W
284284

285285
Adding the `no-title` attribute will remove the `title` attribute from the `<relative-time>` element. The `title` attribute is inaccessible to screen reader and keyboard users, so not adding a title attribute allows a user to create a custom, accessible tooltip if one is desired.
286286

287+
## Styling
288+
289+
The element renders its text inside a Shadow DOM `<span>` with a [`part="root"`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/part) attribute. This allows you to style the element inside the Shadow DOM from outside using the `::part()` CSS pseudo-element:
290+
291+
```css
292+
relative-time::part(root) {
293+
color: rebeccapurple;
294+
font-weight: bold;
295+
}
296+
relative-time::part(root)::selection {
297+
background: lightgreen;
298+
}
299+
```
300+
287301
## Browser Support
288302

289303
Browsers without native [custom element support][support] require a [polyfill][ce-polyfill].

package-lock.json

Lines changed: 39 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/duration-format-ponyfill.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export default class DurationFormat {
109109
? twoDigitFormatOptions
110110
: unitStyle === 'numeric'
111111
? {}
112-
: {style: 'unit', unit: nfUnit, unitDisplay: unitStyle}
112+
: {style: 'unit' as const, unit: nfUnit, unitDisplay: unitStyle}
113113

114114
let formattedValue = new Intl.NumberFormat(locale, nfOpts).format(value)
115115

src/relative-time-element.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -272,14 +272,13 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor
272272
}
273273

274274
#updateRenderRootContent(content: string | null): void {
275+
const span = document.createElement('span')
276+
span.setAttribute('part', 'root')
275277
if (this.hasAttribute('aria-hidden') && this.getAttribute('aria-hidden') === 'true') {
276-
const span = document.createElement('span')
277278
span.setAttribute('aria-hidden', 'true')
278-
span.textContent = content
279-
;(this.#renderRoot as Element).replaceChildren(span)
280-
} else {
281-
this.#renderRoot.textContent = content
282279
}
280+
span.textContent = content
281+
;(this.#renderRoot as Element).replaceChildren(span)
283282
}
284283

285284
#shouldDisplayUserPreferredAbsoluteTime(format: ResolvedFormat): boolean {

test/relative-time.js

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -523,14 +523,15 @@ suite('relative-time', function () {
523523
})
524524

525525
test('micro formats years', async () => {
526-
const datetime = new Date()
527-
datetime.setFullYear(datetime.getFullYear() - 10)
526+
// FIXME: there is still a bug, if the duration is long enough (say, 10 or 100 years)
527+
// then the `month = Math.floor(day / 30)` in elapsedTime causes errors, then "10 years" would output "11y"
528+
const now = new Date(Date.now() - 2 * 365 * 24 * 60 * 60 * 1000).toISOString()
528529
const time = document.createElement('relative-time')
529530
time.setAttribute('tense', 'past')
530-
time.setAttribute('datetime', datetime)
531+
time.setAttribute('datetime', now)
531532
time.setAttribute('format', 'micro')
532533
await Promise.resolve()
533-
assert.equal(time.shadowRoot.textContent, '10y')
534+
assert.equal(time.shadowRoot.textContent, '2y')
534535
})
535536

536537
test('micro formats future times', async () => {
@@ -1029,7 +1030,7 @@ suite('relative-time', function () {
10291030
datetime: '2022-10-24T14:46:50.000Z',
10301031
format: 'relative',
10311032
formatStyle: 'narrow',
1032-
expected: 'in 50 sec.',
1033+
expected: 'in 50s',
10331034
},
10341035
{
10351036
datetime: '2022-10-24T14:46:50.000Z',
@@ -1108,7 +1109,7 @@ suite('relative-time', function () {
11081109
datetime: '2022-10-24T14:47:30.000Z',
11091110
format: 'relative',
11101111
formatStyle: 'narrow',
1111-
expected: 'in 1 min.',
1112+
expected: 'in 1m',
11121113
},
11131114
{
11141115
datetime: '2022-10-24T14:47:30.000Z',
@@ -1181,7 +1182,7 @@ suite('relative-time', function () {
11811182
datetime: '2022-11-13T15:46:00.000Z',
11821183
format: 'relative',
11831184
formatStyle: 'narrow',
1184-
expected: 'in 3 wk.',
1185+
expected: 'in 3w',
11851186
},
11861187
{
11871188
datetime: '2022-11-13T15:46:00.000Z',
@@ -1558,7 +1559,7 @@ suite('relative-time', function () {
15581559
datetime: '2022-10-24T14:44:30.000Z',
15591560
format: 'relative',
15601561
formatStyle: 'narrow',
1561-
expected: '1 min. ago',
1562+
expected: '1m ago',
15621563
},
15631564
{
15641565
datetime: '2022-10-24T14:44:30.000Z',
@@ -1631,7 +1632,7 @@ suite('relative-time', function () {
16311632
datetime: '2022-10-04T14:46:00.000Z',
16321633
format: 'relative',
16331634
formatStyle: 'narrow',
1634-
expected: '3 wk. ago',
1635+
expected: '3w ago',
16351636
},
16361637
{
16371638
datetime: '2022-10-04T14:46:00.000Z',
@@ -2121,7 +2122,6 @@ suite('relative-time', function () {
21212122
await Promise.resolve()
21222123

21232124
assert.isNull(time.shadowRoot.querySelector('[aria-hidden]'), 'Expected no aria-hidden to be present')
2124-
assert.isNull(time.shadowRoot.querySelector('span'), 'Expected no span to be present')
21252125
})
21262126

21272127
test('no aria-hidden applies to shadow root', async () => {
@@ -2131,7 +2131,30 @@ suite('relative-time', function () {
21312131
await Promise.resolve()
21322132

21332133
assert.isNull(time.shadowRoot.querySelector('[aria-hidden]'), 'Expected no aria-hidden to be present')
2134-
assert.isNull(time.shadowRoot.querySelector('span'), 'Expected no span to be present')
2134+
})
2135+
})
2136+
2137+
suite('[part]', () => {
2138+
test('shadow root span has part="root"', async () => {
2139+
const now = new Date().toISOString()
2140+
const time = document.createElement('relative-time')
2141+
time.setAttribute('datetime', now)
2142+
await Promise.resolve()
2143+
2144+
const span = time.shadowRoot.querySelector('span')
2145+
assert.equal(span.getAttribute('part'), 'root')
2146+
})
2147+
2148+
test('shadow root span has part="root" alongside aria-hidden="true"', async () => {
2149+
const now = new Date().toISOString()
2150+
const time = document.createElement('relative-time')
2151+
time.setAttribute('datetime', now)
2152+
time.setAttribute('aria-hidden', 'true')
2153+
await Promise.resolve()
2154+
2155+
const span = time.shadowRoot.querySelector('span')
2156+
assert.equal(span.getAttribute('part'), 'root')
2157+
assert.equal(span.getAttribute('aria-hidden'), 'true')
21352158
})
21362159
})
21372160

@@ -2506,28 +2529,28 @@ suite('relative-time', function () {
25062529
lang: 'en',
25072530
tense: 'future',
25082531
formatStyle: 'narrow',
2509-
expected: 'in 1 hr.',
2532+
expected: 'in 1h',
25102533
},
25112534
{
25122535
datetime: '2022-10-24T16:00:00.000Z',
25132536
lang: 'en',
25142537
tense: 'future',
25152538
formatStyle: 'narrow',
2516-
expected: 'in 1 hr.',
2539+
expected: 'in 1h',
25172540
},
25182541
{
25192542
datetime: '2022-10-24T16:15:00.000Z',
25202543
lang: 'en',
25212544
tense: 'future',
25222545
formatStyle: 'narrow',
2523-
expected: 'in 1 hr.',
2546+
expected: 'in 1h',
25242547
},
25252548
{
25262549
datetime: '2022-10-24T16:31:00.000Z',
25272550
lang: 'en',
25282551
tense: 'future',
25292552
formatStyle: 'narrow',
2530-
expected: 'in 1 hr.',
2553+
expected: 'in 1h',
25312554
},
25322555
{
25332556
datetime: '2022-10-30T14:46:00.000Z',
@@ -2562,14 +2585,14 @@ suite('relative-time', function () {
25622585
lang: 'en',
25632586
tense: 'future',
25642587
formatStyle: 'narrow',
2565-
expected: 'in 2 yr.',
2588+
expected: 'in 2y',
25662589
},
25672590
{
25682591
datetime: '2024-04-01T14:46:00.000Z',
25692592
lang: 'en',
25702593
tense: 'future',
25712594
formatStyle: 'narrow',
2572-
expected: 'in 2 yr.',
2595+
expected: 'in 2y',
25732596
},
25742597

25752598
// Dates in the future
@@ -2658,28 +2681,28 @@ suite('relative-time', function () {
26582681
lang: 'en',
26592682
tense: 'past',
26602683
formatStyle: 'narrow',
2661-
expected: '1 hr. ago',
2684+
expected: '1h ago',
26622685
},
26632686
{
26642687
datetime: '2022-10-24T13:30:00.000Z',
26652688
lang: 'en',
26662689
tense: 'past',
26672690
formatStyle: 'narrow',
2668-
expected: '1 hr. ago',
2691+
expected: '1h ago',
26692692
},
26702693
{
26712694
datetime: '2022-10-24T13:17:00.000Z',
26722695
lang: 'en',
26732696
tense: 'past',
26742697
formatStyle: 'narrow',
2675-
expected: '1 hr. ago',
2698+
expected: '1h ago',
26762699
},
26772700
{
26782701
datetime: '2022-10-24T13:01:00.000Z',
26792702
lang: 'en',
26802703
tense: 'past',
26812704
formatStyle: 'narrow',
2682-
expected: '1 hr. ago',
2705+
expected: '1h ago',
26832706
},
26842707
{
26852708
datetime: '2022-10-18T14:46:00.000Z',

0 commit comments

Comments
 (0)