Skip to content

Support explicit micro thresholds#354

Open
maxbeizer wants to merge 7 commits into
mainfrom
mb/micro-explicit-threshold
Open

Support explicit micro thresholds#354
maxbeizer wants to merge 7 commits into
mainfrom
mb/micro-explicit-threshold

Conversation

@maxbeizer
Copy link
Copy Markdown

@maxbeizer maxbeizer commented Jun 2, 2026

Summary

format="micro" currently ignores threshold because it always resolves to duration output. This makes consumers compose their own cutoff logic, which can drift from the element's live updates.

This PR makes threshold support opt-in for micro timestamps:

  • format="micro" threshold="P30D" shows compact durations within the threshold and absolute dates outside it
  • existing format="micro" usages without threshold keep rendering old dates as compact durations
  • threshold comparisons use full elapsed time, independent of display precision
  • future dates outside the threshold schedule an update at the threshold boundary so they switch to micro output on time
  • data-prefers-absolute-time="true" now applies to micro output while duration and elapsed remain excluded

Refs #353

Tests

  • npm test
  • npm run lint

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 2, 2026 21:19
@maxbeizer maxbeizer requested a review from a team as a code owner June 2, 2026 21:19
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates <relative-time> to make format="micro" honor an explicitly provided threshold attribute (while keeping legacy micro behavior when threshold is not set), and to allow data-prefers-absolute-time="true" to override micro output to an absolute format. It also adds/updates tests and documentation to describe and verify the new behavior.

Changes:

  • Update format="micro" resolution to fall back to absolute datetime output when an explicit threshold attribute is present and exceeded.
  • Allow data-prefers-absolute-time="true" to activate even when micro resolves to duration.
  • Add tests and documentation clarifying the “explicit threshold only” behavior for micro.
Show a summary per file
File Description
src/relative-time-element.ts Implements explicit-threshold handling for micro and enables user absolute-time preference for micro-resolved duration.
test/relative-time.js Adds new micro/threshold coverage and updates absolute-time preference expectations for format="micro".
README.md Documents explicit micro threshold behavior and updates threshold guidance.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 3/3 changed files
  • Comments generated: 2

Comment thread README.md
Comment on lines 233 to 236
##### threshold (`string`, default: `P30D`)

If `tense` is anything other than `'auto'`, or `format` is `'relative'` (or the deprecated `'auto'` or `'micro'` values), then this value will be ignored.
If `tense` is anything other than `'auto'`, or `format` is `'relative'` (or the deprecated `'auto'` value), then this value will be ignored. For `format="micro"`, `threshold` is honored only when the `threshold` attribute is explicitly set.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 26ca974 by correcting the threshold docs: threshold applies to relative/auto when tense is auto, and micro only honors it when explicitly set.

Comment on lines 308 to 313
}

#shouldDisplayUserPreferredAbsoluteTime(format: ResolvedFormat): boolean {
// Never override duration format with absolute format.
if (format === 'duration') return false
// Never override duration or elapsed format with absolute format.
if (format === 'duration' && this.format !== 'micro') return false

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 26ca974 by making observation conditional on rendered output: user-preferred absolute micro output no longer keeps duration-style polling except for Today/current-year absolute-time updates.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
maxbeizer and others added 5 commits June 2, 2026 16:54
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
const threshold = getExplicitThreshold(el)
if (el.format === 'micro' && threshold) {
const thresholdDuration = Duration.from(threshold)
const signedThresholdDuration = date.getTime() > now ? negateDuration(thresholdDuration) : thresholdDuration
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the important live-update bit for threshold fallback: the normal observer cadence can be too late, so explicit micro thresholds schedule at date - threshold for future dates and date + threshold for past dates.

observe(element: RelativeTimeElement) {
if (this.elements.has(element)) return
this.elements.add(element)
if (this.updating) return
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This intentionally allows already-observed elements to be rescheduled when threshold is added or changed. The updating guard keeps that from creating duplicate timers while the observer loop is running.


const duration = elapsedTime(date, this.precision, now)
const format = this.#resolveFormat(duration)
const format = this.#resolveFormat(duration, elapsedTime(date, 'millisecond', now))
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a millisecond-precision duration here keeps threshold resolution independent of display precision. Micro still renders with its normal minute floor, but threshold cutoffs are based on the actual elapsed time.

const shouldObserve =
format === 'relative' ||
format === 'duration' ||
(!displayUserPreferredAbsoluteTime && (format === 'relative' || format === 'duration')) ||
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This keeps user-preferred absolute output from polling like duration output. Micro only remains observed for explicit threshold transitions or the existing Today/current-year absolute-time cases.

Comment thread test/relative-time.js
assert.isAtLeast(delays[0], 59000)

delays.length = 0
time.setAttribute('threshold', 'PT1M')
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test covers the dynamic attribute case: a micro element can already be observed, then gain an explicit threshold that requires an earlier reschedule.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants