@getmicdrop/svelte-components 5.3.15 → 5.4.1

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.
@@ -130,4 +130,11 @@ export declare const EVENT_DEFAULTS: {
130
130
  /** Default doors open time before event start (minutes) */
131
131
  readonly DEFAULT_DOORS_BEFORE_MINUTES: 30;
132
132
  };
133
+ /**
134
+ * Legacy timezone mappings from venue data.
135
+ * Maps human-readable location names to IANA timezone identifiers.
136
+ * Used for backwards compatibility with older venue data that stored
137
+ * location names instead of proper IANA timezone IDs.
138
+ */
139
+ export declare const LEGACY_TIMEZONE_MAP: Record<string, string>;
133
140
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/lib/datetime/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,eAAO,MAAM,SAAS;IACpB,iCAAiC;;IAEjC,iCAAiC;;IAEjC,+BAA+B;;IAE/B,8BAA8B;;IAE9B,+BAA+B;;CAEvB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,iBAAiB;IAC5B,0BAA0B;;IAE1B,yBAAyB;;IAEzB,0BAA0B;;CAElB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,YAAY;IACvB,iCAAiC;;IAEjC,gCAAgC;;IAEhC,0CAA0C;;IAE1C,iDAAiD;;IAEjD,qCAAqC;;IAErC,qDAAqD;;IAErD,yDAAyD;;IAEzD,4EAA4E;;IAE5E,sCAAsC;;IAEtC,wCAAwC;;IAExC,gCAAgC;;IAEhC,oCAAoC;;IAEpC,+BAA+B;;IAE/B,mCAAmC;;CAE3B,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQtB,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAG,qBAA8B,CAAC;AAE/D;;GAEG;AACH,eAAO,MAAM,wBAAwB;IACnC,+CAA+C;;IAE/C,6DAA6D;;IAE7D,yDAAyD;;IAEzD,uDAAuD;;IAEvD,yDAAyD;;CAEjD,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,cAAc;IACzB,wCAAwC;;IAExC,wCAAwC;;IAExC,mDAAmD;;IAEnD,2DAA2D;;CAEnD,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/lib/datetime/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,eAAO,MAAM,SAAS;IACpB,iCAAiC;;IAEjC,iCAAiC;;IAEjC,+BAA+B;;IAE/B,8BAA8B;;IAE9B,+BAA+B;;CAEvB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,iBAAiB;IAC5B,0BAA0B;;IAE1B,yBAAyB;;IAEzB,0BAA0B;;CAElB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,YAAY;IACvB,iCAAiC;;IAEjC,gCAAgC;;IAEhC,0CAA0C;;IAE1C,iDAAiD;;IAEjD,qCAAqC;;IAErC,qDAAqD;;IAErD,yDAAyD;;IAEzD,4EAA4E;;IAE5E,sCAAsC;;IAEtC,wCAAwC;;IAExC,gCAAgC;;IAEhC,oCAAoC;;IAEpC,+BAA+B;;IAE/B,mCAAmC;;CAE3B,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQtB,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAG,qBAA8B,CAAC;AAE/D;;GAEG;AACH,eAAO,MAAM,wBAAwB;IACnC,+CAA+C;;IAE/C,6DAA6D;;IAE7D,yDAAyD;;IAEzD,uDAAuD;;IAEvD,yDAAyD;;CAEjD,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,cAAc;IACzB,wCAAwC;;IAExC,wCAAwC;;IAExC,mDAAmD;;IAEnD,2DAA2D;;CAEnD,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAmB7C,CAAC"}
@@ -110,3 +110,29 @@ export const EVENT_DEFAULTS = {
110
110
  /** Default doors open time before event start (minutes) */
111
111
  DEFAULT_DOORS_BEFORE_MINUTES: 30,
112
112
  };
113
+ /**
114
+ * Legacy timezone mappings from venue data.
115
+ * Maps human-readable location names to IANA timezone identifiers.
116
+ * Used for backwards compatibility with older venue data that stored
117
+ * location names instead of proper IANA timezone IDs.
118
+ */
119
+ export const LEGACY_TIMEZONE_MAP = {
120
+ 'UTC': 'UTC',
121
+ // California
122
+ 'California USA': 'America/Los_Angeles',
123
+ 'California': 'America/Los_Angeles',
124
+ 'Los Angeles': 'America/Los_Angeles',
125
+ 'Los Angeles USA': 'America/Los_Angeles',
126
+ // New York
127
+ 'New York': 'America/New_York',
128
+ 'New York USA': 'America/New_York',
129
+ // Chicago
130
+ 'Chicago': 'America/Chicago',
131
+ 'Chicago USA': 'America/Chicago',
132
+ // Denver
133
+ 'Denver': 'America/Denver',
134
+ 'Denver USA': 'America/Denver',
135
+ // Phoenix (no DST)
136
+ 'Phoenix': 'America/Phoenix',
137
+ 'Phoenix USA': 'America/Phoenix',
138
+ };
@@ -35,8 +35,9 @@
35
35
  */
36
36
  export type { DateParts, FormatOptions, FormattedTimeRange, ISODateString, LocalDateString, LocalDateTimeString, LocalTimeString, TimeRange, TimezoneId, VenueWithTimezone, } from './types';
37
37
  export { DateTimeError, DateTimeErrorCode } from './types';
38
- export { COMMON_US_TIMEZONES, DATE_FORMATS, DEFAULT_TIMEZONE, DURATIONS, DURATIONS_MINUTES, EVENT_DEFAULTS, RELATIVE_TIME_THRESHOLDS, } from './constants';
39
- export { getTimezoneDisplayName, getTimezoneOffset, getUserTimezone, getVenueTimezone, isDST, isValidTimezone, normalizeTimezone, } from './timezone';
38
+ export { COMMON_US_TIMEZONES, DATE_FORMATS, DEFAULT_TIMEZONE, DURATIONS, DURATIONS_MINUTES, EVENT_DEFAULTS, LEGACY_TIMEZONE_MAP, RELATIVE_TIME_THRESHOLDS, } from './constants';
39
+ export { formatTimezoneForDisplay, getAllTimezones, getCommonUSTimezoneOptions, getIANATimezone, getTimezoneDisplayName, getTimezoneOffset, getTimezoneOptions, getUserTimezone, getVenueTimezone, isDST, isValidIANATimezone, isValidTimezone, normalizeTimezone, } from './timezone';
40
+ export type { TimezoneOption } from './timezone';
40
41
  export { formatDateRange, formatDayOfWeek, formatEventDate, formatEventDateTime, formatEventTime, formatMonth, formatNotificationTime, formatRelativeTime, formatTimeRange, getDateInTimezone, getDateParts, getHourInTimezone, } from './format';
41
42
  export { combineDateAndTime, formatDateTimeForAPI, isNextDayTime, minutesToTimeString, parseDateTimeFromAPI, parseEndOfDay, parseLocalToUTC, parseStartOfDay, parseTimeToMinutes, parseUTCToLocal, stripNextDayPrefix, } from './parse';
42
43
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/datetime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,YAAY,EACV,SAAS,EACT,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,UAAU,EACV,iBAAiB,GAClB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAG3D,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,wBAAwB,GACzB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,KAAK,EACL,eAAe,EACf,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,eAAe,EACf,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,WAAW,EACX,sBAAsB,EACtB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,kBAAkB,GACnB,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/datetime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,YAAY,EACV,SAAS,EACT,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,UAAU,EACV,iBAAiB,GAClB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAG3D,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,wBAAwB,EACxB,eAAe,EACf,0BAA0B,EAC1B,eAAe,EACf,sBAAsB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,KAAK,EACL,mBAAmB,EACnB,eAAe,EACf,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,EACL,eAAe,EACf,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,WAAW,EACX,sBAAsB,EACtB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,kBAAkB,GACnB,MAAM,SAAS,CAAC"}
@@ -35,9 +35,9 @@
35
35
  */
36
36
  export { DateTimeError, DateTimeErrorCode } from './types';
37
37
  // Constants
38
- export { COMMON_US_TIMEZONES, DATE_FORMATS, DEFAULT_TIMEZONE, DURATIONS, DURATIONS_MINUTES, EVENT_DEFAULTS, RELATIVE_TIME_THRESHOLDS, } from './constants';
38
+ export { COMMON_US_TIMEZONES, DATE_FORMATS, DEFAULT_TIMEZONE, DURATIONS, DURATIONS_MINUTES, EVENT_DEFAULTS, LEGACY_TIMEZONE_MAP, RELATIVE_TIME_THRESHOLDS, } from './constants';
39
39
  // Timezone utilities
40
- export { getTimezoneDisplayName, getTimezoneOffset, getUserTimezone, getVenueTimezone, isDST, isValidTimezone, normalizeTimezone, } from './timezone';
40
+ export { formatTimezoneForDisplay, getAllTimezones, getCommonUSTimezoneOptions, getIANATimezone, getTimezoneDisplayName, getTimezoneOffset, getTimezoneOptions, getUserTimezone, getVenueTimezone, isDST, isValidIANATimezone, isValidTimezone, normalizeTimezone, } from './timezone';
41
41
  // Format functions
42
42
  export { formatDateRange, formatDayOfWeek, formatEventDate, formatEventDateTime, formatEventTime, formatMonth, formatNotificationTime, formatRelativeTime, formatTimeRange, getDateInTimezone, getDateParts, getHourInTimezone, } from './format';
43
43
  // Parse functions
@@ -7,6 +7,11 @@
7
7
  * @module datetime/timezone
8
8
  */
9
9
  import type { TimezoneId, VenueWithTimezone } from './types';
10
+ /** Options for formatting timezone in Select components */
11
+ export interface TimezoneOption {
12
+ value: string;
13
+ name: string;
14
+ }
10
15
  /**
11
16
  * Validates whether a string is a valid IANA timezone identifier.
12
17
  * Rejects common abbreviations like PST, EST, etc. even if the runtime accepts them.
@@ -92,4 +97,71 @@ export declare function normalizeTimezone(timezone: string): TimezoneId;
92
97
  * @throws {DateTimeError} If timezone is invalid
93
98
  */
94
99
  export declare function isDST(timezone: TimezoneId, date?: Date): boolean;
100
+ /**
101
+ * Convert a potentially legacy timezone string to an IANA identifier.
102
+ * Handles legacy location names (e.g., "California USA"), IANA identifiers,
103
+ * and timezone abbreviations (e.g., "PST").
104
+ *
105
+ * This is the primary function for normalizing timezone strings from
106
+ * older venue data or user input.
107
+ *
108
+ * @param tzString - Timezone string from API or user input
109
+ * @returns Valid IANA timezone identifier
110
+ *
111
+ * @example
112
+ * getIANATimezone('California USA') // 'America/Los_Angeles'
113
+ * getIANATimezone('America/New_York') // 'America/New_York' (passthrough)
114
+ * getIANATimezone('PST') // 'America/Los_Angeles'
115
+ * getIANATimezone(null) // 'America/Los_Angeles' (default)
116
+ */
117
+ export declare function getIANATimezone(tzString: string | null | undefined): TimezoneId;
118
+ /**
119
+ * Alias for isValidTimezone for backwards compatibility.
120
+ * @deprecated Use isValidTimezone instead
121
+ */
122
+ export declare const isValidIANATimezone: typeof isValidTimezone;
123
+ /**
124
+ * Get all supported IANA timezone identifiers.
125
+ * Uses the browser's Intl API to get the complete list.
126
+ *
127
+ * @returns Array of all valid IANA timezone identifiers
128
+ *
129
+ * @example
130
+ * const timezones = getAllTimezones();
131
+ * // ['Africa/Abidjan', 'Africa/Accra', ..., 'Pacific/Wallis']
132
+ */
133
+ export declare function getAllTimezones(): string[];
134
+ /**
135
+ * Format a timezone identifier into a human-readable display string.
136
+ * Includes the timezone abbreviation and UTC offset.
137
+ *
138
+ * @param timezone - IANA timezone identifier
139
+ * @returns Formatted display string
140
+ *
141
+ * @example
142
+ * formatTimezoneForDisplay('America/Los_Angeles')
143
+ * // "America / Los Angeles (PST)"
144
+ */
145
+ export declare function formatTimezoneForDisplay(timezone: string): string;
146
+ /**
147
+ * Get all timezones formatted for use in a Select component.
148
+ *
149
+ * @returns Array of timezone options with value and display name
150
+ *
151
+ * @example
152
+ * const options = getTimezoneOptions();
153
+ * // [{ value: 'Africa/Abidjan', name: 'Africa / Abidjan (GMT)' }, ...]
154
+ */
155
+ export declare function getTimezoneOptions(): TimezoneOption[];
156
+ /**
157
+ * Get commonly used US timezones formatted for Select component.
158
+ * Useful for quick timezone selection when most users are in the US.
159
+ *
160
+ * @returns Array of common US timezone options
161
+ *
162
+ * @example
163
+ * const options = getCommonUSTimezoneOptions();
164
+ * // [{ value: 'America/Los_Angeles', name: 'America / Los Angeles (PST)' }, ...]
165
+ */
166
+ export declare function getCommonUSTimezoneOptions(): TimezoneOption[];
95
167
  //# sourceMappingURL=timezone.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"timezone.d.ts","sourceRoot":"","sources":["../../src/lib/datetime/timezone.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAiC7D;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CA0BzD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,GAAG,UAAU,CAoBrE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,IAAI,UAAU,CAE5C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,UAAU,EACpB,IAAI,GAAE,IAAiB,GACtB,MAAM,CA2BR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,CAiBnE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CA+C9D;AAED;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,GAAE,IAAiB,GAAG,OAAO,CA0B5E"}
1
+ {"version":3,"file":"timezone.d.ts","sourceRoot":"","sources":["../../src/lib/datetime/timezone.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE7D,2DAA2D;AAC3D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAiCD;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CA0BzD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,GAAG,UAAU,CAoBrE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,IAAI,UAAU,CAE5C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,UAAU,EACpB,IAAI,GAAE,IAAiB,GACtB,MAAM,CA2BR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,CAiBnE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CA+C9D;AAED;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,GAAE,IAAiB,GAAG,OAAO,CA0B5E;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,UAAU,CAuB/E;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,wBAAkB,CAAC;AAEnD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA0BjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,IAAI,cAAc,EAAE,CAOrD;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,IAAI,cAAc,EAAE,CAe7D"}
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * @module datetime/timezone
8
8
  */
9
+ import { DEFAULT_TIMEZONE, LEGACY_TIMEZONE_MAP } from './constants';
9
10
  import { DateTimeError, DateTimeErrorCode } from './types';
10
11
  /**
11
12
  * Cache for timezone validation results to avoid repeated Intl calls.
@@ -239,3 +240,140 @@ export function isDST(timezone, date = new Date()) {
239
240
  const dstOffset = Math.max(janOffset, julOffset);
240
241
  return currentOffset === dstOffset && janOffset !== julOffset;
241
242
  }
243
+ // ============================================================================
244
+ // Legacy Timezone Support & Select Component Utilities
245
+ // ============================================================================
246
+ /**
247
+ * Convert a potentially legacy timezone string to an IANA identifier.
248
+ * Handles legacy location names (e.g., "California USA"), IANA identifiers,
249
+ * and timezone abbreviations (e.g., "PST").
250
+ *
251
+ * This is the primary function for normalizing timezone strings from
252
+ * older venue data or user input.
253
+ *
254
+ * @param tzString - Timezone string from API or user input
255
+ * @returns Valid IANA timezone identifier
256
+ *
257
+ * @example
258
+ * getIANATimezone('California USA') // 'America/Los_Angeles'
259
+ * getIANATimezone('America/New_York') // 'America/New_York' (passthrough)
260
+ * getIANATimezone('PST') // 'America/Los_Angeles'
261
+ * getIANATimezone(null) // 'America/Los_Angeles' (default)
262
+ */
263
+ export function getIANATimezone(tzString) {
264
+ if (!tzString || tzString === 'NaN') {
265
+ return DEFAULT_TIMEZONE;
266
+ }
267
+ // Check legacy mappings first (e.g., "California USA" -> "America/Los_Angeles")
268
+ const legacyMatch = LEGACY_TIMEZONE_MAP[tzString];
269
+ if (legacyMatch) {
270
+ return legacyMatch;
271
+ }
272
+ // Try to validate as IANA timezone
273
+ if (isValidTimezone(tzString)) {
274
+ return tzString;
275
+ }
276
+ // Try normalizing abbreviations (PST, EST, etc.)
277
+ try {
278
+ return normalizeTimezone(tzString);
279
+ }
280
+ catch {
281
+ // If all else fails, return default
282
+ return DEFAULT_TIMEZONE;
283
+ }
284
+ }
285
+ /**
286
+ * Alias for isValidTimezone for backwards compatibility.
287
+ * @deprecated Use isValidTimezone instead
288
+ */
289
+ export const isValidIANATimezone = isValidTimezone;
290
+ /**
291
+ * Get all supported IANA timezone identifiers.
292
+ * Uses the browser's Intl API to get the complete list.
293
+ *
294
+ * @returns Array of all valid IANA timezone identifiers
295
+ *
296
+ * @example
297
+ * const timezones = getAllTimezones();
298
+ * // ['Africa/Abidjan', 'Africa/Accra', ..., 'Pacific/Wallis']
299
+ */
300
+ export function getAllTimezones() {
301
+ return Intl.supportedValuesOf('timeZone');
302
+ }
303
+ /**
304
+ * Format a timezone identifier into a human-readable display string.
305
+ * Includes the timezone abbreviation and UTC offset.
306
+ *
307
+ * @param timezone - IANA timezone identifier
308
+ * @returns Formatted display string
309
+ *
310
+ * @example
311
+ * formatTimezoneForDisplay('America/Los_Angeles')
312
+ * // "America / Los Angeles (PST)"
313
+ */
314
+ export function formatTimezoneForDisplay(timezone) {
315
+ try {
316
+ const now = new Date();
317
+ const formatter = new Intl.DateTimeFormat('en-US', {
318
+ timeZone: timezone,
319
+ timeZoneName: 'short',
320
+ });
321
+ const parts = formatter.formatToParts(now);
322
+ const tzAbbrev = parts.find(p => p.type === 'timeZoneName')?.value || '';
323
+ // Get UTC offset
324
+ const offsetFormatter = new Intl.DateTimeFormat('en-US', {
325
+ timeZone: timezone,
326
+ timeZoneName: 'longOffset',
327
+ });
328
+ const offsetParts = offsetFormatter.formatToParts(now);
329
+ const offset = offsetParts.find(p => p.type === 'timeZoneName')?.value || '';
330
+ // Format the display name
331
+ const displayName = timezone.replace(/_/g, ' ').replace(/\//g, ' / ');
332
+ return `${displayName} (${tzAbbrev || offset})`;
333
+ }
334
+ catch {
335
+ // Fallback if formatting fails
336
+ return timezone.replace(/_/g, ' ');
337
+ }
338
+ }
339
+ /**
340
+ * Get all timezones formatted for use in a Select component.
341
+ *
342
+ * @returns Array of timezone options with value and display name
343
+ *
344
+ * @example
345
+ * const options = getTimezoneOptions();
346
+ * // [{ value: 'Africa/Abidjan', name: 'Africa / Abidjan (GMT)' }, ...]
347
+ */
348
+ export function getTimezoneOptions() {
349
+ const timezones = getAllTimezones();
350
+ return timezones.map(tz => ({
351
+ value: tz,
352
+ name: formatTimezoneForDisplay(tz),
353
+ }));
354
+ }
355
+ /**
356
+ * Get commonly used US timezones formatted for Select component.
357
+ * Useful for quick timezone selection when most users are in the US.
358
+ *
359
+ * @returns Array of common US timezone options
360
+ *
361
+ * @example
362
+ * const options = getCommonUSTimezoneOptions();
363
+ * // [{ value: 'America/Los_Angeles', name: 'America / Los Angeles (PST)' }, ...]
364
+ */
365
+ export function getCommonUSTimezoneOptions() {
366
+ const commonTimezones = [
367
+ 'America/Los_Angeles',
368
+ 'America/Denver',
369
+ 'America/Phoenix',
370
+ 'America/Chicago',
371
+ 'America/New_York',
372
+ 'America/Anchorage',
373
+ 'Pacific/Honolulu',
374
+ ];
375
+ return commonTimezones.map(tz => ({
376
+ value: tz,
377
+ name: formatTimezoneForDisplay(tz),
378
+ }));
379
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"createFieldTracker.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/forms/createFieldTracker.svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAMH,MAAM,WAAW,YAAY;IAE3B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IAGjB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAG1B,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC;IAGvC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;CAC3D;AAMD,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,OAAO,GAAG,YAAY,CAqEzE"}
1
+ {"version":3,"file":"createFieldTracker.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/forms/createFieldTracker.svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAMH,MAAM,WAAW,YAAY;IAE3B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IAGjB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAG1B,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC;IAGvC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;CAC3D;AAMD,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,OAAO,GAAG,YAAY,CAkEzE"}
@@ -36,12 +36,9 @@ export function createFieldTracker(isDirtyFn) {
36
36
  let isSaved = $state(false);
37
37
  // Use the provided function to compute isDirty
38
38
  const isDirty = $derived(isDirtyFn());
39
- // Auto-reset isSaved when form becomes dirty
40
- $effect(() => {
41
- if (isDirty && isSaved) {
42
- isSaved = false;
43
- }
44
- });
39
+ // Note: Auto-reset of isSaved when dirty is now handled by consumers
40
+ // via watching isDirty in their component's $effect, or simply by the
41
+ // save() method which sets isSaved = true after success.
45
42
  function canSave(isValid) {
46
43
  return isDirty && isValid && !isSaving;
47
44
  }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Stripe Utilities
3
+ *
4
+ * Shared utilities for Stripe integration including theme detection
5
+ * and reactive dark mode support.
6
+ */
7
+ export { useStripeTheme, detectDarkMode, getStripeTheme, getInitialStripeTheme, type StripeTheme, type StripeThemeOptions, } from './useStripeTheme.svelte';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/stripe/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,cAAc,EACd,cAAc,EACd,cAAc,EACd,qBAAqB,EACrB,KAAK,WAAW,EAChB,KAAK,kBAAkB,GACxB,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Stripe Utilities
3
+ *
4
+ * Shared utilities for Stripe integration including theme detection
5
+ * and reactive dark mode support.
6
+ */
7
+ export { useStripeTheme, detectDarkMode, getStripeTheme, getInitialStripeTheme, } from './useStripeTheme.svelte';
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Stripe Theme Utility
3
+ *
4
+ * Provides reactive dark mode detection for Stripe Elements.
5
+ * Automatically watches for theme changes via MutationObserver.
6
+ *
7
+ * @example
8
+ * ```svelte
9
+ * <script>
10
+ * import { useStripeTheme } from '@getmicdrop/svelte-components/stripe';
11
+ *
12
+ * const stripeTheme = useStripeTheme();
13
+ * // stripeTheme.current is 'stripe' | 'night'
14
+ * // Automatically updates when theme changes
15
+ * </script>
16
+ *
17
+ * <Elements theme={stripeTheme.current} {stripe} clientSecret={paymentIntent}>
18
+ * <PaymentElement />
19
+ * </Elements>
20
+ * ```
21
+ */
22
+ export type StripeTheme = 'stripe' | 'night' | 'flat';
23
+ export interface StripeThemeOptions {
24
+ /**
25
+ * Selector for the container element that has .dark/.light classes.
26
+ * @default '.dark, .light, .micdrop, [data-theme]'
27
+ */
28
+ containerSelector?: string;
29
+ /**
30
+ * Whether to watch for theme changes via MutationObserver.
31
+ * @default true
32
+ */
33
+ watchChanges?: boolean;
34
+ /**
35
+ * Initial theme if detection fails.
36
+ * @default 'stripe'
37
+ */
38
+ fallback?: StripeTheme;
39
+ }
40
+ /**
41
+ * Detects if dark mode is active.
42
+ *
43
+ * Checks in order:
44
+ * 1. localStorage 'theme' value
45
+ * 2. Container element classes (.dark, [data-theme="dark"])
46
+ * 3. System preference (prefers-color-scheme)
47
+ */
48
+ export declare function detectDarkMode(containerSelector?: string): boolean;
49
+ /**
50
+ * Maps dark mode state to Stripe theme.
51
+ */
52
+ export declare function getStripeTheme(isDark: boolean): StripeTheme;
53
+ /**
54
+ * Creates a reactive Stripe theme that watches for dark mode changes.
55
+ *
56
+ * Returns an object with a `current` property that is reactive and
57
+ * automatically updates when the theme changes.
58
+ *
59
+ * @example
60
+ * ```svelte
61
+ * <script>
62
+ * import { useStripeTheme } from '@getmicdrop/svelte-components/stripe';
63
+ * const stripeTheme = useStripeTheme();
64
+ * </script>
65
+ *
66
+ * <Elements theme={stripeTheme.current} ...>
67
+ * ```
68
+ */
69
+ export declare function useStripeTheme(options?: StripeThemeOptions): {
70
+ readonly current: StripeTheme;
71
+ /** Force refresh the theme detection */
72
+ refresh: () => void;
73
+ };
74
+ /**
75
+ * Simple synchronous dark mode detection without reactivity.
76
+ * Use this when you only need a one-time check.
77
+ */
78
+ export declare function getInitialStripeTheme(containerSelector?: string): StripeTheme;
79
+ //# sourceMappingURL=useStripeTheme.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStripeTheme.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/stripe/useStripeTheme.svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAEtD,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;OAGG;IACH,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAG,OAAO,CA6BlE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,WAAW,CAE3D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,kBAAuB;;IA0D3D,wCAAwC;;EAG3C;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,iBAAiB,CAAC,EAAE,MAAM,GACzB,WAAW,CAEb"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Stripe Theme Utility
3
+ *
4
+ * Provides reactive dark mode detection for Stripe Elements.
5
+ * Automatically watches for theme changes via MutationObserver.
6
+ *
7
+ * @example
8
+ * ```svelte
9
+ * <script>
10
+ * import { useStripeTheme } from '@getmicdrop/svelte-components/stripe';
11
+ *
12
+ * const stripeTheme = useStripeTheme();
13
+ * // stripeTheme.current is 'stripe' | 'night'
14
+ * // Automatically updates when theme changes
15
+ * </script>
16
+ *
17
+ * <Elements theme={stripeTheme.current} {stripe} clientSecret={paymentIntent}>
18
+ * <PaymentElement />
19
+ * </Elements>
20
+ * ```
21
+ */
22
+ import { onMount, onDestroy } from 'svelte';
23
+ /**
24
+ * Detects if dark mode is active.
25
+ *
26
+ * Checks in order:
27
+ * 1. localStorage 'theme' value
28
+ * 2. Container element classes (.dark, [data-theme="dark"])
29
+ * 3. System preference (prefers-color-scheme)
30
+ */
31
+ export function detectDarkMode(containerSelector) {
32
+ if (typeof window === 'undefined')
33
+ return false;
34
+ try {
35
+ // Check localStorage first
36
+ const saved = localStorage.getItem('theme');
37
+ if (saved === 'dark')
38
+ return true;
39
+ if (saved === 'light')
40
+ return false;
41
+ // Check for dark class on common containers
42
+ const selector = containerSelector || '.dark, .light, .micdrop, [data-theme]';
43
+ const containers = document.querySelectorAll(selector);
44
+ for (const container of containers) {
45
+ if (container.classList.contains('dark'))
46
+ return true;
47
+ if (container.getAttribute('data-theme') === 'dark')
48
+ return true;
49
+ }
50
+ // Check document root
51
+ if (document.documentElement.classList.contains('dark'))
52
+ return true;
53
+ if (document.documentElement.getAttribute('data-theme') === 'dark')
54
+ return true;
55
+ // Fallback to system preference
56
+ return window.matchMedia?.('(prefers-color-scheme: dark)')?.matches ?? false;
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ }
62
+ /**
63
+ * Maps dark mode state to Stripe theme.
64
+ */
65
+ export function getStripeTheme(isDark) {
66
+ return isDark ? 'night' : 'stripe';
67
+ }
68
+ /**
69
+ * Creates a reactive Stripe theme that watches for dark mode changes.
70
+ *
71
+ * Returns an object with a `current` property that is reactive and
72
+ * automatically updates when the theme changes.
73
+ *
74
+ * @example
75
+ * ```svelte
76
+ * <script>
77
+ * import { useStripeTheme } from '@getmicdrop/svelte-components/stripe';
78
+ * const stripeTheme = useStripeTheme();
79
+ * </script>
80
+ *
81
+ * <Elements theme={stripeTheme.current} ...>
82
+ * ```
83
+ */
84
+ export function useStripeTheme(options = {}) {
85
+ const { containerSelector = '.dark, .light, .micdrop, [data-theme]', watchChanges = true, fallback = 'stripe', } = options;
86
+ let current = $state(fallback);
87
+ let observer = null;
88
+ function updateTheme() {
89
+ current = getStripeTheme(detectDarkMode(containerSelector));
90
+ }
91
+ onMount(() => {
92
+ // Initial detection
93
+ updateTheme();
94
+ if (watchChanges && typeof MutationObserver !== 'undefined') {
95
+ // Watch for class changes on potential theme containers
96
+ const containers = document.querySelectorAll(containerSelector);
97
+ const root = document.documentElement;
98
+ observer = new MutationObserver(() => {
99
+ updateTheme();
100
+ });
101
+ // Observe document root
102
+ observer.observe(root, {
103
+ attributes: true,
104
+ attributeFilter: ['class', 'data-theme'],
105
+ });
106
+ // Observe other containers
107
+ containers.forEach(container => {
108
+ observer?.observe(container, {
109
+ attributes: true,
110
+ attributeFilter: ['class', 'data-theme'],
111
+ });
112
+ });
113
+ // Also listen for system preference changes
114
+ const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
115
+ mediaQuery.addEventListener('change', updateTheme);
116
+ }
117
+ });
118
+ onDestroy(() => {
119
+ if (observer) {
120
+ observer.disconnect();
121
+ observer = null;
122
+ }
123
+ });
124
+ return {
125
+ get current() {
126
+ return current;
127
+ },
128
+ /** Force refresh the theme detection */
129
+ refresh: updateTheme,
130
+ };
131
+ }
132
+ /**
133
+ * Simple synchronous dark mode detection without reactivity.
134
+ * Use this when you only need a one-time check.
135
+ */
136
+ export function getInitialStripeTheme(containerSelector) {
137
+ return getStripeTheme(detectDarkMode(containerSelector));
138
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getmicdrop/svelte-components",
3
- "version": "5.3.15",
3
+ "version": "5.4.1",
4
4
  "description": "Shared component library for Micdrop applications",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -126,6 +126,14 @@
126
126
  },
127
127
  "./telemetry": {
128
128
  "import": "./dist/telemetry.js"
129
+ },
130
+ "./stripe": {
131
+ "types": "./dist/stripe/index.d.ts",
132
+ "import": "./dist/stripe/index.js"
133
+ },
134
+ "./stripe/useStripeTheme": {
135
+ "types": "./dist/stripe/useStripeTheme.svelte.d.ts",
136
+ "import": "./dist/stripe/useStripeTheme.svelte.js"
129
137
  }
130
138
  },
131
139
  "svelte": "./dist/index.js",