@honuware/ui 0.1.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.
@@ -0,0 +1,745 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, inject, Component } from '@angular/core';
3
+ import * as i1 from '@angular/material/snack-bar';
4
+ import * as i1$1 from '@angular/material/dialog';
5
+ import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
6
+ import * as i2 from '@angular/material/button';
7
+ import { MatButtonModule } from '@angular/material/button';
8
+ import { trigger, state, style, transition, animate, keyframes } from '@angular/animations';
9
+
10
+ class ToastService {
11
+ snackBar;
12
+ defaultDuration = 5000;
13
+ constructor(snackBar) {
14
+ this.snackBar = snackBar;
15
+ }
16
+ /**
17
+ * Show a success toast notification
18
+ */
19
+ success(message, duration) {
20
+ this.show(message, 'success', duration);
21
+ }
22
+ /**
23
+ * Show an error toast notification
24
+ */
25
+ error(message, duration) {
26
+ this.show(message, 'error', duration);
27
+ }
28
+ /**
29
+ * Show a warning toast notification
30
+ */
31
+ warning(message, duration) {
32
+ this.show(message, 'warning', duration);
33
+ }
34
+ /**
35
+ * Show an info toast notification
36
+ */
37
+ info(message, duration) {
38
+ this.show(message, 'info', duration);
39
+ }
40
+ /**
41
+ * Show a toast notification with the specified type
42
+ */
43
+ show(message, type = 'info', duration) {
44
+ const config = {
45
+ duration: duration ?? this.defaultDuration,
46
+ horizontalPosition: 'center',
47
+ verticalPosition: 'bottom',
48
+ panelClass: [`toast-${type}`],
49
+ };
50
+ this.snackBar.open(message, 'Dismiss', config);
51
+ }
52
+ /**
53
+ * Dismiss any currently visible toast
54
+ */
55
+ dismiss() {
56
+ this.snackBar.dismiss();
57
+ }
58
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ToastService, deps: [{ token: i1.MatSnackBar }], target: i0.ɵɵFactoryTarget.Injectable });
59
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ToastService, providedIn: 'root' });
60
+ }
61
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ToastService, decorators: [{
62
+ type: Injectable,
63
+ args: [{
64
+ providedIn: 'root',
65
+ }]
66
+ }], ctorParameters: () => [{ type: i1.MatSnackBar }] });
67
+
68
+ class ConfirmDialogComponent {
69
+ dialogRef = inject((MatDialogRef));
70
+ data = inject(MAT_DIALOG_DATA);
71
+ clickConfirm() {
72
+ this.dialogRef.close(true);
73
+ }
74
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ConfirmDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
75
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.18", type: ConfirmDialogComponent, isStandalone: true, selector: "hw-confirm-dialog", ngImport: i0, template: "<h2 mat-dialog-title>{{data.title}}</h2>\n<mat-dialog-content>\n {{data.description}}\n</mat-dialog-content>\n<mat-dialog-actions>\n <button type=\"button\" mat-raised-button color=\"primary\" (click)=\"clickConfirm()\">\n {{data.buttonText ?? 'Confirm'}}\n </button>\n <button type=\"button\" mat-button mat-dialog-close>Cancel</button>\n</mat-dialog-actions>", dependencies: [{ kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1$1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i1$1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1$1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }] });
76
+ }
77
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ConfirmDialogComponent, decorators: [{
78
+ type: Component,
79
+ args: [{ selector: 'hw-confirm-dialog', imports: [MatDialogModule, MatButtonModule], template: "<h2 mat-dialog-title>{{data.title}}</h2>\n<mat-dialog-content>\n {{data.description}}\n</mat-dialog-content>\n<mat-dialog-actions>\n <button type=\"button\" mat-raised-button color=\"primary\" (click)=\"clickConfirm()\">\n {{data.buttonText ?? 'Confirm'}}\n </button>\n <button type=\"button\" mat-button mat-dialog-close>Cancel</button>\n</mat-dialog-actions>" }]
80
+ }] });
81
+
82
+ class FuseAnimationCurves {
83
+ static standard = 'cubic-bezier(0.4, 0.0, 0.2, 1)';
84
+ static deceleration = 'cubic-bezier(0.0, 0.0, 0.2, 1)';
85
+ static acceleration = 'cubic-bezier(0.4, 0.0, 1, 1)';
86
+ static sharp = 'cubic-bezier(0.4, 0.0, 0.6, 1)';
87
+ }
88
+ class FuseAnimationDurations {
89
+ static complex = '375ms';
90
+ static entering = '225ms';
91
+ static exiting = '195ms';
92
+ }
93
+
94
+ // -----------------------------------------------------------------------------------------------------
95
+ // @ Expand / collapse
96
+ // -----------------------------------------------------------------------------------------------------
97
+ const expandCollapse = trigger('expandCollapse', [
98
+ state('void, collapsed', style({
99
+ height: '0',
100
+ opacity: '0',
101
+ })),
102
+ state('*, expanded', style('*')),
103
+ // Prevent the transition if the state is false
104
+ transition('void <=> false, collapsed <=> false, expanded <=> false', []),
105
+ // Transition
106
+ transition('void <=> *, collapsed <=> expanded', animate('{{timings}}'), {
107
+ params: {
108
+ timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
109
+ },
110
+ }),
111
+ ]);
112
+
113
+ // -----------------------------------------------------------------------------------------------------
114
+ // @ Fade in
115
+ // -----------------------------------------------------------------------------------------------------
116
+ const fadeIn = trigger('fadeIn', [
117
+ state('void', style({
118
+ opacity: 0,
119
+ })),
120
+ state('*', style({
121
+ opacity: 1,
122
+ })),
123
+ // Prevent the transition if the state is false
124
+ transition('void => false', []),
125
+ // Transition
126
+ transition('void => *', animate('{{timings}}'), {
127
+ params: {
128
+ timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
129
+ },
130
+ }),
131
+ ]);
132
+ // -----------------------------------------------------------------------------------------------------
133
+ // @ Fade in top
134
+ // -----------------------------------------------------------------------------------------------------
135
+ const fadeInTop = trigger('fadeInTop', [
136
+ state('void', style({
137
+ opacity: 0,
138
+ transform: 'translate3d(0, -100%, 0)',
139
+ })),
140
+ state('*', style({
141
+ opacity: 1,
142
+ transform: 'translate3d(0, 0, 0)',
143
+ })),
144
+ // Prevent the transition if the state is false
145
+ transition('void => false', []),
146
+ // Transition
147
+ transition('void => *', animate('{{timings}}'), {
148
+ params: {
149
+ timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
150
+ },
151
+ }),
152
+ ]);
153
+ // -----------------------------------------------------------------------------------------------------
154
+ // @ Fade in bottom
155
+ // -----------------------------------------------------------------------------------------------------
156
+ const fadeInBottom = trigger('fadeInBottom', [
157
+ state('void', style({
158
+ opacity: 0,
159
+ transform: 'translate3d(0, 100%, 0)',
160
+ })),
161
+ state('*', style({
162
+ opacity: 1,
163
+ transform: 'translate3d(0, 0, 0)',
164
+ })),
165
+ // Prevent the transition if the state is false
166
+ transition('void => false', []),
167
+ // Transition
168
+ transition('void => *', animate('{{timings}}'), {
169
+ params: {
170
+ timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
171
+ },
172
+ }),
173
+ ]);
174
+ // -----------------------------------------------------------------------------------------------------
175
+ // @ Fade in left
176
+ // -----------------------------------------------------------------------------------------------------
177
+ const fadeInLeft = trigger('fadeInLeft', [
178
+ state('void', style({
179
+ opacity: 0,
180
+ transform: 'translate3d(-100%, 0, 0)',
181
+ })),
182
+ state('*', style({
183
+ opacity: 1,
184
+ transform: 'translate3d(0, 0, 0)',
185
+ })),
186
+ // Prevent the transition if the state is false
187
+ transition('void => false', []),
188
+ // Transition
189
+ transition('void => *', animate('{{timings}}'), {
190
+ params: {
191
+ timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
192
+ },
193
+ }),
194
+ ]);
195
+ // -----------------------------------------------------------------------------------------------------
196
+ // @ Fade in right
197
+ // -----------------------------------------------------------------------------------------------------
198
+ const fadeInRight = trigger('fadeInRight', [
199
+ state('void', style({
200
+ opacity: 0,
201
+ transform: 'translate3d(100%, 0, 0)',
202
+ })),
203
+ state('*', style({
204
+ opacity: 1,
205
+ transform: 'translate3d(0, 0, 0)',
206
+ })),
207
+ // Prevent the transition if the state is false
208
+ transition('void => false', []),
209
+ // Transition
210
+ transition('void => *', animate('{{timings}}'), {
211
+ params: {
212
+ timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
213
+ },
214
+ }),
215
+ ]);
216
+ // -----------------------------------------------------------------------------------------------------
217
+ // @ Fade out
218
+ // -----------------------------------------------------------------------------------------------------
219
+ const fadeOut = trigger('fadeOut', [
220
+ state('*', style({
221
+ opacity: 1,
222
+ })),
223
+ state('void', style({
224
+ opacity: 0,
225
+ })),
226
+ // Prevent the transition if the state is false
227
+ transition('false => void', []),
228
+ // Transition
229
+ transition('* => void', animate('{{timings}}'), {
230
+ params: {
231
+ timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
232
+ },
233
+ }),
234
+ ]);
235
+ // -----------------------------------------------------------------------------------------------------
236
+ // @ Fade out top
237
+ // -----------------------------------------------------------------------------------------------------
238
+ const fadeOutTop = trigger('fadeOutTop', [
239
+ state('*', style({
240
+ opacity: 1,
241
+ transform: 'translate3d(0, 0, 0)',
242
+ })),
243
+ state('void', style({
244
+ opacity: 0,
245
+ transform: 'translate3d(0, -100%, 0)',
246
+ })),
247
+ // Prevent the transition if the state is false
248
+ transition('false => void', []),
249
+ // Transition
250
+ transition('* => void', animate('{{timings}}'), {
251
+ params: {
252
+ timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
253
+ },
254
+ }),
255
+ ]);
256
+ // -----------------------------------------------------------------------------------------------------
257
+ // @ Fade out bottom
258
+ // -----------------------------------------------------------------------------------------------------
259
+ const fadeOutBottom = trigger('fadeOutBottom', [
260
+ state('*', style({
261
+ opacity: 1,
262
+ transform: 'translate3d(0, 0, 0)',
263
+ })),
264
+ state('void', style({
265
+ opacity: 0,
266
+ transform: 'translate3d(0, 100%, 0)',
267
+ })),
268
+ // Prevent the transition if the state is false
269
+ transition('false => void', []),
270
+ // Transition
271
+ transition('* => void', animate('{{timings}}'), {
272
+ params: {
273
+ timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
274
+ },
275
+ }),
276
+ ]);
277
+ // -----------------------------------------------------------------------------------------------------
278
+ // @ Fade out left
279
+ // -----------------------------------------------------------------------------------------------------
280
+ const fadeOutLeft = trigger('fadeOutLeft', [
281
+ state('*', style({
282
+ opacity: 1,
283
+ transform: 'translate3d(0, 0, 0)',
284
+ })),
285
+ state('void', style({
286
+ opacity: 0,
287
+ transform: 'translate3d(-100%, 0, 0)',
288
+ })),
289
+ // Prevent the transition if the state is false
290
+ transition('false => void', []),
291
+ // Transition
292
+ transition('* => void', animate('{{timings}}'), {
293
+ params: {
294
+ timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
295
+ },
296
+ }),
297
+ ]);
298
+ // -----------------------------------------------------------------------------------------------------
299
+ // @ Fade out right
300
+ // -----------------------------------------------------------------------------------------------------
301
+ const fadeOutRight = trigger('fadeOutRight', [
302
+ state('*', style({
303
+ opacity: 1,
304
+ transform: 'translate3d(0, 0, 0)',
305
+ })),
306
+ state('void', style({
307
+ opacity: 0,
308
+ transform: 'translate3d(100%, 0, 0)',
309
+ })),
310
+ // Prevent the transition if the state is false
311
+ transition('false => void', []),
312
+ // Transition
313
+ transition('* => void', animate('{{timings}}'), {
314
+ params: {
315
+ timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
316
+ },
317
+ }),
318
+ ]);
319
+
320
+ // -----------------------------------------------------------------------------------------------------
321
+ // @ Shake
322
+ // -----------------------------------------------------------------------------------------------------
323
+ const shake = trigger('shake', [
324
+ // Prevent the transition if the state is false
325
+ transition('void => false', []),
326
+ // Transition
327
+ transition('void => *, * => true', [
328
+ animate('{{timings}}', keyframes([
329
+ style({
330
+ transform: 'translate3d(0, 0, 0)',
331
+ offset: 0,
332
+ }),
333
+ style({
334
+ transform: 'translate3d(-10px, 0, 0)',
335
+ offset: 0.1,
336
+ }),
337
+ style({
338
+ transform: 'translate3d(10px, 0, 0)',
339
+ offset: 0.2,
340
+ }),
341
+ style({
342
+ transform: 'translate3d(-10px, 0, 0)',
343
+ offset: 0.3,
344
+ }),
345
+ style({
346
+ transform: 'translate3d(10px, 0, 0)',
347
+ offset: 0.4,
348
+ }),
349
+ style({
350
+ transform: 'translate3d(-10px, 0, 0)',
351
+ offset: 0.5,
352
+ }),
353
+ style({
354
+ transform: 'translate3d(10px, 0, 0)',
355
+ offset: 0.6,
356
+ }),
357
+ style({
358
+ transform: 'translate3d(-10px, 0, 0)',
359
+ offset: 0.7,
360
+ }),
361
+ style({
362
+ transform: 'translate3d(10px, 0, 0)',
363
+ offset: 0.8,
364
+ }),
365
+ style({
366
+ transform: 'translate3d(-10px, 0, 0)',
367
+ offset: 0.9,
368
+ }),
369
+ style({
370
+ transform: 'translate3d(0, 0, 0)',
371
+ offset: 1,
372
+ }),
373
+ ])),
374
+ ], {
375
+ params: {
376
+ timings: '0.8s cubic-bezier(0.455, 0.03, 0.515, 0.955)',
377
+ },
378
+ }),
379
+ ]);
380
+
381
+ // -----------------------------------------------------------------------------------------------------
382
+ // @ Slide in top
383
+ // -----------------------------------------------------------------------------------------------------
384
+ const slideInTop = trigger('slideInTop', [
385
+ state('void', style({
386
+ transform: 'translate3d(0, -100%, 0)',
387
+ })),
388
+ state('*', style({
389
+ transform: 'translate3d(0, 0, 0)',
390
+ })),
391
+ // Prevent the transition if the state is false
392
+ transition('void => false', []),
393
+ // Transition
394
+ transition('void => *', animate('{{timings}}'), {
395
+ params: {
396
+ timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
397
+ },
398
+ }),
399
+ ]);
400
+ // -----------------------------------------------------------------------------------------------------
401
+ // @ Slide in bottom
402
+ // -----------------------------------------------------------------------------------------------------
403
+ const slideInBottom = trigger('slideInBottom', [
404
+ state('void', style({
405
+ transform: 'translate3d(0, 100%, 0)',
406
+ })),
407
+ state('*', style({
408
+ transform: 'translate3d(0, 0, 0)',
409
+ })),
410
+ // Prevent the transition if the state is false
411
+ transition('void => false', []),
412
+ // Transition
413
+ transition('void => *', animate('{{timings}}'), {
414
+ params: {
415
+ timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
416
+ },
417
+ }),
418
+ ]);
419
+ // -----------------------------------------------------------------------------------------------------
420
+ // @ Slide in left
421
+ // -----------------------------------------------------------------------------------------------------
422
+ const slideInLeft = trigger('slideInLeft', [
423
+ state('void', style({
424
+ transform: 'translate3d(-100%, 0, 0)',
425
+ })),
426
+ state('*', style({
427
+ transform: 'translate3d(0, 0, 0)',
428
+ })),
429
+ // Prevent the transition if the state is false
430
+ transition('void => false', []),
431
+ // Transition
432
+ transition('void => *', animate('{{timings}}'), {
433
+ params: {
434
+ timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
435
+ },
436
+ }),
437
+ ]);
438
+ // -----------------------------------------------------------------------------------------------------
439
+ // @ Slide in right
440
+ // -----------------------------------------------------------------------------------------------------
441
+ const slideInRight = trigger('slideInRight', [
442
+ state('void', style({
443
+ transform: 'translate3d(100%, 0, 0)',
444
+ })),
445
+ state('*', style({
446
+ transform: 'translate3d(0, 0, 0)',
447
+ })),
448
+ // Prevent the transition if the state is false
449
+ transition('void => false', []),
450
+ // Transition
451
+ transition('void => *', animate('{{timings}}'), {
452
+ params: {
453
+ timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
454
+ },
455
+ }),
456
+ ]);
457
+ // -----------------------------------------------------------------------------------------------------
458
+ // @ Slide out top
459
+ // -----------------------------------------------------------------------------------------------------
460
+ const slideOutTop = trigger('slideOutTop', [
461
+ state('*', style({
462
+ transform: 'translate3d(0, 0, 0)',
463
+ })),
464
+ state('void', style({
465
+ transform: 'translate3d(0, -100%, 0)',
466
+ })),
467
+ // Prevent the transition if the state is false
468
+ transition('false => void', []),
469
+ // Transition
470
+ transition('* => void', animate('{{timings}}'), {
471
+ params: {
472
+ timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
473
+ },
474
+ }),
475
+ ]);
476
+ // -----------------------------------------------------------------------------------------------------
477
+ // @ Slide out bottom
478
+ // -----------------------------------------------------------------------------------------------------
479
+ const slideOutBottom = trigger('slideOutBottom', [
480
+ state('*', style({
481
+ transform: 'translate3d(0, 0, 0)',
482
+ })),
483
+ state('void', style({
484
+ transform: 'translate3d(0, 100%, 0)',
485
+ })),
486
+ // Prevent the transition if the state is false
487
+ transition('false => void', []),
488
+ // Transition
489
+ transition('* => void', animate('{{timings}}'), {
490
+ params: {
491
+ timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
492
+ },
493
+ }),
494
+ ]);
495
+ // -----------------------------------------------------------------------------------------------------
496
+ // @ Slide out left
497
+ // -----------------------------------------------------------------------------------------------------
498
+ const slideOutLeft = trigger('slideOutLeft', [
499
+ state('*', style({
500
+ transform: 'translate3d(0, 0, 0)',
501
+ })),
502
+ state('void', style({
503
+ transform: 'translate3d(-100%, 0, 0)',
504
+ })),
505
+ // Prevent the transition if the state is false
506
+ transition('false => void', []),
507
+ // Transition
508
+ transition('* => void', animate('{{timings}}'), {
509
+ params: {
510
+ timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
511
+ },
512
+ }),
513
+ ]);
514
+ // -----------------------------------------------------------------------------------------------------
515
+ // @ Slide out right
516
+ // -----------------------------------------------------------------------------------------------------
517
+ const slideOutRight = trigger('slideOutRight', [
518
+ state('*', style({
519
+ transform: 'translate3d(0, 0, 0)',
520
+ })),
521
+ state('void', style({
522
+ transform: 'translate3d(100%, 0, 0)',
523
+ })),
524
+ // Prevent the transition if the state is false
525
+ transition('false => void', []),
526
+ // Transition
527
+ transition('* => void', animate('{{timings}}'), {
528
+ params: {
529
+ timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
530
+ },
531
+ }),
532
+ ]);
533
+
534
+ // -----------------------------------------------------------------------------------------------------
535
+ // @ Zoom in
536
+ // -----------------------------------------------------------------------------------------------------
537
+ const zoomIn = trigger('zoomIn', [
538
+ state('void', style({
539
+ opacity: 0,
540
+ transform: 'scale(0.5)',
541
+ })),
542
+ state('*', style({
543
+ opacity: 1,
544
+ transform: 'scale(1)',
545
+ })),
546
+ // Prevent the transition if the state is false
547
+ transition('void => false', []),
548
+ // Transition
549
+ transition('void => *', animate('{{timings}}'), {
550
+ params: {
551
+ timings: `${FuseAnimationDurations.entering} ${FuseAnimationCurves.deceleration}`,
552
+ },
553
+ }),
554
+ ]);
555
+ // -----------------------------------------------------------------------------------------------------
556
+ // @ Zoom out
557
+ // -----------------------------------------------------------------------------------------------------
558
+ const zoomOut = trigger('zoomOut', [
559
+ state('*', style({
560
+ opacity: 1,
561
+ transform: 'scale(1)',
562
+ })),
563
+ state('void', style({
564
+ opacity: 0,
565
+ transform: 'scale(0.5)',
566
+ })),
567
+ // Prevent the transition if the state is false
568
+ transition('false => void', []),
569
+ // Transition
570
+ transition('* => void', animate('{{timings}}'), {
571
+ params: {
572
+ timings: `${FuseAnimationDurations.exiting} ${FuseAnimationCurves.acceleration}`,
573
+ },
574
+ }),
575
+ ]);
576
+
577
+ const fuseAnimations = [
578
+ expandCollapse,
579
+ fadeIn, fadeInTop, fadeInBottom, fadeInLeft, fadeInRight,
580
+ fadeOut, fadeOutTop, fadeOutBottom, fadeOutLeft, fadeOutRight,
581
+ shake,
582
+ slideInTop, slideInBottom, slideInLeft, slideInRight,
583
+ slideOutTop, slideOutBottom, slideOutLeft, slideOutRight,
584
+ zoomIn, zoomOut,
585
+ ];
586
+
587
+ // Open-redirect defense for a post-login `returnUrl` query parameter. An
588
+ // unvalidated returnUrl lets an attacker craft a phishing flow like
589
+ // `/login?returnUrl=https://evil.example/` — the user logs in legitimately and
590
+ // then gets bounced to an attacker-controlled origin.
591
+ //
592
+ // Restricts returnUrl to same-origin paths under a known feature area. The
593
+ // allow-list is a REQUIRED parameter (foundation sits below auth, so it can't
594
+ // default to the auth-routes allow-list) — callers pass their own set of
595
+ // permitted path prefixes. Returns `/` for any input that's missing,
596
+ // non-string, or fails the same-origin + allow-list checks; the default-deny
597
+ // stance degrades safely to a home-page redirect.
598
+ function sanitizeReturnUrl(raw, allowlist) {
599
+ if (typeof raw !== 'string' || raw.length === 0)
600
+ return '/';
601
+ // Reject anything that escapes same-origin:
602
+ // - Protocol-relative URLs (`//evil.com/...`)
603
+ // - Backslash-prefixed variants (`/\evil.com` — some browsers
604
+ // normalize backslashes to forward slashes during navigation)
605
+ // - Anything that doesn't start with a single `/`
606
+ if (!raw.startsWith('/'))
607
+ return '/';
608
+ if (raw.startsWith('//'))
609
+ return '/';
610
+ if (raw.startsWith('/\\'))
611
+ return '/';
612
+ // Allow the exact root path.
613
+ if (raw === '/')
614
+ return '/';
615
+ // Otherwise require a known prefix followed by either end-of-string
616
+ // or another `/` (so `/admin` matches `/admin` and `/admin/users`,
617
+ // but NOT a hypothetical `/administer-evil` route).
618
+ for (const prefix of allowlist) {
619
+ if (raw === prefix || raw.startsWith(prefix + '/')) {
620
+ return raw;
621
+ }
622
+ }
623
+ return '/';
624
+ }
625
+
626
+ function isMicrosecondTimestamp(value) {
627
+ return /^\d{11,}$/.test(value);
628
+ }
629
+ function microsToDate(value) {
630
+ return new Date(Number(value) / 1000);
631
+ }
632
+ function dateToMicros(date) {
633
+ return String(date.getTime() * 1000);
634
+ }
635
+ const ONE_DAY_US = 86400000000;
636
+ /**
637
+ * Format a microsecond timestamp as a UTC calendar date.
638
+ * Use for dates that represent calendar days stored as UTC midnight
639
+ * (e.g., period_start_us, valid_from_us, next_billing_us).
640
+ */
641
+ function formatCalendarDate(value, long = false) {
642
+ const us = typeof value === 'string' ? Number(value) : value;
643
+ if (!us || isNaN(us))
644
+ return '';
645
+ return new Intl.DateTimeFormat('en-US', {
646
+ month: long ? 'long' : 'short', day: 'numeric', year: 'numeric', timeZone: 'UTC',
647
+ }).format(new Date(us / 1000));
648
+ }
649
+ /**
650
+ * Format an exclusive-end microsecond timestamp as an inclusive UTC date.
651
+ * Subtracts 1 day to convert from "first moment of next period" to "last day of period".
652
+ * Use for period_end_us, valid_to_us where the stored value is the start of the next period.
653
+ */
654
+ function formatPeriodEndDate(value, long = false) {
655
+ const us = typeof value === 'string' ? Number(value) : value;
656
+ if (!us || isNaN(us))
657
+ return '';
658
+ return formatCalendarDate(us - ONE_DAY_US, long);
659
+ }
660
+ /** Get the UTC year from a microsecond timestamp string. */
661
+ function getUtcYear(value) {
662
+ return new Date(Number(value) / 1000).getUTCFullYear();
663
+ }
664
+ /** Get the UTC month (0-indexed) from a microsecond timestamp string. */
665
+ function getUtcMonth(value) {
666
+ return new Date(Number(value) / 1000).getUTCMonth();
667
+ }
668
+ // ---------------------------------------------------------------------------
669
+ // Local calendar-date arithmetic (used by the calendar views). These operate
670
+ // on local-time Date objects and never mutate their inputs.
671
+ // ---------------------------------------------------------------------------
672
+ function areSameDates(date1, date2) {
673
+ return (date1.getFullYear() === date2.getFullYear() &&
674
+ date1.getMonth() === date2.getMonth() &&
675
+ date1.getDate() === date2.getDate());
676
+ }
677
+ /** The Sunday starting the week containing `date` (local time). */
678
+ function firstDayOfWeek(date) {
679
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate() - date.getDay());
680
+ }
681
+ /** The Saturday ending the week containing `date` (local time). */
682
+ function lastDayOfWeek(date) {
683
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate() - date.getDay() + 6);
684
+ }
685
+ function firstDayOfMonth(date) {
686
+ return new Date(date.getFullYear(), date.getMonth(), 1);
687
+ }
688
+ /** Expects the first day of a month; returns that month's last day. */
689
+ function lastDayOfMonth(date) {
690
+ return addDaysToDate(addMonthsToDate(date, 1), -1);
691
+ }
692
+ function addDaysToDate(date, days) {
693
+ const dateValue = new Date(date.valueOf());
694
+ return new Date(dateValue.setDate(dateValue.getDate() + days));
695
+ }
696
+ function addWeeksToDate(date, weeks) {
697
+ return addDaysToDate(date, weeks * 7);
698
+ }
699
+ function addMonthsToDate(date, months) {
700
+ const dateValue = new Date(date.valueOf());
701
+ return new Date(dateValue.setMonth(dateValue.getMonth() + months));
702
+ }
703
+ function formatMicroseconds(value) {
704
+ if (!value || !isMicrosecondTimestamp(value)) {
705
+ return value;
706
+ }
707
+ const date = microsToDate(value);
708
+ if (isNaN(date.getTime())) {
709
+ return value;
710
+ }
711
+ const now = Date.now();
712
+ const diffMs = now - date.getTime();
713
+ if (diffMs < 60 * 1000) {
714
+ return 'just now';
715
+ }
716
+ if (diffMs < 60 * 60 * 1000) {
717
+ const minutes = Math.floor(diffMs / (60 * 1000));
718
+ return minutes === 1 ? '1 minute ago' : `${minutes} minutes ago`;
719
+ }
720
+ if (diffMs < 24 * 60 * 60 * 1000) {
721
+ const hours = Math.floor(diffMs / (60 * 60 * 1000));
722
+ return hours === 1 ? '1 hour ago' : `${hours} hours ago`;
723
+ }
724
+ return new Intl.DateTimeFormat('en-US', {
725
+ month: 'short',
726
+ day: 'numeric',
727
+ year: 'numeric',
728
+ hour: 'numeric',
729
+ minute: '2-digit',
730
+ hour12: true
731
+ }).format(date);
732
+ }
733
+
734
+ /*
735
+ * @honuware/ui/foundation — the bottom layer (no internal dependencies).
736
+ * Toast, ConfirmDialog, fuse animations, microsecond date utilities, and the
737
+ * open-redirect returnUrl sanitizer.
738
+ */
739
+
740
+ /**
741
+ * Generated bundle index. Do not edit.
742
+ */
743
+
744
+ export { ConfirmDialogComponent, ToastService, addDaysToDate, addMonthsToDate, addWeeksToDate, areSameDates, dateToMicros, firstDayOfMonth, firstDayOfWeek, formatCalendarDate, formatMicroseconds, formatPeriodEndDate, fuseAnimations, getUtcMonth, getUtcYear, isMicrosecondTimestamp, lastDayOfMonth, lastDayOfWeek, microsToDate, sanitizeReturnUrl };
745
+ //# sourceMappingURL=honuware-ui-foundation.mjs.map