@canonical/react-ds-app-launchpad 0.9.0-experimental.5 → 0.9.0-experimental.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/esm/ui/RelativeTime/RelativeTime.js +66 -0
  2. package/dist/esm/ui/RelativeTime/RelativeTime.js.map +1 -0
  3. package/dist/esm/ui/RelativeTime/index.js +4 -0
  4. package/dist/esm/ui/RelativeTime/index.js.map +1 -0
  5. package/dist/esm/ui/RelativeTime/types.js +2 -0
  6. package/dist/esm/ui/RelativeTime/types.js.map +1 -0
  7. package/dist/esm/ui/RelativeTime/utils/constants.js +6 -0
  8. package/dist/esm/ui/RelativeTime/utils/constants.js.map +1 -0
  9. package/dist/esm/ui/RelativeTime/utils/formatHumanTime.js +43 -0
  10. package/dist/esm/ui/RelativeTime/utils/formatHumanTime.js.map +1 -0
  11. package/dist/esm/ui/RelativeTime/utils/getOptimalUpdateInterval.js +24 -0
  12. package/dist/esm/ui/RelativeTime/utils/getOptimalUpdateInterval.js.map +1 -0
  13. package/dist/esm/ui/RelativeTime/utils/index.js +4 -0
  14. package/dist/esm/ui/RelativeTime/utils/index.js.map +1 -0
  15. package/dist/esm/ui/RelativeTime/utils/parseInstant.js +22 -0
  16. package/dist/esm/ui/RelativeTime/utils/parseInstant.js.map +1 -0
  17. package/dist/types/ui/RelativeTime/RelativeTime.d.ts +11 -0
  18. package/dist/types/ui/RelativeTime/RelativeTime.d.ts.map +1 -0
  19. package/dist/types/ui/RelativeTime/index.d.ts +3 -0
  20. package/dist/types/ui/RelativeTime/index.d.ts.map +1 -0
  21. package/dist/types/ui/RelativeTime/types.d.ts +36 -0
  22. package/dist/types/ui/RelativeTime/types.d.ts.map +1 -0
  23. package/dist/types/ui/RelativeTime/utils/constants.d.ts +6 -0
  24. package/dist/types/ui/RelativeTime/utils/constants.d.ts.map +1 -0
  25. package/dist/types/ui/RelativeTime/utils/formatHumanTime.d.ts +21 -0
  26. package/dist/types/ui/RelativeTime/utils/formatHumanTime.d.ts.map +1 -0
  27. package/dist/types/ui/RelativeTime/utils/getOptimalUpdateInterval.d.ts +8 -0
  28. package/dist/types/ui/RelativeTime/utils/getOptimalUpdateInterval.d.ts.map +1 -0
  29. package/dist/types/ui/RelativeTime/utils/index.d.ts +4 -0
  30. package/dist/types/ui/RelativeTime/utils/index.d.ts.map +1 -0
  31. package/dist/types/ui/RelativeTime/utils/parseInstant.d.ts +9 -0
  32. package/dist/types/ui/RelativeTime/utils/parseInstant.d.ts.map +1 -0
  33. package/package.json +3 -2
@@ -0,0 +1,66 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
+ import { formatHumanTime, getOptimalUpdateInterval, parseInstant, } from "./utils/index.js";
4
+ const componentCssClassName = "ds relative-time";
5
+ /**
6
+ * The RelativeTime component displays timestamps in a human-readable relative format (like "2 hours ago" or "in 3 days").
7
+ *
8
+ * It features automatic live updates with interval optimization based on time distance, configurable "now" threshold,
9
+ * and renders as proper semantic HTML using the <time> element. The component leverages the Temporal API for calculations and Intl.RelativeTimeFormat for localization.
10
+ */
11
+ const RelativeTime = ({ id, className, style, time, relativeTimeFormat, nowThreshold = 10, disableLiveUpdate = false, nowKeyword = "now", invalidDateKeyword = "invalid date", }) => {
12
+ const [relativeTime, setRelativeTime] = useState("");
13
+ const [localeTimeString, setLocaleTimeString] = useState("");
14
+ const [stringTime, setStringTime] = useState("");
15
+ const intervalRef = useRef(null);
16
+ const instantTime = useMemo(() => {
17
+ try {
18
+ return parseInstant(time);
19
+ }
20
+ catch (error) {
21
+ console.error(error);
22
+ return null;
23
+ }
24
+ }, [time]);
25
+ const updateRelativeTime = useCallback(() => {
26
+ if (instantTime === null) {
27
+ setRelativeTime(invalidDateKeyword);
28
+ setLocaleTimeString("");
29
+ setStringTime("");
30
+ return null;
31
+ }
32
+ const timeFormatter = relativeTimeFormat ||
33
+ new Intl.RelativeTimeFormat(undefined, { numeric: "auto" });
34
+ setRelativeTime(formatHumanTime(instantTime, {
35
+ nowThreshold,
36
+ nowKeyword,
37
+ relativeTimeFormat: timeFormatter,
38
+ }));
39
+ setLocaleTimeString(instantTime.toLocaleString());
40
+ setStringTime(instantTime.toString());
41
+ }, [
42
+ instantTime,
43
+ relativeTimeFormat,
44
+ nowThreshold,
45
+ nowKeyword,
46
+ invalidDateKeyword,
47
+ ]);
48
+ useEffect(() => {
49
+ // initial calculation
50
+ updateRelativeTime();
51
+ if (disableLiveUpdate || instantTime === null)
52
+ return;
53
+ const updateInterval = getOptimalUpdateInterval(instantTime);
54
+ // SSR check
55
+ if (typeof window === "undefined")
56
+ return;
57
+ intervalRef.current = window.setInterval(updateRelativeTime, updateInterval);
58
+ return () => {
59
+ if (intervalRef.current)
60
+ window.clearInterval(intervalRef.current);
61
+ };
62
+ }, [instantTime, disableLiveUpdate, updateRelativeTime]);
63
+ return (_jsx("time", { id: id, style: style, className: [componentCssClassName, className].filter(Boolean).join(" "), title: localeTimeString, dateTime: stringTime, children: relativeTime }));
64
+ };
65
+ export default RelativeTime;
66
+ //# sourceMappingURL=RelativeTime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RelativeTime.js","sourceRoot":"","sources":["../../../../src/ui/RelativeTime/RelativeTime.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /* @canonical/generator-ds 0.9.0-experimental.4 */
2
+ export { default as RelativeTime } from "./RelativeTime.js";
3
+ export * from "./types.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/ui/RelativeTime/index.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC5D,cAAc,YAAY,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/ui/RelativeTime/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ export const MINUTE_IN_SECONDS = 60;
2
+ export const HOUR_IN_SECONDS = MINUTE_IN_SECONDS * 60;
3
+ export const DAY_IN_SECONDS = HOUR_IN_SECONDS * 24;
4
+ export const MONTH_IN_SECONDS = DAY_IN_SECONDS * 30;
5
+ export const YEAR_IN_SECONDS = DAY_IN_SECONDS * 365;
6
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../../src/ui/RelativeTime/utils/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AACpC,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,GAAG,EAAE,CAAC;AACtD,MAAM,CAAC,MAAM,cAAc,GAAG,eAAe,GAAG,EAAE,CAAC;AACnD,MAAM,CAAC,MAAM,gBAAgB,GAAG,cAAc,GAAG,EAAE,CAAC;AACpD,MAAM,CAAC,MAAM,eAAe,GAAG,cAAc,GAAG,GAAG,CAAC"}
@@ -0,0 +1,43 @@
1
+ import { Temporal } from "@js-temporal/polyfill";
2
+ /**
3
+ * Formats a given instant as a human-readable time relative to the current time.
4
+ * @param instant The instant to format.
5
+ * @param options The options to use for formatting.
6
+ * @returns A human-readable relative time string
7
+ */
8
+ function formatHumanTime(instant, options) {
9
+ const now = Temporal.Now.instant();
10
+ const deltaSeconds = instant.epochSeconds - now.epochSeconds;
11
+ const absDeltaSeconds = Math.abs(deltaSeconds);
12
+ if (absDeltaSeconds < options.nowThreshold) {
13
+ return options.nowKeyword;
14
+ }
15
+ const timeZone = Temporal.Now.timeZoneId() || "UTC";
16
+ const instantZDT = instant.toZonedDateTimeISO(timeZone);
17
+ const nowZDT = now.toZonedDateTimeISO(timeZone);
18
+ const diff = instantZDT.since(nowZDT, { largestUnit: "years" });
19
+ const units = [
20
+ "years",
21
+ "months",
22
+ "days",
23
+ "hours",
24
+ "minutes",
25
+ "seconds",
26
+ ];
27
+ let rtfUnit = "seconds";
28
+ let rtfValue = 0;
29
+ for (const unit of units) {
30
+ const value = diff[unit];
31
+ if (value !== 0) {
32
+ rtfUnit = unit;
33
+ rtfValue = value;
34
+ break;
35
+ }
36
+ }
37
+ if (rtfValue === 0) {
38
+ return options.nowKeyword;
39
+ }
40
+ return options.relativeTimeFormat.format(rtfValue, rtfUnit);
41
+ }
42
+ export default formatHumanTime;
43
+ //# sourceMappingURL=formatHumanTime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatHumanTime.js","sourceRoot":"","sources":["../../../../../src/ui/RelativeTime/utils/formatHumanTime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAgBjD;;;;;GAKG;AACH,SAAS,eAAe,CACtB,OAAyB,EACzB,OAAyB;IAEzB,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IACnC,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC;IAC7D,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAE/C,IAAI,eAAe,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;QAC3C,OAAO,OAAO,CAAC,UAAU,CAAC;IAC5B,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,KAAK,CAAC;IACpD,MAAM,UAAU,GAAG,OAAO,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,GAAG,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;IAEhE,MAAM,KAAK,GAAG;QACZ,OAAO;QACP,QAAQ;QACR,MAAM;QACN,OAAO;QACP,SAAS;QACT,SAAS;KAC8B,CAAC;IAE1C,IAAI,OAAO,GAAgC,SAAS,CAAC;IACrD,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YAChB,OAAO,GAAG,IAAI,CAAC;YACf,QAAQ,GAAG,KAAK,CAAC;YACjB,MAAM;QACR,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;QACnB,OAAO,OAAO,CAAC,UAAU,CAAC;IAC5B,CAAC;IAED,OAAO,OAAO,CAAC,kBAAkB,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC;AAED,eAAe,eAAe,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { Temporal } from "@js-temporal/polyfill";
2
+ import * as constants from "./constants.js";
3
+ /**
4
+ * Calcualte the optimal update interval for a given instant based on the time distance from now.
5
+ * @returns The optimal update interval in milliseconds.
6
+ */
7
+ function getOptimalUpdateInterval(instant) {
8
+ const now = Temporal.Now.instant();
9
+ const deltaSeconds = instant.epochSeconds - now.epochSeconds;
10
+ const absDeltaSeconds = Math.abs(deltaSeconds);
11
+ if (absDeltaSeconds < constants.MINUTE_IN_SECONDS) {
12
+ return 1000;
13
+ }
14
+ if (absDeltaSeconds < constants.HOUR_IN_SECONDS) {
15
+ return constants.MINUTE_IN_SECONDS * 1000;
16
+ }
17
+ if (absDeltaSeconds < constants.DAY_IN_SECONDS) {
18
+ return constants.HOUR_IN_SECONDS * 1000;
19
+ }
20
+ // for any other time distance, update once a day
21
+ return constants.DAY_IN_SECONDS * 1000;
22
+ }
23
+ export default getOptimalUpdateInterval;
24
+ //# sourceMappingURL=getOptimalUpdateInterval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getOptimalUpdateInterval.js","sourceRoot":"","sources":["../../../../../src/ui/RelativeTime/utils/getOptimalUpdateInterval.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAE5C;;;GAGG;AACH,SAAS,wBAAwB,CAAC,OAAyB;IACzD,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IACnC,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC;IAC7D,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAE/C,IAAI,eAAe,GAAG,SAAS,CAAC,iBAAiB,EAAE,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,eAAe,GAAG,SAAS,CAAC,eAAe,EAAE,CAAC;QAChD,OAAO,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAC5C,CAAC;IAED,IAAI,eAAe,GAAG,SAAS,CAAC,cAAc,EAAE,CAAC;QAC/C,OAAO,SAAS,CAAC,eAAe,GAAG,IAAI,CAAC;IAC1C,CAAC;IACD,iDAAiD;IACjD,OAAO,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC;AACzC,CAAC;AAED,eAAe,wBAAwB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { default as formatHumanTime } from "./formatHumanTime.js";
2
+ export { default as getOptimalUpdateInterval } from "./getOptimalUpdateInterval.js";
3
+ export { default as parseInstant } from "./parseInstant.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/ui/RelativeTime/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { Temporal } from "@js-temporal/polyfill";
2
+ /**
3
+ * Parser for Temporal.Instant.
4
+ * @param time - instance, date or string to parse
5
+ * @throws Error if time is invalid
6
+ */
7
+ function parseInstant(time) {
8
+ if (time instanceof Temporal.Instant) {
9
+ return time;
10
+ }
11
+ if (time instanceof Date) {
12
+ return Temporal.Instant.fromEpochMilliseconds(time.getTime());
13
+ }
14
+ try {
15
+ return Temporal.Instant.from(time);
16
+ }
17
+ catch (e) {
18
+ throw new Error(`Invalid time string (ISO string or Date object expected): ${time}`);
19
+ }
20
+ }
21
+ export default parseInstant;
22
+ //# sourceMappingURL=parseInstant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseInstant.js","sourceRoot":"","sources":["../../../../../src/ui/RelativeTime/utils/parseInstant.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD;;;;GAIG;AACH,SAAS,YAAY,CAAC,IAAsC;IAC1D,IAAI,IAAI,YAAY,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,IAAI,YAAY,IAAI,EAAE,CAAC;QACzB,OAAO,QAAQ,CAAC,OAAO,CAAC,qBAAqB,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAChE,CAAC;IACD,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,6DAA6D,IAAI,EAAE,CACpE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,eAAe,YAAY,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type React from "react";
2
+ import type { RelativeTimeProps } from "./types.js";
3
+ /**
4
+ * The RelativeTime component displays timestamps in a human-readable relative format (like "2 hours ago" or "in 3 days").
5
+ *
6
+ * It features automatic live updates with interval optimization based on time distance, configurable "now" threshold,
7
+ * and renders as proper semantic HTML using the <time> element. The component leverages the Temporal API for calculations and Intl.RelativeTimeFormat for localization.
8
+ */
9
+ declare const RelativeTime: ({ id, className, style, time, relativeTimeFormat, nowThreshold, disableLiveUpdate, nowKeyword, invalidDateKeyword, }: RelativeTimeProps) => React.ReactElement;
10
+ export default RelativeTime;
11
+ //# sourceMappingURL=RelativeTime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RelativeTime.d.ts","sourceRoot":"","sources":["../../../../src/ui/RelativeTime/RelativeTime.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AASpD;;;;;GAKG;AACH,QAAA,MAAM,YAAY,yHAUf,iBAAiB,KAAG,KAAK,CAAC,YA0E5B,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { default as RelativeTime } from "./RelativeTime.js";
2
+ export * from "./types.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ui/RelativeTime/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC5D,cAAc,YAAY,CAAC"}
@@ -0,0 +1,36 @@
1
+ import type { Temporal } from "@js-temporal/polyfill";
2
+ import type React from "react";
3
+ export interface RelativeTimeProps {
4
+ /** A unique identifier for the RelativeTime */
5
+ id?: string;
6
+ /** Additional CSS classes */
7
+ className?: string;
8
+ /** Inline styles */
9
+ style?: React.CSSProperties;
10
+ /**
11
+ * The time to be displayed as a relative time (ISO string or Date object).
12
+ */
13
+ time: string | Date | Temporal.Instant;
14
+ /**
15
+ * Disable live duration updates (default: false).
16
+ */
17
+ disableLiveUpdate?: boolean;
18
+ /**
19
+ * custom relative time format (default: local language and narrow style).
20
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat
21
+ */
22
+ relativeTimeFormat?: Intl.RelativeTimeFormat;
23
+ /**
24
+ * The threshold in seconds for when to display the relative time as "just now" (default is 10).
25
+ */
26
+ nowThreshold?: number;
27
+ /**
28
+ * The keyword to use for "now" (default: "now")
29
+ */
30
+ nowKeyword?: string;
31
+ /**
32
+ * The keyword to use when the given time is not a valid. (default: "invalid date")
33
+ */
34
+ invalidDateKeyword?: string;
35
+ }
36
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/ui/RelativeTime/types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,WAAW,iBAAiB;IAChC,+CAA+C;IAC/C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,oBAAoB;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAE5B;;OAEG;IACH,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC;IAEvC;;OAEG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,IAAI,CAAC,kBAAkB,CAAC;IAE7C;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B"}
@@ -0,0 +1,6 @@
1
+ export declare const MINUTE_IN_SECONDS = 60;
2
+ export declare const HOUR_IN_SECONDS: number;
3
+ export declare const DAY_IN_SECONDS: number;
4
+ export declare const MONTH_IN_SECONDS: number;
5
+ export declare const YEAR_IN_SECONDS: number;
6
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../../src/ui/RelativeTime/utils/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,eAAe,QAAyB,CAAC;AACtD,eAAO,MAAM,cAAc,QAAuB,CAAC;AACnD,eAAO,MAAM,gBAAgB,QAAsB,CAAC;AACpD,eAAO,MAAM,eAAe,QAAuB,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { Temporal } from "@js-temporal/polyfill";
2
+ type FormatterOptions = {
3
+ /** The threshold in seconds for considering the time as "now". */
4
+ nowThreshold: number;
5
+ /** The keyword to use for "now". */
6
+ nowKeyword: string;
7
+ /**
8
+ * The Intl.RelativeTimeFormat instance to use for formatting.
9
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat
10
+ */
11
+ relativeTimeFormat: Intl.RelativeTimeFormat;
12
+ };
13
+ /**
14
+ * Formats a given instant as a human-readable time relative to the current time.
15
+ * @param instant The instant to format.
16
+ * @param options The options to use for formatting.
17
+ * @returns A human-readable relative time string
18
+ */
19
+ declare function formatHumanTime(instant: Temporal.Instant, options: FormatterOptions): string;
20
+ export default formatHumanTime;
21
+ //# sourceMappingURL=formatHumanTime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatHumanTime.d.ts","sourceRoot":"","sources":["../../../../../src/ui/RelativeTime/utils/formatHumanTime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,KAAK,gBAAgB,GAAG;IACtB,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAC;IAErB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,kBAAkB,EAAE,IAAI,CAAC,kBAAkB,CAAC;CAC7C,CAAC;AAEF;;;;;GAKG;AACH,iBAAS,eAAe,CACtB,OAAO,EAAE,QAAQ,CAAC,OAAO,EACzB,OAAO,EAAE,gBAAgB,GACxB,MAAM,CAwCR;AAED,eAAe,eAAe,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { Temporal } from "@js-temporal/polyfill";
2
+ /**
3
+ * Calcualte the optimal update interval for a given instant based on the time distance from now.
4
+ * @returns The optimal update interval in milliseconds.
5
+ */
6
+ declare function getOptimalUpdateInterval(instant: Temporal.Instant): number;
7
+ export default getOptimalUpdateInterval;
8
+ //# sourceMappingURL=getOptimalUpdateInterval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getOptimalUpdateInterval.d.ts","sourceRoot":"","sources":["../../../../../src/ui/RelativeTime/utils/getOptimalUpdateInterval.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGjD;;;GAGG;AACH,iBAAS,wBAAwB,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,GAAG,MAAM,CAkBnE;AAED,eAAe,wBAAwB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { default as formatHumanTime } from "./formatHumanTime.js";
2
+ export { default as getOptimalUpdateInterval } from "./getOptimalUpdateInterval.js";
3
+ export { default as parseInstant } from "./parseInstant.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/ui/RelativeTime/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { Temporal } from "@js-temporal/polyfill";
2
+ /**
3
+ * Parser for Temporal.Instant.
4
+ * @param time - instance, date or string to parse
5
+ * @throws Error if time is invalid
6
+ */
7
+ declare function parseInstant(time: Temporal.Instant | Date | string): Temporal.Instant;
8
+ export default parseInstant;
9
+ //# sourceMappingURL=parseInstant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseInstant.d.ts","sourceRoot":"","sources":["../../../../../src/ui/RelativeTime/utils/parseInstant.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD;;;;GAIG;AACH,iBAAS,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,GAAG,IAAI,GAAG,MAAM,oBAc3D;AAED,eAAe,YAAY,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonical/react-ds-app-launchpad",
3
- "version": "0.9.0-experimental.5",
3
+ "version": "0.9.0-experimental.6",
4
4
  "type": "module",
5
5
  "module": "dist/esm/index.js",
6
6
  "types": "dist/types/index.d.ts",
@@ -41,6 +41,7 @@
41
41
  "@canonical/storybook-config": "^0.9.0-experimental.5",
42
42
  "@canonical/styles": "^0.9.0-experimental.2",
43
43
  "@canonical/utils": "^0.9.0-experimental.4",
44
+ "@js-temporal/polyfill": "^0.4.4",
44
45
  "highlight.js": "^11.11.1",
45
46
  "react": "^19.0.0",
46
47
  "react-dom": "^19.0.0"
@@ -68,5 +69,5 @@
68
69
  "vite-tsconfig-paths": "^5.1.4",
69
70
  "vitest": "^2.1.8"
70
71
  },
71
- "gitHead": "bc797d0c134200c372d31a8db89659caba2d6384"
72
+ "gitHead": "88907393fcb7f317006ac5198c849fd6ba0b8c0b"
72
73
  }