Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inline utilities only used in <relative-time> #186

Merged
merged 4 commits into from
Oct 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 44 additions & 4 deletions src/relative-time-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,71 @@ import RelativeTime from './relative-time.js'
import ExtendedTimeElement from './extended-time-element.js'
import {localeFromElement} from './utils.js'
import {isDuration, withinDuration} from './duration.js'
import {strftime} from './strftime.js'

export default class RelativeTimeElement extends ExtendedTimeElement {
export default class RelativeTimeElement extends ExtendedTimeElement implements Intl.DateTimeFormatOptions {
static get observedAttributes() {
return [...ExtendedTimeElement.observedAttributes, 'prefix']
}

getFormattedDate(now = new Date()): string | undefined {
const date = this.date
if (!date) return
const relativeTime = new RelativeTime(date, localeFromElement(this))
const format = this.format
if (format !== 'auto' && format !== 'micro') {
return relativeTime.formatDate(format)
return strftime(date, format)
}
const tense = this.tense
const micro = format === 'micro'
const inFuture = now.getTime() < date.getTime()
const within = withinDuration(now, date, this.threshold)
const relativeTime = new RelativeTime(date, localeFromElement(this))
if (tense === 'past' || (tense === 'auto' && !inFuture && within)) {
return micro ? relativeTime.microTimeAgo() : relativeTime.timeAgo()
}
if (tense === 'future' || (tense === 'auto' && inFuture && within)) {
return micro ? relativeTime.microTimeUntil() : relativeTime.timeUntil()
}
return `${this.prefix ? `${this.prefix} ` : ''}${relativeTime.formatDate()}`
if ('Intl' in window && 'DateTimeFormat' in Intl) {
const formatter = new Intl.DateTimeFormat(localeFromElement(this), {
minute: this.minute,
hour: this.hour,
day: this.day,
month: this.month,
year: this.year
})
return `${this.prefix} ${formatter.format(date)}`.trim()
}
return `${this.prefix} ${strftime(date, `%b %e${this.year === 'numeric' ? ', %Y' : ''}`)}`.trim()
}

get minute() {
const minute = this.getAttribute('minute')
if (minute === 'numeric' || minute === '2-digit') return minute
}
get hour() {
const hour = this.getAttribute('hour')
if (hour === 'numeric' || hour === '2-digit') return hour
}

get day() {
const day = this.getAttribute('day') ?? 'numeric'
if (day === 'numeric' || day === '2-digit') return day
}

get month() {
const month = this.getAttribute('month') ?? 'short'
if (month === 'numeric' || month === '2-digit' || month === 'short' || month === 'long' || month === 'narrow')
return month
}

get year() {
const year = this.getAttribute('year')
if (year === 'numeric' || year === '2-digit') return year

if (new Date().getUTCFullYear() !== this.date?.getUTCFullYear()) {
return 'numeric'
}
}

/** @deprecated */
Expand Down
13 changes: 0 additions & 13 deletions src/relative-time.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import {isDayFirst, isThisYear, isYearSeparator} from './utils.js'
import {strftime} from './strftime.js'
import {RelativeTime as RelativeTimePonyfill} from './relative-time-ponyfill.js'

export type Format = 'auto' | 'micro' | string
Expand Down Expand Up @@ -123,17 +121,6 @@ export default class RelativeTime {
return '1m'
}
}

formatDate(defaultFormat?: string): string {
let format = defaultFormat
if (format == null) {
format = isDayFirst() ? '%e %b' : '%b %e'
if (!isThisYear(this.date)) {
format += isYearSeparator() ? ', %Y' : ' %Y'
}
}
return strftime(this.date, format)
}
}

function formatRelativeTime(locale: string, value: number, unit: Intl.RelativeTimeFormatUnit): string {
Expand Down
32 changes: 0 additions & 32 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,38 +37,6 @@ export function isDayFirst(locale = 'default'): boolean {
}
}

let yearSeparator: boolean | null = null
const yearFormatter = makeFormatter({day: 'numeric', month: 'short', year: 'numeric'})

// Private: Determine if the year should be separated from the month and day
// with a comma. For example, `9 Jun 2014` in en-GB and `Jun 9, 2014` in en-US.
//
// Returns true if the date needs a separator.
export function isYearSeparator(): boolean {
if (yearSeparator !== null) {
return yearSeparator
}

const formatter = yearFormatter()
if (formatter) {
const output = formatter.format(new Date(0))
yearSeparator = !!output.match(/\d,/)
return yearSeparator
} else {
return true
}
}

// Private: Determine if the date occurs in the same year as today's date.
//
// date - The Date to test.
//
// Returns true if it's this year.
export function isThisYear(date: Date): boolean {
const now = new Date()
return now.getUTCFullYear() === date.getUTCFullYear()
}

// Private: Get preferred Intl locale for a target element.
//
// Traverses parents until it finds an explicit `lang` other returns "default".
Expand Down