@hashicorp/design-system-components
Version:
Helios Design System Components
214 lines (202 loc) • 7.61 kB
JavaScript
import { buildTask } from 'ember-concurrency/async-arrow-runtime';
import Service from '@ember/service';
import { timeout } from 'ember-concurrency';
import { tracked } from '@glimmer/tracking';
import { DateTime } from 'luxon';
import { isTesting } from '@embroider/macros';
import { g, i } from 'decorator-transforms/runtime';
const MILLISECOND_IN_MS = 1;
const SECOND_IN_MS = 1000 * MILLISECOND_IN_MS;
const MINUTE_IN_MS = 60 * SECOND_IN_MS;
const HOUR_IN_MS = 60 * MINUTE_IN_MS;
const DAY_IN_MS = 24 * HOUR_IN_MS;
const WEEK_IN_MS = 7 * DAY_IN_MS;
const THRESHOLD_RELATIVE_TIME_IN_MS = WEEK_IN_MS;
let HdsTimeRelativeUnitValues = /*#__PURE__*/function (HdsTimeRelativeUnitValues) {
HdsTimeRelativeUnitValues["Second"] = "second";
HdsTimeRelativeUnitValues["Hour"] = "hour";
HdsTimeRelativeUnitValues["Minute"] = "minute";
HdsTimeRelativeUnitValues["Day"] = "day";
HdsTimeRelativeUnitValues["Week"] = "week";
return HdsTimeRelativeUnitValues;
}({});
const DEFAULT_RELATIVE_THRESHOLDS = {
[HdsTimeRelativeUnitValues.Second]: 1 * MINUTE_IN_MS,
[HdsTimeRelativeUnitValues.Minute]: 1 * HOUR_IN_MS,
[HdsTimeRelativeUnitValues.Hour]: 1 * DAY_IN_MS,
[HdsTimeRelativeUnitValues.Day]: 100 * WEEK_IN_MS
};
let HdsDisplayKeyValues = /*#__PURE__*/function (HdsDisplayKeyValues) {
HdsDisplayKeyValues["FriendlyRelative"] = "friendly-relative";
// Example: 'Sep 5, 2018 (30 minutes ago)'
HdsDisplayKeyValues["FriendlyLocal"] = "friendly-local";
// Example: 'Sep 5, 2018, 4:07:32 pm'
HdsDisplayKeyValues["FriendlyOnly"] = "friendly-only";
// Example: 'Sep 5, 2018'
HdsDisplayKeyValues["Relative"] = "relative";
// Example: 'in 7 days'
HdsDisplayKeyValues["Utc"] = "utc"; // Example: '2018-09-05T23:15:17345Z'
return HdsDisplayKeyValues;
}({});
const FORMAT_PRECISION_SHORT_DATE = {
month: 'short',
day: 'numeric',
year: 'numeric'
};
const FORMAT_PRECISION_MINUTE = {
...FORMAT_PRECISION_SHORT_DATE,
hour: 'numeric',
minute: 'numeric'
};
const FORMAT_PRECISION_SECOND = {
...FORMAT_PRECISION_SHORT_DATE,
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
timeZoneName: 'short'
};
const DATE_DISPLAY_FORMATS = {
[HdsDisplayKeyValues.FriendlyLocal]: FORMAT_PRECISION_SECOND,
[HdsDisplayKeyValues.FriendlyOnly]: FORMAT_PRECISION_SHORT_DATE
};
const DEFAULT_DISPLAY = '';
const DEFAULT_DISPLAY_MAPPING = {
[HdsDisplayKeyValues.FriendlyRelative]: {
displayFormat: FORMAT_PRECISION_SHORT_DATE,
showFriendly: true,
showRelative: true,
tooltipFormat: FORMAT_PRECISION_SECOND
},
[HdsDisplayKeyValues.FriendlyLocal]: {
displayFormat: DATE_DISPLAY_FORMATS[HdsDisplayKeyValues.FriendlyLocal],
showFriendly: true,
showRelative: false,
tooltipFormat: null
},
[HdsDisplayKeyValues.FriendlyOnly]: {
displayFormat: DATE_DISPLAY_FORMATS[HdsDisplayKeyValues.FriendlyOnly],
showFriendly: true,
showRelative: false,
tooltipFormat: null
},
[HdsDisplayKeyValues.Relative]: {
displayFormat: null,
showFriendly: false,
showRelative: true,
tooltipFormat: FORMAT_PRECISION_MINUTE
},
[HdsDisplayKeyValues.Utc]: {
displayFormat: null,
showFriendly: true,
showRelative: false,
tooltipFormat: null
}
};
const DISPLAY_SCALE = Object.keys(DEFAULT_DISPLAY_MAPPING);
const DISPLAYS = [HdsDisplayKeyValues.FriendlyRelative, HdsDisplayKeyValues.FriendlyLocal, HdsDisplayKeyValues.FriendlyOnly, HdsDisplayKeyValues.Relative, HdsDisplayKeyValues.Utc];
class TimeService extends Service {
#listeners = new Set();
static {
g(this.prototype, "now", [tracked], function () {
return Date.now();
});
}
#now = (i(this, "now"), void 0);
format(difference, display = DEFAULT_DISPLAY) {
let displayKey;
// If the scale display is defined and valid then set that display.
if (display && DISPLAY_SCALE.includes(display)) {
displayKey = display;
} else {
// If there's no defined display then we will execute the design system's
// prefered algorithm.
// By default, we assume we will display just a relative display only.
displayKey = HdsDisplayKeyValues.Relative;
// If the difference in date is greater than the threshold for showing the
// relative time then switch the display key.
if (difference.absValueInMs > THRESHOLD_RELATIVE_TIME_IN_MS) {
displayKey = HdsDisplayKeyValues.FriendlyLocal;
}
}
const options = DEFAULT_DISPLAY_MAPPING[displayKey];
return {
options,
difference,
relative: this.selectTimeRelativeUnit(difference)
};
}
// Formats the value of a relative unit.
formatTimeRelativeUnit(value, unit) {
return {
value: Math.trunc(value),
unit
};
}
// Selects an appropriate display format for the difference.
selectTimeRelativeUnit({
absValueInMs,
valueInMs
}, thresholds = DEFAULT_RELATIVE_THRESHOLDS) {
if (absValueInMs < thresholds[HdsTimeRelativeUnitValues.Second]) {
return this.formatTimeRelativeUnit(valueInMs / SECOND_IN_MS, HdsTimeRelativeUnitValues.Second);
}
if (absValueInMs < thresholds[HdsTimeRelativeUnitValues.Minute]) {
return this.formatTimeRelativeUnit(valueInMs / MINUTE_IN_MS, HdsTimeRelativeUnitValues.Minute);
}
if (absValueInMs < thresholds[HdsTimeRelativeUnitValues.Hour]) {
return this.formatTimeRelativeUnit(valueInMs / HOUR_IN_MS, HdsTimeRelativeUnitValues.Hour);
}
if (absValueInMs < thresholds[HdsTimeRelativeUnitValues.Day]) {
return this.formatTimeRelativeUnit(valueInMs / DAY_IN_MS, HdsTimeRelativeUnitValues.Day);
}
return this.formatTimeRelativeUnit(valueInMs / WEEK_IN_MS, HdsTimeRelativeUnitValues.Week);
}
// Gets the currently subscribed listeners.
timeDifference(startDate, endDate) {
const valueInMs = Number(endDate) - Number(startDate);
return {
absValueInMs: Math.abs(valueInMs),
valueInMs
};
}
// Subscribes a listener to the ticking task for time changes.
register(id) {
this.#listeners.add(id);
void this.start.perform();
return () => {
this.unregister(id);
};
}
// Unregisters listener for the time task.
unregister(id) {
return this.#listeners.delete(id);
}
start = buildTask(() => ({
context: this,
generator: function* () {
while (this.listeners.size) {
this.now = Date.now();
// When testing and canceling a EC task, a timer will never resolve and
// cause the test to hang while waiting for a permanently hanging timeout.
// This condition breaks the test out of that.
// via: http://ember-concurrency.com/docs/testing-debugging/
if (isTesting()) return;
yield timeout(SECOND_IN_MS);
}
}
}), null, "start", "drop");
// Transforms a JS date to a string representing the UTC ISO date.
toIsoUtcString(date) {
try {
return DateTime.fromJSDate(date).toUTC().toJSDate().toISOString();
} catch (error) {
console.error('Error: Could not convert date to ISO UTC string; ', error);
}
}
// Gets the currently subscribed listeners.
get listeners() {
return this.#listeners;
}
}
export { DATE_DISPLAY_FORMATS, DAY_IN_MS, DEFAULT_DISPLAY, DEFAULT_DISPLAY_MAPPING, DEFAULT_RELATIVE_THRESHOLDS, DISPLAYS, DISPLAY_SCALE, FORMAT_PRECISION_MINUTE, FORMAT_PRECISION_SECOND, FORMAT_PRECISION_SHORT_DATE, HOUR_IN_MS, HdsDisplayKeyValues, HdsTimeRelativeUnitValues, MILLISECOND_IN_MS, MINUTE_IN_MS, SECOND_IN_MS, THRESHOLD_RELATIVE_TIME_IN_MS, WEEK_IN_MS, TimeService as default };
//# sourceMappingURL=hds-time.js.map