{"version":3,"file":"RelativeTimestamp.jsx","names":["memo","relativeDateFormatter","Intl","RelativeTimeFormat","style","numeric","relativeDateFormatterNarrow","absoluteFormatter","DateTimeFormat","dateStyle","timeStyle","formatterMap","long","narrow","short","format","value","unit","v","Math","abs","round","RelativeTimestamp","t0","$","_c","date","relativeToDate","t1","longDateTime","relativeDate","t2","d","Date","t3","getRelativeDate","toISOString","unitsInMs","year","month","week","day","hour","minute","second","relativeTo","elapsed","getTime","divisor","Object","entries","formatter"],"sources":["../src/RelativeTimestamp.tsx"],"sourcesContent":["import { memo } from \"react\";\n\n// This component always renders the server time / UTC.\n// It does not (yet) support rendering some parts in the time zone of the client.\n// It is also not language-/locale-aware.\n\n// For DE locale, usually returns something like \"vor 10 Tagen\"\n// `numeric: \"auto\"` results in additional wordings to be used.\n// For example, instead of \"vor 1 Tag\", it will return \"gestern\"\n// `style: \"long\"` will return \"vor 6 Minuten\"\n// `style: \"short\"` will return \"vor 6 Min.\"\nconst relativeDateFormatter = new Intl.RelativeTimeFormat([\"de\", \"en\"], {\n\tstyle: \"long\",\n\tnumeric: \"auto\",\n});\n\nconst relativeDateFormatterNarrow = new Intl.RelativeTimeFormat([\"de\", \"en\"], {\n\tstyle: \"narrow\",\n\tnumeric: \"auto\",\n});\n\nconst absoluteFormatter = new Intl.DateTimeFormat([\"de\", \"en\"], {\n\tdateStyle: \"long\",\n\ttimeStyle: \"long\",\n});\n\nexport type RelativeTimestampStyle = \"long\" | \"narrow\" | \"short\";\n\ntype ValidUnit = Intl.RelativeTimeFormatUnit &\n\t(\"year\" | \"month\" | \"week\" | \"day\" | \"hour\" | \"minute\" | \"second\");\n\ninterface Formatter {\n\tformat(value: number, unit: ValidUnit): string;\n}\n\nconst formatterMap = {\n\tlong: relativeDateFormatter,\n\tnarrow: relativeDateFormatterNarrow,\n\tshort: {\n\t\t// Intl does not offer a meaningful \"short\" style for relative time. We use our own.\n\t\tformat(value: number, unit: ValidUnit) {\n\t\t\tconst v = Math.abs(Math.round(value));\n\t\t\tswitch (unit) {\n\t\t\t\t// The char \" \" between the number and the unit is a narrow no-break space (U+202F).\n\t\t\t\tcase \"day\":\n\t\t\t\t\treturn `${v} T`;\n\t\t\t\tcase \"hour\":\n\t\t\t\t\treturn `${v} Std.`;\n\t\t\t\tcase \"minute\":\n\t\t\t\t\treturn `${v} min`;\n\t\t\t\tcase \"second\":\n\t\t\t\t\treturn `${v} s`;\n\t\t\t\tcase \"month\":\n\t\t\t\t\treturn `${v} M`;\n\t\t\t\tcase \"week\":\n\t\t\t\t\treturn `${v} W`;\n\t\t\t\tcase \"year\":\n\t\t\t\t\treturn `${v} J`;\n\t\t\t}\n\t\t},\n\t},\n} satisfies Record<RelativeTimestampStyle, Formatter>;\n\n/**\n * @remarks This component uses api.Timestamp instead of `Date` to avoid re-renders (Dates are objects and therefore compared by reference).\n */\nexport interface RelativeTimestampProps {\n\t/**\n\t * **Unix time in seconds**.\n\t * @remarks We use a `number` instead of `Date` because `Date`s are objects and would cause unnecessary re-renders. `number`s are easier to memoize and to compare.\n\t */\n\tdate: number;\n\n\t/**\n\t * **Unix time in seconds**. Does not have a default, so items in a list can all use the same exact date. Use something like `(Date.getTime() / 1000) | 0` to get some date to compare with.\n\t * @remarks We use a `number` instead of `Date` because `Date`s are objects and would cause unnecessary re-renders. `number`s are easier to memoize and to compare.\n\t */\n\trelativeToDate: number;\n\n\tstyle?: RelativeTimestampStyle;\n}\n\nexport default memo(function RelativeTimestamp({\n\tdate,\n\trelativeToDate,\n\tstyle,\n}: RelativeTimestampProps) {\n\tconst d = new Date(date * 1000); // TODO: We seem to have time zone issues\n\n\tconst longDateTime = absoluteFormatter.format(d);\n\tconst relativeDate = getRelativeDate(\n\t\td,\n\t\ttypeof relativeToDate === \"number\"\n\t\t\t? new Date(relativeToDate * 1000)\n\t\t\t: relativeToDate,\n\t\tstyle,\n\t);\n\treturn (\n\t\t<time dateTime={d.toISOString()} title={longDateTime}>\n\t\t\t{relativeDate}\n\t\t</time>\n\t);\n});\n\nconst unitsInMs: Record<ValidUnit, number> = {\n\tyear: 365 * 24 * 60 * 60 * 1000,\n\tmonth: (365 * 24 * 60 * 60 * 1000) / 12,\n\tweek: 7 * 24 * 60 * 60 * 1000,\n\tday: 24 * 60 * 60 * 1000,\n\thour: 60 * 60 * 1000,\n\tminute: 60 * 1000,\n\tsecond: 1000,\n};\n\nfunction getRelativeDate(\n\tdate: Date,\n\trelativeTo: Date,\n\tstyle: RelativeTimestampStyle = \"long\",\n): string {\n\tconst elapsed = date.getTime() - relativeTo.getTime();\n\tfor (const [unit, divisor] of Object.entries(unitsInMs)) {\n\t\tif (Math.abs(elapsed) > divisor || unit === \"second\") {\n\t\t\tconst formatter = formatterMap[style];\n\t\t\treturn formatter.format(\n\t\t\t\tMath.round(elapsed / divisor),\n\t\t\t\tunit as ValidUnit,\n\t\t\t);\n\t\t}\n\t}\n\treturn absoluteFormatter.format(date);\n}\n"],"mappings":";AAAA,SAASA,IAAI,QAAQ,OAAO;;AAE5B;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAMC,qBAAqB,GAAG,IAAIC,IAAI,CAACC,kBAAkB,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE;EACvEC,KAAK,EAAE,MAAM;EACbC,OAAO,EAAE;AACV,CAAC,CAAC;AAEF,MAAMC,2BAA2B,GAAG,IAAIJ,IAAI,CAACC,kBAAkB,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE;EAC7EC,KAAK,EAAE,QAAQ;EACfC,OAAO,EAAE;AACV,CAAC,CAAC;AAEF,MAAME,iBAAiB,GAAG,IAAIL,IAAI,CAACM,cAAc,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE;EAC/DC,SAAS,EAAE,MAAM;EACjBC,SAAS,EAAE;AACZ,CAAC,CAAC;AAWF,MAAMC,YAAY,GAAG;EACpBC,IAAI,EAAEX,qBAAqB;EAC3BY,MAAM,EAAEP,2BAA2B;EACnCQ,KAAK,EAAE;IACN;IACAC,MAAMA,CAACC,KAAa,EAAEC,IAAe,EAAE;MACtC,MAAMC,CAAC,GAAGC,IAAI,CAACC,GAAG,CAACD,IAAI,CAACE,KAAK,CAACL,KAAK,CAAC,CAAC;MACrC,QAAQC,IAAI;QACX;QACA,KAAK,KAAK;UACT,OAAO,GAAGC,CAAC,IAAI;QAChB,KAAK,MAAM;UACV,OAAO,GAAGA,CAAC,OAAO;QACnB,KAAK,QAAQ;UACZ,OAAO,GAAGA,CAAC,MAAM;QAClB,KAAK,QAAQ;UACZ,OAAO,GAAGA,CAAC,IAAI;QAChB,KAAK,OAAO;UACX,OAAO,GAAGA,CAAC,IAAI;QAChB,KAAK,MAAM;UACV,OAAO,GAAGA,CAAC,IAAI;QAChB,KAAK,MAAM;UACV,OAAO,GAAGA,CAAC,IAAI;MACjB;IACD;EACD;AACD,CAAqD;;AAErD;AACA;AACA;;AAiBA,eAAelB,IAAI,CAAC,SAAAsB,kBAAAC,EAAA;EAAA,MAAAC,CAAA,GAAAC,EAAA;EAA2B;IAAAC,IAAA;IAAAC,cAAA;IAAAvB;EAAA,IAAAmB,EAItB;EACL,MAAAK,EAAA,GAAAF,IAAI,OAAO;EAAA,IAAAG,YAAA;EAAA,IAAAC,YAAA;EAAA,IAAAC,EAAA;EAAA,IAAAP,CAAA,QAAAG,cAAA,IAAAH,CAAA,QAAApB,KAAA,IAAAoB,CAAA,QAAAI,EAAA;IAA9B,MAAAI,CAAA,OAAAC,IAAA,CAAmBL,EAAW;IAE9BC,YAAA,GAAqBtB,iBAAA,CAAAQ,MAAA,CAAyBiB,CAAC,CAAC;IAAC,IAAAE,EAAA;IAAA,IAAAV,CAAA,QAAAG,cAAA;MAGhDO,EAAA,UAAOP,cAAc,KAAK,QAAQ,OAAAM,IAAA,CACtBN,cAAc,OAAO,IAC9BA,cAAc;MAAAH,CAAA,MAAAG,cAAA;MAAAH,CAAA,MAAAU,EAAA;IAAA;MAAAA,EAAA,GAAAV,CAAA;IAAA;IAJlBM,YAAA,GAAqBK,eAAA,CACpBH,CAAC,EACDE,EAEiB,EACjB9B,KACD,CAAC;IAEgB2B,EAAA,GAAAC,CAAC,CAAAI,WAAA,CAAa,CAAC;IAAAZ,CAAA,MAAAG,cAAA;IAAAH,CAAA,MAAApB,KAAA;IAAAoB,CAAA,MAAAI,EAAA;IAAAJ,CAAA,MAAAK,YAAA;IAAAL,CAAA,MAAAM,YAAA;IAAAN,CAAA,MAAAO,EAAA;EAAA;IAAAF,YAAA,GAAAL,CAAA;IAAAM,YAAA,GAAAN,CAAA;IAAAO,EAAA,GAAAP,CAAA;EAAA;EAAA,IAAAU,EAAA;EAAA,IAAAV,CAAA,QAAAK,YAAA,IAAAL,CAAA,QAAAM,YAAA,IAAAN,CAAA,SAAAO,EAAA;IAA/BG,EAAA,QAEO,CAFS,QAAe,CAAf,CAAAH,EAAc,CAAC,CAASF,KAAY,CAAZA,aAAW,CAAC,CAClDC,aAAW,CACb,EAFA,IAEO;IAAAN,CAAA,MAAAK,YAAA;IAAAL,CAAA,MAAAM,YAAA;IAAAN,CAAA,OAAAO,EAAA;IAAAP,CAAA,OAAAU,EAAA;EAAA;IAAAA,EAAA,GAAAV,CAAA;EAAA;EAAA,OAFPU,EAEO;AAAA,CAER,CAAC;AAEF,MAAMG,SAAoC,GAAG;EAC5CC,IAAI,EAAE,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;EAC/BC,KAAK,EAAG,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,GAAI,EAAE;EACvCC,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;EAC7BC,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;EACxBC,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI;EACpBC,MAAM,EAAE,EAAE,GAAG,IAAI;EACjBC,MAAM,EAAE;AACT,CAAC;AAED,SAAST,eAAeA,CACvBT,IAAU,EACVmB,UAAgB,EAChBzC,KAA6B,GAAG,MAAM,EAC7B;EACT,MAAM0C,OAAO,GAAGpB,IAAI,CAACqB,OAAO,CAAC,CAAC,GAAGF,UAAU,CAACE,OAAO,CAAC,CAAC;EACrD,KAAK,MAAM,CAAC9B,IAAI,EAAE+B,OAAO,CAAC,IAAIC,MAAM,CAACC,OAAO,CAACb,SAAS,CAAC,EAAE;IACxD,IAAIlB,IAAI,CAACC,GAAG,CAAC0B,OAAO,CAAC,GAAGE,OAAO,IAAI/B,IAAI,KAAK,QAAQ,EAAE;MACrD,MAAMkC,SAAS,GAAGxC,YAAY,CAACP,KAAK,CAAC;MACrC,OAAO+C,SAAS,CAACpC,MAAM,CACtBI,IAAI,CAACE,KAAK,CAACyB,OAAO,GAAGE,OAAO,CAAC,EAC7B/B,IACD,CAAC;IACF;EACD;EACA,OAAOV,iBAAiB,CAACQ,MAAM,CAACW,IAAI,CAAC;AACtC","ignoreList":[]}