runeforge 0.0.50 → 0.0.51

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.
@@ -1,4 +1,4 @@
1
1
  export declare const formatBoolean: (trueLabel?: string, falseLabel?: string) => () => (value: boolean) => string;
2
- export declare const formatDatetime: (format?: string) => (() => (value: Date) => string);
2
+ export declare const formatDatetime: (format?: string, timeZone?: string) => (() => (value: Date) => string);
3
3
  export declare function formatTruncateTextUpTo(maxLength: number): () => (value: string) => string;
4
4
  export declare function formatInstance<T extends Record<string, unknown>>(attribute: keyof T & string, instances: T[], urlPath: string, idKey?: keyof T & string): (value: unknown) => string;
@@ -8,7 +8,36 @@ const TOKENS = {
8
8
  MM: (d) => String(d.getMinutes()).padStart(2, '0'),
9
9
  ss: (d) => String(d.getSeconds()).padStart(2, '0')
10
10
  };
11
- export const formatDatetime = (format = 'dd/mm/YYYY HH:MM') => {
11
+ // Same tokens, read from Intl.DateTimeFormat parts instead of local Date
12
+ // getters, so the result depends only on `timeZone` — never on the
13
+ // environment (SSR host vs. browser) running the code.
14
+ function tokensFor(d, timeZone) {
15
+ const parts = new Intl.DateTimeFormat('en-US', {
16
+ timeZone,
17
+ year: 'numeric',
18
+ month: '2-digit',
19
+ day: '2-digit',
20
+ hour: '2-digit',
21
+ minute: '2-digit',
22
+ second: '2-digit',
23
+ hourCycle: 'h23'
24
+ }).formatToParts(d);
25
+ const get = (type) => parts.find((p) => p.type === type)?.value ?? '';
26
+ return {
27
+ dd: get('day'),
28
+ mm: get('month'),
29
+ YYYY: get('year'),
30
+ HH: get('hour'),
31
+ MM: get('minute'),
32
+ ss: get('second')
33
+ };
34
+ }
35
+ // `timeZone` is an IANA zone name (e.g. 'America/Argentina/Buenos_Aires').
36
+ // Omit it to keep formatting in whichever timezone the running environment
37
+ // is in — this differs between SSR (server) and CSR (browser) and will
38
+ // render the same instant differently depending on where it runs, so pass
39
+ // an explicit `timeZone` for any value that must display consistently.
40
+ export const formatDatetime = (format = 'dd/mm/YYYY HH:MM', timeZone) => {
12
41
  const fmt = (value) => {
13
42
  // `null`/`undefined`/`''` (an unset field) must render blank, not epoch 0
14
43
  // — `new Date(null)` is 1970-01-01, a "valid" Date whose getTime() isn't
@@ -18,7 +47,8 @@ export const formatDatetime = (format = 'dd/mm/YYYY HH:MM') => {
18
47
  const d = new Date(value);
19
48
  if (isNaN(d.getTime()))
20
49
  return '';
21
- return format.replace(/dd|mm|YYYY|HH|MM|ss/g, (token) => TOKENS[token](d));
50
+ const tokens = timeZone ? tokensFor(d, timeZone) : null;
51
+ return format.replace(/dd|mm|YYYY|HH|MM|ss/g, (token) => tokens ? tokens[token] : TOKENS[token](d));
22
52
  };
23
53
  return () => fmt;
24
54
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runeforge",
3
- "version": "0.0.50",
3
+ "version": "0.0.51",
4
4
  "description": "SvelteKit toolkit for building metadata-driven CRUD interfaces with tables, forms, and actions",
5
5
  "license": "MIT",
6
6
  "author": "Ezequiel Puerta",