@esmalley/ts-utils 5.0.0 → 6.0.0

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 CHANGED
@@ -1,2 +1,616 @@
1
1
  # ts-utils
2
- Utility functions for typescript
2
+
3
+ A modular collection of TypeScript utilities for modern web development.
4
+
5
+ * Data transformation & CSV generation
6
+ * CSS-in-JS styling & Material Design shadows
7
+ * Comprehensive color manipulation
8
+ * Robust date parsing and formatting
9
+ * Object deep cloning and merging
10
+ * Event handling systems
11
+ * Array shuffling and combinations
12
+
13
+ # Table of Contents
14
+
15
+ * [Installation](#installation)
16
+ * [Modules](#modules)
17
+ * [Arithmetic](#arithmetic)
18
+ * [Arrayifier](#arrayifier)
19
+ * [Color](#color)
20
+ * [CSV](#csv)
21
+ * [Dates](#dates)
22
+ * [Kontororu (Events)](#kontororu-events)
23
+ * [Objector](#objector)
24
+ * [Sorter](#sorter)
25
+ * [Style](#style)
26
+ * [Textor](#textor)
27
+ * [Theme](#theme)
28
+ * [Toaster](#toaster)
29
+
30
+
31
+ * [Testing](#testing)
32
+ * [License](#license)
33
+
34
+ ---
35
+
36
+ # Installation
37
+
38
+ ```bash
39
+ npm install @esmalley/ts-utils
40
+ # or
41
+ yarn add @esmalley/ts-utils
42
+
43
+ ```
44
+
45
+ ---
46
+
47
+ # Modules
48
+
49
+ ## Arithmetic
50
+
51
+ Math helpers for bounding and calculation.
52
+
53
+ ### `clamp(number, min, max)`
54
+
55
+ Restricts a given number to be within the specified minimum and maximum range.
56
+
57
+ * **Example 1: Restricting UI Scroll**
58
+ Ensure a scroll position never goes out of bounds.
59
+ ```ts
60
+ import { Arithmetic } from '@esmalley/ts-utils';
61
+
62
+ const rawScroll = -50;
63
+ const boundedScroll = Arithmetic.clamp(rawScroll, 0, 500);
64
+ console.log(boundedScroll); // Output: 0
65
+
66
+ ```
67
+
68
+
69
+ * **Example 2: Normalizing Health Points**
70
+ Prevent health from exceeding maximum or falling below zero.
71
+ ```ts
72
+ const currentHealth = 120;
73
+ const actualHealth = Arithmetic.clamp(currentHealth, 0, 100);
74
+ console.log(actualHealth); // Output: 100
75
+
76
+ ```
77
+
78
+
79
+
80
+ ---
81
+
82
+ ## Arrayifier
83
+
84
+ Utilities for manipulating arrays and generating sets.
85
+
86
+ ### `shuffle(array)`
87
+
88
+ Randomizes the order of elements in an array in-place using the Fisher-Yates algorithm.
89
+
90
+ * **Example 1: Shuffling a Deck**
91
+ ```ts
92
+ import { Arrayifier } from '@esmalley/ts-utils';
93
+
94
+ const deck = ['Ace', 'King', 'Queen', 'Jack'];
95
+ Arrayifier.shuffle(deck);
96
+ console.log(deck); // e.g., ['Queen', 'Ace', 'Jack', 'King']
97
+
98
+ ```
99
+
100
+
101
+
102
+ ### `getCombinations(arr, r)`
103
+
104
+ Returns all possible combinations of a specific size `r` from an array.
105
+
106
+ * **Example 1: Tournament Matchups**
107
+ Get all unique pairs from a list of players.
108
+ ```ts
109
+ const players = [1, 2, 3, 4];
110
+ const matchups = Arrayifier.getCombinations(players, 2);
111
+ // Output: [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
112
+
113
+ ```
114
+
115
+
116
+
117
+ ---
118
+
119
+ ## Color
120
+
121
+ Comprehensive suite for hex, RGB, and HSL manipulation.
122
+
123
+ ### `lerpColor(a, b, amount)`
124
+
125
+ Linearly interpolates between two hexadecimal colors.
126
+
127
+ * **Example 1: Health Bar Gradient**
128
+ Get the color at the 50% mark between Red and Green.
129
+ ```ts
130
+ import { Color } from '@esmalley/ts-utils';
131
+ const midPoint = Color.lerpColor('#ff0000', '#00ff00', 0.5);
132
+ console.log(midPoint); // Output: #7f7f00
133
+
134
+ ```
135
+
136
+
137
+
138
+ ### `getTextColor(color, backgroundColor)`
139
+
140
+ Determines a high-contrast text color based on the background color to ensure accessibility (WCAG compliance).
141
+
142
+ * **Example 1: Dynamic Label Styling**
143
+ ```ts
144
+ const bg = '#000000'; // Black background
145
+ const text = Color.getTextColor('#333333', bg);
146
+ console.log(text); // Output: #FFFFFF (returns white for better contrast)
147
+
148
+ ```
149
+
150
+
151
+
152
+ ### `darken(hex, amount)`
153
+
154
+ Darkens a hex color by a specified percentage (0 to 1).
155
+
156
+ * **Example 1: Button Hover State**
157
+ ```ts
158
+ const primary = '#3498db';
159
+ const hover = Color.darken(primary, 0.2); // 20% darker
160
+
161
+ ```
162
+
163
+
164
+
165
+ ### `alphaColor(hex, alpha)`
166
+
167
+ Converts a hex color to an `rgba()` string with the provided transparency.
168
+
169
+ * **Example 1: Transparent Overlay**
170
+ ```ts
171
+ const overlay = Color.alphaColor('#000000', 0.5);
172
+ console.log(overlay); // Output: rgba(0, 0, 0, 0.5)
173
+
174
+ ```
175
+
176
+
177
+
178
+ ---
179
+
180
+ ## CSV
181
+
182
+ Utilities for data exportation.
183
+
184
+ ### `download(data)`
185
+
186
+ Takes a nested object and triggers a browser download of a generated `.csv` file.
187
+
188
+ * **Example 1: Exporting User Lists**
189
+ ```ts
190
+ import { CSV } from '@esmalley/ts-utils';
191
+
192
+ const userData = {
193
+ user_1: { name: 'Alice', email: 'alice@example.com' },
194
+ user_2: { name: 'Bob', email: 'bob@example.com' }
195
+ };
196
+
197
+ CSV.download(userData); // Triggers download of 'srating-data.csv'
198
+
199
+ ```
200
+
201
+
202
+
203
+ ---
204
+
205
+ ## Dates
206
+
207
+ Powerful date parsing, formatting, and arithmetic.
208
+
209
+ ### `parse(input, utc?)`
210
+
211
+ A robust parser that handles ISO strings, US formats, timestamps, and mixed time strings (e.g., "5:00pm").
212
+
213
+ * **Example 1: Parsing US Format**
214
+ ```ts
215
+ import { Dates } from '@esmalley/ts-utils';
216
+ const date = Dates.parse('01/25/2026 5:30 pm');
217
+
218
+ ```
219
+
220
+
221
+
222
+ ### `format(date, formatString)`
223
+
224
+ Formats a date using a variety of tokens (Y, y, m, n, F, M, d, j, D, l, H, h, G, g, i, s, a, A).
225
+
226
+ * **Example 1: Friendly Date String**
227
+ ```ts
228
+ const now = new Date();
229
+ console.log(Dates.format(now, 'l, F jS, Y')); // Output: "Sunday, January 25th, 2026"
230
+
231
+ ```
232
+
233
+
234
+
235
+ ### `add(date, amount, unit)`
236
+
237
+ Adds a specific amount of time to a date (years, months, days, hours, minutes).
238
+
239
+ * **Example 1: Expiration Calculation**
240
+ ```ts
241
+ const today = new Date();
242
+ const nextYear = Dates.add(today, 1, 'years');
243
+
244
+ ```
245
+
246
+
247
+
248
+ ### `isSameDay(date1, date2)`
249
+
250
+ Checks if two dates refer to the same calendar day, ignoring time.
251
+
252
+ * **Example 1: Calendar Highlighting**
253
+ ```ts
254
+ const d1 = '2026-01-25 10:00';
255
+ const d2 = '2026-01-25 18:00';
256
+ console.log(Dates.isSameDay(d1, d2)); // true
257
+
258
+ ```
259
+
260
+
261
+ ---
262
+
263
+ ## Objector
264
+
265
+ Utilities for deep object manipulation.
266
+
267
+ ### `deepClone(obj)`
268
+
269
+ Creates a full, recursive copy of an object, including Maps, Sets, Dates, and RegEx.
270
+
271
+ * **Example 1: State Immutability**
272
+ ```ts
273
+ import { Objector } from '@esmalley/ts-utils';
274
+ const state = { user: { id: 1 } };
275
+ const newState = Objector.deepClone(state);
276
+ newState.user.id = 2;
277
+ console.log(state.user.id); // 1 (unchanged)
278
+
279
+ ```
280
+
281
+
282
+
283
+ ### `extender(target, ...sources)`
284
+
285
+ Deeply merges multiple source objects into a target object.
286
+
287
+ * **Example 1: Configuration Merging**
288
+ ```ts
289
+ const defaults = { theme: 'light', flags: { debug: false } };
290
+ const userConfig = { flags: { debug: true } };
291
+ Objector.extender(defaults, userConfig);
292
+ // defaults is now { theme: 'light', flags: { debug: true } }
293
+
294
+ ```
295
+
296
+
297
+
298
+ ---
299
+
300
+ ## Sorter
301
+
302
+ Table and collection sorting helpers.
303
+
304
+ ### `getComparator(order, orderBy)`
305
+
306
+ Returns a comparison function for use with `Array.sort()`.
307
+
308
+ * **Example 1: Sorting Table Data**
309
+ ```ts
310
+ import { Sorter } from '@esmalley/ts-utils';
311
+ const rows = [{ val: 10 }, { val: 5 }, { val: 20 }];
312
+ const comparator = Sorter.getComparator('desc', 'val');
313
+ rows.sort(comparator); // [{ val: 20 }, { val: 10 }, { val: 5 }]
314
+
315
+ ```
316
+
317
+
318
+
319
+ ---
320
+
321
+ ## Style
322
+
323
+ Utilities for dynamic CSS injection and style management.
324
+
325
+ ### `getStyleClassName(css, debug?)`
326
+
327
+ Hashes a CSS object/string, generates a unique class name, and injects the style into the document head.
328
+
329
+ * **Example 1: Scoped Dynamic Styling**
330
+ ```ts
331
+ import { Style } from '@esmalley/ts-utils';
332
+
333
+ const className = Style.getStyleClassName({
334
+ backgroundColor: 'red',
335
+ '&:hover': {
336
+ backgroundColor: 'blue'
337
+ },
338
+ '@media (max-width: 600px)': {
339
+ fontSize: 12
340
+ }
341
+ });
342
+
343
+ // Returns a unique hash like 'css-1a2b3c' and injects the CSS.
344
+
345
+ ```
346
+
347
+
348
+
349
+ ### `getShadow(depth)`
350
+
351
+ Returns a Material Design elevation shadow string (0-24).
352
+
353
+ * **Example 1: Component Elevation**
354
+ ```ts
355
+ const shadow = Style.getShadow(4);
356
+ // Returns: "0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14)..."
357
+
358
+ ```
359
+
360
+
361
+ ## Textor
362
+
363
+ String manipulation and linguistic utility functions.
364
+
365
+ ### `levenshtein(a, b)`
366
+
367
+ Calculates the Levenshtein distance between two strings. This is a string metric for measuring the difference between two sequences (the minimum number of single-character edits required to change one word into the other).
368
+
369
+ * **Example 1: Search Suggestions / "Did you mean?"**
370
+ Determine how close a user's typo is to a correct keyword.
371
+ ```ts
372
+ import { Textor } from '@esmalley/ts-utils';
373
+
374
+ const input = 'Gogle';
375
+ const target = 'Google';
376
+ const distance = Textor.levenshtein(input, target);
377
+
378
+ console.log(distance); // Output: 1
379
+ if (distance <= 2) {
380
+ console.log(`Did you mean ${target}?`);
381
+ }
382
+
383
+ ```
384
+
385
+
386
+ * **Example 2: Deduplicating Data**
387
+ Check if two strings are likely the same record with minor variations.
388
+ ```ts
389
+ const user1 = "Johnathan Doe";
390
+ const user2 = "Jonathan Doe";
391
+ const diff = Textor.levenshtein(user1, user2);
392
+
393
+ // A distance of 1 suggests a very high similarity
394
+ const isLikelySame = diff < 3;
395
+
396
+ ```
397
+
398
+
399
+
400
+ ### `toSentenceCase(str)`
401
+
402
+ Converts a string to sentence case by capitalizing the first letter of the first word and making the rest of the string lowercase. It also handles trimming whitespace.
403
+
404
+ * **Example 1: Formatting User-Generated Content**
405
+ Clean up a messy title submitted via a form.
406
+ ```ts
407
+ const rawTitle = " WELCOME TO THE DASHBOARD ";
408
+ const cleanTitle = Textor.toSentenceCase(rawTitle);
409
+
410
+ console.log(cleanTitle); // Output: "Welcome to the dashboard"
411
+
412
+ ```
413
+
414
+
415
+ * **Example 2: Normalizing Table Headers**
416
+ ```ts
417
+ const keys = ["USER_NAME", "EMAIL_ADDRESS"];
418
+ const labels = keys.map(k => Textor.toSentenceCase(k.replace('_', ' ')));
419
+
420
+ console.log(labels); // Output: ["User name", "Email address"]
421
+
422
+ ```
423
+
424
+
425
+
426
+ ---
427
+
428
+ ## Theme
429
+
430
+ A comprehensive Material Design-inspired theming engine providing light and dark modes with a full 50-900 color palette.
431
+
432
+ ### `constructor(mode)`
433
+
434
+ Initializes the theme engine with either `'light'` or `'dark'`. Throws an error if an invalid mode is provided.
435
+
436
+ * **Example 1: Dynamic Theme Initialization**
437
+ ```ts
438
+ import { Theme } from '@esmalley/ts-utils';
439
+
440
+ const userPreference = localStorage.getItem('theme') || 'light';
441
+ const themeEngine = new Theme(userPreference);
442
+
443
+ ```
444
+
445
+
446
+
447
+ ### `getTheme()`
448
+
449
+ Returns the full theme object (background, primary, secondary, warning, success, error, and text palettes) based on the mode selected in the constructor.
450
+
451
+ * **Example 1: Consuming Theme in a Style Object**
452
+ ```ts
453
+ const myTheme = new Theme('dark').getTheme();
454
+
455
+ const headerStyle = {
456
+ backgroundColor: myTheme.header.main,
457
+ color: myTheme.text.primary,
458
+ borderBottom: `1px solid ${myTheme.primary.main}`
459
+ };
460
+
461
+ ```
462
+
463
+
464
+
465
+ ### `getDarkTheme()` / `getLightTheme()`
466
+
467
+ Explicitly retrieves the configuration for a specific mode, regardless of the current instance state.
468
+
469
+ * **Example 1: Comparing Modes**
470
+ ```ts
471
+ const theme = new Theme('light');
472
+ const dark = theme.getDarkTheme();
473
+ const light = theme.getLightTheme();
474
+
475
+ console.log(dark.background.main); // #121212
476
+ console.log(light.background.main); // #ffffff
477
+
478
+ ```
479
+
480
+
481
+
482
+ ### Palette Accessors (e.g., `getGrey()`, `getAmber()`, etc.)
483
+
484
+ The class provides access to the standard Material Design color ramps.
485
+
486
+ * **Example 1: Using Specific Color Weights**
487
+ ```ts
488
+ const theme = new Theme('light');
489
+ const greys = theme.getGrey();
490
+
491
+ const dividerStyle = {
492
+ backgroundColor: greys[300] // Light grey for dividers
493
+ };
494
+
495
+ const secondaryText = {
496
+ color: greys[600] // Medium grey for subtext
497
+ };
498
+
499
+ ```
500
+
501
+
502
+
503
+ ---
504
+
505
+ ## Toaster
506
+
507
+ A global state manager for UI notifications (Toasts). It supports subscriptions, auto-dismissal, and exit animations.
508
+
509
+ ### `subscribe(listener)`
510
+
511
+ Allows a UI component (like a React or Vue component) to listen for changes to the toast list. Returns an unsubscribe function.
512
+
513
+ * **Example 1: Integrating with a Framework (React-like)**
514
+ ```ts
515
+ import { toaster } from '@esmalley/ts-utils';
516
+
517
+ const unsubscribe = toaster.subscribe((newList) => {
518
+ console.log("Toasts updated:", newList);
519
+ this.setState({ toasts: newList });
520
+ });
521
+
522
+ // Later, clean up the listener
523
+ // unsubscribe();
524
+
525
+ ```
526
+
527
+
528
+
529
+ ### `add(message, type)`
530
+
531
+ Adds a new notification to the stack. Defaults to `'info'` type. Automatically triggers a close request after 4 seconds.
532
+
533
+ * **Example 1: Error Handling**
534
+ ```ts
535
+ try {
536
+ await api.save();
537
+ toaster.add("Changes saved successfully!", "success");
538
+ } catch (e) {
539
+ toaster.add("Failed to save changes. Please try again.", "error");
540
+ }
541
+
542
+ ```
543
+
544
+
545
+ * **Example 2: Basic Notification**
546
+ ```ts
547
+ toaster.add("You have a new message."); // Defaults to 'info'
548
+
549
+ ```
550
+
551
+
552
+
553
+ ### `requestClose(id)`
554
+
555
+ Starts the "exit" phase for a toast. It marks the toast as `exiting: true`, allowing the UI to play a fade-out animation before the toast is fully removed 500ms later.
556
+
557
+ * **Example 1: Manual Dismiss Button**
558
+ ```ts
559
+ // Inside your UI component's "X" button click handler
560
+ const handleClose = (toastId) => {
561
+ toaster.requestClose(toastId);
562
+ };
563
+
564
+ ```
565
+
566
+
567
+
568
+ ### `remove(id)`
569
+
570
+ Immediately removes a toast from the list without waiting for an animation or timeout.
571
+
572
+ * **Example 1: Force Clearing a specific alert**
573
+ ```ts
574
+ toaster.remove(currentToastId);
575
+
576
+ ```
577
+
578
+
579
+
580
+ ### `getToasts()`
581
+
582
+ Returns the current array of active `ToastItem` objects.
583
+
584
+ * **Example 1: Checking Toast Count**
585
+ ```ts
586
+ const activeToasts = toaster.getToasts();
587
+ if (activeToasts.length > 5) {
588
+ console.log("The user is being flooded with notifications!");
589
+ }
590
+
591
+ ```
592
+
593
+
594
+
595
+ ---
596
+
597
+ ## Kontororu (Events)
598
+
599
+ An EventTarget wrapper for managing custom listeners.
600
+
601
+ ### `addEventListener(type, listener)`
602
+
603
+ Registers an event handler.
604
+
605
+ * **Example 1: Custom Socket Events**
606
+ ```ts
607
+ import { Kontororu } from '@esmalley/ts-utils';
608
+ const bus = new Kontororu();
609
+ bus.addEventListener('data', (payload) => console.log(payload));
610
+
611
+ ```
612
+
613
+
614
+
615
+
616
+
package/dist/cjs/index.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var j=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var tt=Object.prototype.hasOwnProperty;var et=(c,e)=>{for(var t in e)j(c,t,{get:e[t],enumerable:!0})},nt=(c,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of X(e))!tt.call(c,n)&&n!==t&&j(c,n,{get:()=>e[n],enumerable:!(r=Q(e,n))||r.enumerable});return c};var rt=c=>nt(j({},"__esModule",{value:!0}),c);var at={};et(at,{Arithmetic:()=>N,Arrayifier:()=>H,CSV:()=>W,Color:()=>P,Dates:()=>U,Kontororu:()=>_,Objector:()=>G,Sorter:()=>z,Style:()=>F,Textor:()=>J,Theme:()=>Y,socket:()=>st,toast:()=>it,toaster:()=>I});module.exports=rt(at);var _=class extends EventTarget{constructor(){super(),this.listeners={}}addEventListener(e,t){super.addEventListener(e,t),this.listeners[e]||(this.listeners[e]=[]),this.listeners[e].push(t)}removeEventListener(e,t){super.removeEventListener(e,t),this.listeners[e]&&(this.listeners[e]=this.listeners[e].filter(r=>r!==t))}getListeners(e){return this.listeners[e]||[]}};var k=!1,B=class extends _{constructor(){super();this.connection_state="connected";this.message_queue=[];this.reconnect_attempts=0;this.should_reconnect=!0;this.last_heartbeat_timestamp=Date.now();this.HEARTBEAT_INTERVAL_MS=5e3;this.SUSPENSION_THRESHOLD_MS=this.HEARTBEAT_INTERVAL_MS*2+1e3;this.DISCONNECT_THRESHOLD_MS=this.HEARTBEAT_INTERVAL_MS*3+1e3;if(typeof document<"u"&&document.addEventListener("visibilitychange",t=>{document.visibilityState==="visible"&&this.check_staleness("tab_switch")}),typeof window<"u"){let t=()=>{let n=1,s=()=>{n>3||setTimeout(()=>{this.check_staleness("offline"),n++,s()},this.HEARTBEAT_INTERVAL_MS+500)};s()};window.addEventListener("online",()=>{window.removeEventListener("offline",t)}),window.addEventListener("offline",t)}}get_url(){if(!this.config)throw new Error("Socket not configured");let{hostname:t,port:r,path:n}=this.config;return`${typeof window<"u"&&window.location&&window.location.protocol&&window.location.protocol==="https:"?"wss:":"ws:"}//${t}${r?`:${r}`:""}/${n}`}connect(t,r){if(r&&(this.config=r),!t){console.warn("session_id required to open ws");return}this.ws&&(this.ws.readyState===WebSocket.OPEN||this.ws.readyState===WebSocket.CONNECTING)||(this.ws=new WebSocket(this.get_url()),k&&console.log("new websocket"),this.session_id=t,this.last_heartbeat_timestamp=Date.now(),this.ws.addEventListener("open",n=>this.handle_open(n)),this.ws.addEventListener("message",n=>this.handle_message(n)),this.ws.addEventListener("close",n=>this.handle_close(n)),this.ws.addEventListener("error",n=>this.handle_error(n)))}message({type:t,table:r,id:n}){let s={type:t,table:r,id:n};this.ws&&this.ws.readyState===WebSocket.OPEN?this.ws.send(JSON.stringify(s)):this.message_queue.push(s)}disconnect(){k&&console.log("websocket disconnect()"),this.update_connection_state("disconnected"),this.should_reconnect=!1,this.ws?.close(),this.ws=void 0,this.reconnect_timeout&&clearTimeout(this.reconnect_timeout)}update_connection_state(t){let r=this.connection_state;this.connection_state!==t&&(k&&console.log("update_connection_state",t),this.connection_state=t,k&&console.warn(`[Socket] State changed to: ${this.connection_state}`),this.dispatchEvent(new CustomEvent("connection_state",{detail:this.connection_state})),(t==="connected"||t==="reconnected")&&(r==="stale"||r==="disconnected")&&this.dispatchEvent(new CustomEvent("refresh",{bubbles:!0})))}check_staleness(t){let n=Date.now()-this.last_heartbeat_timestamp;if(k&&console.log("websocket check_staleness()",t,n),!this.ws||this.ws.readyState===this.ws.CLOSED||n>this.DISCONNECT_THRESHOLD_MS){this.update_connection_state("disconnected");return}n>this.SUSPENSION_THRESHOLD_MS?this.update_connection_state("stale"):this.update_connection_state("connected")}handle_open(t){for(k&&console.log("websocket handle open()"),this.ws&&this.ws.readyState===this.ws.OPEN&&this.update_connection_state("connected"),this.reconnect_timeout&&clearTimeout(this.reconnect_timeout),this.reconnect_attempts>0&&(k&&console.log("[Socket] Reconnected. Triggering refresh."),this.dispatchEvent(new CustomEvent("refresh",{bubbles:!0}))),this.reconnect_attempts=0,this.ws?.send(JSON.stringify({type:"session",table:"session",id:this.session_id}));this.message_queue.length>0;){let r=this.message_queue.shift();this.ws?.send(JSON.stringify(r))}}handle_message(t){k&&console.log("websocket handle message()");try{let r=JSON.parse(t.data);if(k&&console.log("data",r),r.type==="heartbeat"){this.check_staleness("heartbeat"),this.last_heartbeat_timestamp=Date.now();return}let n=new CustomEvent("message",{detail:JSON.parse(t.data),bubbles:!0});this.dispatchEvent(n)}catch{let n=new CustomEvent("message",{detail:t.data,bubbles:!0});this.dispatchEvent(n)}}handle_close(t){if(k&&console.log("websocket handle close()"),this.update_connection_state("disconnected"),this.should_reconnect){let r=Math.min(1e3*Math.pow(2,this.reconnect_attempts),3e4);k&&console.log(`Connection lost. Retrying in ${r}ms... (Attempt ${this.reconnect_attempts+1})`),this.reconnect_timeout=setTimeout(()=>{this.reconnect_attempts++,this.session_id&&this.connect(this.session_id)},r)}this.ws=void 0}handle_error(t){k&&console.log("websocket handle error()"),this.update_connection_state("disconnected"),console.error("WebSocket Error:",t),this.ws?.close()}},st=new B;var N=class{static clamp(e,t,r){return Math.max(t,Math.min(e,r))}};var H=class{shuffle(e){let t=e.length,r;for(;t!==0;)r=Math.floor(Math.random()*t),t--,[e[t],e[r]]=[e[r],e[t]];return e}combination(e,t,r,n,s,a,i){if(n===r){let o=[];for(let p=0;p<r;p++)o.push(s[p]);return i.push(o),i}return a>=t||(s[n]=e[a],this.combination(e,t,r,n+1,s,a+1,i),this.combination(e,t,r,n,s,a+1,i)),i}getCombinations(e,t,r){let n=new Array(r),s=[];return s=this.combination(e,t,r,0,n,0,s),s}};var P=class c{static lerpColor(e,t,r){let n=+e.replace("#","0x"),s=n>>16,a=n>>8&255,i=n&255,o=+t.replace("#","0x"),p=o>>16,g=o>>8&255,h=o&255,d=s+r*(p-s),l=a+r*(g-a),m=i+r*(h-i);return`#${((1<<24)+(d<<16)+(l<<8)+m|0).toString(16).slice(1)}`}static getTextColor(e,t,r=!1){let[n,s,a]=c.hexToRgb(e),[i,o,p]=c.hexToRgb(t),g=4.5;if(r&&console.log("Color.getContrastRatio([r, g, b], [br, bg, bb])",c.getContrastRatio([n,s,a],[i,o,p])),c.getContrastRatio([n,s,a],[i,o,p])>=g)return c.rgbToHex(n,s,a);let h=c.getContrastRatio([0,0,0],[i,o,p]),d=c.getContrastRatio([255,255,255],[i,o,p]),l=d>h?"lighter":"darker";r&&(console.log("contrastToBlack",h),console.log("contrastToWhite",d),console.log("direction",l));let m=(C,D)=>D?Math.min(255,C+10):Math.max(0,C-10);for(let C=0;C<25&&(n=m(n,l==="lighter"),s=m(s,l==="lighter"),a=m(a,l==="lighter"),r&&console.log("Color.getContrastRatio([r, g, b], [br, bg, bb]) 2",c.getContrastRatio([n,s,a],[i,o,p])),!(c.getContrastRatio([n,s,a],[i,o,p])>=g));C++);return c.rgbToHex(n,s,a)}static getContrastRatio(e,t){let r=(a,i,o)=>{let p=[a,i,o].map(g=>(g/=255,g<=.03928?g/12.92:Math.pow((g+.055)/1.055,2.4)));return p[0]*.2126+p[1]*.7152+p[2]*.0722},n=r(...e)+.05,s=r(...t)+.05;return n>s?n/s:s/n}static darken(e,t=.1){let[r,n,s]=this.hexToRgb(e),a=1-t,i=Math.round(r*a),o=Math.round(n*a),p=Math.round(s*a);return this.rgbToHex(i,o,p)}static lighten(e,t=.1){let[r,n,s]=this.hexToRgb(e),a=Math.round(r+(255-r)*t),i=Math.round(n+(255-n)*t),o=Math.round(s+(255-s)*t);return this.rgbToHex(a,i,o)}static shadeColor(e,t){let[r,n,s]=c.hexToRgb(e);return r=Math.min(255,Math.max(0,Math.round(r+r*(t/100)))),n=Math.min(255,Math.max(0,Math.round(n+n*(t/100)))),s=Math.min(255,Math.max(0,Math.round(s+s*(t/100)))),c.rgbToHex(r,n,s)}static areColorsSimilar(e,t,r=50){return c.colorDistance(e,t)<r}static invertColor(e){let[t,r,n]=c.hexToRgb(e),s=255-t,a=255-r,i=255-n;return c.rgbToHex(s,a,i)}static alphaColor(e,t){let[r,n,s]=this.hexToRgb(e);return`rgba(${r}, ${n}, ${s}, ${t})`}static getAnalogousColors(e){let[t,r,n]=c.hexToRgb(e),[s,a,i]=c.rgbToHsl(t,r,n),o=[],p=30;for(let g=-1;g<=1;g++)if(g!==0){let h=(s+g*p+360)%360,[d,l,m]=c.hslToRgb(h,a,i);o.push(c.rgbToHex(d,l,m))}return o}static hexToRgb(e){let t=e.replace(/^#/,"");if(t.length===3&&(t=t.split("").map(i=>i+i).join("")),t.length!==6)throw new Error(`Invalid hex color format: ${e}`);let r=parseInt(t,16),n=r>>16&255,s=r>>8&255,a=r&255;return[n,s,a]}static rgbToHex(e,t,r){return`#${((1<<24)+(e<<16)+(t<<8)+r).toString(16).slice(1).toUpperCase()}`}static rgbToHsl(e,t,r){e/=255,t/=255,r/=255;let n=Math.max(e,t,r),s=Math.min(e,t,r),a=0,i=0,o=(n+s)/2;if(n===s)a=i=0;else{let p=n-s;switch(i=o>.5?p/(2-n-s):p/(n+s),n){case e:a=(t-r)/p+(t<r?6:0);break;case t:a=(r-e)/p+2;break;case r:a=(e-t)/p+4;break}a/=6}return[a*360,i*100,o*100]}static hslToRgb(e,t,r){let n,s,a;if(e/=360,t/=100,r/=100,t===0)n=s=a=r;else{let i=(g,h,d)=>(d<0&&(d+=1),d>1&&(d-=1),d<.16666666666666666?g+(h-g)*6*d:d<.3333333333333333?h:d<.5?g+(h-g)*(.6666666666666666-d)*6:g),o=r<.5?r*(1+t):r+t-r*t,p=2*r-o;n=i(p,o,e+1/3),s=i(p,o,e),a=i(p,o,e-1/3)}return[Math.round(n*255),Math.round(s*255),Math.round(a*255)]}static calculateBrightness(e,t,r){return(e*299+t*587+r*114)/1e3}static colorDistance(e,t){let[r,n,s]=c.hexToRgb(e),[a,i,o]=c.hexToRgb(t),p=r-a,g=n-i,h=s-o;return Math.sqrt(p*p+g*g+h*h)}};var W=class{static download(e){let t=[],r=!1,n=[];for(let p in e){let g=e[p];r||(n=Object.keys(g),t.push(n.join(",")),r=!0);let h=n.map(d=>JSON.stringify(g[d]||""));t.push(h.join(","))}let s=t.join(`
1
+ "use strict";var j=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var tt=Object.prototype.hasOwnProperty;var et=(c,e)=>{for(var t in e)j(c,t,{get:e[t],enumerable:!0})},nt=(c,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of X(e))!tt.call(c,n)&&n!==t&&j(c,n,{get:()=>e[n],enumerable:!(r=Q(e,n))||r.enumerable});return c};var rt=c=>nt(j({},"__esModule",{value:!0}),c);var at={};et(at,{Arithmetic:()=>N,Arrayifier:()=>H,CSV:()=>W,Color:()=>P,Dates:()=>U,Kontororu:()=>_,Objector:()=>G,Sorter:()=>z,Style:()=>F,Textor:()=>J,Theme:()=>Y,socket:()=>st,toast:()=>it,toaster:()=>I});module.exports=rt(at);var _=class extends EventTarget{constructor(){super(),this.listeners={}}addEventListener(e,t){super.addEventListener(e,t),this.listeners[e]||(this.listeners[e]=[]),this.listeners[e].push(t)}removeEventListener(e,t){super.removeEventListener(e,t),this.listeners[e]&&(this.listeners[e]=this.listeners[e].filter(r=>r!==t))}getListeners(e){return this.listeners[e]||[]}};var k=!1,B=class extends _{constructor(){super();this.connection_state="connected";this.message_queue=[];this.reconnect_attempts=0;this.should_reconnect=!0;this.last_heartbeat_timestamp=Date.now();this.HEARTBEAT_INTERVAL_MS=5e3;this.SUSPENSION_THRESHOLD_MS=this.HEARTBEAT_INTERVAL_MS*2+1e3;this.DISCONNECT_THRESHOLD_MS=this.HEARTBEAT_INTERVAL_MS*3+1e3;if(typeof document<"u"&&document.addEventListener("visibilitychange",t=>{document.visibilityState==="visible"&&this.check_staleness("tab_switch")}),typeof window<"u"){let t=()=>{let n=1,s=()=>{n>3||setTimeout(()=>{this.check_staleness("offline"),n++,s()},this.HEARTBEAT_INTERVAL_MS+500)};s()};window.addEventListener("online",()=>{window.removeEventListener("offline",t)}),window.addEventListener("offline",t)}}get_url(){if(!this.config)throw new Error("Socket not configured");let{hostname:t,port:r,path:n}=this.config;return`${typeof window<"u"&&window.location&&window.location.protocol&&window.location.protocol==="https:"?"wss:":"ws:"}//${t}${r?`:${r}`:""}/${n}`}connect(t,r){if(r&&(this.config=r),!t){console.warn("session_id required to open ws");return}this.ws&&(this.ws.readyState===WebSocket.OPEN||this.ws.readyState===WebSocket.CONNECTING)||(this.ws=new WebSocket(this.get_url()),k&&console.log("new websocket"),this.session_id=t,this.last_heartbeat_timestamp=Date.now(),this.ws.addEventListener("open",n=>this.handle_open(n)),this.ws.addEventListener("message",n=>this.handle_message(n)),this.ws.addEventListener("close",n=>this.handle_close(n)),this.ws.addEventListener("error",n=>this.handle_error(n)))}message({type:t,table:r,id:n}){let s={type:t,table:r,id:n};this.ws&&this.ws.readyState===WebSocket.OPEN?this.ws.send(JSON.stringify(s)):this.message_queue.push(s)}disconnect(){k&&console.log("websocket disconnect()"),this.update_connection_state("disconnected"),this.should_reconnect=!1,this.ws?.close(),this.ws=void 0,this.reconnect_timeout&&clearTimeout(this.reconnect_timeout)}update_connection_state(t){let r=this.connection_state;this.connection_state!==t&&(k&&console.log("update_connection_state",t),this.connection_state=t,k&&console.warn(`[Socket] State changed to: ${this.connection_state}`),this.dispatchEvent(new CustomEvent("connection_state",{detail:this.connection_state})),(t==="connected"||t==="reconnected")&&(r==="stale"||r==="disconnected")&&this.dispatchEvent(new CustomEvent("refresh",{bubbles:!0})))}check_staleness(t){let n=Date.now()-this.last_heartbeat_timestamp;if(k&&console.log("websocket check_staleness()",t,n),!this.ws||this.ws.readyState===this.ws.CLOSED||n>this.DISCONNECT_THRESHOLD_MS){this.update_connection_state("disconnected");return}n>this.SUSPENSION_THRESHOLD_MS?this.update_connection_state("stale"):this.update_connection_state("connected")}handle_open(t){for(k&&console.log("websocket handle open()"),this.ws&&this.ws.readyState===this.ws.OPEN&&this.update_connection_state("connected"),this.reconnect_timeout&&clearTimeout(this.reconnect_timeout),this.reconnect_attempts>0&&(k&&console.log("[Socket] Reconnected. Triggering refresh."),this.dispatchEvent(new CustomEvent("refresh",{bubbles:!0}))),this.reconnect_attempts=0,this.ws?.send(JSON.stringify({type:"session",table:"session",id:this.session_id}));this.message_queue.length>0;){let r=this.message_queue.shift();this.ws?.send(JSON.stringify(r))}}handle_message(t){k&&console.log("websocket handle message()");try{let r=JSON.parse(t.data);if(k&&console.log("data",r),r.type==="heartbeat"){this.check_staleness("heartbeat"),this.last_heartbeat_timestamp=Date.now();return}let n=new CustomEvent("message",{detail:JSON.parse(t.data),bubbles:!0});this.dispatchEvent(n)}catch{let n=new CustomEvent("message",{detail:t.data,bubbles:!0});this.dispatchEvent(n)}}handle_close(t){if(k&&console.log("websocket handle close()"),this.update_connection_state("disconnected"),this.should_reconnect){let r=Math.min(1e3*Math.pow(2,this.reconnect_attempts),3e4);k&&console.log(`Connection lost. Retrying in ${r}ms... (Attempt ${this.reconnect_attempts+1})`),this.reconnect_timeout=setTimeout(()=>{this.reconnect_attempts++,this.session_id&&this.connect(this.session_id)},r)}this.ws=void 0}handle_error(t){k&&console.log("websocket handle error()"),this.update_connection_state("disconnected"),console.error("WebSocket Error:",t),this.ws?.close()}},st=new B;var N=class{static clamp(e,t,r){return Math.max(t,Math.min(e,r))}};var H=class{static shuffle(e){let t=e.length,r;for(;t!==0;)r=Math.floor(Math.random()*t),t--,[e[t],e[r]]=[e[r],e[t]];return e}static combination(e,t,r,n,s,a,i){if(n===r){let o=[];for(let p=0;p<r;p++)o.push(s[p]);return i.push(o),i}return a>=t||(s[n]=e[a],this.combination(e,t,r,n+1,s,a+1,i),this.combination(e,t,r,n,s,a+1,i)),i}static getCombinations(e,t,r){let n=new Array(r),s=[];return s=this.combination(e,t,r,0,n,0,s),s}};var P=class c{static lerpColor(e,t,r){let n=+e.replace("#","0x"),s=n>>16,a=n>>8&255,i=n&255,o=+t.replace("#","0x"),p=o>>16,g=o>>8&255,h=o&255,d=s+r*(p-s),l=a+r*(g-a),m=i+r*(h-i);return`#${((1<<24)+(d<<16)+(l<<8)+m|0).toString(16).slice(1)}`}static getTextColor(e,t,r=!1){let[n,s,a]=c.hexToRgb(e),[i,o,p]=c.hexToRgb(t),g=4.5;if(r&&console.log("Color.getContrastRatio([r, g, b], [br, bg, bb])",c.getContrastRatio([n,s,a],[i,o,p])),c.getContrastRatio([n,s,a],[i,o,p])>=g)return c.rgbToHex(n,s,a);let h=c.getContrastRatio([0,0,0],[i,o,p]),d=c.getContrastRatio([255,255,255],[i,o,p]),l=d>h?"lighter":"darker";r&&(console.log("contrastToBlack",h),console.log("contrastToWhite",d),console.log("direction",l));let m=(C,D)=>D?Math.min(255,C+10):Math.max(0,C-10);for(let C=0;C<25&&(n=m(n,l==="lighter"),s=m(s,l==="lighter"),a=m(a,l==="lighter"),r&&console.log("Color.getContrastRatio([r, g, b], [br, bg, bb]) 2",c.getContrastRatio([n,s,a],[i,o,p])),!(c.getContrastRatio([n,s,a],[i,o,p])>=g));C++);return c.rgbToHex(n,s,a)}static getContrastRatio(e,t){let r=(a,i,o)=>{let p=[a,i,o].map(g=>(g/=255,g<=.03928?g/12.92:Math.pow((g+.055)/1.055,2.4)));return p[0]*.2126+p[1]*.7152+p[2]*.0722},n=r(...e)+.05,s=r(...t)+.05;return n>s?n/s:s/n}static darken(e,t=.1){let[r,n,s]=this.hexToRgb(e),a=1-t,i=Math.round(r*a),o=Math.round(n*a),p=Math.round(s*a);return this.rgbToHex(i,o,p)}static lighten(e,t=.1){let[r,n,s]=this.hexToRgb(e),a=Math.round(r+(255-r)*t),i=Math.round(n+(255-n)*t),o=Math.round(s+(255-s)*t);return this.rgbToHex(a,i,o)}static shadeColor(e,t){let[r,n,s]=c.hexToRgb(e);return r=Math.min(255,Math.max(0,Math.round(r+r*(t/100)))),n=Math.min(255,Math.max(0,Math.round(n+n*(t/100)))),s=Math.min(255,Math.max(0,Math.round(s+s*(t/100)))),c.rgbToHex(r,n,s)}static areColorsSimilar(e,t,r=50){return c.colorDistance(e,t)<r}static invertColor(e){let[t,r,n]=c.hexToRgb(e),s=255-t,a=255-r,i=255-n;return c.rgbToHex(s,a,i)}static alphaColor(e,t){let[r,n,s]=this.hexToRgb(e);return`rgba(${r}, ${n}, ${s}, ${t})`}static getAnalogousColors(e){let[t,r,n]=c.hexToRgb(e),[s,a,i]=c.rgbToHsl(t,r,n),o=[],p=30;for(let g=-1;g<=1;g++)if(g!==0){let h=(s+g*p+360)%360,[d,l,m]=c.hslToRgb(h,a,i);o.push(c.rgbToHex(d,l,m))}return o}static hexToRgb(e){let t=e.replace(/^#/,"");if(t.length===3&&(t=t.split("").map(i=>i+i).join("")),t.length!==6)throw new Error(`Invalid hex color format: ${e}`);let r=parseInt(t,16),n=r>>16&255,s=r>>8&255,a=r&255;return[n,s,a]}static rgbToHex(e,t,r){return`#${((1<<24)+(e<<16)+(t<<8)+r).toString(16).slice(1).toUpperCase()}`}static rgbToHsl(e,t,r){e/=255,t/=255,r/=255;let n=Math.max(e,t,r),s=Math.min(e,t,r),a=0,i=0,o=(n+s)/2;if(n===s)a=i=0;else{let p=n-s;switch(i=o>.5?p/(2-n-s):p/(n+s),n){case e:a=(t-r)/p+(t<r?6:0);break;case t:a=(r-e)/p+2;break;case r:a=(e-t)/p+4;break}a/=6}return[a*360,i*100,o*100]}static hslToRgb(e,t,r){let n,s,a;if(e/=360,t/=100,r/=100,t===0)n=s=a=r;else{let i=(g,h,d)=>(d<0&&(d+=1),d>1&&(d-=1),d<.16666666666666666?g+(h-g)*6*d:d<.3333333333333333?h:d<.5?g+(h-g)*(.6666666666666666-d)*6:g),o=r<.5?r*(1+t):r+t-r*t,p=2*r-o;n=i(p,o,e+1/3),s=i(p,o,e),a=i(p,o,e-1/3)}return[Math.round(n*255),Math.round(s*255),Math.round(a*255)]}static calculateBrightness(e,t,r){return(e*299+t*587+r*114)/1e3}static colorDistance(e,t){let[r,n,s]=c.hexToRgb(e),[a,i,o]=c.hexToRgb(t),p=r-a,g=n-i,h=s-o;return Math.sqrt(p*p+g*g+h*h)}};var W=class{static download(e){let t=[],r=!1,n=[];for(let p in e){let g=e[p];r||(n=Object.keys(g),t.push(n.join(",")),r=!0);let h=n.map(d=>JSON.stringify(g[d]||""));t.push(h.join(","))}let s=t.join(`
2
2
  `),a=new Blob([s],{type:"text/csv"}),i=URL.createObjectURL(a),o=document.createElement("a");o.href=i,o.download="srating-data.csv",document.body.appendChild(o),o.click(),URL.revokeObjectURL(i),o.remove()}};var U=class{static parse(e,t=!1){if(!e)return new Date;if(e instanceof Date)return new Date(e.getTime());if(typeof e=="number")return new Date(e);if(typeof e=="string"){let r=e.trim();if(/^\d{4}-\d{2}-\d{2}$/.test(r))return new Date(`${r}T00:00:00`);let n,s,a,i="",o=r.match(/^(\d{4})[-/](\d{1,2})[-/](\d{1,2})(.*)$/),p=r.match(/^(\d{1,2})[-/](\d{1,2})[-/](\d{4})(.*)$/);if(o)n=parseInt(o[1],10),s=parseInt(o[2],10)-1,a=parseInt(o[3],10),i=o[4];else if(p)n=parseInt(p[3],10),s=parseInt(p[1],10)-1,a=parseInt(p[2],10),i=p[4];else{let l=new Date(r);return isNaN(l.getTime())?new Date:l}let g=0,h=0,d=0;if(i&&i.trim().length>0){let l=i.match(/(\d{1,2}):(\d{1,2})(?::(\d{1,2}))?\s*(am|pm|AM|PM)?/);if(l){g=parseInt(l[1],10),h=parseInt(l[2],10),d=l[3]?parseInt(l[3],10):0;let m=l[4]?l[4].toLowerCase():null;m==="pm"&&g<12&&(g+=12),m==="am"&&g===12&&(g=0)}}return t?new Date(Date.UTC(n,s,a,g,h,d)):new Date(n,s,a,g,h,d)}return new Date}static utc(e){let t=this.parse(e);return new Date(t.getTime()+t.getTimezoneOffset()*6e4)}static getMonthsShort(){return["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]}static getMonths(){return["January","February","March","April","May","June","July","August","September","October","November","December"]}static getDaysShort(){return["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]}static getDays(){return["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]}static format(e,t){let r=this.parse(e),n=y=>String(y).padStart(2,"0"),s=this.getMonthsShort(),a=this.getMonths(),i=this.getDaysShort(),o=this.getDays(),p=r.getFullYear(),g=String(p).slice(-2),h=r.getMonth(),d=r.getDate(),l=r.getDay(),m=r.getHours(),C=r.getMinutes(),D=r.getSeconds(),O=y=>{let T=y%100;if(T>=11&&T<=13)return"th";switch(y%10){case 1:return"st";case 2:return"nd";case 3:return"rd";default:return"th"}},M={Y:String(p),y:g,m:n(h+1),n:String(h+1),M:s[h],F:a[h],d:n(d),j:String(d),D:i[l],l:o[l],w:String(l),N:String(l===0?7:l),S:O(d),H:n(m),G:String(m),h:n((m+11)%12+1),g:String((m+11)%12+1),i:n(C),s:n(D),A:m<12?"AM":"PM",a:m<12?"am":"pm"};return t.replace(/\\(.)|([a-zA-Z])/g,(y,T,A)=>T||(M[A]??A))}static add(e,t,r){let n=this.parse(e);if(r==="years"){let s=n.getDate();n.setFullYear(n.getFullYear()+t),n.getDate()!==s&&n.setDate(0)}else if(r==="months"){let s=n.getDate();n.setMonth(n.getMonth()+t),n.getDate()!==s&&n.setDate(0)}else if(r==="days")n.setDate(n.getDate()+t);else{let s={hours:t*60*60*1e3,minutes:t*60*1e3};n.setTime(n.getTime()+s[r])}return n}static subtract(e,t,r){return this.add(e,-t,r)}static fromNow(e){let t=this.parse(e),r=Date.now()-t.getTime(),n=Math.floor(r/6e4);if(Math.abs(n)<1)return"just now";if(n<0)return"in the future";if(n<60)return`${n}m ago`;let s=Math.floor(n/60);return s<24?`${s}h ago`:`${Math.floor(s/24)}d ago`}static getClosestDate(e,t){if(!t.length)return null;let r=this.parse(e).getTime(),n=null,s=1/0;for(let a of t){let i=this.parse(a).getTime(),o=Math.abs(i-r);o<s?(s=o,n=a):o===s&&i>r&&(n=a)}return n}static getTodayEST(){return this.format(new Date().toLocaleString("en-US",{timeZone:"America/New_York"}),"Y-m-d")}static getStartOfDay(e){let t=this.parse(e);return t.setHours(0,0,0,0),t}static getStartOfMonth(e){let t=this.parse(e);return t.setDate(1),t.setHours(0,0,0,0),t}static getStartOfGrid(e){let t=this.getStartOfMonth(e),r=t.getDay(),n=this.parse(t);return n.setDate(t.getDate()-r),n}static isSameDay(e,t){if(!e||!t)return!1;let r=this.parse(e),n=this.parse(t);return r.getFullYear()===n.getFullYear()&&r.getMonth()===n.getMonth()&&r.getDate()===n.getDate()}static isBeforeDay(e,t){return!e||!t?!1:this.getStartOfDay(e).getTime()<this.getStartOfDay(t).getTime()}static isAfterDay(e,t){return!e||!t?!1:this.getStartOfDay(e).getTime()>this.getStartOfDay(t).getTime()}};var G=class c{static deepClone(e,t=new WeakMap){if(e===null||typeof e!="object")return e;if(t.has(e))return t.get(e);if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp)return new RegExp(e.source,e.flags);if(e instanceof Map){let s=new Map;return t.set(e,s),e.forEach((a,i)=>s.set(i,c.deepClone(a,t))),s}if(e instanceof Set){let s=new Set;for(let a of e)s.add(c.deepClone(a));return s}if(Array.isArray(e)){let s=e.map(a=>c.deepClone(a,t));return t.set(e,s),s}let r=Object.create(Object.getPrototypeOf(e));t.set(e,r);let n=e;return Object.keys(n).forEach(s=>{r[s]=c.deepClone(n[s],t)}),Object.getOwnPropertySymbols(n).forEach(s=>{Object.prototype.propertyIsEnumerable.call(n,s)&&(r[s]=c.deepClone(n[s],t))}),r}static extender(e,...t){if(e==null)throw new TypeError("Cannot convert undefined or null to object");let r=Object(e);for(let n of t)if(n!=null){let s=n;for(let i of Object.keys(s))r[i]=c.deepClone(s[i]);let a=Object.getOwnPropertySymbols(s);for(let i of a)Object.prototype.propertyIsEnumerable.call(s,i)&&(r[i]=c.deepClone(s[i]))}return r}};var z=class{static descendingComparator(e,t,r,n){if(r in e&&t[r]===null)return 1;if(e[r]===null&&r in t)return-1;let s=e[r],a=t[r],i=n||"lower";return a<s?i==="higher"?1:-1:a>s?i==="higher"?-1:1:0}static getComparator(e,t,r){return e==="desc"?(n,s)=>this.descendingComparator(n,s,t,r):(n,s)=>-this.descendingComparator(n,s,t,r)}};var $=class ${static getStyle(){return{zIndex:$.getZIndex()}}static getZIndex(){return{appBar:1100,drawer:1200,fab:1050,calendar:1e3,mobileStepper:1e3,modal:1300,toast:1400,speedDial:1050,tooltip:1500}}static getNavBar(){return{width:"100%",display:"flex",justifyContent:"center",zIndex:$.getZIndex().drawer,position:"fixed",overflowX:"scroll",overflowY:"hidden",scrollbarWidth:"none"}}static getShadow(e){let t=["none","0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)","0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)","0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)","0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)","0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)","0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)","0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)","0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)","0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)","0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)","0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)","0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)","0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)","0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)","0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)","0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)","0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)","0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)","0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)","0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)","0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)","0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)","0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)","0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)"];if(e>t.length||e<0)throw new Error(`min depth is 0, max depth is ${t.length}. Sent ${e}`);return t[e]}static getStyleClassName(e,t=!1){t&&console.log("getStyleClassName",e);let r=`css-${this.hashCSS(e,t)}`;return this.injectStyle(r,e,t),r}static getCSS(){return console.warn("this does not work yet, in root layout need to add a context thing so it attaches css to style when streamed from server"),Array.from(this.cssMap.values()).join(`
3
3
  `)}static flush(){this.styleCache.clear(),this.cssMap.clear()}static hashCSS(e,t=!1){let r=i=>{if(typeof i!="object"||i===null)return i;if(Array.isArray(i))return i.map(r);let o=Object.keys(i).sort(),p={},g=i;for(let h of o)p[h]=r(g[h]);return p},s=(i=>{if(typeof i=="string")return i;if(typeof i=="object"&&i!==null){let o=r(i);return JSON.stringify(o)}return String(i)})(e);t&&console.log("normalizedInput",s);let a=5381;for(let i=0;i<s.length;i++)a=a*33^s.charCodeAt(i);return(a>>>0).toString(36)}static injectStyle(e,t,r=!1){if(this.styleCache.has(e))return;let n=this.processCSS(e,t,!1,r);if(typeof window>"u")this.cssMap.set(e,n);else{let s=document.createElement("style");s.textContent=n,document.head.appendChild(s)}this.styleCache.add(e),this.cssMap.set(e,n)}static processCSS(e,t,r=!1,n=!1){let s=f=>f.replace(/:$/g,""),a=f=>f.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),i=f=>{if(f.length===0)return;let u=f.length-1,x=f[u],b=x.lastIndexOf("}");if(b!==-1){let w=x.substring(0,b)+x.substring(b+1);w.trim()?f[u]=w:f.pop()}},o=new Set(["content","quotes","cue","cue-before","cue-after","src"]),p=new Set(["width","height","top","left","right","bottom","margin","margin-top","margin-right","margin-bottom","margin-left","padding","padding-top","padding-right","padding-bottom","padding-left","font-size","border-width","border-radius","gap","column-gap","row-gap","min-width","min-height","max-width","max-height"]),g=["@keyframes","@-webkit-keyframes","@font-face","@counter-style"],h=f=>g.some(u=>f.startsWith(u)),d=(f,u)=>{if(!p.has(f))return u;if(typeof u=="number")return`${u}px`;if(typeof u=="string"){let x=u.trim();return/^-?\d+(\.\d+)?$/.test(x)?`${x}px`:x}return u},l=f=>{let u=f.indexOf(":");if(u===-1)return f;let x=f.slice(0,u).trim(),b=f.slice(u+1).trim(),w=a(x);b.endsWith(",")&&(b=b.slice(0,-1).trim()),o.has(w)||(b.startsWith('"')&&b.endsWith('"')||b.startsWith("'")&&b.endsWith("'"))&&(b=b.slice(1,-1)),b=d(w,b);let E=`${w}: ${b}`;return E.endsWith(";")||(E+=";"),E},m=f=>{let u=[],x=f;for(let b in x){let w=x[b];if(typeof w=="object"&&w!==null){u.push(`${b} {`);let E=m(w);u.push(...E),u.push("}")}else{let E=typeof w=="string"?w:String(w);u.push(`${b}: ${E},`)}}return u},C=typeof t=="string"?t.trim().split(`
4
4
  `).map(f=>f.trim()).filter(Boolean):m(t),D=[],O=[],M=[],y=null,T=!1,A=[],S=null,L=!1,v=[],R=0;for(let f of C){if(L){if(v.push(f),R+=(f.match(/{/g)||[]).length,R-=(f.match(/}/g)||[]).length,R===0){if(i(v),S&&h(S)){let u=v.map(x=>l(x)).join(`