@sonny-ui/core 0.1.0-alpha.13 → 0.1.0-alpha.15
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/fesm2022/sonny-ui-core.mjs +2239 -632
- package/fesm2022/sonny-ui-core.mjs.map +1 -1
- package/package.json +1 -1
- package/src/lib/calendar/calendar.component.spec.ts +87 -0
- package/src/lib/calendar/calendar.component.ts +184 -61
- package/src/lib/calendar/calendar.types.ts +24 -0
- package/src/lib/calendar/index.ts +6 -0
- package/src/lib/data-table/data-table.component.spec.ts +443 -0
- package/src/lib/data-table/data-table.component.ts +603 -0
- package/src/lib/data-table/data-table.directives.ts +35 -0
- package/src/lib/data-table/data-table.types.ts +20 -0
- package/src/lib/data-table/index.ts +13 -0
- package/src/lib/date-picker/date-picker.component.spec.ts +131 -0
- package/src/lib/date-picker/date-picker.component.ts +220 -0
- package/src/lib/date-picker/date-picker.variants.ts +17 -0
- package/src/lib/date-picker/index.ts +2 -0
- package/src/lib/date-range-picker/date-range-picker.component.spec.ts +151 -0
- package/src/lib/date-range-picker/date-range-picker.component.ts +340 -0
- package/src/lib/date-range-picker/index.ts +1 -0
- package/types/sonny-ui-core.d.ts +234 -7
|
@@ -3,8 +3,8 @@ import { twMerge } from 'tailwind-merge';
|
|
|
3
3
|
import { cva } from 'class-variance-authority';
|
|
4
4
|
export { cva } from 'class-variance-authority';
|
|
5
5
|
import * as i0 from '@angular/core';
|
|
6
|
-
import { inject, PLATFORM_ID, signal, computed, Injectable, InjectionToken, makeEnvironmentProviders, provideEnvironmentInitializer, input, Directive, ChangeDetectionStrategy, Component, ElementRef, model, viewChild, forwardRef, HostListener,
|
|
7
|
-
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
|
|
6
|
+
import { inject, PLATFORM_ID, signal, computed, Injectable, InjectionToken, makeEnvironmentProviders, provideEnvironmentInitializer, input, Directive, ChangeDetectionStrategy, Component, ElementRef, model, viewChild, forwardRef, HostListener, TemplateRef, output, contentChildren, contentChild, effect, untracked, Injector, afterNextRender, Renderer2, linkedSignal } from '@angular/core';
|
|
7
|
+
import { DOCUMENT, isPlatformBrowser, NgTemplateOutlet } from '@angular/common';
|
|
8
8
|
import { Dialog, DialogRef } from '@angular/cdk/dialog';
|
|
9
9
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
10
10
|
import { createGlobalPositionStrategy } from '@angular/cdk/overlay';
|
|
@@ -2417,6 +2417,1146 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
2417
2417
|
}]
|
|
2418
2418
|
}], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
2419
2419
|
|
|
2420
|
+
const paginationItemVariants = cva('inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50', {
|
|
2421
|
+
variants: {
|
|
2422
|
+
variant: {
|
|
2423
|
+
default: 'bg-background hover:bg-accent hover:text-accent-foreground',
|
|
2424
|
+
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
|
|
2425
|
+
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
|
2426
|
+
},
|
|
2427
|
+
size: {
|
|
2428
|
+
sm: 'h-8 w-8 text-xs',
|
|
2429
|
+
md: 'h-9 w-9',
|
|
2430
|
+
lg: 'h-10 w-10',
|
|
2431
|
+
},
|
|
2432
|
+
active: {
|
|
2433
|
+
true: 'bg-primary text-primary-foreground hover:bg-primary/90 hover:text-primary-foreground',
|
|
2434
|
+
false: '',
|
|
2435
|
+
},
|
|
2436
|
+
},
|
|
2437
|
+
defaultVariants: {
|
|
2438
|
+
variant: 'default',
|
|
2439
|
+
size: 'md',
|
|
2440
|
+
active: false,
|
|
2441
|
+
},
|
|
2442
|
+
});
|
|
2443
|
+
|
|
2444
|
+
function computePageRange(totalPages, currentPage, siblingCount, boundaryCount) {
|
|
2445
|
+
const range = (start, end) => Array.from({ length: end - start + 1 }, (_, i) => start + i);
|
|
2446
|
+
const startPages = range(1, Math.min(boundaryCount, totalPages));
|
|
2447
|
+
const endPages = range(Math.max(totalPages - boundaryCount + 1, boundaryCount + 1), totalPages);
|
|
2448
|
+
const siblingsStart = Math.max(Math.min(currentPage - siblingCount, totalPages - boundaryCount - siblingCount * 2 - 1), boundaryCount + 2);
|
|
2449
|
+
const siblingsEnd = Math.min(Math.max(currentPage + siblingCount, boundaryCount + siblingCount * 2 + 2), endPages.length > 0 ? endPages[0] - 2 : totalPages - 1);
|
|
2450
|
+
const result = [...startPages];
|
|
2451
|
+
if (siblingsStart > boundaryCount + 2) {
|
|
2452
|
+
result.push('ellipsis');
|
|
2453
|
+
}
|
|
2454
|
+
else if (boundaryCount + 1 < totalPages - boundaryCount) {
|
|
2455
|
+
result.push(boundaryCount + 1);
|
|
2456
|
+
}
|
|
2457
|
+
result.push(...range(siblingsStart, siblingsEnd));
|
|
2458
|
+
if (siblingsEnd < totalPages - boundaryCount - 1) {
|
|
2459
|
+
result.push('ellipsis');
|
|
2460
|
+
}
|
|
2461
|
+
else if (totalPages - boundaryCount > boundaryCount) {
|
|
2462
|
+
result.push(totalPages - boundaryCount);
|
|
2463
|
+
}
|
|
2464
|
+
result.push(...endPages);
|
|
2465
|
+
return [...new Set(result)].sort((a, b) => {
|
|
2466
|
+
if (a === 'ellipsis')
|
|
2467
|
+
return 0;
|
|
2468
|
+
if (b === 'ellipsis')
|
|
2469
|
+
return 0;
|
|
2470
|
+
return a - b;
|
|
2471
|
+
});
|
|
2472
|
+
}
|
|
2473
|
+
class SnyPaginationComponent {
|
|
2474
|
+
currentPage = model(1, ...(ngDevMode ? [{ debugName: "currentPage" }] : /* istanbul ignore next */ []));
|
|
2475
|
+
totalPages = input.required(...(ngDevMode ? [{ debugName: "totalPages" }] : /* istanbul ignore next */ []));
|
|
2476
|
+
siblingCount = input(1, ...(ngDevMode ? [{ debugName: "siblingCount" }] : /* istanbul ignore next */ []));
|
|
2477
|
+
boundaryCount = input(1, ...(ngDevMode ? [{ debugName: "boundaryCount" }] : /* istanbul ignore next */ []));
|
|
2478
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
2479
|
+
variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
2480
|
+
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
2481
|
+
pages = computed(() => computePageRange(this.totalPages(), this.currentPage(), this.siblingCount(), this.boundaryCount()), ...(ngDevMode ? [{ debugName: "pages" }] : /* istanbul ignore next */ []));
|
|
2482
|
+
hasPrev = computed(() => this.currentPage() > 1, ...(ngDevMode ? [{ debugName: "hasPrev" }] : /* istanbul ignore next */ []));
|
|
2483
|
+
hasNext = computed(() => this.currentPage() < this.totalPages(), ...(ngDevMode ? [{ debugName: "hasNext" }] : /* istanbul ignore next */ []));
|
|
2484
|
+
goToPage(page) {
|
|
2485
|
+
if (page === 'ellipsis')
|
|
2486
|
+
return;
|
|
2487
|
+
this.currentPage.set(page);
|
|
2488
|
+
}
|
|
2489
|
+
prev() {
|
|
2490
|
+
if (this.hasPrev())
|
|
2491
|
+
this.currentPage.update((p) => p - 1);
|
|
2492
|
+
}
|
|
2493
|
+
next() {
|
|
2494
|
+
if (this.hasNext())
|
|
2495
|
+
this.currentPage.update((p) => p + 1);
|
|
2496
|
+
}
|
|
2497
|
+
pageClass(page) {
|
|
2498
|
+
return cn(paginationItemVariants({
|
|
2499
|
+
variant: this.variant(),
|
|
2500
|
+
size: this.size(),
|
|
2501
|
+
active: page === this.currentPage(),
|
|
2502
|
+
}));
|
|
2503
|
+
}
|
|
2504
|
+
navBtnClass() {
|
|
2505
|
+
return cn(paginationItemVariants({ variant: this.variant(), size: this.size(), active: false }));
|
|
2506
|
+
}
|
|
2507
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyPaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2508
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: SnyPaginationComponent, isStandalone: true, selector: "sny-pagination", inputs: { currentPage: { classPropertyName: "currentPage", publicName: "currentPage", isSignal: true, isRequired: false, transformFunction: null }, totalPages: { classPropertyName: "totalPages", publicName: "totalPages", isSignal: true, isRequired: true, transformFunction: null }, siblingCount: { classPropertyName: "siblingCount", publicName: "siblingCount", isSignal: true, isRequired: false, transformFunction: null }, boundaryCount: { classPropertyName: "boundaryCount", publicName: "boundaryCount", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { currentPage: "currentPageChange" }, host: { attributes: { "role": "navigation", "aria-label": "Pagination" } }, ngImport: i0, template: `
|
|
2509
|
+
<div class="flex items-center gap-1">
|
|
2510
|
+
<button
|
|
2511
|
+
[class]="navBtnClass()"
|
|
2512
|
+
[disabled]="!hasPrev()"
|
|
2513
|
+
[attr.aria-label]="'Go to previous page'"
|
|
2514
|
+
(click)="prev()"
|
|
2515
|
+
>
|
|
2516
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
|
|
2517
|
+
</button>
|
|
2518
|
+
|
|
2519
|
+
@for (page of pages(); track $index) {
|
|
2520
|
+
@if (page === 'ellipsis') {
|
|
2521
|
+
<span class="flex h-9 w-9 items-center justify-center" aria-hidden="true">...</span>
|
|
2522
|
+
} @else {
|
|
2523
|
+
<button
|
|
2524
|
+
[class]="pageClass(page)"
|
|
2525
|
+
[attr.aria-label]="'Page ' + page"
|
|
2526
|
+
[attr.aria-current]="page === currentPage() ? 'page' : null"
|
|
2527
|
+
(click)="goToPage(page)"
|
|
2528
|
+
>
|
|
2529
|
+
{{ page }}
|
|
2530
|
+
</button>
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
|
|
2534
|
+
<button
|
|
2535
|
+
[class]="navBtnClass()"
|
|
2536
|
+
[disabled]="!hasNext()"
|
|
2537
|
+
[attr.aria-label]="'Go to next page'"
|
|
2538
|
+
(click)="next()"
|
|
2539
|
+
>
|
|
2540
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
|
|
2541
|
+
</button>
|
|
2542
|
+
</div>
|
|
2543
|
+
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2544
|
+
}
|
|
2545
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyPaginationComponent, decorators: [{
|
|
2546
|
+
type: Component,
|
|
2547
|
+
args: [{
|
|
2548
|
+
selector: 'sny-pagination',
|
|
2549
|
+
standalone: true,
|
|
2550
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
2551
|
+
host: {
|
|
2552
|
+
'role': 'navigation',
|
|
2553
|
+
'aria-label': 'Pagination',
|
|
2554
|
+
},
|
|
2555
|
+
template: `
|
|
2556
|
+
<div class="flex items-center gap-1">
|
|
2557
|
+
<button
|
|
2558
|
+
[class]="navBtnClass()"
|
|
2559
|
+
[disabled]="!hasPrev()"
|
|
2560
|
+
[attr.aria-label]="'Go to previous page'"
|
|
2561
|
+
(click)="prev()"
|
|
2562
|
+
>
|
|
2563
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
|
|
2564
|
+
</button>
|
|
2565
|
+
|
|
2566
|
+
@for (page of pages(); track $index) {
|
|
2567
|
+
@if (page === 'ellipsis') {
|
|
2568
|
+
<span class="flex h-9 w-9 items-center justify-center" aria-hidden="true">...</span>
|
|
2569
|
+
} @else {
|
|
2570
|
+
<button
|
|
2571
|
+
[class]="pageClass(page)"
|
|
2572
|
+
[attr.aria-label]="'Page ' + page"
|
|
2573
|
+
[attr.aria-current]="page === currentPage() ? 'page' : null"
|
|
2574
|
+
(click)="goToPage(page)"
|
|
2575
|
+
>
|
|
2576
|
+
{{ page }}
|
|
2577
|
+
</button>
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
|
|
2581
|
+
<button
|
|
2582
|
+
[class]="navBtnClass()"
|
|
2583
|
+
[disabled]="!hasNext()"
|
|
2584
|
+
[attr.aria-label]="'Go to next page'"
|
|
2585
|
+
(click)="next()"
|
|
2586
|
+
>
|
|
2587
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
|
|
2588
|
+
</button>
|
|
2589
|
+
</div>
|
|
2590
|
+
`,
|
|
2591
|
+
}]
|
|
2592
|
+
}], propDecorators: { currentPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentPage", required: false }] }, { type: i0.Output, args: ["currentPageChange"] }], totalPages: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalPages", required: true }] }], siblingCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "siblingCount", required: false }] }], boundaryCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "boundaryCount", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
2593
|
+
|
|
2594
|
+
const dropdownContentVariants = cva('z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md', {
|
|
2595
|
+
variants: {},
|
|
2596
|
+
defaultVariants: {},
|
|
2597
|
+
});
|
|
2598
|
+
const dropdownItemVariants = cva('relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[active]:bg-accent data-[active]:text-accent-foreground', {
|
|
2599
|
+
variants: {
|
|
2600
|
+
variant: {
|
|
2601
|
+
default: '',
|
|
2602
|
+
destructive: 'text-destructive data-[active]:bg-destructive/10 data-[active]:text-destructive',
|
|
2603
|
+
},
|
|
2604
|
+
},
|
|
2605
|
+
defaultVariants: {
|
|
2606
|
+
variant: 'default',
|
|
2607
|
+
},
|
|
2608
|
+
});
|
|
2609
|
+
|
|
2610
|
+
const SNY_DROPDOWN = new InjectionToken('SnyDropdown');
|
|
2611
|
+
class SnyDropdownDirective {
|
|
2612
|
+
elementRef = inject(ElementRef);
|
|
2613
|
+
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
|
|
2614
|
+
toggle() { this.isOpen.update((v) => !v); }
|
|
2615
|
+
open() { this.isOpen.set(true); }
|
|
2616
|
+
close() { this.isOpen.set(false); }
|
|
2617
|
+
onDocumentClick(event) {
|
|
2618
|
+
if (!this.elementRef.nativeElement.contains(event.target)) {
|
|
2619
|
+
this.close();
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
onEscape() {
|
|
2623
|
+
this.close();
|
|
2624
|
+
}
|
|
2625
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDropdownDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2626
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.5", type: SnyDropdownDirective, isStandalone: true, selector: "[snyDropdown]", host: { listeners: { "document:click": "onDocumentClick($event)", "keydown.escape": "onEscape()" }, properties: { "class": "\"relative inline-block\"" } }, providers: [{ provide: SNY_DROPDOWN, useExisting: SnyDropdownDirective }], exportAs: ["snyDropdown"], ngImport: i0 });
|
|
2627
|
+
}
|
|
2628
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDropdownDirective, decorators: [{
|
|
2629
|
+
type: Directive,
|
|
2630
|
+
args: [{
|
|
2631
|
+
selector: '[snyDropdown]',
|
|
2632
|
+
standalone: true,
|
|
2633
|
+
exportAs: 'snyDropdown',
|
|
2634
|
+
providers: [{ provide: SNY_DROPDOWN, useExisting: SnyDropdownDirective }],
|
|
2635
|
+
host: {
|
|
2636
|
+
'[class]': '"relative inline-block"',
|
|
2637
|
+
},
|
|
2638
|
+
}]
|
|
2639
|
+
}], propDecorators: { onDocumentClick: [{
|
|
2640
|
+
type: HostListener,
|
|
2641
|
+
args: ['document:click', ['$event']]
|
|
2642
|
+
}], onEscape: [{
|
|
2643
|
+
type: HostListener,
|
|
2644
|
+
args: ['keydown.escape']
|
|
2645
|
+
}] } });
|
|
2646
|
+
class SnyDropdownTriggerDirective {
|
|
2647
|
+
dropdown = inject(SNY_DROPDOWN);
|
|
2648
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDropdownTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2649
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.5", type: SnyDropdownTriggerDirective, isStandalone: true, selector: "[snyDropdownTrigger]", host: { listeners: { "click": "dropdown.toggle()" }, properties: { "attr.aria-expanded": "dropdown.isOpen()", "attr.aria-haspopup": "\"menu\"" } }, ngImport: i0 });
|
|
2650
|
+
}
|
|
2651
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDropdownTriggerDirective, decorators: [{
|
|
2652
|
+
type: Directive,
|
|
2653
|
+
args: [{
|
|
2654
|
+
selector: '[snyDropdownTrigger]',
|
|
2655
|
+
standalone: true,
|
|
2656
|
+
host: {
|
|
2657
|
+
'(click)': 'dropdown.toggle()',
|
|
2658
|
+
'[attr.aria-expanded]': 'dropdown.isOpen()',
|
|
2659
|
+
'[attr.aria-haspopup]': '"menu"',
|
|
2660
|
+
},
|
|
2661
|
+
}]
|
|
2662
|
+
}] });
|
|
2663
|
+
class SnyDropdownContentDirective {
|
|
2664
|
+
dropdown = inject(SNY_DROPDOWN);
|
|
2665
|
+
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
2666
|
+
computedClass = computed(() => cn(dropdownContentVariants(), 'absolute mt-1 left-0 animate-in fade-in-0 zoom-in-95', this.class()), ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
2667
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDropdownContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2668
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: SnyDropdownContentDirective, isStandalone: true, selector: "[snyDropdownContent]", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "menu" }, properties: { "class": "computedClass()", "style.display": "dropdown.isOpen() ? \"\" : \"none\"" } }, ngImport: i0 });
|
|
2669
|
+
}
|
|
2670
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDropdownContentDirective, decorators: [{
|
|
2671
|
+
type: Directive,
|
|
2672
|
+
args: [{
|
|
2673
|
+
selector: '[snyDropdownContent]',
|
|
2674
|
+
standalone: true,
|
|
2675
|
+
host: {
|
|
2676
|
+
'role': 'menu',
|
|
2677
|
+
'[class]': 'computedClass()',
|
|
2678
|
+
'[style.display]': 'dropdown.isOpen() ? "" : "none"',
|
|
2679
|
+
},
|
|
2680
|
+
}]
|
|
2681
|
+
}], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
2682
|
+
class SnyMenuContentDirective {
|
|
2683
|
+
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
2684
|
+
computedClass = computed(() => cn(dropdownContentVariants(), this.class()), ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
2685
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyMenuContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2686
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: SnyMenuContentDirective, isStandalone: true, selector: "[snyMenuContent]", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "computedClass()" } }, ngImport: i0 });
|
|
2687
|
+
}
|
|
2688
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyMenuContentDirective, decorators: [{
|
|
2689
|
+
type: Directive,
|
|
2690
|
+
args: [{
|
|
2691
|
+
selector: '[snyMenuContent]',
|
|
2692
|
+
standalone: true,
|
|
2693
|
+
host: {
|
|
2694
|
+
'[class]': 'computedClass()',
|
|
2695
|
+
},
|
|
2696
|
+
}]
|
|
2697
|
+
}], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
2698
|
+
class SnyMenuItemDirective {
|
|
2699
|
+
dropdown = inject(SNY_DROPDOWN, { optional: true });
|
|
2700
|
+
variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
2701
|
+
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
2702
|
+
computedClass = computed(() => cn(dropdownItemVariants({ variant: this.variant() }), 'cursor-pointer hover:bg-accent hover:text-accent-foreground', this.class()), ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
2703
|
+
onClick() {
|
|
2704
|
+
this.dropdown?.close();
|
|
2705
|
+
}
|
|
2706
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyMenuItemDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2707
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: SnyMenuItemDirective, isStandalone: true, selector: "[snyMenuItem]", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "menuitem" }, listeners: { "click": "onClick()" }, properties: { "class": "computedClass()" } }, ngImport: i0 });
|
|
2708
|
+
}
|
|
2709
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyMenuItemDirective, decorators: [{
|
|
2710
|
+
type: Directive,
|
|
2711
|
+
args: [{
|
|
2712
|
+
selector: '[snyMenuItem]',
|
|
2713
|
+
standalone: true,
|
|
2714
|
+
host: {
|
|
2715
|
+
'role': 'menuitem',
|
|
2716
|
+
'[class]': 'computedClass()',
|
|
2717
|
+
'(click)': 'onClick()',
|
|
2718
|
+
},
|
|
2719
|
+
}]
|
|
2720
|
+
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
2721
|
+
class SnyMenuSeparatorDirective {
|
|
2722
|
+
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
2723
|
+
computedClass = computed(() => cn('-mx-1 my-1 h-px bg-muted', this.class()), ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
2724
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyMenuSeparatorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2725
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: SnyMenuSeparatorDirective, isStandalone: true, selector: "[snyMenuSeparator]", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "separator" }, properties: { "class": "computedClass()" } }, ngImport: i0 });
|
|
2726
|
+
}
|
|
2727
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyMenuSeparatorDirective, decorators: [{
|
|
2728
|
+
type: Directive,
|
|
2729
|
+
args: [{
|
|
2730
|
+
selector: '[snyMenuSeparator]',
|
|
2731
|
+
standalone: true,
|
|
2732
|
+
host: {
|
|
2733
|
+
'role': 'separator',
|
|
2734
|
+
'[class]': 'computedClass()',
|
|
2735
|
+
},
|
|
2736
|
+
}]
|
|
2737
|
+
}], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
2738
|
+
class SnyMenuLabelDirective {
|
|
2739
|
+
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
2740
|
+
computedClass = computed(() => cn('px-2 py-1.5 text-sm font-semibold', this.class()), ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
2741
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyMenuLabelDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2742
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: SnyMenuLabelDirective, isStandalone: true, selector: "[snyMenuLabel]", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "computedClass()" } }, ngImport: i0 });
|
|
2743
|
+
}
|
|
2744
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyMenuLabelDirective, decorators: [{
|
|
2745
|
+
type: Directive,
|
|
2746
|
+
args: [{
|
|
2747
|
+
selector: '[snyMenuLabel]',
|
|
2748
|
+
standalone: true,
|
|
2749
|
+
host: {
|
|
2750
|
+
'[class]': 'computedClass()',
|
|
2751
|
+
},
|
|
2752
|
+
}]
|
|
2753
|
+
}], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
2754
|
+
|
|
2755
|
+
class SnyCellDefDirective {
|
|
2756
|
+
snyCell = input.required(...(ngDevMode ? [{ debugName: "snyCell" }] : /* istanbul ignore next */ []));
|
|
2757
|
+
template = inject(TemplateRef);
|
|
2758
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyCellDefDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2759
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: SnyCellDefDirective, isStandalone: true, selector: "[snyCell]", inputs: { snyCell: { classPropertyName: "snyCell", publicName: "snyCell", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
|
|
2760
|
+
}
|
|
2761
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyCellDefDirective, decorators: [{
|
|
2762
|
+
type: Directive,
|
|
2763
|
+
args: [{
|
|
2764
|
+
selector: '[snyCell]',
|
|
2765
|
+
standalone: true,
|
|
2766
|
+
}]
|
|
2767
|
+
}], propDecorators: { snyCell: [{ type: i0.Input, args: [{ isSignal: true, alias: "snyCell", required: true }] }] } });
|
|
2768
|
+
class SnyHeaderCellDefDirective {
|
|
2769
|
+
snyHeaderCell = input.required(...(ngDevMode ? [{ debugName: "snyHeaderCell" }] : /* istanbul ignore next */ []));
|
|
2770
|
+
template = inject(TemplateRef);
|
|
2771
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyHeaderCellDefDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2772
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: SnyHeaderCellDefDirective, isStandalone: true, selector: "[snyHeaderCell]", inputs: { snyHeaderCell: { classPropertyName: "snyHeaderCell", publicName: "snyHeaderCell", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
|
|
2773
|
+
}
|
|
2774
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyHeaderCellDefDirective, decorators: [{
|
|
2775
|
+
type: Directive,
|
|
2776
|
+
args: [{
|
|
2777
|
+
selector: '[snyHeaderCell]',
|
|
2778
|
+
standalone: true,
|
|
2779
|
+
}]
|
|
2780
|
+
}], propDecorators: { snyHeaderCell: [{ type: i0.Input, args: [{ isSignal: true, alias: "snyHeaderCell", required: true }] }] } });
|
|
2781
|
+
class SnyBulkActionsDefDirective {
|
|
2782
|
+
template = inject(TemplateRef);
|
|
2783
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyBulkActionsDefDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2784
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.5", type: SnyBulkActionsDefDirective, isStandalone: true, selector: "[snyBulkActions]", ngImport: i0 });
|
|
2785
|
+
}
|
|
2786
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyBulkActionsDefDirective, decorators: [{
|
|
2787
|
+
type: Directive,
|
|
2788
|
+
args: [{
|
|
2789
|
+
selector: '[snyBulkActions]',
|
|
2790
|
+
standalone: true,
|
|
2791
|
+
}]
|
|
2792
|
+
}] });
|
|
2793
|
+
class SnyRowExpandDefDirective {
|
|
2794
|
+
template = inject(TemplateRef);
|
|
2795
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyRowExpandDefDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2796
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.5", type: SnyRowExpandDefDirective, isStandalone: true, selector: "[snyRowExpand]", ngImport: i0 });
|
|
2797
|
+
}
|
|
2798
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyRowExpandDefDirective, decorators: [{
|
|
2799
|
+
type: Directive,
|
|
2800
|
+
args: [{
|
|
2801
|
+
selector: '[snyRowExpand]',
|
|
2802
|
+
standalone: true,
|
|
2803
|
+
}]
|
|
2804
|
+
}] });
|
|
2805
|
+
|
|
2806
|
+
const DEFAULT_PAGINATION = {
|
|
2807
|
+
pageSize: 10,
|
|
2808
|
+
pageSizeOptions: [5, 10, 25, 50],
|
|
2809
|
+
};
|
|
2810
|
+
class SnyDataTableComponent {
|
|
2811
|
+
// Inputs
|
|
2812
|
+
columns = input.required(...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
2813
|
+
data = input.required(...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
2814
|
+
variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
2815
|
+
density = input('normal', ...(ngDevMode ? [{ debugName: "density" }] : /* istanbul ignore next */ []));
|
|
2816
|
+
hoverable = input(true, ...(ngDevMode ? [{ debugName: "hoverable" }] : /* istanbul ignore next */ []));
|
|
2817
|
+
stickyHeader = input(false, ...(ngDevMode ? [{ debugName: "stickyHeader" }] : /* istanbul ignore next */ []));
|
|
2818
|
+
selectable = input(false, ...(ngDevMode ? [{ debugName: "selectable" }] : /* istanbul ignore next */ []));
|
|
2819
|
+
paginated = input(true, ...(ngDevMode ? [{ debugName: "paginated" }] : /* istanbul ignore next */ []));
|
|
2820
|
+
filterable = input(true, ...(ngDevMode ? [{ debugName: "filterable" }] : /* istanbul ignore next */ []));
|
|
2821
|
+
showExport = input(false, ...(ngDevMode ? [{ debugName: "showExport" }] : /* istanbul ignore next */ []));
|
|
2822
|
+
showColumnToggle = input(false, ...(ngDevMode ? [{ debugName: "showColumnToggle" }] : /* istanbul ignore next */ []));
|
|
2823
|
+
expandable = input(false, ...(ngDevMode ? [{ debugName: "expandable" }] : /* istanbul ignore next */ []));
|
|
2824
|
+
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
2825
|
+
loadingRows = input(5, ...(ngDevMode ? [{ debugName: "loadingRows" }] : /* istanbul ignore next */ []));
|
|
2826
|
+
paginationConfig = input(DEFAULT_PAGINATION, ...(ngDevMode ? [{ debugName: "paginationConfig" }] : /* istanbul ignore next */ []));
|
|
2827
|
+
trackBy = input('', ...(ngDevMode ? [{ debugName: "trackBy" }] : /* istanbul ignore next */ []));
|
|
2828
|
+
noDataText = input('No data available', ...(ngDevMode ? [{ debugName: "noDataText" }] : /* istanbul ignore next */ []));
|
|
2829
|
+
// Model
|
|
2830
|
+
selectedRows = model([], ...(ngDevMode ? [{ debugName: "selectedRows" }] : /* istanbul ignore next */ []));
|
|
2831
|
+
// Outputs
|
|
2832
|
+
sortChanged = output();
|
|
2833
|
+
rowClicked = output();
|
|
2834
|
+
dataExported = output();
|
|
2835
|
+
// Content queries
|
|
2836
|
+
cellDefs = contentChildren(SnyCellDefDirective, ...(ngDevMode ? [{ debugName: "cellDefs" }] : /* istanbul ignore next */ []));
|
|
2837
|
+
headerCellDefs = contentChildren(SnyHeaderCellDefDirective, ...(ngDevMode ? [{ debugName: "headerCellDefs" }] : /* istanbul ignore next */ []));
|
|
2838
|
+
bulkActionsDef = contentChild(SnyBulkActionsDefDirective, ...(ngDevMode ? [{ debugName: "bulkActionsDef" }] : /* istanbul ignore next */ []));
|
|
2839
|
+
rowExpandDef = contentChild(SnyRowExpandDefDirective, ...(ngDevMode ? [{ debugName: "rowExpandDef" }] : /* istanbul ignore next */ []));
|
|
2840
|
+
// Internal state
|
|
2841
|
+
sortState = signal({ key: '', direction: null }, ...(ngDevMode ? [{ debugName: "sortState" }] : /* istanbul ignore next */ []));
|
|
2842
|
+
filterText = signal('', ...(ngDevMode ? [{ debugName: "filterText" }] : /* istanbul ignore next */ []));
|
|
2843
|
+
currentPage = signal(1, ...(ngDevMode ? [{ debugName: "currentPage" }] : /* istanbul ignore next */ []));
|
|
2844
|
+
pageSize = signal(10, ...(ngDevMode ? [{ debugName: "pageSize" }] : /* istanbul ignore next */ []));
|
|
2845
|
+
hiddenColumns = signal(new Set(), ...(ngDevMode ? [{ debugName: "hiddenColumns" }] : /* istanbul ignore next */ []));
|
|
2846
|
+
expandedRows = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedRows" }] : /* istanbul ignore next */ []));
|
|
2847
|
+
// Template def maps
|
|
2848
|
+
cellDefMap = computed(() => {
|
|
2849
|
+
const map = new Map();
|
|
2850
|
+
for (const def of this.cellDefs()) {
|
|
2851
|
+
map.set(def.snyCell(), def.template);
|
|
2852
|
+
}
|
|
2853
|
+
return map;
|
|
2854
|
+
}, ...(ngDevMode ? [{ debugName: "cellDefMap" }] : /* istanbul ignore next */ []));
|
|
2855
|
+
headerCellDefMap = computed(() => {
|
|
2856
|
+
const map = new Map();
|
|
2857
|
+
for (const def of this.headerCellDefs()) {
|
|
2858
|
+
map.set(def.snyHeaderCell(), def.template);
|
|
2859
|
+
}
|
|
2860
|
+
return map;
|
|
2861
|
+
}, ...(ngDevMode ? [{ debugName: "headerCellDefMap" }] : /* istanbul ignore next */ []));
|
|
2862
|
+
// Visible columns
|
|
2863
|
+
visibleColumns = computed(() => this.columns().filter((col) => col.visible !== false && !this.hiddenColumns().has(col.key)), ...(ngDevMode ? [{ debugName: "visibleColumns" }] : /* istanbul ignore next */ []));
|
|
2864
|
+
// Page size options
|
|
2865
|
+
pageSizeOptions = computed(() => this.paginationConfig().pageSizeOptions.map((n) => ({
|
|
2866
|
+
value: String(n),
|
|
2867
|
+
label: String(n),
|
|
2868
|
+
})), ...(ngDevMode ? [{ debugName: "pageSizeOptions" }] : /* istanbul ignore next */ []));
|
|
2869
|
+
pageSizeValue = computed(() => String(this.pageSize()), ...(ngDevMode ? [{ debugName: "pageSizeValue" }] : /* istanbul ignore next */ []));
|
|
2870
|
+
// Skeleton rows
|
|
2871
|
+
skeletonRows = computed(() => Array.from({ length: this.loadingRows() }, (_, i) => i), ...(ngDevMode ? [{ debugName: "skeletonRows" }] : /* istanbul ignore next */ []));
|
|
2872
|
+
// Bulk actions visibility
|
|
2873
|
+
showBulkActions = computed(() => this.selectable() &&
|
|
2874
|
+
this.selectedRows().length > 0 &&
|
|
2875
|
+
this.bulkActionsDef() != null, ...(ngDevMode ? [{ debugName: "showBulkActions" }] : /* istanbul ignore next */ []));
|
|
2876
|
+
// Data pipeline (filter uses all columns, not just visible)
|
|
2877
|
+
filteredData = computed(() => {
|
|
2878
|
+
const text = this.filterText().toLowerCase().trim();
|
|
2879
|
+
const rows = this.data();
|
|
2880
|
+
if (!text)
|
|
2881
|
+
return rows;
|
|
2882
|
+
const cols = this.columns().filter((c) => c.filterable !== false);
|
|
2883
|
+
return rows.filter((row) => cols.some((col) => String(row[col.key] ?? '').toLowerCase().includes(text)));
|
|
2884
|
+
}, ...(ngDevMode ? [{ debugName: "filteredData" }] : /* istanbul ignore next */ []));
|
|
2885
|
+
sortedData = computed(() => {
|
|
2886
|
+
const { key, direction } = this.sortState();
|
|
2887
|
+
const rows = this.filteredData();
|
|
2888
|
+
if (!key || !direction)
|
|
2889
|
+
return rows;
|
|
2890
|
+
return [...rows].sort((a, b) => {
|
|
2891
|
+
const aVal = a[key];
|
|
2892
|
+
const bVal = b[key];
|
|
2893
|
+
if (aVal == null && bVal == null)
|
|
2894
|
+
return 0;
|
|
2895
|
+
if (aVal == null)
|
|
2896
|
+
return direction === 'asc' ? -1 : 1;
|
|
2897
|
+
if (bVal == null)
|
|
2898
|
+
return direction === 'asc' ? 1 : -1;
|
|
2899
|
+
if (typeof aVal === 'number' && typeof bVal === 'number') {
|
|
2900
|
+
return direction === 'asc' ? aVal - bVal : bVal - aVal;
|
|
2901
|
+
}
|
|
2902
|
+
const cmp = String(aVal).localeCompare(String(bVal));
|
|
2903
|
+
return direction === 'asc' ? cmp : -cmp;
|
|
2904
|
+
});
|
|
2905
|
+
}, ...(ngDevMode ? [{ debugName: "sortedData" }] : /* istanbul ignore next */ []));
|
|
2906
|
+
totalPages = computed(() => Math.max(1, Math.ceil(this.filteredData().length / this.pageSize())), ...(ngDevMode ? [{ debugName: "totalPages" }] : /* istanbul ignore next */ []));
|
|
2907
|
+
paginatedData = computed(() => {
|
|
2908
|
+
if (!this.paginated())
|
|
2909
|
+
return this.sortedData();
|
|
2910
|
+
const start = (this.currentPage() - 1) * this.pageSize();
|
|
2911
|
+
return this.sortedData().slice(start, start + this.pageSize());
|
|
2912
|
+
}, ...(ngDevMode ? [{ debugName: "paginatedData" }] : /* istanbul ignore next */ []));
|
|
2913
|
+
totalColSpan = computed(() => this.visibleColumns().length +
|
|
2914
|
+
(this.selectable() ? 1 : 0) +
|
|
2915
|
+
(this.expandable() ? 1 : 0), ...(ngDevMode ? [{ debugName: "totalColSpan" }] : /* istanbul ignore next */ []));
|
|
2916
|
+
// Selection computed
|
|
2917
|
+
allSelected = computed(() => {
|
|
2918
|
+
const page = this.paginatedData();
|
|
2919
|
+
if (page.length === 0)
|
|
2920
|
+
return false;
|
|
2921
|
+
const selected = this.selectedRows();
|
|
2922
|
+
return page.every((row) => this.isRowInList(row, selected));
|
|
2923
|
+
}, ...(ngDevMode ? [{ debugName: "allSelected" }] : /* istanbul ignore next */ []));
|
|
2924
|
+
someSelected = computed(() => {
|
|
2925
|
+
const page = this.paginatedData();
|
|
2926
|
+
const selected = this.selectedRows();
|
|
2927
|
+
return page.some((row) => this.isRowInList(row, selected));
|
|
2928
|
+
}, ...(ngDevMode ? [{ debugName: "someSelected" }] : /* istanbul ignore next */ []));
|
|
2929
|
+
constructor() {
|
|
2930
|
+
effect(() => {
|
|
2931
|
+
const config = this.paginationConfig();
|
|
2932
|
+
untracked(() => this.pageSize.set(config.pageSize));
|
|
2933
|
+
});
|
|
2934
|
+
effect(() => {
|
|
2935
|
+
this.filterText();
|
|
2936
|
+
this.pageSize();
|
|
2937
|
+
this.data();
|
|
2938
|
+
untracked(() => this.currentPage.set(1));
|
|
2939
|
+
});
|
|
2940
|
+
}
|
|
2941
|
+
// Sort
|
|
2942
|
+
toggleSort(key) {
|
|
2943
|
+
const current = this.sortState();
|
|
2944
|
+
let direction;
|
|
2945
|
+
if (current.key !== key) {
|
|
2946
|
+
direction = 'asc';
|
|
2947
|
+
}
|
|
2948
|
+
else if (current.direction === 'asc') {
|
|
2949
|
+
direction = 'desc';
|
|
2950
|
+
}
|
|
2951
|
+
else if (current.direction === 'desc') {
|
|
2952
|
+
direction = null;
|
|
2953
|
+
}
|
|
2954
|
+
else {
|
|
2955
|
+
direction = 'asc';
|
|
2956
|
+
}
|
|
2957
|
+
const next = { key: direction ? key : '', direction };
|
|
2958
|
+
this.sortState.set(next);
|
|
2959
|
+
this.sortChanged.emit(next);
|
|
2960
|
+
}
|
|
2961
|
+
// Filter
|
|
2962
|
+
onFilterInput(event) {
|
|
2963
|
+
this.filterText.set(event.target.value);
|
|
2964
|
+
}
|
|
2965
|
+
// Page size
|
|
2966
|
+
onPageSizeChange(value) {
|
|
2967
|
+
this.pageSize.set(Number(value));
|
|
2968
|
+
}
|
|
2969
|
+
// Selection
|
|
2970
|
+
toggleSelectAll() {
|
|
2971
|
+
if (this.allSelected()) {
|
|
2972
|
+
const page = this.paginatedData();
|
|
2973
|
+
this.selectedRows.update((sel) => sel.filter((r) => !page.some((p) => this.rowsEqual(r, p))));
|
|
2974
|
+
}
|
|
2975
|
+
else {
|
|
2976
|
+
const page = this.paginatedData();
|
|
2977
|
+
this.selectedRows.update((sel) => {
|
|
2978
|
+
const newSel = [...sel];
|
|
2979
|
+
for (const row of page) {
|
|
2980
|
+
if (!this.isRowInList(row, newSel))
|
|
2981
|
+
newSel.push(row);
|
|
2982
|
+
}
|
|
2983
|
+
return newSel;
|
|
2984
|
+
});
|
|
2985
|
+
}
|
|
2986
|
+
}
|
|
2987
|
+
toggleRowSelection(row) {
|
|
2988
|
+
this.selectedRows.update((sel) => this.isRowInList(row, sel)
|
|
2989
|
+
? sel.filter((r) => !this.rowsEqual(r, row))
|
|
2990
|
+
: [...sel, row]);
|
|
2991
|
+
}
|
|
2992
|
+
// Row click
|
|
2993
|
+
onRowClick(row) {
|
|
2994
|
+
this.rowClicked.emit(row);
|
|
2995
|
+
}
|
|
2996
|
+
// Export
|
|
2997
|
+
onExport() {
|
|
2998
|
+
this.dataExported.emit(this.filteredData());
|
|
2999
|
+
}
|
|
3000
|
+
// Column visibility
|
|
3001
|
+
toggleColumnVisibility(key) {
|
|
3002
|
+
this.hiddenColumns.update((set) => {
|
|
3003
|
+
const next = new Set(set);
|
|
3004
|
+
if (next.has(key))
|
|
3005
|
+
next.delete(key);
|
|
3006
|
+
else
|
|
3007
|
+
next.add(key);
|
|
3008
|
+
return next;
|
|
3009
|
+
});
|
|
3010
|
+
}
|
|
3011
|
+
// Expansion
|
|
3012
|
+
toggleRowExpansion(row) {
|
|
3013
|
+
const key = this.trackBy() ? row[this.trackBy()] : row;
|
|
3014
|
+
this.expandedRows.update((set) => {
|
|
3015
|
+
const next = new Set(set);
|
|
3016
|
+
if (next.has(key))
|
|
3017
|
+
next.delete(key);
|
|
3018
|
+
else
|
|
3019
|
+
next.add(key);
|
|
3020
|
+
return next;
|
|
3021
|
+
});
|
|
3022
|
+
}
|
|
3023
|
+
isExpanded(row) {
|
|
3024
|
+
const key = this.trackBy() ? row[this.trackBy()] : row;
|
|
3025
|
+
return this.expandedRows().has(key);
|
|
3026
|
+
}
|
|
3027
|
+
// Helpers
|
|
3028
|
+
isSelected(row) {
|
|
3029
|
+
return this.isRowInList(row, this.selectedRows());
|
|
3030
|
+
}
|
|
3031
|
+
trackByFn(row, index) {
|
|
3032
|
+
const key = this.trackBy();
|
|
3033
|
+
return key ? row[key] : index;
|
|
3034
|
+
}
|
|
3035
|
+
isRowInList(row, list) {
|
|
3036
|
+
return list.some((r) => this.rowsEqual(r, row));
|
|
3037
|
+
}
|
|
3038
|
+
rowsEqual(a, b) {
|
|
3039
|
+
const key = this.trackBy();
|
|
3040
|
+
if (key)
|
|
3041
|
+
return a[key] === b[key];
|
|
3042
|
+
return a === b;
|
|
3043
|
+
}
|
|
3044
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDataTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3045
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: SnyDataTableComponent, isStandalone: true, selector: "sny-data-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, density: { classPropertyName: "density", publicName: "density", isSignal: true, isRequired: false, transformFunction: null }, hoverable: { classPropertyName: "hoverable", publicName: "hoverable", isSignal: true, isRequired: false, transformFunction: null }, stickyHeader: { classPropertyName: "stickyHeader", publicName: "stickyHeader", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, paginated: { classPropertyName: "paginated", publicName: "paginated", isSignal: true, isRequired: false, transformFunction: null }, filterable: { classPropertyName: "filterable", publicName: "filterable", isSignal: true, isRequired: false, transformFunction: null }, showExport: { classPropertyName: "showExport", publicName: "showExport", isSignal: true, isRequired: false, transformFunction: null }, showColumnToggle: { classPropertyName: "showColumnToggle", publicName: "showColumnToggle", isSignal: true, isRequired: false, transformFunction: null }, expandable: { classPropertyName: "expandable", publicName: "expandable", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingRows: { classPropertyName: "loadingRows", publicName: "loadingRows", isSignal: true, isRequired: false, transformFunction: null }, paginationConfig: { classPropertyName: "paginationConfig", publicName: "paginationConfig", isSignal: true, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null }, noDataText: { classPropertyName: "noDataText", publicName: "noDataText", isSignal: true, isRequired: false, transformFunction: null }, selectedRows: { classPropertyName: "selectedRows", publicName: "selectedRows", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedRows: "selectedRowsChange", sortChanged: "sortChanged", rowClicked: "rowClicked", dataExported: "dataExported" }, queries: [{ propertyName: "cellDefs", predicate: SnyCellDefDirective, isSignal: true }, { propertyName: "headerCellDefs", predicate: SnyHeaderCellDefDirective, isSignal: true }, { propertyName: "bulkActionsDef", first: true, predicate: SnyBulkActionsDefDirective, descendants: true, isSignal: true }, { propertyName: "rowExpandDef", first: true, predicate: SnyRowExpandDefDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
3046
|
+
<!-- Toolbar -->
|
|
3047
|
+
@if (filterable() || showExport() || showColumnToggle()) {
|
|
3048
|
+
<div class="flex items-center justify-between gap-4 mb-4 flex-wrap">
|
|
3049
|
+
@if (filterable()) {
|
|
3050
|
+
<input
|
|
3051
|
+
snyInput
|
|
3052
|
+
[value]="filterText()"
|
|
3053
|
+
(input)="onFilterInput($event)"
|
|
3054
|
+
placeholder="Filter..."
|
|
3055
|
+
class="w-full sm:max-w-sm"
|
|
3056
|
+
/>
|
|
3057
|
+
}
|
|
3058
|
+
<div class="flex items-center gap-2">
|
|
3059
|
+
@if (showExport()) {
|
|
3060
|
+
<button snyBtn variant="outline" size="sm" (click)="onExport()">
|
|
3061
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="sm:mr-2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"/><path d="M14 2v6h6"/><path d="M12 18v-6"/><path d="m9 15 3-3 3 3"/></svg>
|
|
3062
|
+
<span class="hidden sm:inline">Export</span>
|
|
3063
|
+
</button>
|
|
3064
|
+
}
|
|
3065
|
+
@if (showColumnToggle()) {
|
|
3066
|
+
<div snyDropdown class="relative">
|
|
3067
|
+
<button snyBtn variant="outline" size="sm" snyDropdownTrigger>
|
|
3068
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="sm:mr-2"><path d="M12 3v18"/><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M3 9h18"/><path d="M3 15h18"/></svg>
|
|
3069
|
+
<span class="hidden sm:inline">Columns</span>
|
|
3070
|
+
</button>
|
|
3071
|
+
<div snyDropdownContent class="w-48 right-0 left-auto">
|
|
3072
|
+
@for (col of columns(); track col.key) {
|
|
3073
|
+
<label snyMenuItem class="flex items-center gap-2 cursor-pointer">
|
|
3074
|
+
<input
|
|
3075
|
+
type="checkbox"
|
|
3076
|
+
snyCheckbox
|
|
3077
|
+
[checked]="!hiddenColumns().has(col.key)"
|
|
3078
|
+
(change)="toggleColumnVisibility(col.key)"
|
|
3079
|
+
(click)="$event.stopPropagation()"
|
|
3080
|
+
/>
|
|
3081
|
+
{{ col.label }}
|
|
3082
|
+
</label>
|
|
3083
|
+
}
|
|
3084
|
+
</div>
|
|
3085
|
+
</div>
|
|
3086
|
+
}
|
|
3087
|
+
</div>
|
|
3088
|
+
</div>
|
|
3089
|
+
}
|
|
3090
|
+
|
|
3091
|
+
<!-- Bulk Actions Bar -->
|
|
3092
|
+
@if (showBulkActions()) {
|
|
3093
|
+
@let selected = selectedRows();
|
|
3094
|
+
<div class="flex items-center gap-2 mb-4 p-3 bg-muted/50 rounded-sm border border-border flex-wrap">
|
|
3095
|
+
<span class="text-sm font-medium text-muted-foreground mr-2">
|
|
3096
|
+
{{ selected.length }} selected
|
|
3097
|
+
</span>
|
|
3098
|
+
<ng-container
|
|
3099
|
+
[ngTemplateOutlet]="bulkActionsDef()!.template"
|
|
3100
|
+
[ngTemplateOutletContext]="{ $implicit: selected }"
|
|
3101
|
+
/>
|
|
3102
|
+
<button
|
|
3103
|
+
snyBtn variant="ghost" size="sm" class="ml-auto"
|
|
3104
|
+
(click)="selectedRows.set([])"
|
|
3105
|
+
>
|
|
3106
|
+
Clear
|
|
3107
|
+
</button>
|
|
3108
|
+
</div>
|
|
3109
|
+
}
|
|
3110
|
+
|
|
3111
|
+
<!-- Table -->
|
|
3112
|
+
<div class="overflow-auto border border-border rounded-sm">
|
|
3113
|
+
<table
|
|
3114
|
+
snyTable
|
|
3115
|
+
[variant]="variant()"
|
|
3116
|
+
[density]="density()"
|
|
3117
|
+
[hoverable]="hoverable()"
|
|
3118
|
+
[stickyHeader]="stickyHeader()"
|
|
3119
|
+
>
|
|
3120
|
+
<thead snyTableHeader>
|
|
3121
|
+
<tr snyTableRow>
|
|
3122
|
+
@if (selectable()) {
|
|
3123
|
+
<th snyTableHead class="w-12">
|
|
3124
|
+
<input
|
|
3125
|
+
type="checkbox"
|
|
3126
|
+
snyCheckbox
|
|
3127
|
+
[checked]="allSelected()"
|
|
3128
|
+
[indeterminate]="someSelected() && !allSelected()"
|
|
3129
|
+
(change)="toggleSelectAll()"
|
|
3130
|
+
/>
|
|
3131
|
+
</th>
|
|
3132
|
+
}
|
|
3133
|
+
@if (expandable()) {
|
|
3134
|
+
<th snyTableHead class="w-10"></th>
|
|
3135
|
+
}
|
|
3136
|
+
@let sort = sortState();
|
|
3137
|
+
@let headerDefs = headerCellDefMap();
|
|
3138
|
+
@for (col of visibleColumns(); track col.key) {
|
|
3139
|
+
<th
|
|
3140
|
+
snyTableHead
|
|
3141
|
+
[style.width]="col.width ?? null"
|
|
3142
|
+
[class]="col.sortable ? 'cursor-pointer select-none' : ''"
|
|
3143
|
+
(click)="col.sortable ? toggleSort(col.key) : null"
|
|
3144
|
+
>
|
|
3145
|
+
@if (headerDefs.has(col.key)) {
|
|
3146
|
+
<ng-container
|
|
3147
|
+
[ngTemplateOutlet]="headerDefs.get(col.key)!"
|
|
3148
|
+
[ngTemplateOutletContext]="{ $implicit: col }"
|
|
3149
|
+
/>
|
|
3150
|
+
} @else {
|
|
3151
|
+
<div class="flex items-center gap-1">
|
|
3152
|
+
<span>{{ col.label }}</span>
|
|
3153
|
+
@if (col.sortable) {
|
|
3154
|
+
@let isActive = sort.key === col.key;
|
|
3155
|
+
@if (isActive && sort.direction === 'asc') {
|
|
3156
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m5 12 7-7 7 7"/></svg>
|
|
3157
|
+
} @else if (isActive && sort.direction === 'desc') {
|
|
3158
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m19 12-7 7-7-7"/></svg>
|
|
3159
|
+
} @else {
|
|
3160
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="opacity-30"><path d="m7 15 5 5 5-5"/><path d="m7 9 5-5 5 5"/></svg>
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
3163
|
+
</div>
|
|
3164
|
+
}
|
|
3165
|
+
</th>
|
|
3166
|
+
}
|
|
3167
|
+
</tr>
|
|
3168
|
+
</thead>
|
|
3169
|
+
<tbody snyTableBody>
|
|
3170
|
+
@if (loading()) {
|
|
3171
|
+
@for (i of skeletonRows(); track i) {
|
|
3172
|
+
<tr snyTableRow>
|
|
3173
|
+
@if (selectable()) {
|
|
3174
|
+
<td snyTableCell class="w-12"><div snySkeleton class="w-4 h-4 rounded"></div></td>
|
|
3175
|
+
}
|
|
3176
|
+
@if (expandable()) {
|
|
3177
|
+
<td snyTableCell class="w-10"><div snySkeleton class="w-4 h-4 rounded"></div></td>
|
|
3178
|
+
}
|
|
3179
|
+
@for (col of visibleColumns(); track col.key) {
|
|
3180
|
+
<td snyTableCell [style.width]="col.width ?? null">
|
|
3181
|
+
<div snySkeleton class="w-full h-4 rounded"></div>
|
|
3182
|
+
</td>
|
|
3183
|
+
}
|
|
3184
|
+
</tr>
|
|
3185
|
+
}
|
|
3186
|
+
} @else if (paginatedData().length === 0) {
|
|
3187
|
+
<tr snyTableRow>
|
|
3188
|
+
<td
|
|
3189
|
+
snyTableCell
|
|
3190
|
+
[attr.colspan]="totalColSpan()"
|
|
3191
|
+
class="text-center text-muted-foreground py-8"
|
|
3192
|
+
>
|
|
3193
|
+
{{ noDataText() }}
|
|
3194
|
+
</td>
|
|
3195
|
+
</tr>
|
|
3196
|
+
} @else {
|
|
3197
|
+
@let cellDefs = cellDefMap();
|
|
3198
|
+
@let cols = visibleColumns();
|
|
3199
|
+
@let expandTpl = rowExpandDef();
|
|
3200
|
+
@for (row of paginatedData(); track trackByFn(row, $index)) {
|
|
3201
|
+
<tr
|
|
3202
|
+
snyTableRow
|
|
3203
|
+
[attr.data-state]="isSelected(row) ? 'selected' : null"
|
|
3204
|
+
(click)="onRowClick(row)"
|
|
3205
|
+
class="cursor-pointer"
|
|
3206
|
+
>
|
|
3207
|
+
@if (selectable()) {
|
|
3208
|
+
<td snyTableCell class="w-12">
|
|
3209
|
+
<input
|
|
3210
|
+
type="checkbox"
|
|
3211
|
+
snyCheckbox
|
|
3212
|
+
[checked]="isSelected(row)"
|
|
3213
|
+
(change)="toggleRowSelection(row)"
|
|
3214
|
+
(click)="$event.stopPropagation()"
|
|
3215
|
+
/>
|
|
3216
|
+
</td>
|
|
3217
|
+
}
|
|
3218
|
+
@if (expandable()) {
|
|
3219
|
+
<td snyTableCell class="w-10">
|
|
3220
|
+
<button
|
|
3221
|
+
class="p-0.5 rounded hover:bg-accent transition-transform duration-150"
|
|
3222
|
+
[class.rotate-90]="isExpanded(row)"
|
|
3223
|
+
(click)="toggleRowExpansion(row); $event.stopPropagation()"
|
|
3224
|
+
>
|
|
3225
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
|
|
3226
|
+
</button>
|
|
3227
|
+
</td>
|
|
3228
|
+
}
|
|
3229
|
+
@for (col of cols; track col.key) {
|
|
3230
|
+
<td snyTableCell [style.width]="col.width ?? null">
|
|
3231
|
+
@if (cellDefs.has(col.key)) {
|
|
3232
|
+
<ng-container
|
|
3233
|
+
[ngTemplateOutlet]="cellDefs.get(col.key)!"
|
|
3234
|
+
[ngTemplateOutletContext]="{ $implicit: row[col.key], row: row }"
|
|
3235
|
+
/>
|
|
3236
|
+
} @else {
|
|
3237
|
+
{{ row[col.key] }}
|
|
3238
|
+
}
|
|
3239
|
+
</td>
|
|
3240
|
+
}
|
|
3241
|
+
</tr>
|
|
3242
|
+
@if (expandable() && isExpanded(row) && expandTpl) {
|
|
3243
|
+
<tr snyTableRow>
|
|
3244
|
+
<td snyTableCell [attr.colspan]="totalColSpan()" class="bg-muted/30">
|
|
3245
|
+
<ng-container
|
|
3246
|
+
[ngTemplateOutlet]="expandTpl.template"
|
|
3247
|
+
[ngTemplateOutletContext]="{ $implicit: row }"
|
|
3248
|
+
/>
|
|
3249
|
+
</td>
|
|
3250
|
+
</tr>
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
</tbody>
|
|
3255
|
+
</table>
|
|
3256
|
+
</div>
|
|
3257
|
+
|
|
3258
|
+
<!-- Footer -->
|
|
3259
|
+
@if (paginated()) {
|
|
3260
|
+
<div class="flex flex-col sm:flex-row items-start sm:items-center justify-between mt-4 gap-3 sm:gap-4">
|
|
3261
|
+
<span class="text-sm text-muted-foreground">
|
|
3262
|
+
@if (selectable()) {
|
|
3263
|
+
{{ selectedRows().length }} of {{ filteredData().length }} row(s) selected
|
|
3264
|
+
} @else {
|
|
3265
|
+
{{ filteredData().length }} row(s)
|
|
3266
|
+
}
|
|
3267
|
+
</span>
|
|
3268
|
+
<div class="flex items-center gap-3 sm:gap-4 flex-wrap">
|
|
3269
|
+
<div class="flex items-center gap-2">
|
|
3270
|
+
<span class="hidden sm:inline text-sm text-muted-foreground whitespace-nowrap">Rows per page</span>
|
|
3271
|
+
<sny-select
|
|
3272
|
+
[options]="pageSizeOptions()"
|
|
3273
|
+
[value]="pageSizeValue()"
|
|
3274
|
+
(valueChange)="onPageSizeChange($event)"
|
|
3275
|
+
size="sm"
|
|
3276
|
+
class="w-20"
|
|
3277
|
+
/>
|
|
3278
|
+
</div>
|
|
3279
|
+
<sny-pagination
|
|
3280
|
+
[currentPage]="currentPage()"
|
|
3281
|
+
(currentPageChange)="currentPage.set($event)"
|
|
3282
|
+
[totalPages]="totalPages()"
|
|
3283
|
+
/>
|
|
3284
|
+
</div>
|
|
3285
|
+
</div>
|
|
3286
|
+
}
|
|
3287
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: SnyTableDirective, selector: "table[snyTable]", inputs: ["variant", "density", "hoverable", "stickyHeader", "class"] }, { kind: "directive", type: SnyTableHeaderDirective, selector: "thead[snyTableHeader]", inputs: ["class"] }, { kind: "directive", type: SnyTableBodyDirective, selector: "tbody[snyTableBody]", inputs: ["class"] }, { kind: "directive", type: SnyTableRowDirective, selector: "tr[snyTableRow]", inputs: ["class"] }, { kind: "directive", type: SnyTableHeadDirective, selector: "th[snyTableHead]", inputs: ["class"] }, { kind: "directive", type: SnyTableCellDirective, selector: "td[snyTableCell]", inputs: ["class"] }, { kind: "component", type: SnyPaginationComponent, selector: "sny-pagination", inputs: ["currentPage", "totalPages", "siblingCount", "boundaryCount", "size", "variant", "class"], outputs: ["currentPageChange"] }, { kind: "directive", type: SnyCheckboxDirective, selector: "input[type=\"checkbox\"][snyCheckbox]", inputs: ["size", "class"] }, { kind: "directive", type: SnyInputDirective, selector: "input[snyInput], textarea[snyInput]", inputs: ["variant", "inputSize", "class", "ariaDescribedBy"] }, { kind: "directive", type: SnyButtonDirective, selector: "button[snyBtn], a[snyBtn]", inputs: ["variant", "size", "disabled", "loading", "class"] }, { kind: "component", type: SnySelectComponent, selector: "sny-select", inputs: ["options", "placeholder", "size", "disabled", "class", "value"], outputs: ["valueChange"] }, { kind: "directive", type: SnySkeletonDirective, selector: "[snySkeleton]", inputs: ["variant", "size", "class"] }, { kind: "directive", type: SnyDropdownDirective, selector: "[snyDropdown]", exportAs: ["snyDropdown"] }, { kind: "directive", type: SnyDropdownTriggerDirective, selector: "[snyDropdownTrigger]" }, { kind: "directive", type: SnyDropdownContentDirective, selector: "[snyDropdownContent]", inputs: ["class"] }, { kind: "directive", type: SnyMenuItemDirective, selector: "[snyMenuItem]", inputs: ["variant", "class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3288
|
+
}
|
|
3289
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDataTableComponent, decorators: [{
|
|
3290
|
+
type: Component,
|
|
3291
|
+
args: [{
|
|
3292
|
+
selector: 'sny-data-table',
|
|
3293
|
+
standalone: true,
|
|
3294
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
3295
|
+
imports: [
|
|
3296
|
+
NgTemplateOutlet,
|
|
3297
|
+
SnyTableDirective,
|
|
3298
|
+
SnyTableHeaderDirective,
|
|
3299
|
+
SnyTableBodyDirective,
|
|
3300
|
+
SnyTableRowDirective,
|
|
3301
|
+
SnyTableHeadDirective,
|
|
3302
|
+
SnyTableCellDirective,
|
|
3303
|
+
SnyPaginationComponent,
|
|
3304
|
+
SnyCheckboxDirective,
|
|
3305
|
+
SnyInputDirective,
|
|
3306
|
+
SnyButtonDirective,
|
|
3307
|
+
SnySelectComponent,
|
|
3308
|
+
SnySkeletonDirective,
|
|
3309
|
+
SnyDropdownDirective,
|
|
3310
|
+
SnyDropdownTriggerDirective,
|
|
3311
|
+
SnyDropdownContentDirective,
|
|
3312
|
+
SnyMenuItemDirective,
|
|
3313
|
+
],
|
|
3314
|
+
template: `
|
|
3315
|
+
<!-- Toolbar -->
|
|
3316
|
+
@if (filterable() || showExport() || showColumnToggle()) {
|
|
3317
|
+
<div class="flex items-center justify-between gap-4 mb-4 flex-wrap">
|
|
3318
|
+
@if (filterable()) {
|
|
3319
|
+
<input
|
|
3320
|
+
snyInput
|
|
3321
|
+
[value]="filterText()"
|
|
3322
|
+
(input)="onFilterInput($event)"
|
|
3323
|
+
placeholder="Filter..."
|
|
3324
|
+
class="w-full sm:max-w-sm"
|
|
3325
|
+
/>
|
|
3326
|
+
}
|
|
3327
|
+
<div class="flex items-center gap-2">
|
|
3328
|
+
@if (showExport()) {
|
|
3329
|
+
<button snyBtn variant="outline" size="sm" (click)="onExport()">
|
|
3330
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="sm:mr-2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"/><path d="M14 2v6h6"/><path d="M12 18v-6"/><path d="m9 15 3-3 3 3"/></svg>
|
|
3331
|
+
<span class="hidden sm:inline">Export</span>
|
|
3332
|
+
</button>
|
|
3333
|
+
}
|
|
3334
|
+
@if (showColumnToggle()) {
|
|
3335
|
+
<div snyDropdown class="relative">
|
|
3336
|
+
<button snyBtn variant="outline" size="sm" snyDropdownTrigger>
|
|
3337
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="sm:mr-2"><path d="M12 3v18"/><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M3 9h18"/><path d="M3 15h18"/></svg>
|
|
3338
|
+
<span class="hidden sm:inline">Columns</span>
|
|
3339
|
+
</button>
|
|
3340
|
+
<div snyDropdownContent class="w-48 right-0 left-auto">
|
|
3341
|
+
@for (col of columns(); track col.key) {
|
|
3342
|
+
<label snyMenuItem class="flex items-center gap-2 cursor-pointer">
|
|
3343
|
+
<input
|
|
3344
|
+
type="checkbox"
|
|
3345
|
+
snyCheckbox
|
|
3346
|
+
[checked]="!hiddenColumns().has(col.key)"
|
|
3347
|
+
(change)="toggleColumnVisibility(col.key)"
|
|
3348
|
+
(click)="$event.stopPropagation()"
|
|
3349
|
+
/>
|
|
3350
|
+
{{ col.label }}
|
|
3351
|
+
</label>
|
|
3352
|
+
}
|
|
3353
|
+
</div>
|
|
3354
|
+
</div>
|
|
3355
|
+
}
|
|
3356
|
+
</div>
|
|
3357
|
+
</div>
|
|
3358
|
+
}
|
|
3359
|
+
|
|
3360
|
+
<!-- Bulk Actions Bar -->
|
|
3361
|
+
@if (showBulkActions()) {
|
|
3362
|
+
@let selected = selectedRows();
|
|
3363
|
+
<div class="flex items-center gap-2 mb-4 p-3 bg-muted/50 rounded-sm border border-border flex-wrap">
|
|
3364
|
+
<span class="text-sm font-medium text-muted-foreground mr-2">
|
|
3365
|
+
{{ selected.length }} selected
|
|
3366
|
+
</span>
|
|
3367
|
+
<ng-container
|
|
3368
|
+
[ngTemplateOutlet]="bulkActionsDef()!.template"
|
|
3369
|
+
[ngTemplateOutletContext]="{ $implicit: selected }"
|
|
3370
|
+
/>
|
|
3371
|
+
<button
|
|
3372
|
+
snyBtn variant="ghost" size="sm" class="ml-auto"
|
|
3373
|
+
(click)="selectedRows.set([])"
|
|
3374
|
+
>
|
|
3375
|
+
Clear
|
|
3376
|
+
</button>
|
|
3377
|
+
</div>
|
|
3378
|
+
}
|
|
3379
|
+
|
|
3380
|
+
<!-- Table -->
|
|
3381
|
+
<div class="overflow-auto border border-border rounded-sm">
|
|
3382
|
+
<table
|
|
3383
|
+
snyTable
|
|
3384
|
+
[variant]="variant()"
|
|
3385
|
+
[density]="density()"
|
|
3386
|
+
[hoverable]="hoverable()"
|
|
3387
|
+
[stickyHeader]="stickyHeader()"
|
|
3388
|
+
>
|
|
3389
|
+
<thead snyTableHeader>
|
|
3390
|
+
<tr snyTableRow>
|
|
3391
|
+
@if (selectable()) {
|
|
3392
|
+
<th snyTableHead class="w-12">
|
|
3393
|
+
<input
|
|
3394
|
+
type="checkbox"
|
|
3395
|
+
snyCheckbox
|
|
3396
|
+
[checked]="allSelected()"
|
|
3397
|
+
[indeterminate]="someSelected() && !allSelected()"
|
|
3398
|
+
(change)="toggleSelectAll()"
|
|
3399
|
+
/>
|
|
3400
|
+
</th>
|
|
3401
|
+
}
|
|
3402
|
+
@if (expandable()) {
|
|
3403
|
+
<th snyTableHead class="w-10"></th>
|
|
3404
|
+
}
|
|
3405
|
+
@let sort = sortState();
|
|
3406
|
+
@let headerDefs = headerCellDefMap();
|
|
3407
|
+
@for (col of visibleColumns(); track col.key) {
|
|
3408
|
+
<th
|
|
3409
|
+
snyTableHead
|
|
3410
|
+
[style.width]="col.width ?? null"
|
|
3411
|
+
[class]="col.sortable ? 'cursor-pointer select-none' : ''"
|
|
3412
|
+
(click)="col.sortable ? toggleSort(col.key) : null"
|
|
3413
|
+
>
|
|
3414
|
+
@if (headerDefs.has(col.key)) {
|
|
3415
|
+
<ng-container
|
|
3416
|
+
[ngTemplateOutlet]="headerDefs.get(col.key)!"
|
|
3417
|
+
[ngTemplateOutletContext]="{ $implicit: col }"
|
|
3418
|
+
/>
|
|
3419
|
+
} @else {
|
|
3420
|
+
<div class="flex items-center gap-1">
|
|
3421
|
+
<span>{{ col.label }}</span>
|
|
3422
|
+
@if (col.sortable) {
|
|
3423
|
+
@let isActive = sort.key === col.key;
|
|
3424
|
+
@if (isActive && sort.direction === 'asc') {
|
|
3425
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m5 12 7-7 7 7"/></svg>
|
|
3426
|
+
} @else if (isActive && sort.direction === 'desc') {
|
|
3427
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m19 12-7 7-7-7"/></svg>
|
|
3428
|
+
} @else {
|
|
3429
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="opacity-30"><path d="m7 15 5 5 5-5"/><path d="m7 9 5-5 5 5"/></svg>
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
</div>
|
|
3433
|
+
}
|
|
3434
|
+
</th>
|
|
3435
|
+
}
|
|
3436
|
+
</tr>
|
|
3437
|
+
</thead>
|
|
3438
|
+
<tbody snyTableBody>
|
|
3439
|
+
@if (loading()) {
|
|
3440
|
+
@for (i of skeletonRows(); track i) {
|
|
3441
|
+
<tr snyTableRow>
|
|
3442
|
+
@if (selectable()) {
|
|
3443
|
+
<td snyTableCell class="w-12"><div snySkeleton class="w-4 h-4 rounded"></div></td>
|
|
3444
|
+
}
|
|
3445
|
+
@if (expandable()) {
|
|
3446
|
+
<td snyTableCell class="w-10"><div snySkeleton class="w-4 h-4 rounded"></div></td>
|
|
3447
|
+
}
|
|
3448
|
+
@for (col of visibleColumns(); track col.key) {
|
|
3449
|
+
<td snyTableCell [style.width]="col.width ?? null">
|
|
3450
|
+
<div snySkeleton class="w-full h-4 rounded"></div>
|
|
3451
|
+
</td>
|
|
3452
|
+
}
|
|
3453
|
+
</tr>
|
|
3454
|
+
}
|
|
3455
|
+
} @else if (paginatedData().length === 0) {
|
|
3456
|
+
<tr snyTableRow>
|
|
3457
|
+
<td
|
|
3458
|
+
snyTableCell
|
|
3459
|
+
[attr.colspan]="totalColSpan()"
|
|
3460
|
+
class="text-center text-muted-foreground py-8"
|
|
3461
|
+
>
|
|
3462
|
+
{{ noDataText() }}
|
|
3463
|
+
</td>
|
|
3464
|
+
</tr>
|
|
3465
|
+
} @else {
|
|
3466
|
+
@let cellDefs = cellDefMap();
|
|
3467
|
+
@let cols = visibleColumns();
|
|
3468
|
+
@let expandTpl = rowExpandDef();
|
|
3469
|
+
@for (row of paginatedData(); track trackByFn(row, $index)) {
|
|
3470
|
+
<tr
|
|
3471
|
+
snyTableRow
|
|
3472
|
+
[attr.data-state]="isSelected(row) ? 'selected' : null"
|
|
3473
|
+
(click)="onRowClick(row)"
|
|
3474
|
+
class="cursor-pointer"
|
|
3475
|
+
>
|
|
3476
|
+
@if (selectable()) {
|
|
3477
|
+
<td snyTableCell class="w-12">
|
|
3478
|
+
<input
|
|
3479
|
+
type="checkbox"
|
|
3480
|
+
snyCheckbox
|
|
3481
|
+
[checked]="isSelected(row)"
|
|
3482
|
+
(change)="toggleRowSelection(row)"
|
|
3483
|
+
(click)="$event.stopPropagation()"
|
|
3484
|
+
/>
|
|
3485
|
+
</td>
|
|
3486
|
+
}
|
|
3487
|
+
@if (expandable()) {
|
|
3488
|
+
<td snyTableCell class="w-10">
|
|
3489
|
+
<button
|
|
3490
|
+
class="p-0.5 rounded hover:bg-accent transition-transform duration-150"
|
|
3491
|
+
[class.rotate-90]="isExpanded(row)"
|
|
3492
|
+
(click)="toggleRowExpansion(row); $event.stopPropagation()"
|
|
3493
|
+
>
|
|
3494
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
|
|
3495
|
+
</button>
|
|
3496
|
+
</td>
|
|
3497
|
+
}
|
|
3498
|
+
@for (col of cols; track col.key) {
|
|
3499
|
+
<td snyTableCell [style.width]="col.width ?? null">
|
|
3500
|
+
@if (cellDefs.has(col.key)) {
|
|
3501
|
+
<ng-container
|
|
3502
|
+
[ngTemplateOutlet]="cellDefs.get(col.key)!"
|
|
3503
|
+
[ngTemplateOutletContext]="{ $implicit: row[col.key], row: row }"
|
|
3504
|
+
/>
|
|
3505
|
+
} @else {
|
|
3506
|
+
{{ row[col.key] }}
|
|
3507
|
+
}
|
|
3508
|
+
</td>
|
|
3509
|
+
}
|
|
3510
|
+
</tr>
|
|
3511
|
+
@if (expandable() && isExpanded(row) && expandTpl) {
|
|
3512
|
+
<tr snyTableRow>
|
|
3513
|
+
<td snyTableCell [attr.colspan]="totalColSpan()" class="bg-muted/30">
|
|
3514
|
+
<ng-container
|
|
3515
|
+
[ngTemplateOutlet]="expandTpl.template"
|
|
3516
|
+
[ngTemplateOutletContext]="{ $implicit: row }"
|
|
3517
|
+
/>
|
|
3518
|
+
</td>
|
|
3519
|
+
</tr>
|
|
3520
|
+
}
|
|
3521
|
+
}
|
|
3522
|
+
}
|
|
3523
|
+
</tbody>
|
|
3524
|
+
</table>
|
|
3525
|
+
</div>
|
|
3526
|
+
|
|
3527
|
+
<!-- Footer -->
|
|
3528
|
+
@if (paginated()) {
|
|
3529
|
+
<div class="flex flex-col sm:flex-row items-start sm:items-center justify-between mt-4 gap-3 sm:gap-4">
|
|
3530
|
+
<span class="text-sm text-muted-foreground">
|
|
3531
|
+
@if (selectable()) {
|
|
3532
|
+
{{ selectedRows().length }} of {{ filteredData().length }} row(s) selected
|
|
3533
|
+
} @else {
|
|
3534
|
+
{{ filteredData().length }} row(s)
|
|
3535
|
+
}
|
|
3536
|
+
</span>
|
|
3537
|
+
<div class="flex items-center gap-3 sm:gap-4 flex-wrap">
|
|
3538
|
+
<div class="flex items-center gap-2">
|
|
3539
|
+
<span class="hidden sm:inline text-sm text-muted-foreground whitespace-nowrap">Rows per page</span>
|
|
3540
|
+
<sny-select
|
|
3541
|
+
[options]="pageSizeOptions()"
|
|
3542
|
+
[value]="pageSizeValue()"
|
|
3543
|
+
(valueChange)="onPageSizeChange($event)"
|
|
3544
|
+
size="sm"
|
|
3545
|
+
class="w-20"
|
|
3546
|
+
/>
|
|
3547
|
+
</div>
|
|
3548
|
+
<sny-pagination
|
|
3549
|
+
[currentPage]="currentPage()"
|
|
3550
|
+
(currentPageChange)="currentPage.set($event)"
|
|
3551
|
+
[totalPages]="totalPages()"
|
|
3552
|
+
/>
|
|
3553
|
+
</div>
|
|
3554
|
+
</div>
|
|
3555
|
+
}
|
|
3556
|
+
`,
|
|
3557
|
+
}]
|
|
3558
|
+
}], ctorParameters: () => [], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], density: [{ type: i0.Input, args: [{ isSignal: true, alias: "density", required: false }] }], hoverable: [{ type: i0.Input, args: [{ isSignal: true, alias: "hoverable", required: false }] }], stickyHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "stickyHeader", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], paginated: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginated", required: false }] }], filterable: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterable", required: false }] }], showExport: [{ type: i0.Input, args: [{ isSignal: true, alias: "showExport", required: false }] }], showColumnToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showColumnToggle", required: false }] }], expandable: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandable", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingRows", required: false }] }], paginationConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginationConfig", required: false }] }], trackBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "trackBy", required: false }] }], noDataText: [{ type: i0.Input, args: [{ isSignal: true, alias: "noDataText", required: false }] }], selectedRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedRows", required: false }] }, { type: i0.Output, args: ["selectedRowsChange"] }], sortChanged: [{ type: i0.Output, args: ["sortChanged"] }], rowClicked: [{ type: i0.Output, args: ["rowClicked"] }], dataExported: [{ type: i0.Output, args: ["dataExported"] }], cellDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SnyCellDefDirective), { isSignal: true }] }], headerCellDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SnyHeaderCellDefDirective), { isSignal: true }] }], bulkActionsDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SnyBulkActionsDefDirective), { isSignal: true }] }], rowExpandDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SnyRowExpandDefDirective), { isSignal: true }] }] } });
|
|
3559
|
+
|
|
2420
3560
|
class SnySheetRef {
|
|
2421
3561
|
cdkRef;
|
|
2422
3562
|
constructor(cdkRef) {
|
|
@@ -2896,226 +4036,65 @@ class SnyTooltipDirective {
|
|
|
2896
4036
|
tooltip.setAttribute('role', 'tooltip');
|
|
2897
4037
|
tooltip.className = cn(tooltipVariants({ position: this.tooltipPosition() }), 'fixed pointer-events-none', this.class());
|
|
2898
4038
|
tooltip.textContent = this.snyTooltip();
|
|
2899
|
-
this.renderer.appendChild(document.body, tooltip);
|
|
2900
|
-
this.tooltipEl = tooltip;
|
|
2901
|
-
this.positionTooltip();
|
|
2902
|
-
}
|
|
2903
|
-
positionTooltip() {
|
|
2904
|
-
if (!this.tooltipEl)
|
|
2905
|
-
return;
|
|
2906
|
-
const hostRect = this.el.nativeElement.getBoundingClientRect();
|
|
2907
|
-
const tooltipRect = this.tooltipEl.getBoundingClientRect();
|
|
2908
|
-
const position = this.tooltipPosition();
|
|
2909
|
-
const gap = 8;
|
|
2910
|
-
let top = 0;
|
|
2911
|
-
let left = 0;
|
|
2912
|
-
switch (position) {
|
|
2913
|
-
case 'top':
|
|
2914
|
-
top = hostRect.top - tooltipRect.height - gap;
|
|
2915
|
-
left = hostRect.left + (hostRect.width - tooltipRect.width) / 2;
|
|
2916
|
-
break;
|
|
2917
|
-
case 'bottom':
|
|
2918
|
-
top = hostRect.bottom + gap;
|
|
2919
|
-
left = hostRect.left + (hostRect.width - tooltipRect.width) / 2;
|
|
2920
|
-
break;
|
|
2921
|
-
case 'left':
|
|
2922
|
-
top = hostRect.top + (hostRect.height - tooltipRect.height) / 2;
|
|
2923
|
-
left = hostRect.left - tooltipRect.width - gap;
|
|
2924
|
-
break;
|
|
2925
|
-
case 'right':
|
|
2926
|
-
top = hostRect.top + (hostRect.height - tooltipRect.height) / 2;
|
|
2927
|
-
left = hostRect.right + gap;
|
|
2928
|
-
break;
|
|
2929
|
-
}
|
|
2930
|
-
this.tooltipEl.style.top = `${top}px`;
|
|
2931
|
-
this.tooltipEl.style.left = `${left}px`;
|
|
2932
|
-
}
|
|
2933
|
-
destroyTooltip() {
|
|
2934
|
-
if (this.tooltipEl) {
|
|
2935
|
-
this.tooltipEl.remove();
|
|
2936
|
-
this.tooltipEl = null;
|
|
2937
|
-
}
|
|
2938
|
-
}
|
|
2939
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyTooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2940
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: SnyTooltipDirective, isStandalone: true, selector: "[snyTooltip]", inputs: { snyTooltip: { classPropertyName: "snyTooltip", publicName: "snyTooltip", isSignal: true, isRequired: true, transformFunction: null }, tooltipPosition: { classPropertyName: "tooltipPosition", publicName: "tooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, tooltipDelay: { classPropertyName: "tooltipDelay", publicName: "tooltipDelay", isSignal: true, isRequired: false, transformFunction: null }, tooltipDisabled: { classPropertyName: "tooltipDisabled", publicName: "tooltipDisabled", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "show()", "mouseleave": "hide()", "focus": "show()", "blur": "hide()", "keydown.escape": "hide()" }, properties: { "attr.aria-describedby": "isOpen() ? tooltipId : null" } }, exportAs: ["snyTooltip"], ngImport: i0 });
|
|
2941
|
-
}
|
|
2942
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyTooltipDirective, decorators: [{
|
|
2943
|
-
type: Directive,
|
|
2944
|
-
args: [{
|
|
2945
|
-
selector: '[snyTooltip]',
|
|
2946
|
-
standalone: true,
|
|
2947
|
-
exportAs: 'snyTooltip',
|
|
2948
|
-
host: {
|
|
2949
|
-
'(mouseenter)': 'show()',
|
|
2950
|
-
'(mouseleave)': 'hide()',
|
|
2951
|
-
'(focus)': 'show()',
|
|
2952
|
-
'(blur)': 'hide()',
|
|
2953
|
-
'(keydown.escape)': 'hide()',
|
|
2954
|
-
'[attr.aria-describedby]': 'isOpen() ? tooltipId : null',
|
|
2955
|
-
},
|
|
2956
|
-
}]
|
|
2957
|
-
}], ctorParameters: () => [], propDecorators: { snyTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "snyTooltip", required: true }] }], tooltipPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipPosition", required: false }] }], tooltipDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipDelay", required: false }] }], tooltipDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipDisabled", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
2958
|
-
|
|
2959
|
-
const dropdownContentVariants = cva('z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md', {
|
|
2960
|
-
variants: {},
|
|
2961
|
-
defaultVariants: {},
|
|
2962
|
-
});
|
|
2963
|
-
const dropdownItemVariants = cva('relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[active]:bg-accent data-[active]:text-accent-foreground', {
|
|
2964
|
-
variants: {
|
|
2965
|
-
variant: {
|
|
2966
|
-
default: '',
|
|
2967
|
-
destructive: 'text-destructive data-[active]:bg-destructive/10 data-[active]:text-destructive',
|
|
2968
|
-
},
|
|
2969
|
-
},
|
|
2970
|
-
defaultVariants: {
|
|
2971
|
-
variant: 'default',
|
|
2972
|
-
},
|
|
2973
|
-
});
|
|
2974
|
-
|
|
2975
|
-
const SNY_DROPDOWN = new InjectionToken('SnyDropdown');
|
|
2976
|
-
class SnyDropdownDirective {
|
|
2977
|
-
elementRef = inject(ElementRef);
|
|
2978
|
-
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
|
|
2979
|
-
toggle() { this.isOpen.update((v) => !v); }
|
|
2980
|
-
open() { this.isOpen.set(true); }
|
|
2981
|
-
close() { this.isOpen.set(false); }
|
|
2982
|
-
onDocumentClick(event) {
|
|
2983
|
-
if (!this.elementRef.nativeElement.contains(event.target)) {
|
|
2984
|
-
this.close();
|
|
2985
|
-
}
|
|
2986
|
-
}
|
|
2987
|
-
onEscape() {
|
|
2988
|
-
this.close();
|
|
2989
|
-
}
|
|
2990
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDropdownDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2991
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.5", type: SnyDropdownDirective, isStandalone: true, selector: "[snyDropdown]", host: { listeners: { "document:click": "onDocumentClick($event)", "keydown.escape": "onEscape()" }, properties: { "class": "\"relative inline-block\"" } }, providers: [{ provide: SNY_DROPDOWN, useExisting: SnyDropdownDirective }], exportAs: ["snyDropdown"], ngImport: i0 });
|
|
2992
|
-
}
|
|
2993
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDropdownDirective, decorators: [{
|
|
2994
|
-
type: Directive,
|
|
2995
|
-
args: [{
|
|
2996
|
-
selector: '[snyDropdown]',
|
|
2997
|
-
standalone: true,
|
|
2998
|
-
exportAs: 'snyDropdown',
|
|
2999
|
-
providers: [{ provide: SNY_DROPDOWN, useExisting: SnyDropdownDirective }],
|
|
3000
|
-
host: {
|
|
3001
|
-
'[class]': '"relative inline-block"',
|
|
3002
|
-
},
|
|
3003
|
-
}]
|
|
3004
|
-
}], propDecorators: { onDocumentClick: [{
|
|
3005
|
-
type: HostListener,
|
|
3006
|
-
args: ['document:click', ['$event']]
|
|
3007
|
-
}], onEscape: [{
|
|
3008
|
-
type: HostListener,
|
|
3009
|
-
args: ['keydown.escape']
|
|
3010
|
-
}] } });
|
|
3011
|
-
class SnyDropdownTriggerDirective {
|
|
3012
|
-
dropdown = inject(SNY_DROPDOWN);
|
|
3013
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDropdownTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3014
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.5", type: SnyDropdownTriggerDirective, isStandalone: true, selector: "[snyDropdownTrigger]", host: { listeners: { "click": "dropdown.toggle()" }, properties: { "attr.aria-expanded": "dropdown.isOpen()", "attr.aria-haspopup": "\"menu\"" } }, ngImport: i0 });
|
|
3015
|
-
}
|
|
3016
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDropdownTriggerDirective, decorators: [{
|
|
3017
|
-
type: Directive,
|
|
3018
|
-
args: [{
|
|
3019
|
-
selector: '[snyDropdownTrigger]',
|
|
3020
|
-
standalone: true,
|
|
3021
|
-
host: {
|
|
3022
|
-
'(click)': 'dropdown.toggle()',
|
|
3023
|
-
'[attr.aria-expanded]': 'dropdown.isOpen()',
|
|
3024
|
-
'[attr.aria-haspopup]': '"menu"',
|
|
3025
|
-
},
|
|
3026
|
-
}]
|
|
3027
|
-
}] });
|
|
3028
|
-
class SnyDropdownContentDirective {
|
|
3029
|
-
dropdown = inject(SNY_DROPDOWN);
|
|
3030
|
-
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
3031
|
-
computedClass = computed(() => cn(dropdownContentVariants(), 'absolute mt-1 left-0 animate-in fade-in-0 zoom-in-95', this.class()), ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
3032
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDropdownContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3033
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: SnyDropdownContentDirective, isStandalone: true, selector: "[snyDropdownContent]", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "menu" }, properties: { "class": "computedClass()", "style.display": "dropdown.isOpen() ? \"\" : \"none\"" } }, ngImport: i0 });
|
|
3034
|
-
}
|
|
3035
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDropdownContentDirective, decorators: [{
|
|
3036
|
-
type: Directive,
|
|
3037
|
-
args: [{
|
|
3038
|
-
selector: '[snyDropdownContent]',
|
|
3039
|
-
standalone: true,
|
|
3040
|
-
host: {
|
|
3041
|
-
'role': 'menu',
|
|
3042
|
-
'[class]': 'computedClass()',
|
|
3043
|
-
'[style.display]': 'dropdown.isOpen() ? "" : "none"',
|
|
3044
|
-
},
|
|
3045
|
-
}]
|
|
3046
|
-
}], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
3047
|
-
class SnyMenuContentDirective {
|
|
3048
|
-
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
3049
|
-
computedClass = computed(() => cn(dropdownContentVariants(), this.class()), ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
3050
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyMenuContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3051
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: SnyMenuContentDirective, isStandalone: true, selector: "[snyMenuContent]", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "computedClass()" } }, ngImport: i0 });
|
|
3052
|
-
}
|
|
3053
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyMenuContentDirective, decorators: [{
|
|
3054
|
-
type: Directive,
|
|
3055
|
-
args: [{
|
|
3056
|
-
selector: '[snyMenuContent]',
|
|
3057
|
-
standalone: true,
|
|
3058
|
-
host: {
|
|
3059
|
-
'[class]': 'computedClass()',
|
|
3060
|
-
},
|
|
3061
|
-
}]
|
|
3062
|
-
}], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
3063
|
-
class SnyMenuItemDirective {
|
|
3064
|
-
dropdown = inject(SNY_DROPDOWN, { optional: true });
|
|
3065
|
-
variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
3066
|
-
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
3067
|
-
computedClass = computed(() => cn(dropdownItemVariants({ variant: this.variant() }), 'cursor-pointer hover:bg-accent hover:text-accent-foreground', this.class()), ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
3068
|
-
onClick() {
|
|
3069
|
-
this.dropdown?.close();
|
|
4039
|
+
this.renderer.appendChild(document.body, tooltip);
|
|
4040
|
+
this.tooltipEl = tooltip;
|
|
4041
|
+
this.positionTooltip();
|
|
3070
4042
|
}
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
static
|
|
4043
|
+
positionTooltip() {
|
|
4044
|
+
if (!this.tooltipEl)
|
|
4045
|
+
return;
|
|
4046
|
+
const hostRect = this.el.nativeElement.getBoundingClientRect();
|
|
4047
|
+
const tooltipRect = this.tooltipEl.getBoundingClientRect();
|
|
4048
|
+
const position = this.tooltipPosition();
|
|
4049
|
+
const gap = 8;
|
|
4050
|
+
let top = 0;
|
|
4051
|
+
let left = 0;
|
|
4052
|
+
switch (position) {
|
|
4053
|
+
case 'top':
|
|
4054
|
+
top = hostRect.top - tooltipRect.height - gap;
|
|
4055
|
+
left = hostRect.left + (hostRect.width - tooltipRect.width) / 2;
|
|
4056
|
+
break;
|
|
4057
|
+
case 'bottom':
|
|
4058
|
+
top = hostRect.bottom + gap;
|
|
4059
|
+
left = hostRect.left + (hostRect.width - tooltipRect.width) / 2;
|
|
4060
|
+
break;
|
|
4061
|
+
case 'left':
|
|
4062
|
+
top = hostRect.top + (hostRect.height - tooltipRect.height) / 2;
|
|
4063
|
+
left = hostRect.left - tooltipRect.width - gap;
|
|
4064
|
+
break;
|
|
4065
|
+
case 'right':
|
|
4066
|
+
top = hostRect.top + (hostRect.height - tooltipRect.height) / 2;
|
|
4067
|
+
left = hostRect.right + gap;
|
|
4068
|
+
break;
|
|
4069
|
+
}
|
|
4070
|
+
this.tooltipEl.style.top = `${top}px`;
|
|
4071
|
+
this.tooltipEl.style.left = `${left}px`;
|
|
4072
|
+
}
|
|
4073
|
+
destroyTooltip() {
|
|
4074
|
+
if (this.tooltipEl) {
|
|
4075
|
+
this.tooltipEl.remove();
|
|
4076
|
+
this.tooltipEl = null;
|
|
4077
|
+
}
|
|
4078
|
+
}
|
|
4079
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyTooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
4080
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: SnyTooltipDirective, isStandalone: true, selector: "[snyTooltip]", inputs: { snyTooltip: { classPropertyName: "snyTooltip", publicName: "snyTooltip", isSignal: true, isRequired: true, transformFunction: null }, tooltipPosition: { classPropertyName: "tooltipPosition", publicName: "tooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, tooltipDelay: { classPropertyName: "tooltipDelay", publicName: "tooltipDelay", isSignal: true, isRequired: false, transformFunction: null }, tooltipDisabled: { classPropertyName: "tooltipDisabled", publicName: "tooltipDisabled", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "show()", "mouseleave": "hide()", "focus": "show()", "blur": "hide()", "keydown.escape": "hide()" }, properties: { "attr.aria-describedby": "isOpen() ? tooltipId : null" } }, exportAs: ["snyTooltip"], ngImport: i0 });
|
|
3108
4081
|
}
|
|
3109
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type:
|
|
4082
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyTooltipDirective, decorators: [{
|
|
3110
4083
|
type: Directive,
|
|
3111
4084
|
args: [{
|
|
3112
|
-
selector: '[
|
|
4085
|
+
selector: '[snyTooltip]',
|
|
3113
4086
|
standalone: true,
|
|
4087
|
+
exportAs: 'snyTooltip',
|
|
3114
4088
|
host: {
|
|
3115
|
-
'
|
|
4089
|
+
'(mouseenter)': 'show()',
|
|
4090
|
+
'(mouseleave)': 'hide()',
|
|
4091
|
+
'(focus)': 'show()',
|
|
4092
|
+
'(blur)': 'hide()',
|
|
4093
|
+
'(keydown.escape)': 'hide()',
|
|
4094
|
+
'[attr.aria-describedby]': 'isOpen() ? tooltipId : null',
|
|
3116
4095
|
},
|
|
3117
4096
|
}]
|
|
3118
|
-
}], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
4097
|
+
}], ctorParameters: () => [], propDecorators: { snyTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "snyTooltip", required: true }] }], tooltipPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipPosition", required: false }] }], tooltipDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipDelay", required: false }] }], tooltipDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipDisabled", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
3119
4098
|
|
|
3120
4099
|
const fileInputVariants = cva('flex w-full cursor-pointer items-center gap-2 rounded-md border bg-background px-3 py-2 text-sm ring-offset-background transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50', {
|
|
3121
4100
|
variants: {
|
|
@@ -3644,219 +4623,45 @@ class SnyDrawerContentDirective {
|
|
|
3644
4623
|
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: SnyDrawerContentDirective, isStandalone: true, selector: "[snyDrawerContent]", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "computedClass()" } }, ngImport: i0 });
|
|
3645
4624
|
}
|
|
3646
4625
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDrawerContentDirective, decorators: [{
|
|
3647
|
-
type: Directive,
|
|
3648
|
-
args: [{
|
|
3649
|
-
selector: '[snyDrawerContent]',
|
|
3650
|
-
standalone: true,
|
|
3651
|
-
host: {
|
|
3652
|
-
'[class]': 'computedClass()',
|
|
3653
|
-
},
|
|
3654
|
-
}]
|
|
3655
|
-
}], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
3656
|
-
class SnyDrawerSideDirective {
|
|
3657
|
-
drawer = inject(SNY_DRAWER);
|
|
3658
|
-
side = input('left', ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
|
|
3659
|
-
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
3660
|
-
computedClass = computed(() => {
|
|
3661
|
-
const isOpen = this.drawer.isOpen();
|
|
3662
|
-
const s = this.side();
|
|
3663
|
-
const base = 'fixed inset-y-0 z-40 w-64 bg-background border-r border-border transition-transform duration-300 ease-in-out';
|
|
3664
|
-
const sideClass = s === 'left' ? 'left-0' : 'right-0 border-l border-r-0';
|
|
3665
|
-
const transformClass = isOpen
|
|
3666
|
-
? 'translate-x-0'
|
|
3667
|
-
: s === 'left' ? '-translate-x-full' : 'translate-x-full';
|
|
3668
|
-
return cn(base, sideClass, transformClass, this.class());
|
|
3669
|
-
}, ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
3670
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDrawerSideDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3671
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: SnyDrawerSideDirective, isStandalone: true, selector: "[snyDrawerSide]", inputs: { side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "navigation", "aria-label": "Sidebar navigation" }, properties: { "attr.aria-modal": "drawer.overlay() && drawer.isOpen() || null", "class": "computedClass()" } }, ngImport: i0 });
|
|
3672
|
-
}
|
|
3673
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDrawerSideDirective, decorators: [{
|
|
3674
|
-
type: Directive,
|
|
3675
|
-
args: [{
|
|
3676
|
-
selector: '[snyDrawerSide]',
|
|
3677
|
-
standalone: true,
|
|
3678
|
-
host: {
|
|
3679
|
-
'role': 'navigation',
|
|
3680
|
-
'aria-label': 'Sidebar navigation',
|
|
3681
|
-
'[attr.aria-modal]': 'drawer.overlay() && drawer.isOpen() || null',
|
|
3682
|
-
'[class]': 'computedClass()',
|
|
3683
|
-
},
|
|
3684
|
-
}]
|
|
3685
|
-
}], propDecorators: { side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
3686
|
-
|
|
3687
|
-
const paginationItemVariants = cva('inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50', {
|
|
3688
|
-
variants: {
|
|
3689
|
-
variant: {
|
|
3690
|
-
default: 'bg-background hover:bg-accent hover:text-accent-foreground',
|
|
3691
|
-
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
|
|
3692
|
-
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
|
3693
|
-
},
|
|
3694
|
-
size: {
|
|
3695
|
-
sm: 'h-8 w-8 text-xs',
|
|
3696
|
-
md: 'h-9 w-9',
|
|
3697
|
-
lg: 'h-10 w-10',
|
|
3698
|
-
},
|
|
3699
|
-
active: {
|
|
3700
|
-
true: 'bg-primary text-primary-foreground hover:bg-primary/90 hover:text-primary-foreground',
|
|
3701
|
-
false: '',
|
|
3702
|
-
},
|
|
3703
|
-
},
|
|
3704
|
-
defaultVariants: {
|
|
3705
|
-
variant: 'default',
|
|
3706
|
-
size: 'md',
|
|
3707
|
-
active: false,
|
|
3708
|
-
},
|
|
3709
|
-
});
|
|
3710
|
-
|
|
3711
|
-
function computePageRange(totalPages, currentPage, siblingCount, boundaryCount) {
|
|
3712
|
-
const range = (start, end) => Array.from({ length: end - start + 1 }, (_, i) => start + i);
|
|
3713
|
-
const startPages = range(1, Math.min(boundaryCount, totalPages));
|
|
3714
|
-
const endPages = range(Math.max(totalPages - boundaryCount + 1, boundaryCount + 1), totalPages);
|
|
3715
|
-
const siblingsStart = Math.max(Math.min(currentPage - siblingCount, totalPages - boundaryCount - siblingCount * 2 - 1), boundaryCount + 2);
|
|
3716
|
-
const siblingsEnd = Math.min(Math.max(currentPage + siblingCount, boundaryCount + siblingCount * 2 + 2), endPages.length > 0 ? endPages[0] - 2 : totalPages - 1);
|
|
3717
|
-
const result = [...startPages];
|
|
3718
|
-
if (siblingsStart > boundaryCount + 2) {
|
|
3719
|
-
result.push('ellipsis');
|
|
3720
|
-
}
|
|
3721
|
-
else if (boundaryCount + 1 < totalPages - boundaryCount) {
|
|
3722
|
-
result.push(boundaryCount + 1);
|
|
3723
|
-
}
|
|
3724
|
-
result.push(...range(siblingsStart, siblingsEnd));
|
|
3725
|
-
if (siblingsEnd < totalPages - boundaryCount - 1) {
|
|
3726
|
-
result.push('ellipsis');
|
|
3727
|
-
}
|
|
3728
|
-
else if (totalPages - boundaryCount > boundaryCount) {
|
|
3729
|
-
result.push(totalPages - boundaryCount);
|
|
3730
|
-
}
|
|
3731
|
-
result.push(...endPages);
|
|
3732
|
-
return [...new Set(result)].sort((a, b) => {
|
|
3733
|
-
if (a === 'ellipsis')
|
|
3734
|
-
return 0;
|
|
3735
|
-
if (b === 'ellipsis')
|
|
3736
|
-
return 0;
|
|
3737
|
-
return a - b;
|
|
3738
|
-
});
|
|
3739
|
-
}
|
|
3740
|
-
class SnyPaginationComponent {
|
|
3741
|
-
currentPage = model(1, ...(ngDevMode ? [{ debugName: "currentPage" }] : /* istanbul ignore next */ []));
|
|
3742
|
-
totalPages = input.required(...(ngDevMode ? [{ debugName: "totalPages" }] : /* istanbul ignore next */ []));
|
|
3743
|
-
siblingCount = input(1, ...(ngDevMode ? [{ debugName: "siblingCount" }] : /* istanbul ignore next */ []));
|
|
3744
|
-
boundaryCount = input(1, ...(ngDevMode ? [{ debugName: "boundaryCount" }] : /* istanbul ignore next */ []));
|
|
3745
|
-
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
3746
|
-
variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
3747
|
-
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
3748
|
-
pages = computed(() => computePageRange(this.totalPages(), this.currentPage(), this.siblingCount(), this.boundaryCount()), ...(ngDevMode ? [{ debugName: "pages" }] : /* istanbul ignore next */ []));
|
|
3749
|
-
hasPrev = computed(() => this.currentPage() > 1, ...(ngDevMode ? [{ debugName: "hasPrev" }] : /* istanbul ignore next */ []));
|
|
3750
|
-
hasNext = computed(() => this.currentPage() < this.totalPages(), ...(ngDevMode ? [{ debugName: "hasNext" }] : /* istanbul ignore next */ []));
|
|
3751
|
-
goToPage(page) {
|
|
3752
|
-
if (page === 'ellipsis')
|
|
3753
|
-
return;
|
|
3754
|
-
this.currentPage.set(page);
|
|
3755
|
-
}
|
|
3756
|
-
prev() {
|
|
3757
|
-
if (this.hasPrev())
|
|
3758
|
-
this.currentPage.update((p) => p - 1);
|
|
3759
|
-
}
|
|
3760
|
-
next() {
|
|
3761
|
-
if (this.hasNext())
|
|
3762
|
-
this.currentPage.update((p) => p + 1);
|
|
3763
|
-
}
|
|
3764
|
-
pageClass(page) {
|
|
3765
|
-
return cn(paginationItemVariants({
|
|
3766
|
-
variant: this.variant(),
|
|
3767
|
-
size: this.size(),
|
|
3768
|
-
active: page === this.currentPage(),
|
|
3769
|
-
}));
|
|
3770
|
-
}
|
|
3771
|
-
navBtnClass() {
|
|
3772
|
-
return cn(paginationItemVariants({ variant: this.variant(), size: this.size(), active: false }));
|
|
3773
|
-
}
|
|
3774
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyPaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3775
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: SnyPaginationComponent, isStandalone: true, selector: "sny-pagination", inputs: { currentPage: { classPropertyName: "currentPage", publicName: "currentPage", isSignal: true, isRequired: false, transformFunction: null }, totalPages: { classPropertyName: "totalPages", publicName: "totalPages", isSignal: true, isRequired: true, transformFunction: null }, siblingCount: { classPropertyName: "siblingCount", publicName: "siblingCount", isSignal: true, isRequired: false, transformFunction: null }, boundaryCount: { classPropertyName: "boundaryCount", publicName: "boundaryCount", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { currentPage: "currentPageChange" }, host: { attributes: { "role": "navigation", "aria-label": "Pagination" } }, ngImport: i0, template: `
|
|
3776
|
-
<div class="flex items-center gap-1">
|
|
3777
|
-
<button
|
|
3778
|
-
[class]="navBtnClass()"
|
|
3779
|
-
[disabled]="!hasPrev()"
|
|
3780
|
-
[attr.aria-label]="'Go to previous page'"
|
|
3781
|
-
(click)="prev()"
|
|
3782
|
-
>
|
|
3783
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
|
|
3784
|
-
</button>
|
|
3785
|
-
|
|
3786
|
-
@for (page of pages(); track $index) {
|
|
3787
|
-
@if (page === 'ellipsis') {
|
|
3788
|
-
<span class="flex h-9 w-9 items-center justify-center" aria-hidden="true">...</span>
|
|
3789
|
-
} @else {
|
|
3790
|
-
<button
|
|
3791
|
-
[class]="pageClass(page)"
|
|
3792
|
-
[attr.aria-label]="'Page ' + page"
|
|
3793
|
-
[attr.aria-current]="page === currentPage() ? 'page' : null"
|
|
3794
|
-
(click)="goToPage(page)"
|
|
3795
|
-
>
|
|
3796
|
-
{{ page }}
|
|
3797
|
-
</button>
|
|
3798
|
-
}
|
|
3799
|
-
}
|
|
3800
|
-
|
|
3801
|
-
<button
|
|
3802
|
-
[class]="navBtnClass()"
|
|
3803
|
-
[disabled]="!hasNext()"
|
|
3804
|
-
[attr.aria-label]="'Go to next page'"
|
|
3805
|
-
(click)="next()"
|
|
3806
|
-
>
|
|
3807
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
|
|
3808
|
-
</button>
|
|
3809
|
-
</div>
|
|
3810
|
-
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4626
|
+
type: Directive,
|
|
4627
|
+
args: [{
|
|
4628
|
+
selector: '[snyDrawerContent]',
|
|
4629
|
+
standalone: true,
|
|
4630
|
+
host: {
|
|
4631
|
+
'[class]': 'computedClass()',
|
|
4632
|
+
},
|
|
4633
|
+
}]
|
|
4634
|
+
}], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
4635
|
+
class SnyDrawerSideDirective {
|
|
4636
|
+
drawer = inject(SNY_DRAWER);
|
|
4637
|
+
side = input('left', ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
|
|
4638
|
+
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
4639
|
+
computedClass = computed(() => {
|
|
4640
|
+
const isOpen = this.drawer.isOpen();
|
|
4641
|
+
const s = this.side();
|
|
4642
|
+
const base = 'fixed inset-y-0 z-40 w-64 bg-background border-r border-border transition-transform duration-300 ease-in-out';
|
|
4643
|
+
const sideClass = s === 'left' ? 'left-0' : 'right-0 border-l border-r-0';
|
|
4644
|
+
const transformClass = isOpen
|
|
4645
|
+
? 'translate-x-0'
|
|
4646
|
+
: s === 'left' ? '-translate-x-full' : 'translate-x-full';
|
|
4647
|
+
return cn(base, sideClass, transformClass, this.class());
|
|
4648
|
+
}, ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
4649
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDrawerSideDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
4650
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: SnyDrawerSideDirective, isStandalone: true, selector: "[snyDrawerSide]", inputs: { side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "navigation", "aria-label": "Sidebar navigation" }, properties: { "attr.aria-modal": "drawer.overlay() && drawer.isOpen() || null", "class": "computedClass()" } }, ngImport: i0 });
|
|
3811
4651
|
}
|
|
3812
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type:
|
|
3813
|
-
type:
|
|
4652
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDrawerSideDirective, decorators: [{
|
|
4653
|
+
type: Directive,
|
|
3814
4654
|
args: [{
|
|
3815
|
-
selector: '
|
|
4655
|
+
selector: '[snyDrawerSide]',
|
|
3816
4656
|
standalone: true,
|
|
3817
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
3818
4657
|
host: {
|
|
3819
4658
|
'role': 'navigation',
|
|
3820
|
-
'aria-label': '
|
|
4659
|
+
'aria-label': 'Sidebar navigation',
|
|
4660
|
+
'[attr.aria-modal]': 'drawer.overlay() && drawer.isOpen() || null',
|
|
4661
|
+
'[class]': 'computedClass()',
|
|
3821
4662
|
},
|
|
3822
|
-
template: `
|
|
3823
|
-
<div class="flex items-center gap-1">
|
|
3824
|
-
<button
|
|
3825
|
-
[class]="navBtnClass()"
|
|
3826
|
-
[disabled]="!hasPrev()"
|
|
3827
|
-
[attr.aria-label]="'Go to previous page'"
|
|
3828
|
-
(click)="prev()"
|
|
3829
|
-
>
|
|
3830
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
|
|
3831
|
-
</button>
|
|
3832
|
-
|
|
3833
|
-
@for (page of pages(); track $index) {
|
|
3834
|
-
@if (page === 'ellipsis') {
|
|
3835
|
-
<span class="flex h-9 w-9 items-center justify-center" aria-hidden="true">...</span>
|
|
3836
|
-
} @else {
|
|
3837
|
-
<button
|
|
3838
|
-
[class]="pageClass(page)"
|
|
3839
|
-
[attr.aria-label]="'Page ' + page"
|
|
3840
|
-
[attr.aria-current]="page === currentPage() ? 'page' : null"
|
|
3841
|
-
(click)="goToPage(page)"
|
|
3842
|
-
>
|
|
3843
|
-
{{ page }}
|
|
3844
|
-
</button>
|
|
3845
|
-
}
|
|
3846
|
-
}
|
|
3847
|
-
|
|
3848
|
-
<button
|
|
3849
|
-
[class]="navBtnClass()"
|
|
3850
|
-
[disabled]="!hasNext()"
|
|
3851
|
-
[attr.aria-label]="'Go to next page'"
|
|
3852
|
-
(click)="next()"
|
|
3853
|
-
>
|
|
3854
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
|
|
3855
|
-
</button>
|
|
3856
|
-
</div>
|
|
3857
|
-
`,
|
|
3858
4663
|
}]
|
|
3859
|
-
}], propDecorators: {
|
|
4664
|
+
}], propDecorators: { side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
3860
4665
|
|
|
3861
4666
|
const dividerVariants = cva('shrink-0 bg-border', {
|
|
3862
4667
|
variants: {
|
|
@@ -4961,93 +5766,714 @@ class SnyDiffComponent {
|
|
|
4961
5766
|
</div>
|
|
4962
5767
|
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4963
5768
|
}
|
|
4964
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDiffComponent, decorators: [{
|
|
5769
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDiffComponent, decorators: [{
|
|
5770
|
+
type: Component,
|
|
5771
|
+
args: [{
|
|
5772
|
+
selector: 'sny-diff',
|
|
5773
|
+
standalone: true,
|
|
5774
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
5775
|
+
host: {
|
|
5776
|
+
'[class]': '"relative overflow-hidden select-none w-full"',
|
|
5777
|
+
'(pointerdown)': 'onPointerDown($event)',
|
|
5778
|
+
'(pointermove)': 'onPointerMove($event)',
|
|
5779
|
+
'(pointerup)': 'onPointerUp()',
|
|
5780
|
+
'(keydown)': 'onKeydown($event)',
|
|
5781
|
+
},
|
|
5782
|
+
template: `
|
|
5783
|
+
<div class="relative w-full" [style.aspect-ratio]="'16/9'">
|
|
5784
|
+
<div class="absolute inset-0">
|
|
5785
|
+
<ng-content select="[snyDiffAfter]" />
|
|
5786
|
+
</div>
|
|
5787
|
+
<div class="absolute inset-0 overflow-hidden" [style.width.%]="value()">
|
|
5788
|
+
<ng-content select="[snyDiffBefore]" />
|
|
5789
|
+
</div>
|
|
5790
|
+
<div
|
|
5791
|
+
class="absolute top-0 bottom-0 w-1 bg-foreground cursor-col-resize z-10"
|
|
5792
|
+
[style.left.%]="value()"
|
|
5793
|
+
role="slider"
|
|
5794
|
+
tabindex="0"
|
|
5795
|
+
[attr.aria-valuenow]="value()"
|
|
5796
|
+
aria-valuemin="0"
|
|
5797
|
+
aria-valuemax="100"
|
|
5798
|
+
aria-label="Comparison slider"
|
|
5799
|
+
>
|
|
5800
|
+
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-8 h-8 rounded-full bg-foreground/80 flex items-center justify-center text-background text-xs">
|
|
5801
|
+
⇔
|
|
5802
|
+
</div>
|
|
5803
|
+
</div>
|
|
5804
|
+
</div>
|
|
5805
|
+
`,
|
|
5806
|
+
}]
|
|
5807
|
+
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
5808
|
+
|
|
5809
|
+
const linkVariants = cva('inline-flex items-center gap-1 underline-offset-4 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded', {
|
|
5810
|
+
variants: {
|
|
5811
|
+
variant: {
|
|
5812
|
+
default: 'text-foreground underline hover:text-foreground/80',
|
|
5813
|
+
primary: 'text-primary underline hover:text-primary/80',
|
|
5814
|
+
secondary: 'text-muted-foreground underline hover:text-foreground',
|
|
5815
|
+
hover: 'text-foreground no-underline hover:underline',
|
|
5816
|
+
},
|
|
5817
|
+
},
|
|
5818
|
+
defaultVariants: {
|
|
5819
|
+
variant: 'default',
|
|
5820
|
+
},
|
|
5821
|
+
});
|
|
5822
|
+
|
|
5823
|
+
class SnyLinkDirective {
|
|
5824
|
+
variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
5825
|
+
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
5826
|
+
computedClass = computed(() => cn(linkVariants({ variant: this.variant() }), this.class()), ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
|
|
5827
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyLinkDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
5828
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: SnyLinkDirective, isStandalone: true, selector: "a[snyLink]", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "computedClass()" } }, ngImport: i0 });
|
|
5829
|
+
}
|
|
5830
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyLinkDirective, decorators: [{
|
|
5831
|
+
type: Directive,
|
|
5832
|
+
args: [{
|
|
5833
|
+
selector: 'a[snyLink]',
|
|
5834
|
+
standalone: true,
|
|
5835
|
+
host: {
|
|
5836
|
+
'[class]': 'computedClass()',
|
|
5837
|
+
},
|
|
5838
|
+
}]
|
|
5839
|
+
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
|
|
5840
|
+
|
|
5841
|
+
class SnyCalendarComponent {
|
|
5842
|
+
// Existing inputs (backwards compatible)
|
|
5843
|
+
value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
5844
|
+
min = input(undefined, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
|
|
5845
|
+
max = input(undefined, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
|
|
5846
|
+
locale = input('en-US', ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
|
|
5847
|
+
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
5848
|
+
// Range mode inputs
|
|
5849
|
+
mode = input('single', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
|
|
5850
|
+
rangeValue = model(null, ...(ngDevMode ? [{ debugName: "rangeValue" }] : /* istanbul ignore next */ []));
|
|
5851
|
+
showNavigation = input(true, ...(ngDevMode ? [{ debugName: "showNavigation" }] : /* istanbul ignore next */ []));
|
|
5852
|
+
initialViewDate = input(undefined, ...(ngDevMode ? [{ debugName: "initialViewDate" }] : /* istanbul ignore next */ []));
|
|
5853
|
+
borderless = input(false, ...(ngDevMode ? [{ debugName: "borderless" }] : /* istanbul ignore next */ []));
|
|
5854
|
+
hostClass = computed(() => this.borderless()
|
|
5855
|
+
? 'inline-block p-3 bg-background'
|
|
5856
|
+
: 'inline-block p-4 rounded-md border border-border bg-background', ...(ngDevMode ? [{ debugName: "hostClass" }] : /* istanbul ignore next */ []));
|
|
5857
|
+
// Internal state
|
|
5858
|
+
_disabledByCva = signal(false, ...(ngDevMode ? [{ debugName: "_disabledByCva" }] : /* istanbul ignore next */ []));
|
|
5859
|
+
hoveredDate = signal(null, ...(ngDevMode ? [{ debugName: "hoveredDate" }] : /* istanbul ignore next */ []));
|
|
5860
|
+
viewDate = linkedSignal(() => this.initialViewDate() ?? new Date(), ...(ngDevMode ? [{ debugName: "viewDate" }] : /* istanbul ignore next */ []));
|
|
5861
|
+
weekDays = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
|
|
5862
|
+
// CVA
|
|
5863
|
+
_onChange = () => { };
|
|
5864
|
+
onTouched = () => { };
|
|
5865
|
+
writeValue(val) {
|
|
5866
|
+
if (this.mode() === 'range') {
|
|
5867
|
+
this.rangeValue.set(val ?? null);
|
|
5868
|
+
const range = val;
|
|
5869
|
+
if (range?.start) {
|
|
5870
|
+
this.viewDate.set(new Date(range.start.getFullYear(), range.start.getMonth(), 1));
|
|
5871
|
+
}
|
|
5872
|
+
}
|
|
5873
|
+
else {
|
|
5874
|
+
this.value.set(val ?? null);
|
|
5875
|
+
if (val) {
|
|
5876
|
+
const d = val;
|
|
5877
|
+
this.viewDate.set(new Date(d.getFullYear(), d.getMonth(), 1));
|
|
5878
|
+
}
|
|
5879
|
+
}
|
|
5880
|
+
}
|
|
5881
|
+
registerOnChange(fn) {
|
|
5882
|
+
this._onChange = fn;
|
|
5883
|
+
}
|
|
5884
|
+
registerOnTouched(fn) {
|
|
5885
|
+
this.onTouched = fn;
|
|
5886
|
+
}
|
|
5887
|
+
setDisabledState(isDisabled) {
|
|
5888
|
+
this._disabledByCva.set(isDisabled);
|
|
5889
|
+
}
|
|
5890
|
+
// Computed
|
|
5891
|
+
monthYearLabel = computed(() => {
|
|
5892
|
+
const d = this.viewDate();
|
|
5893
|
+
return d.toLocaleDateString(this.locale(), { month: 'long', year: 'numeric' });
|
|
5894
|
+
}, ...(ngDevMode ? [{ debugName: "monthYearLabel" }] : /* istanbul ignore next */ []));
|
|
5895
|
+
days = computed(() => {
|
|
5896
|
+
const view = this.viewDate();
|
|
5897
|
+
const year = view.getFullYear();
|
|
5898
|
+
const month = view.getMonth();
|
|
5899
|
+
const today = new Date();
|
|
5900
|
+
const selected = this.value();
|
|
5901
|
+
const rangeVal = this.mode() === 'range' ? this.rangeValue() : null;
|
|
5902
|
+
const hovered = this.hoveredDate();
|
|
5903
|
+
const minDate = this.min();
|
|
5904
|
+
const maxDate = this.max();
|
|
5905
|
+
const firstDay = new Date(year, month, 1);
|
|
5906
|
+
const startDay = firstDay.getDay();
|
|
5907
|
+
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
5908
|
+
const daysInPrevMonth = new Date(year, month, 0).getDate();
|
|
5909
|
+
const days = [];
|
|
5910
|
+
for (let i = startDay - 1; i >= 0; i--) {
|
|
5911
|
+
const date = new Date(year, month - 1, daysInPrevMonth - i);
|
|
5912
|
+
days.push(this.createDay(date, false, today, selected, rangeVal, hovered, minDate, maxDate));
|
|
5913
|
+
}
|
|
5914
|
+
for (let d = 1; d <= daysInMonth; d++) {
|
|
5915
|
+
const date = new Date(year, month, d);
|
|
5916
|
+
days.push(this.createDay(date, true, today, selected, rangeVal, hovered, minDate, maxDate));
|
|
5917
|
+
}
|
|
5918
|
+
const remaining = 42 - days.length;
|
|
5919
|
+
for (let d = 1; d <= remaining; d++) {
|
|
5920
|
+
const date = new Date(year, month + 1, d);
|
|
5921
|
+
days.push(this.createDay(date, false, today, selected, rangeVal, hovered, minDate, maxDate));
|
|
5922
|
+
}
|
|
5923
|
+
return days;
|
|
5924
|
+
}, ...(ngDevMode ? [{ debugName: "days" }] : /* istanbul ignore next */ []));
|
|
5925
|
+
// Navigation
|
|
5926
|
+
prevMonth() {
|
|
5927
|
+
this.viewDate.set(new Date(this.viewDate().getFullYear(), this.viewDate().getMonth() - 1, 1));
|
|
5928
|
+
}
|
|
5929
|
+
nextMonth() {
|
|
5930
|
+
this.viewDate.set(new Date(this.viewDate().getFullYear(), this.viewDate().getMonth() + 1, 1));
|
|
5931
|
+
}
|
|
5932
|
+
// Click handler
|
|
5933
|
+
onDayClick(date) {
|
|
5934
|
+
if (this.mode() === 'single') {
|
|
5935
|
+
this.value.set(date);
|
|
5936
|
+
this._onChange(date);
|
|
5937
|
+
this.onTouched();
|
|
5938
|
+
return;
|
|
5939
|
+
}
|
|
5940
|
+
// Range mode
|
|
5941
|
+
const current = this.rangeValue();
|
|
5942
|
+
if (!current?.start || (current.start && current.end)) {
|
|
5943
|
+
this.rangeValue.set({ start: date, end: null });
|
|
5944
|
+
}
|
|
5945
|
+
else {
|
|
5946
|
+
const start = current.start;
|
|
5947
|
+
if (date < start) {
|
|
5948
|
+
this.rangeValue.set({ start: date, end: start });
|
|
5949
|
+
}
|
|
5950
|
+
else if (this.isSameDay(date, start)) {
|
|
5951
|
+
this.rangeValue.set({ start: date, end: date });
|
|
5952
|
+
}
|
|
5953
|
+
else {
|
|
5954
|
+
this.rangeValue.set({ start, end: date });
|
|
5955
|
+
}
|
|
5956
|
+
}
|
|
5957
|
+
this._onChange(this.rangeValue());
|
|
5958
|
+
this.onTouched();
|
|
5959
|
+
}
|
|
5960
|
+
// Hover handler
|
|
5961
|
+
onDayHover(date) {
|
|
5962
|
+
if (this.mode() === 'range') {
|
|
5963
|
+
this.hoveredDate.set(date);
|
|
5964
|
+
}
|
|
5965
|
+
}
|
|
5966
|
+
// Keyboard
|
|
5967
|
+
onKeydown(event) {
|
|
5968
|
+
switch (event.key) {
|
|
5969
|
+
case 'ArrowLeft':
|
|
5970
|
+
event.preventDefault();
|
|
5971
|
+
this.navigateDays(-1);
|
|
5972
|
+
break;
|
|
5973
|
+
case 'ArrowRight':
|
|
5974
|
+
event.preventDefault();
|
|
5975
|
+
this.navigateDays(1);
|
|
5976
|
+
break;
|
|
5977
|
+
case 'ArrowUp':
|
|
5978
|
+
event.preventDefault();
|
|
5979
|
+
this.navigateDays(-7);
|
|
5980
|
+
break;
|
|
5981
|
+
case 'ArrowDown':
|
|
5982
|
+
event.preventDefault();
|
|
5983
|
+
this.navigateDays(7);
|
|
5984
|
+
break;
|
|
5985
|
+
}
|
|
5986
|
+
}
|
|
5987
|
+
// Styling
|
|
5988
|
+
dayClass(day) {
|
|
5989
|
+
const isEndpoint = day.isRangeStart || day.isRangeEnd;
|
|
5990
|
+
return cn('inline-flex items-center justify-center text-sm h-9 w-9 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
|
5991
|
+
// Shape
|
|
5992
|
+
day.isRangeStart && !day.isRangeEnd ? 'rounded-l-md rounded-r-none' :
|
|
5993
|
+
day.isRangeEnd && !day.isRangeStart ? 'rounded-r-md rounded-l-none' :
|
|
5994
|
+
day.isInRange || day.isRangePreview ? 'rounded-none' :
|
|
5995
|
+
'rounded-md',
|
|
5996
|
+
// Base text color
|
|
5997
|
+
!day.isCurrentMonth && 'text-muted-foreground/40', day.isCurrentMonth && !day.isSelected && !isEndpoint && 'text-foreground',
|
|
5998
|
+
// Today indicator
|
|
5999
|
+
day.isToday && !day.isSelected && !isEndpoint && 'bg-accent text-accent-foreground font-semibold',
|
|
6000
|
+
// Single selected
|
|
6001
|
+
day.isSelected && this.mode() === 'single' && 'bg-primary text-primary-foreground font-semibold shadow-sm',
|
|
6002
|
+
// Range endpoints
|
|
6003
|
+
isEndpoint && 'bg-primary text-primary-foreground font-semibold shadow-sm',
|
|
6004
|
+
// Range band
|
|
6005
|
+
day.isInRange && 'bg-primary/10 text-foreground', day.isRangePreview && 'bg-primary/5 text-foreground',
|
|
6006
|
+
// States
|
|
6007
|
+
day.isDisabled && 'opacity-40 cursor-not-allowed pointer-events-none', !day.isDisabled && !day.isSelected && !isEndpoint && 'hover:bg-accent hover:text-accent-foreground cursor-pointer');
|
|
6008
|
+
}
|
|
6009
|
+
// Private helpers
|
|
6010
|
+
navigateDays(offset) {
|
|
6011
|
+
const current = this.value() ?? new Date();
|
|
6012
|
+
const next = new Date(current);
|
|
6013
|
+
next.setDate(next.getDate() + offset);
|
|
6014
|
+
this.value.set(next);
|
|
6015
|
+
this._onChange(next);
|
|
6016
|
+
this.viewDate.set(new Date(next.getFullYear(), next.getMonth(), 1));
|
|
6017
|
+
}
|
|
6018
|
+
createDay(date, isCurrentMonth, today, selected, rangeVal, hoveredDate, minDate, maxDate) {
|
|
6019
|
+
const isToday = this.isSameDay(date, today);
|
|
6020
|
+
const isSelected = selected ? this.isSameDay(date, selected) : false;
|
|
6021
|
+
const isDisabled = this._disabledByCva() ||
|
|
6022
|
+
(minDate ? date < minDate : false) ||
|
|
6023
|
+
(maxDate ? date > maxDate : false);
|
|
6024
|
+
let isRangeStart = false;
|
|
6025
|
+
let isRangeEnd = false;
|
|
6026
|
+
let isInRange = false;
|
|
6027
|
+
let isRangePreview = false;
|
|
6028
|
+
if (rangeVal) {
|
|
6029
|
+
const { start, end } = rangeVal;
|
|
6030
|
+
if (start)
|
|
6031
|
+
isRangeStart = this.isSameDay(date, start);
|
|
6032
|
+
if (end)
|
|
6033
|
+
isRangeEnd = this.isSameDay(date, end);
|
|
6034
|
+
if (start && end) {
|
|
6035
|
+
isInRange = date > start && date < end && !isRangeStart && !isRangeEnd;
|
|
6036
|
+
}
|
|
6037
|
+
// Preview: start set, no end yet, user hovering
|
|
6038
|
+
if (start && !end && hoveredDate && !this.isSameDay(hoveredDate, start)) {
|
|
6039
|
+
const previewStart = hoveredDate > start ? start : hoveredDate;
|
|
6040
|
+
const previewEnd = hoveredDate > start ? hoveredDate : start;
|
|
6041
|
+
if (date > previewStart && date < previewEnd) {
|
|
6042
|
+
isRangePreview = true;
|
|
6043
|
+
}
|
|
6044
|
+
if (this.isSameDay(date, hoveredDate) && !isRangeStart) {
|
|
6045
|
+
isRangePreview = true;
|
|
6046
|
+
}
|
|
6047
|
+
}
|
|
6048
|
+
}
|
|
6049
|
+
return {
|
|
6050
|
+
date, day: date.getDate(), isCurrentMonth, isToday, isSelected, isDisabled,
|
|
6051
|
+
isRangeStart, isRangeEnd, isInRange, isRangePreview,
|
|
6052
|
+
};
|
|
6053
|
+
}
|
|
6054
|
+
isSameDay(a, b) {
|
|
6055
|
+
return (a.getFullYear() === b.getFullYear() &&
|
|
6056
|
+
a.getMonth() === b.getMonth() &&
|
|
6057
|
+
a.getDate() === b.getDate());
|
|
6058
|
+
}
|
|
6059
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6060
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: SnyCalendarComponent, isStandalone: true, selector: "sny-calendar", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, rangeValue: { classPropertyName: "rangeValue", publicName: "rangeValue", isSignal: true, isRequired: false, transformFunction: null }, showNavigation: { classPropertyName: "showNavigation", publicName: "showNavigation", isSignal: true, isRequired: false, transformFunction: null }, initialViewDate: { classPropertyName: "initialViewDate", publicName: "initialViewDate", isSignal: true, isRequired: false, transformFunction: null }, borderless: { classPropertyName: "borderless", publicName: "borderless", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", rangeValue: "rangeValueChange" }, host: { attributes: { "role": "application", "aria-label": "Calendar" }, listeners: { "keydown": "onKeydown($event)" }, properties: { "class": "hostClass()" } }, providers: [
|
|
6061
|
+
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SnyCalendarComponent), multi: true },
|
|
6062
|
+
], ngImport: i0, template: `
|
|
6063
|
+
@if (showNavigation()) {
|
|
6064
|
+
<div class="flex items-center justify-between mb-3">
|
|
6065
|
+
<button
|
|
6066
|
+
type="button"
|
|
6067
|
+
class="inline-flex items-center justify-center rounded-md h-8 w-8 hover:bg-accent hover:text-accent-foreground transition-colors"
|
|
6068
|
+
(click)="prevMonth()"
|
|
6069
|
+
aria-label="Previous month"
|
|
6070
|
+
>
|
|
6071
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
|
|
6072
|
+
</button>
|
|
6073
|
+
<span class="text-sm font-semibold tracking-tight">{{ monthYearLabel() }}</span>
|
|
6074
|
+
<button
|
|
6075
|
+
type="button"
|
|
6076
|
+
class="inline-flex items-center justify-center rounded-md h-8 w-8 hover:bg-accent hover:text-accent-foreground transition-colors"
|
|
6077
|
+
(click)="nextMonth()"
|
|
6078
|
+
aria-label="Next month"
|
|
6079
|
+
>
|
|
6080
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
|
|
6081
|
+
</button>
|
|
6082
|
+
</div>
|
|
6083
|
+
}
|
|
6084
|
+
|
|
6085
|
+
<div role="grid" class="grid grid-cols-7 gap-1">
|
|
6086
|
+
@for (dayName of weekDays; track dayName) {
|
|
6087
|
+
<div class="text-center text-xs text-muted-foreground font-medium h-9 flex items-center justify-center" role="columnheader">{{ dayName }}</div>
|
|
6088
|
+
}
|
|
6089
|
+
@for (day of days(); track day.date.getTime()) {
|
|
6090
|
+
<button
|
|
6091
|
+
type="button"
|
|
6092
|
+
[class]="dayClass(day)"
|
|
6093
|
+
[disabled]="day.isDisabled"
|
|
6094
|
+
[attr.aria-selected]="day.isSelected || day.isRangeStart || day.isRangeEnd || null"
|
|
6095
|
+
[attr.aria-current]="day.isToday ? 'date' : null"
|
|
6096
|
+
[attr.aria-disabled]="day.isDisabled || null"
|
|
6097
|
+
[attr.aria-label]="day.date.toLocaleDateString(locale(), { month: 'long', day: 'numeric', year: 'numeric' })"
|
|
6098
|
+
role="gridcell"
|
|
6099
|
+
(click)="onDayClick(day.date)"
|
|
6100
|
+
(mouseenter)="onDayHover(day.date)"
|
|
6101
|
+
(mouseleave)="onDayHover(null)"
|
|
6102
|
+
>
|
|
6103
|
+
{{ day.day }}
|
|
6104
|
+
</button>
|
|
6105
|
+
}
|
|
6106
|
+
</div>
|
|
6107
|
+
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6108
|
+
}
|
|
6109
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyCalendarComponent, decorators: [{
|
|
4965
6110
|
type: Component,
|
|
4966
6111
|
args: [{
|
|
4967
|
-
selector: 'sny-
|
|
6112
|
+
selector: 'sny-calendar',
|
|
4968
6113
|
standalone: true,
|
|
4969
6114
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
4970
6115
|
host: {
|
|
4971
|
-
'[class]': '
|
|
4972
|
-
'(pointerdown)': 'onPointerDown($event)',
|
|
4973
|
-
'(pointermove)': 'onPointerMove($event)',
|
|
4974
|
-
'(pointerup)': 'onPointerUp()',
|
|
6116
|
+
'[class]': 'hostClass()',
|
|
4975
6117
|
'(keydown)': 'onKeydown($event)',
|
|
6118
|
+
'role': 'application',
|
|
6119
|
+
'aria-label': 'Calendar',
|
|
4976
6120
|
},
|
|
6121
|
+
providers: [
|
|
6122
|
+
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SnyCalendarComponent), multi: true },
|
|
6123
|
+
],
|
|
4977
6124
|
template: `
|
|
4978
|
-
|
|
4979
|
-
<div class="
|
|
4980
|
-
<
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
</div>
|
|
6125
|
+
@if (showNavigation()) {
|
|
6126
|
+
<div class="flex items-center justify-between mb-3">
|
|
6127
|
+
<button
|
|
6128
|
+
type="button"
|
|
6129
|
+
class="inline-flex items-center justify-center rounded-md h-8 w-8 hover:bg-accent hover:text-accent-foreground transition-colors"
|
|
6130
|
+
(click)="prevMonth()"
|
|
6131
|
+
aria-label="Previous month"
|
|
6132
|
+
>
|
|
6133
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
|
|
6134
|
+
</button>
|
|
6135
|
+
<span class="text-sm font-semibold tracking-tight">{{ monthYearLabel() }}</span>
|
|
6136
|
+
<button
|
|
6137
|
+
type="button"
|
|
6138
|
+
class="inline-flex items-center justify-center rounded-md h-8 w-8 hover:bg-accent hover:text-accent-foreground transition-colors"
|
|
6139
|
+
(click)="nextMonth()"
|
|
6140
|
+
aria-label="Next month"
|
|
6141
|
+
>
|
|
6142
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
|
|
6143
|
+
</button>
|
|
4998
6144
|
</div>
|
|
6145
|
+
}
|
|
6146
|
+
|
|
6147
|
+
<div role="grid" class="grid grid-cols-7 gap-1">
|
|
6148
|
+
@for (dayName of weekDays; track dayName) {
|
|
6149
|
+
<div class="text-center text-xs text-muted-foreground font-medium h-9 flex items-center justify-center" role="columnheader">{{ dayName }}</div>
|
|
6150
|
+
}
|
|
6151
|
+
@for (day of days(); track day.date.getTime()) {
|
|
6152
|
+
<button
|
|
6153
|
+
type="button"
|
|
6154
|
+
[class]="dayClass(day)"
|
|
6155
|
+
[disabled]="day.isDisabled"
|
|
6156
|
+
[attr.aria-selected]="day.isSelected || day.isRangeStart || day.isRangeEnd || null"
|
|
6157
|
+
[attr.aria-current]="day.isToday ? 'date' : null"
|
|
6158
|
+
[attr.aria-disabled]="day.isDisabled || null"
|
|
6159
|
+
[attr.aria-label]="day.date.toLocaleDateString(locale(), { month: 'long', day: 'numeric', year: 'numeric' })"
|
|
6160
|
+
role="gridcell"
|
|
6161
|
+
(click)="onDayClick(day.date)"
|
|
6162
|
+
(mouseenter)="onDayHover(day.date)"
|
|
6163
|
+
(mouseleave)="onDayHover(null)"
|
|
6164
|
+
>
|
|
6165
|
+
{{ day.day }}
|
|
6166
|
+
</button>
|
|
6167
|
+
}
|
|
4999
6168
|
</div>
|
|
5000
6169
|
`,
|
|
5001
6170
|
}]
|
|
5002
|
-
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }],
|
|
6171
|
+
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], rangeValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangeValue", required: false }] }, { type: i0.Output, args: ["rangeValueChange"] }], showNavigation: [{ type: i0.Input, args: [{ isSignal: true, alias: "showNavigation", required: false }] }], initialViewDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialViewDate", required: false }] }], borderless: [{ type: i0.Input, args: [{ isSignal: true, alias: "borderless", required: false }] }] } });
|
|
5003
6172
|
|
|
5004
|
-
const
|
|
6173
|
+
const datePickerTriggerVariants = cva('inline-flex w-full items-center justify-between whitespace-nowrap rounded-sm border border-border bg-background px-3 py-2 text-sm ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', {
|
|
5005
6174
|
variants: {
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
hover: 'text-foreground no-underline hover:underline',
|
|
6175
|
+
size: {
|
|
6176
|
+
sm: 'h-9 text-xs',
|
|
6177
|
+
md: 'h-10 text-sm',
|
|
6178
|
+
lg: 'h-11 text-base',
|
|
5011
6179
|
},
|
|
5012
6180
|
},
|
|
5013
|
-
defaultVariants: {
|
|
5014
|
-
variant: 'default',
|
|
5015
|
-
},
|
|
6181
|
+
defaultVariants: { size: 'md' },
|
|
5016
6182
|
});
|
|
5017
6183
|
|
|
5018
|
-
class
|
|
5019
|
-
|
|
6184
|
+
class SnyDatePickerComponent {
|
|
6185
|
+
value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
6186
|
+
placeholder = input('Pick a date...', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
6187
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
6188
|
+
locale = input('en-US', ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
|
|
6189
|
+
dateFormat = input({
|
|
6190
|
+
month: 'short',
|
|
6191
|
+
day: 'numeric',
|
|
6192
|
+
year: 'numeric',
|
|
6193
|
+
}, ...(ngDevMode ? [{ debugName: "dateFormat" }] : /* istanbul ignore next */ []));
|
|
6194
|
+
min = input(undefined, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
|
|
6195
|
+
max = input(undefined, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
|
|
6196
|
+
clearable = input(true, ...(ngDevMode ? [{ debugName: "clearable" }] : /* istanbul ignore next */ []));
|
|
6197
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
5020
6198
|
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
6199
|
+
open = signal(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
6200
|
+
internalValue = signal(null, ...(ngDevMode ? [{ debugName: "internalValue" }] : /* istanbul ignore next */ []));
|
|
6201
|
+
_disabledByCva = signal(false, ...(ngDevMode ? [{ debugName: "_disabledByCva" }] : /* istanbul ignore next */ []));
|
|
6202
|
+
isDisabled = computed(() => this.disabled() || this._disabledByCva(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
|
|
6203
|
+
triggerRef = viewChild('triggerEl', ...(ngDevMode ? [{ debugName: "triggerRef" }] : /* istanbul ignore next */ []));
|
|
6204
|
+
dropdownRef = viewChild('dropdownEl', ...(ngDevMode ? [{ debugName: "dropdownRef" }] : /* istanbul ignore next */ []));
|
|
6205
|
+
elRef = inject(ElementRef);
|
|
6206
|
+
scrollHandler = null;
|
|
6207
|
+
resizeHandler = null;
|
|
6208
|
+
_onChange = () => { };
|
|
6209
|
+
onTouched = () => { };
|
|
6210
|
+
// CVA
|
|
6211
|
+
writeValue(val) {
|
|
6212
|
+
this.value.set(val ?? null);
|
|
6213
|
+
this.internalValue.set(val ?? null);
|
|
6214
|
+
}
|
|
6215
|
+
registerOnChange(fn) {
|
|
6216
|
+
this._onChange = fn;
|
|
6217
|
+
}
|
|
6218
|
+
registerOnTouched(fn) {
|
|
6219
|
+
this.onTouched = fn;
|
|
6220
|
+
}
|
|
6221
|
+
setDisabledState(isDisabled) {
|
|
6222
|
+
this._disabledByCva.set(isDisabled);
|
|
6223
|
+
}
|
|
6224
|
+
// Display
|
|
6225
|
+
displayValue = computed(() => {
|
|
6226
|
+
const d = this.value();
|
|
6227
|
+
if (!d)
|
|
6228
|
+
return '';
|
|
6229
|
+
return d.toLocaleDateString(this.locale(), this.dateFormat());
|
|
6230
|
+
}, ...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
|
|
6231
|
+
triggerClass = computed(() => cn(datePickerTriggerVariants({ size: this.size() }), this.class()), ...(ngDevMode ? [{ debugName: "triggerClass" }] : /* istanbul ignore next */ []));
|
|
6232
|
+
// Actions
|
|
6233
|
+
onDateSelected(date) {
|
|
6234
|
+
this.value.set(date);
|
|
6235
|
+
this._onChange(date);
|
|
6236
|
+
this.close();
|
|
6237
|
+
}
|
|
6238
|
+
clear(event) {
|
|
6239
|
+
event.stopPropagation();
|
|
6240
|
+
this.value.set(null);
|
|
6241
|
+
this.internalValue.set(null);
|
|
6242
|
+
this._onChange(null);
|
|
6243
|
+
}
|
|
6244
|
+
toggle() {
|
|
6245
|
+
if (this.open()) {
|
|
6246
|
+
this.close();
|
|
6247
|
+
}
|
|
6248
|
+
else {
|
|
6249
|
+
this.internalValue.set(this.value());
|
|
6250
|
+
this.updateDropdownPosition();
|
|
6251
|
+
this.open.set(true);
|
|
6252
|
+
this.addGlobalListeners();
|
|
6253
|
+
setTimeout(() => this.updateDropdownPosition());
|
|
6254
|
+
}
|
|
6255
|
+
}
|
|
6256
|
+
close() {
|
|
6257
|
+
this.open.set(false);
|
|
6258
|
+
this.removeGlobalListeners();
|
|
6259
|
+
}
|
|
6260
|
+
// Positioning (combobox pattern)
|
|
6261
|
+
updateDropdownPosition() {
|
|
6262
|
+
const trigger = this.triggerRef()?.nativeElement;
|
|
6263
|
+
if (!trigger)
|
|
6264
|
+
return;
|
|
6265
|
+
const rect = trigger.getBoundingClientRect();
|
|
6266
|
+
const dropdown = this.dropdownRef()?.nativeElement;
|
|
6267
|
+
if (dropdown) {
|
|
6268
|
+
dropdown.style.top = `${rect.bottom + 4}px`;
|
|
6269
|
+
dropdown.style.left = `${rect.left}px`;
|
|
6270
|
+
}
|
|
6271
|
+
}
|
|
6272
|
+
addGlobalListeners() {
|
|
6273
|
+
this.removeGlobalListeners();
|
|
6274
|
+
this.scrollHandler = () => {
|
|
6275
|
+
requestAnimationFrame(() => this.updateDropdownPosition());
|
|
6276
|
+
};
|
|
6277
|
+
this.resizeHandler = () => {
|
|
6278
|
+
requestAnimationFrame(() => this.updateDropdownPosition());
|
|
6279
|
+
};
|
|
6280
|
+
document.addEventListener('scroll', this.scrollHandler, { capture: true, passive: true });
|
|
6281
|
+
window.addEventListener('resize', this.resizeHandler, { passive: true });
|
|
6282
|
+
}
|
|
6283
|
+
removeGlobalListeners() {
|
|
6284
|
+
if (this.scrollHandler) {
|
|
6285
|
+
document.removeEventListener('scroll', this.scrollHandler, { capture: true });
|
|
6286
|
+
this.scrollHandler = null;
|
|
6287
|
+
}
|
|
6288
|
+
if (this.resizeHandler) {
|
|
6289
|
+
window.removeEventListener('resize', this.resizeHandler);
|
|
6290
|
+
this.resizeHandler = null;
|
|
6291
|
+
}
|
|
6292
|
+
}
|
|
6293
|
+
ngOnDestroy() {
|
|
6294
|
+
this.removeGlobalListeners();
|
|
6295
|
+
}
|
|
6296
|
+
onDocumentClick(event) {
|
|
6297
|
+
if (!this.elRef.nativeElement.contains(event.target)) {
|
|
6298
|
+
this.close();
|
|
6299
|
+
}
|
|
6300
|
+
}
|
|
6301
|
+
onEscape() {
|
|
6302
|
+
this.close();
|
|
6303
|
+
}
|
|
6304
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6305
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: SnyDatePickerComponent, isStandalone: true, selector: "sny-date-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { listeners: { "document:click": "onDocumentClick($event)", "keydown.escape": "onEscape()" }, classAttribute: "relative inline-block w-full" }, providers: [
|
|
6306
|
+
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SnyDatePickerComponent), multi: true },
|
|
6307
|
+
], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "dropdownRef", first: true, predicate: ["dropdownEl"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
6308
|
+
<button
|
|
6309
|
+
#triggerEl
|
|
6310
|
+
type="button"
|
|
6311
|
+
role="combobox"
|
|
6312
|
+
[attr.aria-expanded]="open()"
|
|
6313
|
+
aria-haspopup="dialog"
|
|
6314
|
+
[disabled]="isDisabled()"
|
|
6315
|
+
[class]="triggerClass()"
|
|
6316
|
+
(click)="toggle()"
|
|
6317
|
+
(blur)="onTouched()"
|
|
6318
|
+
>
|
|
6319
|
+
<span [class]="displayValue() ? 'truncate' : 'text-muted-foreground truncate'">
|
|
6320
|
+
{{ displayValue() || placeholder() }}
|
|
6321
|
+
</span>
|
|
6322
|
+
<div class="flex items-center gap-1 shrink-0">
|
|
6323
|
+
@if (clearable() && value()) {
|
|
6324
|
+
<button
|
|
6325
|
+
type="button"
|
|
6326
|
+
class="rounded-sm p-0.5 hover:bg-muted transition-colors text-muted-foreground hover:text-foreground"
|
|
6327
|
+
(click)="clear($event)"
|
|
6328
|
+
aria-label="Clear date"
|
|
6329
|
+
>
|
|
6330
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
|
6331
|
+
</button>
|
|
6332
|
+
}
|
|
6333
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-muted-foreground"><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg>
|
|
6334
|
+
</div>
|
|
6335
|
+
</button>
|
|
6336
|
+
|
|
6337
|
+
@if (open()) {
|
|
6338
|
+
<div
|
|
6339
|
+
#dropdownEl
|
|
6340
|
+
role="dialog"
|
|
6341
|
+
aria-modal="true"
|
|
6342
|
+
aria-label="Choose date"
|
|
6343
|
+
class="fixed z-50 rounded-md border border-border bg-popover text-popover-foreground shadow-lg animate-in fade-in-0 zoom-in-95"
|
|
6344
|
+
>
|
|
6345
|
+
<sny-calendar
|
|
6346
|
+
[(value)]="internalValue"
|
|
6347
|
+
[min]="min()"
|
|
6348
|
+
[max]="max()"
|
|
6349
|
+
[locale]="locale()"
|
|
6350
|
+
(valueChange)="onDateSelected($event)"
|
|
6351
|
+
/>
|
|
6352
|
+
</div>
|
|
6353
|
+
}
|
|
6354
|
+
`, isInline: true, dependencies: [{ kind: "component", type: SnyCalendarComponent, selector: "sny-calendar", inputs: ["value", "min", "max", "locale", "class", "mode", "rangeValue", "showNavigation", "initialViewDate", "borderless"], outputs: ["valueChange", "rangeValueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5024
6355
|
}
|
|
5025
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type:
|
|
5026
|
-
type:
|
|
6356
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDatePickerComponent, decorators: [{
|
|
6357
|
+
type: Component,
|
|
5027
6358
|
args: [{
|
|
5028
|
-
selector: '
|
|
6359
|
+
selector: 'sny-date-picker',
|
|
5029
6360
|
standalone: true,
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
},
|
|
6361
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
6362
|
+
imports: [SnyCalendarComponent],
|
|
6363
|
+
host: { class: 'relative inline-block w-full' },
|
|
6364
|
+
providers: [
|
|
6365
|
+
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SnyDatePickerComponent), multi: true },
|
|
6366
|
+
],
|
|
6367
|
+
template: `
|
|
6368
|
+
<button
|
|
6369
|
+
#triggerEl
|
|
6370
|
+
type="button"
|
|
6371
|
+
role="combobox"
|
|
6372
|
+
[attr.aria-expanded]="open()"
|
|
6373
|
+
aria-haspopup="dialog"
|
|
6374
|
+
[disabled]="isDisabled()"
|
|
6375
|
+
[class]="triggerClass()"
|
|
6376
|
+
(click)="toggle()"
|
|
6377
|
+
(blur)="onTouched()"
|
|
6378
|
+
>
|
|
6379
|
+
<span [class]="displayValue() ? 'truncate' : 'text-muted-foreground truncate'">
|
|
6380
|
+
{{ displayValue() || placeholder() }}
|
|
6381
|
+
</span>
|
|
6382
|
+
<div class="flex items-center gap-1 shrink-0">
|
|
6383
|
+
@if (clearable() && value()) {
|
|
6384
|
+
<button
|
|
6385
|
+
type="button"
|
|
6386
|
+
class="rounded-sm p-0.5 hover:bg-muted transition-colors text-muted-foreground hover:text-foreground"
|
|
6387
|
+
(click)="clear($event)"
|
|
6388
|
+
aria-label="Clear date"
|
|
6389
|
+
>
|
|
6390
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
|
6391
|
+
</button>
|
|
6392
|
+
}
|
|
6393
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-muted-foreground"><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg>
|
|
6394
|
+
</div>
|
|
6395
|
+
</button>
|
|
6396
|
+
|
|
6397
|
+
@if (open()) {
|
|
6398
|
+
<div
|
|
6399
|
+
#dropdownEl
|
|
6400
|
+
role="dialog"
|
|
6401
|
+
aria-modal="true"
|
|
6402
|
+
aria-label="Choose date"
|
|
6403
|
+
class="fixed z-50 rounded-md border border-border bg-popover text-popover-foreground shadow-lg animate-in fade-in-0 zoom-in-95"
|
|
6404
|
+
>
|
|
6405
|
+
<sny-calendar
|
|
6406
|
+
[(value)]="internalValue"
|
|
6407
|
+
[min]="min()"
|
|
6408
|
+
[max]="max()"
|
|
6409
|
+
[locale]="locale()"
|
|
6410
|
+
(valueChange)="onDateSelected($event)"
|
|
6411
|
+
/>
|
|
6412
|
+
</div>
|
|
6413
|
+
}
|
|
6414
|
+
`,
|
|
5033
6415
|
}]
|
|
5034
|
-
}], propDecorators: {
|
|
6416
|
+
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], triggerRef: [{ type: i0.ViewChild, args: ['triggerEl', { isSignal: true }] }], dropdownRef: [{ type: i0.ViewChild, args: ['dropdownEl', { isSignal: true }] }], onDocumentClick: [{
|
|
6417
|
+
type: HostListener,
|
|
6418
|
+
args: ['document:click', ['$event']]
|
|
6419
|
+
}], onEscape: [{
|
|
6420
|
+
type: HostListener,
|
|
6421
|
+
args: ['keydown.escape']
|
|
6422
|
+
}] } });
|
|
5035
6423
|
|
|
5036
|
-
class
|
|
6424
|
+
class SnyDateRangePickerComponent {
|
|
5037
6425
|
value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
6426
|
+
placeholder = input('Pick a date range...', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
6427
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
6428
|
+
locale = input('en-US', ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
|
|
6429
|
+
dateFormat = input({
|
|
6430
|
+
month: 'short',
|
|
6431
|
+
day: 'numeric',
|
|
6432
|
+
year: 'numeric',
|
|
6433
|
+
}, ...(ngDevMode ? [{ debugName: "dateFormat" }] : /* istanbul ignore next */ []));
|
|
6434
|
+
separator = input(' \u2014 ', ...(ngDevMode ? [{ debugName: "separator" }] : /* istanbul ignore next */ []));
|
|
6435
|
+
dualCalendar = input(false, ...(ngDevMode ? [{ debugName: "dualCalendar" }] : /* istanbul ignore next */ []));
|
|
6436
|
+
presets = input([], ...(ngDevMode ? [{ debugName: "presets" }] : /* istanbul ignore next */ []));
|
|
5038
6437
|
min = input(undefined, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
|
|
5039
6438
|
max = input(undefined, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
|
|
5040
|
-
|
|
6439
|
+
clearable = input(true, ...(ngDevMode ? [{ debugName: "clearable" }] : /* istanbul ignore next */ []));
|
|
6440
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
5041
6441
|
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
|
|
6442
|
+
open = signal(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
6443
|
+
internalRange = signal(null, ...(ngDevMode ? [{ debugName: "internalRange" }] : /* istanbul ignore next */ []));
|
|
6444
|
+
leftViewDate = signal(new Date(), ...(ngDevMode ? [{ debugName: "leftViewDate" }] : /* istanbul ignore next */ []));
|
|
5042
6445
|
_disabledByCva = signal(false, ...(ngDevMode ? [{ debugName: "_disabledByCva" }] : /* istanbul ignore next */ []));
|
|
5043
|
-
|
|
5044
|
-
|
|
6446
|
+
isDisabled = computed(() => this.disabled() || this._disabledByCva(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
|
|
6447
|
+
triggerRef = viewChild('triggerEl', ...(ngDevMode ? [{ debugName: "triggerRef" }] : /* istanbul ignore next */ []));
|
|
6448
|
+
dropdownRef = viewChild('dropdownEl', ...(ngDevMode ? [{ debugName: "dropdownRef" }] : /* istanbul ignore next */ []));
|
|
6449
|
+
elRef = inject(ElementRef);
|
|
6450
|
+
scrollHandler = null;
|
|
6451
|
+
resizeHandler = null;
|
|
5045
6452
|
_onChange = () => { };
|
|
5046
6453
|
onTouched = () => { };
|
|
6454
|
+
// Computed
|
|
6455
|
+
rightViewDate = computed(() => {
|
|
6456
|
+
const d = this.leftViewDate();
|
|
6457
|
+
return new Date(d.getFullYear(), d.getMonth() + 1, 1);
|
|
6458
|
+
}, ...(ngDevMode ? [{ debugName: "rightViewDate" }] : /* istanbul ignore next */ []));
|
|
6459
|
+
leftMonthLabel = computed(() => this.leftViewDate().toLocaleDateString(this.locale(), { month: 'long', year: 'numeric' }), ...(ngDevMode ? [{ debugName: "leftMonthLabel" }] : /* istanbul ignore next */ []));
|
|
6460
|
+
rightMonthLabel = computed(() => this.rightViewDate().toLocaleDateString(this.locale(), { month: 'long', year: 'numeric' }), ...(ngDevMode ? [{ debugName: "rightMonthLabel" }] : /* istanbul ignore next */ []));
|
|
6461
|
+
displayValue = computed(() => {
|
|
6462
|
+
const r = this.value();
|
|
6463
|
+
if (!r?.start)
|
|
6464
|
+
return '';
|
|
6465
|
+
const fmt = (d) => d.toLocaleDateString(this.locale(), this.dateFormat());
|
|
6466
|
+
if (!r.end)
|
|
6467
|
+
return fmt(r.start) + this.separator() + '...';
|
|
6468
|
+
return fmt(r.start) + this.separator() + fmt(r.end);
|
|
6469
|
+
}, ...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
|
|
6470
|
+
triggerClass = computed(() => cn(datePickerTriggerVariants({ size: this.size() }), this.class()), ...(ngDevMode ? [{ debugName: "triggerClass" }] : /* istanbul ignore next */ []));
|
|
6471
|
+
// CVA
|
|
5047
6472
|
writeValue(val) {
|
|
5048
6473
|
this.value.set(val ?? null);
|
|
5049
|
-
|
|
5050
|
-
|
|
6474
|
+
this.internalRange.set(val ?? null);
|
|
6475
|
+
if (val?.start) {
|
|
6476
|
+
this.leftViewDate.set(new Date(val.start.getFullYear(), val.start.getMonth(), 1));
|
|
5051
6477
|
}
|
|
5052
6478
|
}
|
|
5053
6479
|
registerOnChange(fn) {
|
|
@@ -5059,189 +6485,370 @@ class SnyCalendarComponent {
|
|
|
5059
6485
|
setDisabledState(isDisabled) {
|
|
5060
6486
|
this._disabledByCva.set(isDisabled);
|
|
5061
6487
|
}
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
const month = view.getMonth();
|
|
5070
|
-
const today = new Date();
|
|
5071
|
-
const selected = this.value();
|
|
5072
|
-
const minDate = this.min();
|
|
5073
|
-
const maxDate = this.max();
|
|
5074
|
-
const firstDay = new Date(year, month, 1);
|
|
5075
|
-
const startDay = firstDay.getDay();
|
|
5076
|
-
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
5077
|
-
const daysInPrevMonth = new Date(year, month, 0).getDate();
|
|
5078
|
-
const days = [];
|
|
5079
|
-
// Previous month
|
|
5080
|
-
for (let i = startDay - 1; i >= 0; i--) {
|
|
5081
|
-
const date = new Date(year, month - 1, daysInPrevMonth - i);
|
|
5082
|
-
days.push(this.createDay(date, false, today, selected, minDate, maxDate));
|
|
5083
|
-
}
|
|
5084
|
-
// Current month
|
|
5085
|
-
for (let d = 1; d <= daysInMonth; d++) {
|
|
5086
|
-
const date = new Date(year, month, d);
|
|
5087
|
-
days.push(this.createDay(date, true, today, selected, minDate, maxDate));
|
|
6488
|
+
// Actions
|
|
6489
|
+
onRangeChanged(range) {
|
|
6490
|
+
this.internalRange.set(range);
|
|
6491
|
+
if (range?.start && range?.end) {
|
|
6492
|
+
this.value.set(range);
|
|
6493
|
+
this._onChange(range);
|
|
6494
|
+
setTimeout(() => this.close(), 150);
|
|
5088
6495
|
}
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
6496
|
+
}
|
|
6497
|
+
selectPreset(preset) {
|
|
6498
|
+
this.value.set(preset.range);
|
|
6499
|
+
this.internalRange.set(preset.range);
|
|
6500
|
+
this._onChange(preset.range);
|
|
6501
|
+
this.close();
|
|
6502
|
+
}
|
|
6503
|
+
clear(event) {
|
|
6504
|
+
event.stopPropagation();
|
|
6505
|
+
this.value.set(null);
|
|
6506
|
+
this.internalRange.set(null);
|
|
6507
|
+
this._onChange(null);
|
|
6508
|
+
}
|
|
5097
6509
|
prevMonth() {
|
|
5098
|
-
this.
|
|
6510
|
+
this.leftViewDate.update((d) => new Date(d.getFullYear(), d.getMonth() - 1, 1));
|
|
5099
6511
|
}
|
|
5100
6512
|
nextMonth() {
|
|
5101
|
-
this.
|
|
6513
|
+
this.leftViewDate.update((d) => new Date(d.getFullYear(), d.getMonth() + 1, 1));
|
|
5102
6514
|
}
|
|
5103
|
-
|
|
5104
|
-
this.
|
|
5105
|
-
|
|
5106
|
-
|
|
6515
|
+
toggle() {
|
|
6516
|
+
if (this.open()) {
|
|
6517
|
+
this.close();
|
|
6518
|
+
}
|
|
6519
|
+
else {
|
|
6520
|
+
this.internalRange.set(this.value());
|
|
6521
|
+
this.updateDropdownPosition();
|
|
6522
|
+
this.open.set(true);
|
|
6523
|
+
this.addGlobalListeners();
|
|
6524
|
+
setTimeout(() => this.updateDropdownPosition());
|
|
6525
|
+
}
|
|
5107
6526
|
}
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
break;
|
|
5123
|
-
case 'ArrowDown':
|
|
5124
|
-
event.preventDefault();
|
|
5125
|
-
this.navigateDays(7);
|
|
5126
|
-
break;
|
|
6527
|
+
close() {
|
|
6528
|
+
this.open.set(false);
|
|
6529
|
+
this.removeGlobalListeners();
|
|
6530
|
+
}
|
|
6531
|
+
// Positioning
|
|
6532
|
+
updateDropdownPosition() {
|
|
6533
|
+
const trigger = this.triggerRef()?.nativeElement;
|
|
6534
|
+
if (!trigger)
|
|
6535
|
+
return;
|
|
6536
|
+
const rect = trigger.getBoundingClientRect();
|
|
6537
|
+
const dropdown = this.dropdownRef()?.nativeElement;
|
|
6538
|
+
if (dropdown) {
|
|
6539
|
+
dropdown.style.top = `${rect.bottom + 4}px`;
|
|
6540
|
+
dropdown.style.left = `${rect.left}px`;
|
|
5127
6541
|
}
|
|
5128
6542
|
}
|
|
5129
|
-
|
|
5130
|
-
|
|
6543
|
+
addGlobalListeners() {
|
|
6544
|
+
this.removeGlobalListeners();
|
|
6545
|
+
this.scrollHandler = () => {
|
|
6546
|
+
requestAnimationFrame(() => this.updateDropdownPosition());
|
|
6547
|
+
};
|
|
6548
|
+
this.resizeHandler = () => {
|
|
6549
|
+
requestAnimationFrame(() => this.updateDropdownPosition());
|
|
6550
|
+
};
|
|
6551
|
+
document.addEventListener('scroll', this.scrollHandler, { capture: true, passive: true });
|
|
6552
|
+
window.addEventListener('resize', this.resizeHandler, { passive: true });
|
|
5131
6553
|
}
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
this.
|
|
5138
|
-
|
|
6554
|
+
removeGlobalListeners() {
|
|
6555
|
+
if (this.scrollHandler) {
|
|
6556
|
+
document.removeEventListener('scroll', this.scrollHandler, { capture: true });
|
|
6557
|
+
this.scrollHandler = null;
|
|
6558
|
+
}
|
|
6559
|
+
if (this.resizeHandler) {
|
|
6560
|
+
window.removeEventListener('resize', this.resizeHandler);
|
|
6561
|
+
this.resizeHandler = null;
|
|
6562
|
+
}
|
|
5139
6563
|
}
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
const isSelected = selected ? this.isSameDay(date, selected) : false;
|
|
5143
|
-
const isDisabled = this._disabledByCva() ||
|
|
5144
|
-
(minDate ? date < minDate : false) || (maxDate ? date > maxDate : false);
|
|
5145
|
-
return { date, day: date.getDate(), isCurrentMonth, isToday, isSelected, isDisabled };
|
|
6564
|
+
ngOnDestroy() {
|
|
6565
|
+
this.removeGlobalListeners();
|
|
5146
6566
|
}
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
6567
|
+
onDocumentClick(event) {
|
|
6568
|
+
if (!this.elRef.nativeElement.contains(event.target)) {
|
|
6569
|
+
this.close();
|
|
6570
|
+
}
|
|
5151
6571
|
}
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
6572
|
+
onEscape() {
|
|
6573
|
+
this.close();
|
|
6574
|
+
}
|
|
6575
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDateRangePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6576
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: SnyDateRangePickerComponent, isStandalone: true, selector: "sny-date-range-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null }, separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null }, dualCalendar: { classPropertyName: "dualCalendar", publicName: "dualCalendar", isSignal: true, isRequired: false, transformFunction: null }, presets: { classPropertyName: "presets", publicName: "presets", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { listeners: { "document:click": "onDocumentClick($event)", "keydown.escape": "onEscape()" }, classAttribute: "relative inline-block w-full" }, providers: [
|
|
6577
|
+
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SnyDateRangePickerComponent), multi: true },
|
|
6578
|
+
], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "dropdownRef", first: true, predicate: ["dropdownEl"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
6579
|
+
<button
|
|
6580
|
+
#triggerEl
|
|
6581
|
+
type="button"
|
|
6582
|
+
role="combobox"
|
|
6583
|
+
[attr.aria-expanded]="open()"
|
|
6584
|
+
aria-haspopup="dialog"
|
|
6585
|
+
[disabled]="isDisabled()"
|
|
6586
|
+
[class]="triggerClass()"
|
|
6587
|
+
(click)="toggle()"
|
|
6588
|
+
(blur)="onTouched()"
|
|
6589
|
+
>
|
|
6590
|
+
<span [class]="displayValue() ? 'truncate' : 'text-muted-foreground truncate'">
|
|
6591
|
+
{{ displayValue() || placeholder() }}
|
|
6592
|
+
</span>
|
|
6593
|
+
<div class="flex items-center gap-1 shrink-0">
|
|
6594
|
+
@if (clearable() && value()?.start) {
|
|
6595
|
+
<button
|
|
6596
|
+
type="button"
|
|
6597
|
+
class="rounded-sm p-0.5 hover:bg-muted transition-colors text-muted-foreground hover:text-foreground"
|
|
6598
|
+
(click)="clear($event)"
|
|
6599
|
+
aria-label="Clear date range"
|
|
6600
|
+
>
|
|
6601
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
|
6602
|
+
</button>
|
|
6603
|
+
}
|
|
6604
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-muted-foreground"><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg>
|
|
6605
|
+
</div>
|
|
6606
|
+
</button>
|
|
6607
|
+
|
|
6608
|
+
@if (open()) {
|
|
6609
|
+
<div
|
|
6610
|
+
#dropdownEl
|
|
6611
|
+
role="dialog"
|
|
6612
|
+
aria-modal="true"
|
|
6613
|
+
aria-label="Choose date range"
|
|
6614
|
+
class="fixed z-50 rounded-md border border-border bg-popover text-popover-foreground shadow-lg animate-in fade-in-0 zoom-in-95"
|
|
5169
6615
|
>
|
|
5170
|
-
<
|
|
5171
|
-
|
|
5172
|
-
|
|
6616
|
+
<div class="flex flex-col sm:flex-row">
|
|
6617
|
+
<!-- Presets sidebar -->
|
|
6618
|
+
@if (presets().length > 0) {
|
|
6619
|
+
<div class="border-b sm:border-b-0 sm:border-r border-border p-3 space-y-0.5 sm:min-w-[150px]">
|
|
6620
|
+
<p class="px-3 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wider">Presets</p>
|
|
6621
|
+
@for (preset of presets(); track preset.label) {
|
|
6622
|
+
<button
|
|
6623
|
+
type="button"
|
|
6624
|
+
class="w-full text-left px-3 py-2 text-sm rounded-md hover:bg-accent hover:text-accent-foreground transition-colors cursor-pointer"
|
|
6625
|
+
(mousedown)="selectPreset(preset); $event.preventDefault()"
|
|
6626
|
+
>
|
|
6627
|
+
{{ preset.label }}
|
|
6628
|
+
</button>
|
|
6629
|
+
}
|
|
6630
|
+
</div>
|
|
6631
|
+
}
|
|
5173
6632
|
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
6633
|
+
<!-- Calendar(s) -->
|
|
6634
|
+
<div class="flex flex-col sm:flex-row">
|
|
6635
|
+
@if (dualCalendar()) {
|
|
6636
|
+
<!-- Left calendar -->
|
|
6637
|
+
<div class="p-1">
|
|
6638
|
+
<div class="flex items-center justify-between px-3 py-2">
|
|
6639
|
+
<button
|
|
6640
|
+
type="button"
|
|
6641
|
+
class="inline-flex items-center justify-center rounded-md h-8 w-8 hover:bg-accent hover:text-accent-foreground transition-colors"
|
|
6642
|
+
(click)="prevMonth()"
|
|
6643
|
+
aria-label="Previous month"
|
|
6644
|
+
>
|
|
6645
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
|
|
6646
|
+
</button>
|
|
6647
|
+
<span class="text-sm font-semibold tracking-tight">{{ leftMonthLabel() }}</span>
|
|
6648
|
+
<div class="w-8"></div>
|
|
6649
|
+
</div>
|
|
6650
|
+
<sny-calendar
|
|
6651
|
+
mode="range"
|
|
6652
|
+
[(rangeValue)]="internalRange"
|
|
6653
|
+
[min]="min()"
|
|
6654
|
+
[max]="max()"
|
|
6655
|
+
[locale]="locale()"
|
|
6656
|
+
[showNavigation]="false"
|
|
6657
|
+
[borderless]="true"
|
|
6658
|
+
[initialViewDate]="leftViewDate()"
|
|
6659
|
+
(rangeValueChange)="onRangeChanged($event)"
|
|
6660
|
+
/>
|
|
6661
|
+
</div>
|
|
6662
|
+
<div class="border-t sm:border-t-0 sm:border-l border-border"></div>
|
|
6663
|
+
<!-- Right calendar -->
|
|
6664
|
+
<div class="p-1">
|
|
6665
|
+
<div class="flex items-center justify-between px-3 py-2">
|
|
6666
|
+
<div class="w-8"></div>
|
|
6667
|
+
<span class="text-sm font-semibold tracking-tight">{{ rightMonthLabel() }}</span>
|
|
6668
|
+
<button
|
|
6669
|
+
type="button"
|
|
6670
|
+
class="inline-flex items-center justify-center rounded-md h-8 w-8 hover:bg-accent hover:text-accent-foreground transition-colors"
|
|
6671
|
+
(click)="nextMonth()"
|
|
6672
|
+
aria-label="Next month"
|
|
6673
|
+
>
|
|
6674
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
|
|
6675
|
+
</button>
|
|
6676
|
+
</div>
|
|
6677
|
+
<sny-calendar
|
|
6678
|
+
mode="range"
|
|
6679
|
+
[(rangeValue)]="internalRange"
|
|
6680
|
+
[min]="min()"
|
|
6681
|
+
[max]="max()"
|
|
6682
|
+
[locale]="locale()"
|
|
6683
|
+
[showNavigation]="false"
|
|
6684
|
+
[borderless]="true"
|
|
6685
|
+
[initialViewDate]="rightViewDate()"
|
|
6686
|
+
(rangeValueChange)="onRangeChanged($event)"
|
|
6687
|
+
/>
|
|
6688
|
+
</div>
|
|
6689
|
+
} @else {
|
|
6690
|
+
<!-- Single calendar -->
|
|
6691
|
+
<sny-calendar
|
|
6692
|
+
mode="range"
|
|
6693
|
+
[(rangeValue)]="internalRange"
|
|
6694
|
+
[min]="min()"
|
|
6695
|
+
[max]="max()"
|
|
6696
|
+
[locale]="locale()"
|
|
6697
|
+
(rangeValueChange)="onRangeChanged($event)"
|
|
6698
|
+
/>
|
|
6699
|
+
}
|
|
6700
|
+
</div>
|
|
6701
|
+
</div>
|
|
6702
|
+
</div>
|
|
6703
|
+
}
|
|
6704
|
+
`, isInline: true, dependencies: [{ kind: "component", type: SnyCalendarComponent, selector: "sny-calendar", inputs: ["value", "min", "max", "locale", "class", "mode", "rangeValue", "showNavigation", "initialViewDate", "borderless"], outputs: ["valueChange", "rangeValueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5192
6705
|
}
|
|
5193
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type:
|
|
6706
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: SnyDateRangePickerComponent, decorators: [{
|
|
5194
6707
|
type: Component,
|
|
5195
6708
|
args: [{
|
|
5196
|
-
selector: 'sny-
|
|
6709
|
+
selector: 'sny-date-range-picker',
|
|
5197
6710
|
standalone: true,
|
|
5198
6711
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
'(keydown)': 'onKeydown($event)',
|
|
5202
|
-
},
|
|
6712
|
+
imports: [SnyCalendarComponent],
|
|
6713
|
+
host: { class: 'relative inline-block w-full' },
|
|
5203
6714
|
providers: [
|
|
5204
|
-
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() =>
|
|
6715
|
+
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SnyDateRangePickerComponent), multi: true },
|
|
5205
6716
|
],
|
|
5206
6717
|
template: `
|
|
5207
|
-
<
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
6718
|
+
<button
|
|
6719
|
+
#triggerEl
|
|
6720
|
+
type="button"
|
|
6721
|
+
role="combobox"
|
|
6722
|
+
[attr.aria-expanded]="open()"
|
|
6723
|
+
aria-haspopup="dialog"
|
|
6724
|
+
[disabled]="isDisabled()"
|
|
6725
|
+
[class]="triggerClass()"
|
|
6726
|
+
(click)="toggle()"
|
|
6727
|
+
(blur)="onTouched()"
|
|
6728
|
+
>
|
|
6729
|
+
<span [class]="displayValue() ? 'truncate' : 'text-muted-foreground truncate'">
|
|
6730
|
+
{{ displayValue() || placeholder() }}
|
|
6731
|
+
</span>
|
|
6732
|
+
<div class="flex items-center gap-1 shrink-0">
|
|
6733
|
+
@if (clearable() && value()?.start) {
|
|
6734
|
+
<button
|
|
6735
|
+
type="button"
|
|
6736
|
+
class="rounded-sm p-0.5 hover:bg-muted transition-colors text-muted-foreground hover:text-foreground"
|
|
6737
|
+
(click)="clear($event)"
|
|
6738
|
+
aria-label="Clear date range"
|
|
6739
|
+
>
|
|
6740
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
|
6741
|
+
</button>
|
|
6742
|
+
}
|
|
6743
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-muted-foreground"><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg>
|
|
6744
|
+
</div>
|
|
6745
|
+
</button>
|
|
6746
|
+
|
|
6747
|
+
@if (open()) {
|
|
6748
|
+
<div
|
|
6749
|
+
#dropdownEl
|
|
6750
|
+
role="dialog"
|
|
6751
|
+
aria-modal="true"
|
|
6752
|
+
aria-label="Choose date range"
|
|
6753
|
+
class="fixed z-50 rounded-md border border-border bg-popover text-popover-foreground shadow-lg animate-in fade-in-0 zoom-in-95"
|
|
5220
6754
|
>
|
|
5221
|
-
<
|
|
5222
|
-
|
|
5223
|
-
|
|
6755
|
+
<div class="flex flex-col sm:flex-row">
|
|
6756
|
+
<!-- Presets sidebar -->
|
|
6757
|
+
@if (presets().length > 0) {
|
|
6758
|
+
<div class="border-b sm:border-b-0 sm:border-r border-border p-3 space-y-0.5 sm:min-w-[150px]">
|
|
6759
|
+
<p class="px-3 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wider">Presets</p>
|
|
6760
|
+
@for (preset of presets(); track preset.label) {
|
|
6761
|
+
<button
|
|
6762
|
+
type="button"
|
|
6763
|
+
class="w-full text-left px-3 py-2 text-sm rounded-md hover:bg-accent hover:text-accent-foreground transition-colors cursor-pointer"
|
|
6764
|
+
(mousedown)="selectPreset(preset); $event.preventDefault()"
|
|
6765
|
+
>
|
|
6766
|
+
{{ preset.label }}
|
|
6767
|
+
</button>
|
|
6768
|
+
}
|
|
6769
|
+
</div>
|
|
6770
|
+
}
|
|
5224
6771
|
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
6772
|
+
<!-- Calendar(s) -->
|
|
6773
|
+
<div class="flex flex-col sm:flex-row">
|
|
6774
|
+
@if (dualCalendar()) {
|
|
6775
|
+
<!-- Left calendar -->
|
|
6776
|
+
<div class="p-1">
|
|
6777
|
+
<div class="flex items-center justify-between px-3 py-2">
|
|
6778
|
+
<button
|
|
6779
|
+
type="button"
|
|
6780
|
+
class="inline-flex items-center justify-center rounded-md h-8 w-8 hover:bg-accent hover:text-accent-foreground transition-colors"
|
|
6781
|
+
(click)="prevMonth()"
|
|
6782
|
+
aria-label="Previous month"
|
|
6783
|
+
>
|
|
6784
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
|
|
6785
|
+
</button>
|
|
6786
|
+
<span class="text-sm font-semibold tracking-tight">{{ leftMonthLabel() }}</span>
|
|
6787
|
+
<div class="w-8"></div>
|
|
6788
|
+
</div>
|
|
6789
|
+
<sny-calendar
|
|
6790
|
+
mode="range"
|
|
6791
|
+
[(rangeValue)]="internalRange"
|
|
6792
|
+
[min]="min()"
|
|
6793
|
+
[max]="max()"
|
|
6794
|
+
[locale]="locale()"
|
|
6795
|
+
[showNavigation]="false"
|
|
6796
|
+
[borderless]="true"
|
|
6797
|
+
[initialViewDate]="leftViewDate()"
|
|
6798
|
+
(rangeValueChange)="onRangeChanged($event)"
|
|
6799
|
+
/>
|
|
6800
|
+
</div>
|
|
6801
|
+
<div class="border-t sm:border-t-0 sm:border-l border-border"></div>
|
|
6802
|
+
<!-- Right calendar -->
|
|
6803
|
+
<div class="p-1">
|
|
6804
|
+
<div class="flex items-center justify-between px-3 py-2">
|
|
6805
|
+
<div class="w-8"></div>
|
|
6806
|
+
<span class="text-sm font-semibold tracking-tight">{{ rightMonthLabel() }}</span>
|
|
6807
|
+
<button
|
|
6808
|
+
type="button"
|
|
6809
|
+
class="inline-flex items-center justify-center rounded-md h-8 w-8 hover:bg-accent hover:text-accent-foreground transition-colors"
|
|
6810
|
+
(click)="nextMonth()"
|
|
6811
|
+
aria-label="Next month"
|
|
6812
|
+
>
|
|
6813
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
|
|
6814
|
+
</button>
|
|
6815
|
+
</div>
|
|
6816
|
+
<sny-calendar
|
|
6817
|
+
mode="range"
|
|
6818
|
+
[(rangeValue)]="internalRange"
|
|
6819
|
+
[min]="min()"
|
|
6820
|
+
[max]="max()"
|
|
6821
|
+
[locale]="locale()"
|
|
6822
|
+
[showNavigation]="false"
|
|
6823
|
+
[borderless]="true"
|
|
6824
|
+
[initialViewDate]="rightViewDate()"
|
|
6825
|
+
(rangeValueChange)="onRangeChanged($event)"
|
|
6826
|
+
/>
|
|
6827
|
+
</div>
|
|
6828
|
+
} @else {
|
|
6829
|
+
<!-- Single calendar -->
|
|
6830
|
+
<sny-calendar
|
|
6831
|
+
mode="range"
|
|
6832
|
+
[(rangeValue)]="internalRange"
|
|
6833
|
+
[min]="min()"
|
|
6834
|
+
[max]="max()"
|
|
6835
|
+
[locale]="locale()"
|
|
6836
|
+
(rangeValueChange)="onRangeChanged($event)"
|
|
6837
|
+
/>
|
|
6838
|
+
}
|
|
6839
|
+
</div>
|
|
6840
|
+
</div>
|
|
6841
|
+
</div>
|
|
6842
|
+
}
|
|
5242
6843
|
`,
|
|
5243
6844
|
}]
|
|
5244
|
-
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }],
|
|
6845
|
+
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }], separator: [{ type: i0.Input, args: [{ isSignal: true, alias: "separator", required: false }] }], dualCalendar: [{ type: i0.Input, args: [{ isSignal: true, alias: "dualCalendar", required: false }] }], presets: [{ type: i0.Input, args: [{ isSignal: true, alias: "presets", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], triggerRef: [{ type: i0.ViewChild, args: ['triggerEl', { isSignal: true }] }], dropdownRef: [{ type: i0.ViewChild, args: ['dropdownEl', { isSignal: true }] }], onDocumentClick: [{
|
|
6846
|
+
type: HostListener,
|
|
6847
|
+
args: ['document:click', ['$event']]
|
|
6848
|
+
}], onEscape: [{
|
|
6849
|
+
type: HostListener,
|
|
6850
|
+
args: ['keydown.escape']
|
|
6851
|
+
}] } });
|
|
5245
6852
|
|
|
5246
6853
|
class SnyValidatorDirective {
|
|
5247
6854
|
control = input(null, ...(ngDevMode ? [{ debugName: "control" }] : /* istanbul ignore next */ []));
|
|
@@ -5302,5 +6909,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
|
|
|
5302
6909
|
* Generated bundle index. Do not edit.
|
|
5303
6910
|
*/
|
|
5304
6911
|
|
|
5305
|
-
export { SNY_ACCORDION, SNY_ACCORDION_ITEM, SNY_CAROUSEL, SNY_CHAT_BUBBLE, SNY_CONFIG, SNY_DIALOG_DATA, SNY_DRAWER, SNY_DROPDOWN, SNY_FAB, SNY_SHEET_DATA, SNY_STEPS, SNY_TABLE, SNY_TABS, SNY_TIMELINE, SnyAccordionContentDirective, SnyAccordionDirective, SnyAccordionItemDirective, SnyAccordionTriggerDirective, SnyAlertDescriptionDirective, SnyAlertDirective, SnyAlertTitleDirective, SnyAvatarComponent, SnyBadgeDirective, SnyBreadcrumbDirective, SnyBreadcrumbItemDirective, SnyBreadcrumbLinkDirective, SnyBreadcrumbListDirective, SnyBreadcrumbPageDirective, SnyBreadcrumbSeparatorDirective, SnyButtonDirective, SnyButtonGroupDirective, SnyCalendarComponent, SnyCardContentDirective, SnyCardDescriptionDirective, SnyCardDirective, SnyCardFooterDirective, SnyCardHeaderDirective, SnyCardTitleDirective, SnyCarouselContentDirective, SnyCarouselDirective, SnyCarouselItemDirective, SnyCarouselNextDirective, SnyCarouselPrevDirective, SnyChatBubbleAvatarDirective, SnyChatBubbleBodyDirective, SnyChatBubbleContentDirective, SnyChatBubbleDirective, SnyChatBubbleFooterDirective, SnyChatBubbleHeaderDirective, SnyCheckboxDirective, SnyComboboxComponent, SnyDialogCloseDirective, SnyDialogContentDirective, SnyDialogDescriptionDirective, SnyDialogFooterDirective, SnyDialogHeaderDirective, SnyDialogRef, SnyDialogService, SnyDialogTitleDirective, SnyDiffComponent, SnyDividerComponent, SnyDockDirective, SnyDockItemDirective, SnyDrawerContentDirective, SnyDrawerLayoutComponent, SnyDrawerLayoutDirective, SnyDrawerSideDirective, SnyDropdownContentDirective, SnyDropdownDirective, SnyDropdownTriggerDirective, SnyFabActionDirective, SnyFabDirective, SnyFabTriggerDirective, SnyFieldsetContentDirective, SnyFieldsetDirective, SnyFieldsetLegendDirective, SnyFileInputComponent, SnyIndicatorBadgeDirective, SnyIndicatorDirective, SnyInputDirective, SnyKbdDirective, SnyLabelDirective, SnyLinkDirective, SnyListDirective, SnyListItemActionDirective, SnyListItemContentDirective, SnyListItemDirective, SnyListItemIconDirective, SnyLoaderComponent, SnyMenuContentDirective, SnyMenuItemDirective, SnyMenuLabelDirective, SnyMenuSeparatorDirective, SnyNavbarBrandDirective, SnyNavbarContentDirective, SnyNavbarDirective, SnyNavbarEndDirective, SnyPaginationComponent, SnyProgressComponent, SnyRadialProgressComponent, SnyRadioDirective, SnyRatingComponent, SnySelectComponent, SnySheetCloseDirective, SnySheetContentDirective, SnySheetDescriptionDirective, SnySheetHeaderDirective, SnySheetRef, SnySheetService, SnySheetTitleDirective, SnySkeletonDirective, SnySliderComponent, SnyStatDescriptionDirective, SnyStatDirective, SnyStatFigureDirective, SnyStatTitleDirective, SnyStatValueDirective, SnyStatusDirective, SnyStepDirective, SnyStepsDirective, SnySwitchComponent, SnyTableBodyDirective, SnyTableCaptionDirective, SnyTableCellDirective, SnyTableDirective, SnyTableFooterDirective, SnyTableHeadDirective, SnyTableHeaderDirective, SnyTableRowDirective, SnyTabsContentDirective, SnyTabsDirective, SnyTabsListDirective, SnyTabsTriggerDirective, SnyTextareaDirective, SnyTimelineDirective, SnyTimelineEndDirective, SnyTimelineItemDirective, SnyTimelineMiddleDirective, SnyTimelineStartDirective, SnyToastService, SnyToasterComponent, SnyToggleDirective, SnyTooltipDirective, SnyValidatorDirective, SnyValidatorHintDirective, ThemeService, alertVariants, avatarVariants, badgeVariants, buttonGroupVariants, buttonVariants, cardVariants, checkboxVariants, cn, comboboxTriggerVariants, dividerVariants, dropdownContentVariants, dropdownItemVariants, fieldsetVariants, fileInputVariants, inputVariants, kbdVariants, labelVariants, linkVariants, loaderVariants, paginationItemVariants, progressBarVariants, progressTrackVariants, provideSonnyUI, radioVariants, ratingVariants, selectTriggerVariants, skeletonVariants, sliderTrackVariants, statusVariants, switchTrackVariants, tableCellVariants, tableVariants, tabsListVariants, tabsTriggerVariants, textareaVariants, toastVariants, toggleVariants, tooltipVariants };
|
|
6912
|
+
export { SNY_ACCORDION, SNY_ACCORDION_ITEM, SNY_CAROUSEL, SNY_CHAT_BUBBLE, SNY_CONFIG, SNY_DIALOG_DATA, SNY_DRAWER, SNY_DROPDOWN, SNY_FAB, SNY_SHEET_DATA, SNY_STEPS, SNY_TABLE, SNY_TABS, SNY_TIMELINE, SnyAccordionContentDirective, SnyAccordionDirective, SnyAccordionItemDirective, SnyAccordionTriggerDirective, SnyAlertDescriptionDirective, SnyAlertDirective, SnyAlertTitleDirective, SnyAvatarComponent, SnyBadgeDirective, SnyBreadcrumbDirective, SnyBreadcrumbItemDirective, SnyBreadcrumbLinkDirective, SnyBreadcrumbListDirective, SnyBreadcrumbPageDirective, SnyBreadcrumbSeparatorDirective, SnyBulkActionsDefDirective, SnyButtonDirective, SnyButtonGroupDirective, SnyCalendarComponent, SnyCardContentDirective, SnyCardDescriptionDirective, SnyCardDirective, SnyCardFooterDirective, SnyCardHeaderDirective, SnyCardTitleDirective, SnyCarouselContentDirective, SnyCarouselDirective, SnyCarouselItemDirective, SnyCarouselNextDirective, SnyCarouselPrevDirective, SnyCellDefDirective, SnyChatBubbleAvatarDirective, SnyChatBubbleBodyDirective, SnyChatBubbleContentDirective, SnyChatBubbleDirective, SnyChatBubbleFooterDirective, SnyChatBubbleHeaderDirective, SnyCheckboxDirective, SnyComboboxComponent, SnyDataTableComponent, SnyDatePickerComponent, SnyDateRangePickerComponent, SnyDialogCloseDirective, SnyDialogContentDirective, SnyDialogDescriptionDirective, SnyDialogFooterDirective, SnyDialogHeaderDirective, SnyDialogRef, SnyDialogService, SnyDialogTitleDirective, SnyDiffComponent, SnyDividerComponent, SnyDockDirective, SnyDockItemDirective, SnyDrawerContentDirective, SnyDrawerLayoutComponent, SnyDrawerLayoutDirective, SnyDrawerSideDirective, SnyDropdownContentDirective, SnyDropdownDirective, SnyDropdownTriggerDirective, SnyFabActionDirective, SnyFabDirective, SnyFabTriggerDirective, SnyFieldsetContentDirective, SnyFieldsetDirective, SnyFieldsetLegendDirective, SnyFileInputComponent, SnyHeaderCellDefDirective, SnyIndicatorBadgeDirective, SnyIndicatorDirective, SnyInputDirective, SnyKbdDirective, SnyLabelDirective, SnyLinkDirective, SnyListDirective, SnyListItemActionDirective, SnyListItemContentDirective, SnyListItemDirective, SnyListItemIconDirective, SnyLoaderComponent, SnyMenuContentDirective, SnyMenuItemDirective, SnyMenuLabelDirective, SnyMenuSeparatorDirective, SnyNavbarBrandDirective, SnyNavbarContentDirective, SnyNavbarDirective, SnyNavbarEndDirective, SnyPaginationComponent, SnyProgressComponent, SnyRadialProgressComponent, SnyRadioDirective, SnyRatingComponent, SnyRowExpandDefDirective, SnySelectComponent, SnySheetCloseDirective, SnySheetContentDirective, SnySheetDescriptionDirective, SnySheetHeaderDirective, SnySheetRef, SnySheetService, SnySheetTitleDirective, SnySkeletonDirective, SnySliderComponent, SnyStatDescriptionDirective, SnyStatDirective, SnyStatFigureDirective, SnyStatTitleDirective, SnyStatValueDirective, SnyStatusDirective, SnyStepDirective, SnyStepsDirective, SnySwitchComponent, SnyTableBodyDirective, SnyTableCaptionDirective, SnyTableCellDirective, SnyTableDirective, SnyTableFooterDirective, SnyTableHeadDirective, SnyTableHeaderDirective, SnyTableRowDirective, SnyTabsContentDirective, SnyTabsDirective, SnyTabsListDirective, SnyTabsTriggerDirective, SnyTextareaDirective, SnyTimelineDirective, SnyTimelineEndDirective, SnyTimelineItemDirective, SnyTimelineMiddleDirective, SnyTimelineStartDirective, SnyToastService, SnyToasterComponent, SnyToggleDirective, SnyTooltipDirective, SnyValidatorDirective, SnyValidatorHintDirective, ThemeService, alertVariants, avatarVariants, badgeVariants, buttonGroupVariants, buttonVariants, cardVariants, checkboxVariants, cn, comboboxTriggerVariants, datePickerTriggerVariants, dividerVariants, dropdownContentVariants, dropdownItemVariants, fieldsetVariants, fileInputVariants, inputVariants, kbdVariants, labelVariants, linkVariants, loaderVariants, paginationItemVariants, progressBarVariants, progressTrackVariants, provideSonnyUI, radioVariants, ratingVariants, selectTriggerVariants, skeletonVariants, sliderTrackVariants, statusVariants, switchTrackVariants, tableCellVariants, tableVariants, tabsListVariants, tabsTriggerVariants, textareaVariants, toastVariants, toggleVariants, tooltipVariants };
|
|
5306
6913
|
//# sourceMappingURL=sonny-ui-core.mjs.map
|