@melodicdev/components 1.6.1 → 1.6.3
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.
- package/README.md +6 -0
- package/assets/melodic-components.js +21 -6
- package/assets/melodic-components.js.map +1 -1
- package/assets/melodic-components.min.js +21 -6
- package/lib/components/data-display/table/table.styles.d.ts.map +1 -1
- package/lib/components/data-display/table/table.styles.js +14 -4
- package/lib/components/data-display/table/table.template.d.ts.map +1 -1
- package/lib/components/data-display/table/table.template.js +7 -2
- package/lib/components/forms/date-time-picker/date-time-picker.component.d.ts +81 -9
- package/lib/components/forms/date-time-picker/date-time-picker.component.d.ts.map +1 -1
- package/lib/components/forms/date-time-picker/date-time-picker.component.js +163 -26
- package/lib/components/forms/date-time-picker/date-time-picker.styles.d.ts.map +1 -1
- package/lib/components/forms/date-time-picker/date-time-picker.styles.js +32 -0
- package/lib/components/forms/date-time-picker/date-time-picker.template.d.ts.map +1 -1
- package/lib/components/forms/date-time-picker/date-time-picker.template.js +8 -0
- package/lib/components/forms/date-time-picker/tz-utils.d.ts +61 -0
- package/lib/components/forms/date-time-picker/tz-utils.d.ts.map +1 -0
- package/lib/components/forms/date-time-picker/tz-utils.js +145 -0
- package/package.json +1 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timezone helpers for ml-date-time-picker.
|
|
3
|
+
*
|
|
4
|
+
* These functions translate between a naive wall-clock string
|
|
5
|
+
* (`YYYY-MM-DDTHH:mm[:ss]`) and a real UTC instant, anchored to an IANA
|
|
6
|
+
* timezone name (e.g. `America/Detroit`). All conversions are done via
|
|
7
|
+
* `Intl.DateTimeFormat` offset reflection — there are no hardcoded zone
|
|
8
|
+
* tables.
|
|
9
|
+
*
|
|
10
|
+
* DST policy:
|
|
11
|
+
* - Spring-forward gap (e.g. 2026-03-08 02:30 in America/Detroit doesn't
|
|
12
|
+
* exist) resolves to the post-jump wall clock, i.e. the input is
|
|
13
|
+
* interpreted one hour forward (03:30 EDT in this example).
|
|
14
|
+
* - Fall-back ambiguity (e.g. 2026-11-01 01:30 happens twice) resolves
|
|
15
|
+
* to the FIRST occurrence (still-DST / EDT). This matches RFC 5545
|
|
16
|
+
* VTIMEZONE behavior and the default in major calendar apps.
|
|
17
|
+
*/
|
|
18
|
+
export type TimezoneLabelFormat = 'short' | 'long' | 'offset' | 'none';
|
|
19
|
+
export declare function isUtcIsoString(value: string): boolean;
|
|
20
|
+
export declare function isNaiveDateTime(value: string): boolean;
|
|
21
|
+
/** Offset of `timeZone` relative to UTC at `date`, in milliseconds (positive = ahead of UTC). */
|
|
22
|
+
export declare function getZoneOffsetMs(date: Date, timeZone: string): number;
|
|
23
|
+
/**
|
|
24
|
+
* Convert a naive wall-clock string to a real UTC instant, treating the
|
|
25
|
+
* naive value as a wall clock in `timeZone`.
|
|
26
|
+
*
|
|
27
|
+
* Returns the UTC ISO 8601 string with `Z` suffix.
|
|
28
|
+
*/
|
|
29
|
+
export declare function naiveToUtcIso(naive: string, timeZone: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Convert a UTC instant (Date or ISO string) to a naive wall-clock string
|
|
32
|
+
* in `timeZone`. Output format: `YYYY-MM-DDTHH:mm`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function utcToNaive(instant: Date | string, timeZone: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Format a timezone name/abbreviation/offset for display next to the input.
|
|
37
|
+
*
|
|
38
|
+
* - `short` → `EDT`
|
|
39
|
+
* - `long` → `Eastern Daylight Time`
|
|
40
|
+
* - `offset` → `GMT-4`
|
|
41
|
+
* - `none` → `''`
|
|
42
|
+
*/
|
|
43
|
+
export declare function formatTimezoneLabel(instant: Date, timeZone: string, format: TimezoneLabelFormat): string;
|
|
44
|
+
/** Resolves the browser's local IANA timezone, falling back to UTC. */
|
|
45
|
+
export declare function getLocalTimeZone(): string;
|
|
46
|
+
/**
|
|
47
|
+
* True iff `timeZone` produces a different UTC offset from the viewer's
|
|
48
|
+
* local zone at the given instant. Compares offsets, not zone names —
|
|
49
|
+
* `America/Detroit` and `America/New_York` won't trigger this because
|
|
50
|
+
* they share an offset year-round.
|
|
51
|
+
*/
|
|
52
|
+
export declare function viewerOffsetDiffersAt(instant: Date, timeZone: string): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Render the viewer's local wall-clock + tz label for the given UTC instant.
|
|
55
|
+
* Used by the optional `viewer-hint` line.
|
|
56
|
+
*/
|
|
57
|
+
export declare function formatViewerHint(instant: Date, format?: TimezoneLabelFormat): {
|
|
58
|
+
wallClock: string;
|
|
59
|
+
label: string;
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=tz-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tz-utils.d.ts","sourceRoot":"","sources":["../../../../src/components/forms/date-time-picker/tz-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAKvE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEtD;AAoCD,iGAAiG;AACjG,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIpE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQrE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,IAAI,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM3E;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAClC,OAAO,EAAE,IAAI,EACb,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,mBAAmB,GACzB,MAAM,CAWR;AAED,uEAAuE;AACvE,wBAAgB,gBAAgB,IAAI,MAAM,CAMzC;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAI9E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,GAAE,mBAA6B,GAAG;IACvF,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACd,CAYA"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timezone helpers for ml-date-time-picker.
|
|
3
|
+
*
|
|
4
|
+
* These functions translate between a naive wall-clock string
|
|
5
|
+
* (`YYYY-MM-DDTHH:mm[:ss]`) and a real UTC instant, anchored to an IANA
|
|
6
|
+
* timezone name (e.g. `America/Detroit`). All conversions are done via
|
|
7
|
+
* `Intl.DateTimeFormat` offset reflection — there are no hardcoded zone
|
|
8
|
+
* tables.
|
|
9
|
+
*
|
|
10
|
+
* DST policy:
|
|
11
|
+
* - Spring-forward gap (e.g. 2026-03-08 02:30 in America/Detroit doesn't
|
|
12
|
+
* exist) resolves to the post-jump wall clock, i.e. the input is
|
|
13
|
+
* interpreted one hour forward (03:30 EDT in this example).
|
|
14
|
+
* - Fall-back ambiguity (e.g. 2026-11-01 01:30 happens twice) resolves
|
|
15
|
+
* to the FIRST occurrence (still-DST / EDT). This matches RFC 5545
|
|
16
|
+
* VTIMEZONE behavior and the default in major calendar apps.
|
|
17
|
+
*/
|
|
18
|
+
const NAIVE_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2})?$/;
|
|
19
|
+
const UTC_RE = /(?:Z|[+-]\d{2}:?\d{2})$/;
|
|
20
|
+
export function isUtcIsoString(value) {
|
|
21
|
+
return !!value && UTC_RE.test(value);
|
|
22
|
+
}
|
|
23
|
+
export function isNaiveDateTime(value) {
|
|
24
|
+
return !!value && NAIVE_RE.test(value);
|
|
25
|
+
}
|
|
26
|
+
function getZonedParts(date, timeZone) {
|
|
27
|
+
const fmt = new Intl.DateTimeFormat('en-US', {
|
|
28
|
+
timeZone,
|
|
29
|
+
hourCycle: 'h23',
|
|
30
|
+
year: 'numeric',
|
|
31
|
+
month: '2-digit',
|
|
32
|
+
day: '2-digit',
|
|
33
|
+
hour: '2-digit',
|
|
34
|
+
minute: '2-digit',
|
|
35
|
+
second: '2-digit'
|
|
36
|
+
});
|
|
37
|
+
const parts = {};
|
|
38
|
+
for (const p of fmt.formatToParts(date)) {
|
|
39
|
+
if (p.type !== 'literal')
|
|
40
|
+
parts[p.type] = p.value;
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
year: Number(parts.year),
|
|
44
|
+
month: Number(parts.month),
|
|
45
|
+
day: Number(parts.day),
|
|
46
|
+
hour: Number(parts.hour) === 24 ? 0 : Number(parts.hour),
|
|
47
|
+
minute: Number(parts.minute),
|
|
48
|
+
second: Number(parts.second)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/** Offset of `timeZone` relative to UTC at `date`, in milliseconds (positive = ahead of UTC). */
|
|
52
|
+
export function getZoneOffsetMs(date, timeZone) {
|
|
53
|
+
const p = getZonedParts(date, timeZone);
|
|
54
|
+
const asUtc = Date.UTC(p.year, p.month - 1, p.day, p.hour, p.minute, p.second);
|
|
55
|
+
return asUtc - date.getTime();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Convert a naive wall-clock string to a real UTC instant, treating the
|
|
59
|
+
* naive value as a wall clock in `timeZone`.
|
|
60
|
+
*
|
|
61
|
+
* Returns the UTC ISO 8601 string with `Z` suffix.
|
|
62
|
+
*/
|
|
63
|
+
export function naiveToUtcIso(naive, timeZone) {
|
|
64
|
+
if (!naive)
|
|
65
|
+
return '';
|
|
66
|
+
const padded = naive.length === 16 ? `${naive}:00` : naive;
|
|
67
|
+
const naiveAsUtc = new Date(`${padded}Z`);
|
|
68
|
+
if (Number.isNaN(naiveAsUtc.getTime()))
|
|
69
|
+
return '';
|
|
70
|
+
const offset = getZoneOffsetMs(naiveAsUtc, timeZone);
|
|
71
|
+
const real = new Date(naiveAsUtc.getTime() - offset);
|
|
72
|
+
return real.toISOString();
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Convert a UTC instant (Date or ISO string) to a naive wall-clock string
|
|
76
|
+
* in `timeZone`. Output format: `YYYY-MM-DDTHH:mm`.
|
|
77
|
+
*/
|
|
78
|
+
export function utcToNaive(instant, timeZone) {
|
|
79
|
+
const date = typeof instant === 'string' ? new Date(instant) : instant;
|
|
80
|
+
if (Number.isNaN(date.getTime()))
|
|
81
|
+
return '';
|
|
82
|
+
const p = getZonedParts(date, timeZone);
|
|
83
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
84
|
+
return `${p.year}-${pad(p.month)}-${pad(p.day)}T${pad(p.hour)}:${pad(p.minute)}`;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Format a timezone name/abbreviation/offset for display next to the input.
|
|
88
|
+
*
|
|
89
|
+
* - `short` → `EDT`
|
|
90
|
+
* - `long` → `Eastern Daylight Time`
|
|
91
|
+
* - `offset` → `GMT-4`
|
|
92
|
+
* - `none` → `''`
|
|
93
|
+
*/
|
|
94
|
+
export function formatTimezoneLabel(instant, timeZone, format) {
|
|
95
|
+
if (format === 'none' || !timeZone)
|
|
96
|
+
return '';
|
|
97
|
+
const timeZoneName = format === 'long' ? 'long' : format === 'offset' ? 'shortOffset' : 'short';
|
|
98
|
+
try {
|
|
99
|
+
const fmt = new Intl.DateTimeFormat('en-US', { timeZone, timeZoneName });
|
|
100
|
+
const part = fmt.formatToParts(instant).find((p) => p.type === 'timeZoneName');
|
|
101
|
+
return part?.value ?? '';
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return '';
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** Resolves the browser's local IANA timezone, falling back to UTC. */
|
|
108
|
+
export function getLocalTimeZone() {
|
|
109
|
+
try {
|
|
110
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return 'UTC';
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* True iff `timeZone` produces a different UTC offset from the viewer's
|
|
118
|
+
* local zone at the given instant. Compares offsets, not zone names —
|
|
119
|
+
* `America/Detroit` and `America/New_York` won't trigger this because
|
|
120
|
+
* they share an offset year-round.
|
|
121
|
+
*/
|
|
122
|
+
export function viewerOffsetDiffersAt(instant, timeZone) {
|
|
123
|
+
const local = getLocalTimeZone();
|
|
124
|
+
if (!timeZone || local === timeZone)
|
|
125
|
+
return false;
|
|
126
|
+
return getZoneOffsetMs(instant, local) !== getZoneOffsetMs(instant, timeZone);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Render the viewer's local wall-clock + tz label for the given UTC instant.
|
|
130
|
+
* Used by the optional `viewer-hint` line.
|
|
131
|
+
*/
|
|
132
|
+
export function formatViewerHint(instant, format = 'short') {
|
|
133
|
+
const local = getLocalTimeZone();
|
|
134
|
+
const naive = utcToNaive(instant, local);
|
|
135
|
+
const [, time] = naive.split('T');
|
|
136
|
+
const [hStr, mStr] = (time ?? '').split(':');
|
|
137
|
+
const h24 = Number(hStr);
|
|
138
|
+
const period = h24 >= 12 ? 'PM' : 'AM';
|
|
139
|
+
let h12 = h24 % 12;
|
|
140
|
+
if (h12 === 0)
|
|
141
|
+
h12 = 12;
|
|
142
|
+
const wallClock = `${h12}:${mStr} ${period}`;
|
|
143
|
+
const label = formatTimezoneLabel(instant, local, format);
|
|
144
|
+
return { wallClock, label };
|
|
145
|
+
}
|