Vendor relative-time-element as local web component (#36853)

Replace the `@github/relative-time-element` npm dependency with a
vendored, simplified implementation.

- Support 24h format rendering [PR
329](https://github.com/github/relative-time-element/pull/329)
- Enable `::selection` styling in Firefox [PR
341](https://github.com/github/relative-time-element/pull/341)
- Remove timezone from tooltips (It's always local timezone)
- Clean up previous `title` workaround in tippy
- Remove unused features
- Use native `Intl.DurationFormat` with fallback for older browsers,
remove dead polyfill
- Add MIT license header to vendored file
- Add unit tests
- Add dedicated devtest page for all component variants

---------

Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude claude-opus-4-6 20250630 <noreply@anthropic.com>
This commit is contained in:
silverwind
2026-03-13 11:43:17 +01:00
committed by GitHub
parent 2601f50026
commit 28e09ffc67
12 changed files with 734 additions and 73 deletions

View File

@@ -1,6 +1,5 @@
import tippy, {followCursor} from 'tippy.js';
import {isDocumentFragmentOrElementNode} from '../utils/dom.ts';
import {formatDatetime} from '../utils/time.ts';
import type {Content, Instance, Placement, Props} from 'tippy.js';
import {html} from '../utils/html.ts';
@@ -100,20 +99,10 @@ function attachTooltip(target: Element, content: Content | null = null): Instanc
}
function switchTitleToTooltip(target: Element): void {
let title = target.getAttribute('title');
const title = target.getAttribute('title');
if (title) {
// apply custom formatting to relative-time's tooltips
if (target.tagName.toLowerCase() === 'relative-time') {
const datetime = target.getAttribute('datetime');
if (datetime) {
title = formatDatetime(new Date(datetime));
}
}
target.setAttribute('data-tooltip-content', title);
target.setAttribute('aria-label', title);
// keep the attribute, in case there are some other "[title]" selectors
// and to prevent infinite loop with <relative-time> which will re-add
// title if it is absent
target.setAttribute('title', '');
}
}
@@ -155,7 +144,7 @@ export function initGlobalTooltips(): void {
const observerConnect = (observer: MutationObserver) => observer.observe(document, {
subtree: true,
childList: true,
attributeFilter: ['data-tooltip-content', 'title'],
attributeFilter: ['data-tooltip-content'],
});
const observer = new MutationObserver((mutationList, observer) => {
const pending = observer.takeRecords();