@tolle_/tolle-ui 0.0.28-beta → 0.0.30-beta
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/esm2022/lib/calendar.component.mjs +275 -81
- package/esm2022/lib/date-picker.component.mjs +126 -29
- package/esm2022/lib/date-range-picker.component.mjs +76 -24
- package/esm2022/lib/multi-select.component.mjs +220 -26
- package/esm2022/lib/pagination.component.mjs +1 -1
- package/esm2022/lib/segment.component.mjs +192 -0
- package/esm2022/lib/select-item.component.mjs +98 -14
- package/esm2022/lib/select.component.mjs +29 -36
- package/esm2022/public-api.mjs +2 -1
- package/fesm2022/tolle-ui.mjs +1002 -203
- package/fesm2022/tolle-ui.mjs.map +1 -1
- package/lib/button.component.d.ts +2 -2
- package/lib/calendar.component.d.ts +23 -2
- package/lib/date-picker.component.d.ts +16 -2
- package/lib/date-range-picker.component.d.ts +3 -1
- package/lib/multi-select.component.d.ts +13 -1
- package/lib/segment.component.d.ts +38 -0
- package/lib/select-item.component.d.ts +4 -1
- package/package.json +1 -1
- package/public-api.d.ts +1 -0
package/fesm2022/tolle-ui.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { clsx } from 'clsx';
|
|
2
2
|
import { twMerge } from 'tailwind-merge';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { Component, Input, forwardRef, ViewChild, Injectable, Optional, HostListener, ContentChildren, EventEmitter, Output, Directive, inject, PLATFORM_ID, Inject, InjectionToken, APP_INITIALIZER, ChangeDetectorRef, ChangeDetectionStrategy, TemplateRef, Injector, HostBinding } from '@angular/core';
|
|
4
|
+
import { Component, Input, forwardRef, ViewChild, Injectable, Optional, HostListener, ContentChildren, EventEmitter, Output, Directive, inject, PLATFORM_ID, Inject, InjectionToken, APP_INITIALIZER, ChangeDetectorRef, ChangeDetectionStrategy, TemplateRef, Injector, HostBinding, ViewChildren } from '@angular/core';
|
|
5
5
|
import * as i1 from '@angular/common';
|
|
6
6
|
import { CommonModule, isPlatformBrowser, DOCUMENT, NgIf, NgTemplateOutlet } from '@angular/common';
|
|
7
7
|
import { cva } from 'class-variance-authority';
|
|
8
8
|
import * as i2 from '@angular/forms';
|
|
9
9
|
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
|
|
10
|
-
import { autoUpdate, computePosition, offset, flip, shift } from '@floating-ui/dom';
|
|
10
|
+
import { autoUpdate, computePosition, offset, flip, shift, size } from '@floating-ui/dom';
|
|
11
11
|
import { Subject, Subscription, BehaviorSubject } from 'rxjs';
|
|
12
|
-
import { startOfWeek, startOfMonth, endOfWeek, endOfMonth, eachDayOfInterval, subMonths, subYears, addMonths, addYears,
|
|
12
|
+
import { format, startOfWeek, startOfMonth, endOfWeek, endOfMonth, eachDayOfInterval, subMonths, subYears, addMonths, addYears, setMonth, setYear, isSameDay, isToday, isSameMonth, isBefore, startOfDay, parse, isValid, isWithinInterval } from 'date-fns';
|
|
13
13
|
import * as i1$1 from '@angular/cdk/overlay';
|
|
14
14
|
import { OverlayConfig } from '@angular/cdk/overlay';
|
|
15
15
|
import { ComponentPortal } from '@angular/cdk/portal';
|
|
@@ -512,6 +512,8 @@ class SelectItemComponent {
|
|
|
512
512
|
value;
|
|
513
513
|
class = '';
|
|
514
514
|
selected = false;
|
|
515
|
+
disabled = false;
|
|
516
|
+
multiSelect = false; // Will be set by parent component
|
|
515
517
|
hidden = false;
|
|
516
518
|
constructor(selectService, el) {
|
|
517
519
|
this.selectService = selectService;
|
|
@@ -519,33 +521,85 @@ class SelectItemComponent {
|
|
|
519
521
|
}
|
|
520
522
|
// Helper method for the parent to get the searchable text
|
|
521
523
|
getLabel() {
|
|
522
|
-
return this.el.nativeElement.
|
|
524
|
+
return this.el.nativeElement.textContent?.trim() || '';
|
|
525
|
+
}
|
|
526
|
+
getItemClasses() {
|
|
527
|
+
return cn(
|
|
528
|
+
// Base state
|
|
529
|
+
'focus:bg-accent focus:text-accent-foreground',
|
|
530
|
+
// Hover states (only if not disabled)
|
|
531
|
+
!this.disabled && [
|
|
532
|
+
'cursor-pointer',
|
|
533
|
+
'hover:bg-accent hover:text-accent-foreground'
|
|
534
|
+
],
|
|
535
|
+
// Selected state
|
|
536
|
+
this.selected && [
|
|
537
|
+
this.multiSelect
|
|
538
|
+
? 'bg-primary/5 text-foreground'
|
|
539
|
+
: 'bg-accent text-accent-foreground'
|
|
540
|
+
],
|
|
541
|
+
// Disabled state
|
|
542
|
+
this.disabled && [
|
|
543
|
+
'opacity-50',
|
|
544
|
+
'cursor-not-allowed',
|
|
545
|
+
'hover:bg-transparent hover:text-foreground'
|
|
546
|
+
]);
|
|
523
547
|
}
|
|
524
548
|
onClick(event) {
|
|
525
|
-
if (this.hidden)
|
|
549
|
+
if (this.hidden || this.disabled)
|
|
526
550
|
return;
|
|
527
551
|
event.stopPropagation();
|
|
528
552
|
if (this.selectService) {
|
|
529
|
-
|
|
530
|
-
|
|
553
|
+
const label = this.getLabel();
|
|
554
|
+
if (this.multiSelect) {
|
|
555
|
+
// For multi-select, toggle selection
|
|
556
|
+
this.selected = !this.selected;
|
|
557
|
+
}
|
|
558
|
+
// For both single and multi-select, notify parent
|
|
531
559
|
this.selectService.registerClick(this.value, label);
|
|
532
560
|
}
|
|
533
561
|
}
|
|
534
562
|
cn = cn;
|
|
535
563
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SelectItemComponent, deps: [{ token: SelectService, optional: true }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
536
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: SelectItemComponent, isStandalone: true, selector: "tolle-select-item", inputs: { value: "value", class: "class", selected: "selected" }, host: { listeners: { "click": "onClick($event)" } }, ngImport: i0, template: `
|
|
564
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: SelectItemComponent, isStandalone: true, selector: "tolle-select-item", inputs: { value: "value", class: "class", selected: "selected", disabled: "disabled", multiSelect: "multiSelect" }, host: { listeners: { "click": "onClick($event)" } }, ngImport: i0, template: `
|
|
537
565
|
<div
|
|
538
566
|
*ngIf="!hidden"
|
|
539
567
|
[class]="cn(
|
|
540
|
-
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none
|
|
541
|
-
|
|
568
|
+
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors',
|
|
569
|
+
getItemClasses(),
|
|
542
570
|
class
|
|
543
571
|
)"
|
|
572
|
+
[attr.aria-disabled]="disabled"
|
|
573
|
+
[attr.aria-selected]="selected"
|
|
574
|
+
role="option"
|
|
544
575
|
>
|
|
545
|
-
|
|
576
|
+
<!-- Single Select: Checkmark -->
|
|
577
|
+
<span *ngIf="!multiSelect && selected" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
546
578
|
<i class="ri-check-line text-primary"></i>
|
|
547
579
|
</span>
|
|
548
|
-
|
|
580
|
+
|
|
581
|
+
<!-- Multi-Select: Checkbox -->
|
|
582
|
+
<span *ngIf="multiSelect" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
583
|
+
<div [class]="cn(
|
|
584
|
+
'flex h-4 w-4 items-center justify-center rounded-sm border transition-all duration-200',
|
|
585
|
+
selected ? 'border-primary bg-primary text-primary-foreground' : 'border-input'
|
|
586
|
+
)">
|
|
587
|
+
<i [class]="cn(
|
|
588
|
+
'ri-check-line text-xs transition-all duration-200',
|
|
589
|
+
selected ? 'opacity-100 scale-100' : 'opacity-0 scale-75'
|
|
590
|
+
)"></i>
|
|
591
|
+
</div>
|
|
592
|
+
</span>
|
|
593
|
+
|
|
594
|
+
<!-- Content -->
|
|
595
|
+
<span class="flex-1 truncate">
|
|
596
|
+
<ng-content></ng-content>
|
|
597
|
+
</span>
|
|
598
|
+
|
|
599
|
+
<!-- Disabled indicator -->
|
|
600
|
+
<span *ngIf="disabled && !selected" class="ml-2 text-xs text-muted-foreground/50">
|
|
601
|
+
<i class="ri-forbid-line"></i>
|
|
602
|
+
</span>
|
|
549
603
|
</div>
|
|
550
604
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
551
605
|
}
|
|
@@ -559,15 +613,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
559
613
|
<div
|
|
560
614
|
*ngIf="!hidden"
|
|
561
615
|
[class]="cn(
|
|
562
|
-
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none
|
|
563
|
-
|
|
616
|
+
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors',
|
|
617
|
+
getItemClasses(),
|
|
564
618
|
class
|
|
565
619
|
)"
|
|
620
|
+
[attr.aria-disabled]="disabled"
|
|
621
|
+
[attr.aria-selected]="selected"
|
|
622
|
+
role="option"
|
|
566
623
|
>
|
|
567
|
-
|
|
624
|
+
<!-- Single Select: Checkmark -->
|
|
625
|
+
<span *ngIf="!multiSelect && selected" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
568
626
|
<i class="ri-check-line text-primary"></i>
|
|
569
627
|
</span>
|
|
570
|
-
|
|
628
|
+
|
|
629
|
+
<!-- Multi-Select: Checkbox -->
|
|
630
|
+
<span *ngIf="multiSelect" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
631
|
+
<div [class]="cn(
|
|
632
|
+
'flex h-4 w-4 items-center justify-center rounded-sm border transition-all duration-200',
|
|
633
|
+
selected ? 'border-primary bg-primary text-primary-foreground' : 'border-input'
|
|
634
|
+
)">
|
|
635
|
+
<i [class]="cn(
|
|
636
|
+
'ri-check-line text-xs transition-all duration-200',
|
|
637
|
+
selected ? 'opacity-100 scale-100' : 'opacity-0 scale-75'
|
|
638
|
+
)"></i>
|
|
639
|
+
</div>
|
|
640
|
+
</span>
|
|
641
|
+
|
|
642
|
+
<!-- Content -->
|
|
643
|
+
<span class="flex-1 truncate">
|
|
644
|
+
<ng-content></ng-content>
|
|
645
|
+
</span>
|
|
646
|
+
|
|
647
|
+
<!-- Disabled indicator -->
|
|
648
|
+
<span *ngIf="disabled && !selected" class="ml-2 text-xs text-muted-foreground/50">
|
|
649
|
+
<i class="ri-forbid-line"></i>
|
|
650
|
+
</span>
|
|
571
651
|
</div>
|
|
572
652
|
`,
|
|
573
653
|
}]
|
|
@@ -579,6 +659,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
579
659
|
type: Input
|
|
580
660
|
}], selected: [{
|
|
581
661
|
type: Input
|
|
662
|
+
}], disabled: [{
|
|
663
|
+
type: Input
|
|
664
|
+
}], multiSelect: [{
|
|
665
|
+
type: Input
|
|
582
666
|
}], onClick: [{
|
|
583
667
|
type: HostListener,
|
|
584
668
|
args: ['click', ['$event']]
|
|
@@ -618,44 +702,25 @@ class SelectComponent {
|
|
|
618
702
|
this.close();
|
|
619
703
|
}));
|
|
620
704
|
}
|
|
621
|
-
// SIMPLIFIED: Zardui-inspired trigger styling
|
|
622
705
|
get computedTriggerClass() {
|
|
623
|
-
return cn(
|
|
624
|
-
// Base styles
|
|
625
|
-
'flex w-full items-center justify-between rounded-md border transition-all duration-200', 'bg-background text-foreground',
|
|
626
|
-
// Border and shadow
|
|
627
|
-
'border-input shadow-sm',
|
|
628
|
-
// Sizing
|
|
629
|
-
this.size === 'xs' && 'h-8 px-2 text-xs', this.size === 'sm' && 'h-9 px-3 text-sm', this.size === 'default' && 'h-10 px-3 text-sm', this.size === 'lg' && 'h-11 px-4 text-base',
|
|
630
|
-
// Focus state - SIMPLE LIKE ZARDUI
|
|
631
|
-
!(this.readonly || this.disabled) && [
|
|
706
|
+
return cn('flex w-full items-center justify-between rounded-md border transition-all duration-200', 'bg-background text-foreground', 'border-input shadow-sm', this.size === 'xs' && 'h-8 px-2 text-xs', this.size === 'sm' && 'h-9 px-3 text-sm', this.size === 'default' && 'h-10 px-3 text-sm', this.size === 'lg' && 'h-11 px-4 text-base', !(this.readonly || this.disabled) && [
|
|
632
707
|
'focus:outline-none',
|
|
633
708
|
'focus:ring-4',
|
|
634
709
|
'focus:ring-ring/30',
|
|
635
710
|
'focus:ring-offset-0',
|
|
636
711
|
'focus:shadow-none',
|
|
637
|
-
// Border darkens on focus automatically
|
|
638
712
|
'focus:border-primary/80'
|
|
639
|
-
],
|
|
640
|
-
// Hover state
|
|
641
|
-
!(this.readonly || this.disabled) && 'hover:border-accent',
|
|
642
|
-
// Disabled state
|
|
643
|
-
this.disabled && [
|
|
713
|
+
], !(this.readonly || this.disabled) && 'hover:border-accent', this.disabled && [
|
|
644
714
|
'cursor-not-allowed opacity-50',
|
|
645
715
|
'border-opacity-50'
|
|
646
|
-
],
|
|
647
|
-
// Readonly state
|
|
648
|
-
this.readonly && [
|
|
716
|
+
], this.readonly && [
|
|
649
717
|
'cursor-default',
|
|
650
718
|
'border-dashed',
|
|
651
719
|
!this.disabled && 'focus:ring-0 focus:border-opacity-100'
|
|
652
720
|
], this.class);
|
|
653
721
|
}
|
|
654
|
-
// UPDATED: Dynamic icon sizing relative to the trigger size
|
|
655
722
|
get iconClass() {
|
|
656
|
-
return cn('ri-arrow-down-s-line text-muted-foreground ml-2 transition-transform duration-200', this.isOpen ? 'rotate-180' : '', (this.size === 'xs' || this.size === 'sm') ? 'text-[14px]' : 'text-[18px]',
|
|
657
|
-
// Hide or fade icon when interaction is blocked
|
|
658
|
-
(this.disabled || this.readonly) && 'opacity-30');
|
|
723
|
+
return cn('ri-arrow-down-s-line text-muted-foreground ml-2 transition-transform duration-200', this.isOpen ? 'rotate-180' : '', (this.size === 'xs' || this.size === 'sm') ? 'text-[14px]' : 'text-[18px]', (this.disabled || this.readonly) && 'opacity-30');
|
|
659
724
|
}
|
|
660
725
|
ngAfterContentInit() {
|
|
661
726
|
this.updateItemSelection();
|
|
@@ -675,9 +740,7 @@ class SelectComponent {
|
|
|
675
740
|
}
|
|
676
741
|
open() {
|
|
677
742
|
this.isOpen = true;
|
|
678
|
-
// Trigger focus on the button for focus styling
|
|
679
743
|
this.trigger.nativeElement.focus();
|
|
680
|
-
// Tick to ensure DOM is rendered before positioning
|
|
681
744
|
setTimeout(() => this.updatePosition());
|
|
682
745
|
}
|
|
683
746
|
close() {
|
|
@@ -692,10 +755,25 @@ class SelectComponent {
|
|
|
692
755
|
return;
|
|
693
756
|
this.cleanupAutoUpdate = autoUpdate(this.trigger.nativeElement, this.popover.nativeElement, () => {
|
|
694
757
|
computePosition(this.trigger.nativeElement, this.popover.nativeElement, {
|
|
758
|
+
strategy: 'fixed', // 3. Use fixed strategy
|
|
695
759
|
placement: 'bottom-start',
|
|
696
|
-
middleware: [
|
|
697
|
-
|
|
760
|
+
middleware: [
|
|
761
|
+
offset(4),
|
|
762
|
+
flip(),
|
|
763
|
+
shift({ padding: 8 }),
|
|
764
|
+
// 4. Use size middleware to sync width and handle constraints
|
|
765
|
+
size({
|
|
766
|
+
apply({ rects, elements, availableHeight }) {
|
|
767
|
+
Object.assign(elements.floating.style, {
|
|
768
|
+
width: `${rects.reference.width}px`,
|
|
769
|
+
maxHeight: `${availableHeight}px`
|
|
770
|
+
});
|
|
771
|
+
},
|
|
772
|
+
}),
|
|
773
|
+
],
|
|
774
|
+
}).then(({ x, y, strategy }) => {
|
|
698
775
|
Object.assign(this.popover.nativeElement.style, {
|
|
776
|
+
position: strategy, // 5. Apply strategy to style
|
|
699
777
|
left: `${x}px`,
|
|
700
778
|
top: `${y}px`,
|
|
701
779
|
visibility: 'visible',
|
|
@@ -746,7 +824,7 @@ class SelectComponent {
|
|
|
746
824
|
multi: true
|
|
747
825
|
}
|
|
748
826
|
], queries: [{ propertyName: "items", predicate: SelectItemComponent, descendants: true }], viewQueries: [{ propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true }, { propertyName: "popover", first: true, predicate: ["popover"], descendants: true }, { propertyName: "container", first: true, predicate: ["container"], descendants: true }], ngImport: i0, template: `
|
|
749
|
-
<div [class]="cn('w-full', 'size-' + size)" #container>
|
|
827
|
+
<div [class]="cn('relative w-full', 'size-' + size)" #container>
|
|
750
828
|
<button
|
|
751
829
|
type="button"
|
|
752
830
|
#trigger
|
|
@@ -763,8 +841,7 @@ class SelectComponent {
|
|
|
763
841
|
<div
|
|
764
842
|
#popover
|
|
765
843
|
*ngIf="isOpen"
|
|
766
|
-
|
|
767
|
-
class="absolute bg-popover z-50 min-w-full max-h-[300px] overflow-auto flex flex-col rounded-md border border-border text-popover-foreground shadow-md"
|
|
844
|
+
class="fixed bg-popover z-[999] overflow-auto flex flex-col rounded-md border border-border text-popover-foreground shadow-md"
|
|
768
845
|
style="visibility: hidden; top: 0; left: 0;">
|
|
769
846
|
<div *ngIf="searchable" class="p-2 border-b border-border bg-popover h-auto">
|
|
770
847
|
<tolle-input
|
|
@@ -785,7 +862,7 @@ class SelectComponent {
|
|
|
785
862
|
</div>
|
|
786
863
|
</div>
|
|
787
864
|
</div>
|
|
788
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "
|
|
865
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: InputComponent, selector: "tolle-input", inputs: ["id", "label", "hint", "errorMessage", "type", "placeholder", "size", "containerClass", "class", "disabled", "readonly", "error", "hideHintOnFocus"] }] });
|
|
789
866
|
}
|
|
790
867
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SelectComponent, decorators: [{
|
|
791
868
|
type: Component,
|
|
@@ -802,7 +879,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
802
879
|
}
|
|
803
880
|
],
|
|
804
881
|
template: `
|
|
805
|
-
<div [class]="cn('w-full', 'size-' + size)" #container>
|
|
882
|
+
<div [class]="cn('relative w-full', 'size-' + size)" #container>
|
|
806
883
|
<button
|
|
807
884
|
type="button"
|
|
808
885
|
#trigger
|
|
@@ -819,8 +896,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
819
896
|
<div
|
|
820
897
|
#popover
|
|
821
898
|
*ngIf="isOpen"
|
|
822
|
-
|
|
823
|
-
class="absolute bg-popover z-50 min-w-full max-h-[300px] overflow-auto flex flex-col rounded-md border border-border text-popover-foreground shadow-md"
|
|
899
|
+
class="fixed bg-popover z-[999] overflow-auto flex flex-col rounded-md border border-border text-popover-foreground shadow-md"
|
|
824
900
|
style="visibility: hidden; top: 0; left: 0;">
|
|
825
901
|
<div *ngIf="searchable" class="p-2 border-b border-border bg-popover h-auto">
|
|
826
902
|
<tolle-input
|
|
@@ -1866,6 +1942,9 @@ class MultiSelectComponent {
|
|
|
1866
1942
|
searchable = false;
|
|
1867
1943
|
disabled = false;
|
|
1868
1944
|
class = '';
|
|
1945
|
+
maxSelections;
|
|
1946
|
+
maxDisplayItems = 3;
|
|
1947
|
+
error = false; // Added to support error styling
|
|
1869
1948
|
trigger;
|
|
1870
1949
|
popover;
|
|
1871
1950
|
items;
|
|
@@ -1882,10 +1961,58 @@ class MultiSelectComponent {
|
|
|
1882
1961
|
this.toggleValue(val);
|
|
1883
1962
|
});
|
|
1884
1963
|
}
|
|
1964
|
+
// NEW: Matches InputComponent styles exactly
|
|
1965
|
+
get computedTriggerClass() {
|
|
1966
|
+
return cn(
|
|
1967
|
+
// Base styles
|
|
1968
|
+
'flex min-h-10 w-full items-center justify-between rounded-md border transition-all duration-200 h-auto', 'bg-background text-sm',
|
|
1969
|
+
// Border and shadow
|
|
1970
|
+
'border-input shadow-sm',
|
|
1971
|
+
// Padding based on size (aligned with InputComponent logic)
|
|
1972
|
+
this.size === 'xs' && 'px-2 py-1', this.size === 'sm' && 'px-3 py-1.5', this.size === 'default' && 'px-3 py-2', this.size === 'lg' && 'px-4 py-2',
|
|
1973
|
+
// Focus state - ZARDUI STYLE (Soft ring, no offset)
|
|
1974
|
+
!this.disabled && [
|
|
1975
|
+
'focus:outline-none',
|
|
1976
|
+
'focus:ring-4',
|
|
1977
|
+
'focus:ring-ring/30',
|
|
1978
|
+
'focus:ring-offset-0',
|
|
1979
|
+
'focus:shadow-none',
|
|
1980
|
+
'focus:border-primary/80' // Darkens border on focus
|
|
1981
|
+
],
|
|
1982
|
+
// Hover state
|
|
1983
|
+
!this.disabled && 'hover:border-accent',
|
|
1984
|
+
// Error state
|
|
1985
|
+
this.error && [
|
|
1986
|
+
'border-destructive',
|
|
1987
|
+
!this.disabled && [
|
|
1988
|
+
'focus:border-destructive/80',
|
|
1989
|
+
'focus:ring-destructive/30'
|
|
1990
|
+
]
|
|
1991
|
+
],
|
|
1992
|
+
// Disabled state
|
|
1993
|
+
this.disabled && [
|
|
1994
|
+
'cursor-not-allowed opacity-50',
|
|
1995
|
+
'border-opacity-50'
|
|
1996
|
+
], this.class);
|
|
1997
|
+
}
|
|
1885
1998
|
ngAfterContentInit() {
|
|
1886
1999
|
this.syncItems();
|
|
1887
2000
|
this.items.changes.subscribe(() => this.syncItems());
|
|
1888
2001
|
}
|
|
2002
|
+
get displayItems() {
|
|
2003
|
+
return this.selectedItems.slice(0, this.maxDisplayItems);
|
|
2004
|
+
}
|
|
2005
|
+
get exceedsDisplayLimit() {
|
|
2006
|
+
return this.value.length > this.maxDisplayItems;
|
|
2007
|
+
}
|
|
2008
|
+
get selectableItems() {
|
|
2009
|
+
return this.items ? this.items.filter(item => !item.disabled) : [];
|
|
2010
|
+
}
|
|
2011
|
+
get availableSelections() {
|
|
2012
|
+
if (!this.maxSelections)
|
|
2013
|
+
return Infinity;
|
|
2014
|
+
return Math.max(0, this.maxSelections - this.value.length);
|
|
2015
|
+
}
|
|
1889
2016
|
toggle() {
|
|
1890
2017
|
if (this.disabled)
|
|
1891
2018
|
return;
|
|
@@ -1897,16 +2024,34 @@ class MultiSelectComponent {
|
|
|
1897
2024
|
}
|
|
1898
2025
|
close() {
|
|
1899
2026
|
this.isOpen = false;
|
|
2027
|
+
this.searchQuery = '';
|
|
2028
|
+
this.onSearchChange('');
|
|
1900
2029
|
if (this.cleanup)
|
|
1901
2030
|
this.cleanup();
|
|
1902
2031
|
}
|
|
1903
2032
|
updatePosition() {
|
|
2033
|
+
if (!this.trigger || !this.popover)
|
|
2034
|
+
return;
|
|
1904
2035
|
this.cleanup = autoUpdate(this.trigger.nativeElement, this.popover.nativeElement, () => {
|
|
1905
2036
|
computePosition(this.trigger.nativeElement, this.popover.nativeElement, {
|
|
2037
|
+
strategy: 'fixed',
|
|
1906
2038
|
placement: 'bottom-start',
|
|
1907
|
-
middleware: [
|
|
1908
|
-
|
|
2039
|
+
middleware: [
|
|
2040
|
+
offset(4),
|
|
2041
|
+
flip(),
|
|
2042
|
+
shift({ padding: 8 }),
|
|
2043
|
+
size({
|
|
2044
|
+
apply({ rects, elements, availableHeight }) {
|
|
2045
|
+
Object.assign(elements.floating.style, {
|
|
2046
|
+
width: `${rects.reference.width}px`,
|
|
2047
|
+
maxHeight: `${availableHeight}px`
|
|
2048
|
+
});
|
|
2049
|
+
},
|
|
2050
|
+
}),
|
|
2051
|
+
],
|
|
2052
|
+
}).then(({ x, y, strategy }) => {
|
|
1909
2053
|
Object.assign(this.popover.nativeElement.style, {
|
|
2054
|
+
position: strategy,
|
|
1910
2055
|
left: `${x}px`,
|
|
1911
2056
|
top: `${y}px`,
|
|
1912
2057
|
visibility: 'visible',
|
|
@@ -1916,12 +2061,32 @@ class MultiSelectComponent {
|
|
|
1916
2061
|
}
|
|
1917
2062
|
toggleValue(val) {
|
|
1918
2063
|
const index = this.value.indexOf(val);
|
|
1919
|
-
index > -1
|
|
2064
|
+
if (index > -1) {
|
|
2065
|
+
this.value.splice(index, 1);
|
|
2066
|
+
}
|
|
2067
|
+
else {
|
|
2068
|
+
if (this.maxSelections && this.value.length >= this.maxSelections)
|
|
2069
|
+
return;
|
|
2070
|
+
this.value.push(val);
|
|
2071
|
+
}
|
|
1920
2072
|
this.syncItems();
|
|
1921
|
-
this.onChange([...this.value]);
|
|
2073
|
+
this.onChange([...this.value]);
|
|
1922
2074
|
}
|
|
1923
2075
|
selectAll() {
|
|
1924
|
-
|
|
2076
|
+
if (!this.items)
|
|
2077
|
+
return;
|
|
2078
|
+
let itemsToSelect = [];
|
|
2079
|
+
if (this.maxSelections) {
|
|
2080
|
+
const availableItems = this.items
|
|
2081
|
+
.filter(item => !item.disabled && !this.value.includes(item.value))
|
|
2082
|
+
.slice(0, this.availableSelections)
|
|
2083
|
+
.map(item => item.value);
|
|
2084
|
+
itemsToSelect = [...this.value, ...availableItems];
|
|
2085
|
+
}
|
|
2086
|
+
else {
|
|
2087
|
+
itemsToSelect = this.items.filter(item => !item.disabled).map(item => item.value);
|
|
2088
|
+
}
|
|
2089
|
+
this.value = itemsToSelect;
|
|
1925
2090
|
this.syncItems();
|
|
1926
2091
|
this.onChange([...this.value]);
|
|
1927
2092
|
}
|
|
@@ -1940,8 +2105,15 @@ class MultiSelectComponent {
|
|
|
1940
2105
|
this.selectedItems = [];
|
|
1941
2106
|
this.items.forEach(item => {
|
|
1942
2107
|
item.selected = this.value.includes(item.value);
|
|
1943
|
-
if (item.selected)
|
|
2108
|
+
if (item.selected) {
|
|
1944
2109
|
this.selectedItems.push({ label: item.getLabel(), value: item.value });
|
|
2110
|
+
}
|
|
2111
|
+
if (this.maxSelections && this.value.length >= this.maxSelections) {
|
|
2112
|
+
item.disabled = !this.value.includes(item.value);
|
|
2113
|
+
}
|
|
2114
|
+
else if (item.disabled) {
|
|
2115
|
+
item.disabled = false;
|
|
2116
|
+
}
|
|
1945
2117
|
});
|
|
1946
2118
|
}
|
|
1947
2119
|
onSearchChange(q) {
|
|
@@ -1963,45 +2135,93 @@ class MultiSelectComponent {
|
|
|
1963
2135
|
// ControlValueAccessor
|
|
1964
2136
|
onChange = () => { };
|
|
1965
2137
|
onTouched = () => { };
|
|
1966
|
-
writeValue(v) {
|
|
2138
|
+
writeValue(v) {
|
|
2139
|
+
this.value = Array.isArray(v) ? v : [];
|
|
2140
|
+
this.syncItems();
|
|
2141
|
+
}
|
|
1967
2142
|
registerOnChange(fn) { this.onChange = fn; }
|
|
1968
2143
|
registerOnTouched(fn) { this.onTouched = fn; }
|
|
2144
|
+
setDisabledState(isDisabled) { this.disabled = isDisabled; }
|
|
1969
2145
|
cn = cn;
|
|
1970
2146
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MultiSelectComponent, deps: [{ token: SelectService }], target: i0.ɵɵFactoryTarget.Component });
|
|
1971
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: MultiSelectComponent, isStandalone: true, selector: "tolle-multi-select", inputs: { placeholder: "placeholder", size: "size", searchable: "searchable", disabled: "disabled", class: "class" }, host: { listeners: { "document:mousedown": "onClickOutside($event)" } }, providers: [
|
|
2147
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: MultiSelectComponent, isStandalone: true, selector: "tolle-multi-select", inputs: { placeholder: "placeholder", size: "size", searchable: "searchable", disabled: "disabled", class: "class", maxSelections: "maxSelections", maxDisplayItems: "maxDisplayItems", error: "error" }, host: { listeners: { "document:mousedown": "onClickOutside($event)" } }, providers: [
|
|
1972
2148
|
SelectService,
|
|
1973
2149
|
{ provide: NG_VALUE_ACCESSOR, useExisting: MultiSelectComponent, multi: true }
|
|
1974
2150
|
], queries: [{ propertyName: "items", predicate: SelectItemComponent, descendants: true }], viewQueries: [{ propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true }, { propertyName: "popover", first: true, predicate: ["popover"], descendants: true }], ngImport: i0, template: `
|
|
1975
2151
|
<div [class]="cn('relative w-full', 'size-' + size)" #container>
|
|
1976
|
-
<button
|
|
1977
|
-
|
|
2152
|
+
<button
|
|
2153
|
+
#trigger
|
|
2154
|
+
type="button"
|
|
2155
|
+
(click)="toggle()"
|
|
2156
|
+
[disabled]="disabled"
|
|
2157
|
+
[class]="computedTriggerClass">
|
|
2158
|
+
|
|
1978
2159
|
<div class="flex flex-wrap gap-1 items-center max-w-[95%]">
|
|
1979
2160
|
<ng-container *ngIf="value?.length; else placeholderTpl">
|
|
1980
|
-
<tolle-badge *ngFor="let item of
|
|
2161
|
+
<tolle-badge *ngFor="let item of displayItems" size="xs" variant="secondary" [removable]="true" (onRemove)="removeValue($event, item.value)">
|
|
1981
2162
|
{{ item.label }}
|
|
1982
2163
|
</tolle-badge>
|
|
2164
|
+
<span *ngIf="exceedsDisplayLimit" class="text-xs text-muted-foreground px-1">
|
|
2165
|
+
+{{ value.length - maxDisplayItems }} more
|
|
2166
|
+
</span>
|
|
2167
|
+
<span *ngIf="maxSelections && value.length >= maxSelections" class="text-xs text-muted-foreground px-1">
|
|
2168
|
+
(Max reached)
|
|
2169
|
+
</span>
|
|
1983
2170
|
</ng-container>
|
|
1984
2171
|
<ng-template #placeholderTpl><span class="text-muted-foreground">{{ placeholder }}</span></ng-template>
|
|
1985
2172
|
</div>
|
|
1986
|
-
<i [class]="cn('ri-arrow-down-s-line text-muted-foreground ml-2 transition-transform', isOpen ? 'rotate-180' : '')"></i>
|
|
2173
|
+
<i [class]="cn('ri-arrow-down-s-line text-muted-foreground ml-2 transition-transform duration-200', isOpen ? 'rotate-180' : '')"></i>
|
|
1987
2174
|
</button>
|
|
1988
2175
|
|
|
1989
|
-
<div #popover *ngIf="isOpen"
|
|
2176
|
+
<div #popover *ngIf="isOpen"
|
|
2177
|
+
class="fixed bg-popover z-[999] rounded-md border border-border shadow-md overflow-hidden"
|
|
2178
|
+
style="visibility: hidden; top: 0; left: 0;">
|
|
1990
2179
|
|
|
1991
2180
|
<div class="p-2 border-b border-border space-y-2 bg-popover">
|
|
2181
|
+
<div class="flex items-center justify-between px-1 text-xs">
|
|
2182
|
+
<span class="text-muted-foreground">
|
|
2183
|
+
{{ value.length }} selected
|
|
2184
|
+
<span *ngIf="maxSelections">/ {{ maxSelections }} max</span>
|
|
2185
|
+
</span>
|
|
2186
|
+
<span *ngIf="maxSelections && value.length >= maxSelections" class="text-destructive text-xs font-medium">
|
|
2187
|
+
Maximum reached
|
|
2188
|
+
</span>
|
|
2189
|
+
</div>
|
|
2190
|
+
|
|
1992
2191
|
<tolle-input *ngIf="searchable" size="xs" placeholder="Search..." [(ngModel)]="searchQuery" (ngModelChange)="onSearchChange($event)">
|
|
1993
2192
|
<i prefix class="ri-search-line"></i>
|
|
1994
2193
|
</tolle-input>
|
|
1995
2194
|
|
|
1996
2195
|
<div class="flex items-center justify-between px-1">
|
|
1997
|
-
<button type="button"
|
|
1998
|
-
|
|
2196
|
+
<button type="button"
|
|
2197
|
+
(click)="selectAll()"
|
|
2198
|
+
[disabled]="maxSelections && selectableItems.length > maxSelections"
|
|
2199
|
+
[class]="cn(
|
|
2200
|
+
'text-[10px] font-bold uppercase transition-colors',
|
|
2201
|
+
maxSelections && selectableItems.length > maxSelections
|
|
2202
|
+
? 'text-muted-foreground cursor-not-allowed'
|
|
2203
|
+
: 'text-primary hover:underline'
|
|
2204
|
+
)">
|
|
2205
|
+
Select All
|
|
2206
|
+
</button>
|
|
2207
|
+
<button type="button" (click)="clearAll()" class="text-[10px] font-bold uppercase text-muted-foreground hover:underline">
|
|
2208
|
+
Clear
|
|
2209
|
+
</button>
|
|
1999
2210
|
</div>
|
|
2000
2211
|
</div>
|
|
2001
2212
|
|
|
2002
2213
|
<div class="p-1 max-h-60 overflow-y-auto">
|
|
2003
2214
|
<ng-content></ng-content>
|
|
2004
|
-
<div *ngIf="noResults" class="py-4 text-center text-xs text-muted-foreground">
|
|
2215
|
+
<div *ngIf="noResults" class="py-4 text-center text-xs text-muted-foreground">
|
|
2216
|
+
No results found for "{{searchQuery}}"
|
|
2217
|
+
</div>
|
|
2218
|
+
<div *ngIf="maxSelections && value.length >= maxSelections"
|
|
2219
|
+
class="p-2 text-center border-t border-border bg-muted/20">
|
|
2220
|
+
<span class="text-xs text-destructive">
|
|
2221
|
+
<i class="ri-alert-line mr-1"></i>
|
|
2222
|
+
Maximum selection limit reached ({{maxSelections}})
|
|
2223
|
+
</span>
|
|
2224
|
+
</div>
|
|
2005
2225
|
</div>
|
|
2006
2226
|
</div>
|
|
2007
2227
|
</div>
|
|
@@ -2019,35 +2239,79 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
2019
2239
|
],
|
|
2020
2240
|
template: `
|
|
2021
2241
|
<div [class]="cn('relative w-full', 'size-' + size)" #container>
|
|
2022
|
-
<button
|
|
2023
|
-
|
|
2242
|
+
<button
|
|
2243
|
+
#trigger
|
|
2244
|
+
type="button"
|
|
2245
|
+
(click)="toggle()"
|
|
2246
|
+
[disabled]="disabled"
|
|
2247
|
+
[class]="computedTriggerClass">
|
|
2248
|
+
|
|
2024
2249
|
<div class="flex flex-wrap gap-1 items-center max-w-[95%]">
|
|
2025
2250
|
<ng-container *ngIf="value?.length; else placeholderTpl">
|
|
2026
|
-
<tolle-badge *ngFor="let item of
|
|
2251
|
+
<tolle-badge *ngFor="let item of displayItems" size="xs" variant="secondary" [removable]="true" (onRemove)="removeValue($event, item.value)">
|
|
2027
2252
|
{{ item.label }}
|
|
2028
2253
|
</tolle-badge>
|
|
2254
|
+
<span *ngIf="exceedsDisplayLimit" class="text-xs text-muted-foreground px-1">
|
|
2255
|
+
+{{ value.length - maxDisplayItems }} more
|
|
2256
|
+
</span>
|
|
2257
|
+
<span *ngIf="maxSelections && value.length >= maxSelections" class="text-xs text-muted-foreground px-1">
|
|
2258
|
+
(Max reached)
|
|
2259
|
+
</span>
|
|
2029
2260
|
</ng-container>
|
|
2030
2261
|
<ng-template #placeholderTpl><span class="text-muted-foreground">{{ placeholder }}</span></ng-template>
|
|
2031
2262
|
</div>
|
|
2032
|
-
<i [class]="cn('ri-arrow-down-s-line text-muted-foreground ml-2 transition-transform', isOpen ? 'rotate-180' : '')"></i>
|
|
2263
|
+
<i [class]="cn('ri-arrow-down-s-line text-muted-foreground ml-2 transition-transform duration-200', isOpen ? 'rotate-180' : '')"></i>
|
|
2033
2264
|
</button>
|
|
2034
2265
|
|
|
2035
|
-
<div #popover *ngIf="isOpen"
|
|
2266
|
+
<div #popover *ngIf="isOpen"
|
|
2267
|
+
class="fixed bg-popover z-[999] rounded-md border border-border shadow-md overflow-hidden"
|
|
2268
|
+
style="visibility: hidden; top: 0; left: 0;">
|
|
2036
2269
|
|
|
2037
2270
|
<div class="p-2 border-b border-border space-y-2 bg-popover">
|
|
2271
|
+
<div class="flex items-center justify-between px-1 text-xs">
|
|
2272
|
+
<span class="text-muted-foreground">
|
|
2273
|
+
{{ value.length }} selected
|
|
2274
|
+
<span *ngIf="maxSelections">/ {{ maxSelections }} max</span>
|
|
2275
|
+
</span>
|
|
2276
|
+
<span *ngIf="maxSelections && value.length >= maxSelections" class="text-destructive text-xs font-medium">
|
|
2277
|
+
Maximum reached
|
|
2278
|
+
</span>
|
|
2279
|
+
</div>
|
|
2280
|
+
|
|
2038
2281
|
<tolle-input *ngIf="searchable" size="xs" placeholder="Search..." [(ngModel)]="searchQuery" (ngModelChange)="onSearchChange($event)">
|
|
2039
2282
|
<i prefix class="ri-search-line"></i>
|
|
2040
2283
|
</tolle-input>
|
|
2041
2284
|
|
|
2042
2285
|
<div class="flex items-center justify-between px-1">
|
|
2043
|
-
<button type="button"
|
|
2044
|
-
|
|
2286
|
+
<button type="button"
|
|
2287
|
+
(click)="selectAll()"
|
|
2288
|
+
[disabled]="maxSelections && selectableItems.length > maxSelections"
|
|
2289
|
+
[class]="cn(
|
|
2290
|
+
'text-[10px] font-bold uppercase transition-colors',
|
|
2291
|
+
maxSelections && selectableItems.length > maxSelections
|
|
2292
|
+
? 'text-muted-foreground cursor-not-allowed'
|
|
2293
|
+
: 'text-primary hover:underline'
|
|
2294
|
+
)">
|
|
2295
|
+
Select All
|
|
2296
|
+
</button>
|
|
2297
|
+
<button type="button" (click)="clearAll()" class="text-[10px] font-bold uppercase text-muted-foreground hover:underline">
|
|
2298
|
+
Clear
|
|
2299
|
+
</button>
|
|
2045
2300
|
</div>
|
|
2046
2301
|
</div>
|
|
2047
2302
|
|
|
2048
2303
|
<div class="p-1 max-h-60 overflow-y-auto">
|
|
2049
2304
|
<ng-content></ng-content>
|
|
2050
|
-
<div *ngIf="noResults" class="py-4 text-center text-xs text-muted-foreground">
|
|
2305
|
+
<div *ngIf="noResults" class="py-4 text-center text-xs text-muted-foreground">
|
|
2306
|
+
No results found for "{{searchQuery}}"
|
|
2307
|
+
</div>
|
|
2308
|
+
<div *ngIf="maxSelections && value.length >= maxSelections"
|
|
2309
|
+
class="p-2 text-center border-t border-border bg-muted/20">
|
|
2310
|
+
<span class="text-xs text-destructive">
|
|
2311
|
+
<i class="ri-alert-line mr-1"></i>
|
|
2312
|
+
Maximum selection limit reached ({{maxSelections}})
|
|
2313
|
+
</span>
|
|
2314
|
+
</div>
|
|
2051
2315
|
</div>
|
|
2052
2316
|
</div>
|
|
2053
2317
|
</div>
|
|
@@ -2063,6 +2327,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
2063
2327
|
type: Input
|
|
2064
2328
|
}], class: [{
|
|
2065
2329
|
type: Input
|
|
2330
|
+
}], maxSelections: [{
|
|
2331
|
+
type: Input
|
|
2332
|
+
}], maxDisplayItems: [{
|
|
2333
|
+
type: Input
|
|
2334
|
+
}], error: [{
|
|
2335
|
+
type: Input
|
|
2066
2336
|
}], trigger: [{
|
|
2067
2337
|
type: ViewChild,
|
|
2068
2338
|
args: ['trigger']
|
|
@@ -2079,7 +2349,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
2079
2349
|
|
|
2080
2350
|
class CalendarComponent {
|
|
2081
2351
|
class = '';
|
|
2352
|
+
mode = 'date';
|
|
2082
2353
|
disablePastDates = false;
|
|
2354
|
+
showQuickActions = true;
|
|
2355
|
+
minDate;
|
|
2356
|
+
maxDate;
|
|
2357
|
+
formatMonthFn;
|
|
2358
|
+
formatYearFn;
|
|
2359
|
+
formatDateFn;
|
|
2360
|
+
dateSelect = new EventEmitter();
|
|
2083
2361
|
currentView = 'date';
|
|
2084
2362
|
viewDate = new Date();
|
|
2085
2363
|
selectedDate = null;
|
|
@@ -2087,87 +2365,219 @@ class CalendarComponent {
|
|
|
2087
2365
|
daysInMonth = [];
|
|
2088
2366
|
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
2089
2367
|
years = [];
|
|
2368
|
+
yearRangeStart;
|
|
2090
2369
|
navBtnClass = cn('h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100 border border-input rounded-md flex items-center justify-center hover:bg-accent hover:text-accent-foreground transition-all');
|
|
2370
|
+
quickActionBtnClass = cn('px-3 py-1.5 text-sm rounded hover:bg-accent text-muted-foreground hover:text-foreground transition-colors');
|
|
2091
2371
|
onTouched = () => { };
|
|
2092
2372
|
onChange = () => { };
|
|
2093
2373
|
cn = cn;
|
|
2374
|
+
constructor() {
|
|
2375
|
+
this.yearRangeStart = new Date().getFullYear() - 6;
|
|
2376
|
+
}
|
|
2094
2377
|
ngOnInit() {
|
|
2378
|
+
// Initialize based on mode
|
|
2379
|
+
if (this.mode === 'month') {
|
|
2380
|
+
this.currentView = 'month';
|
|
2381
|
+
}
|
|
2382
|
+
else if (this.mode === 'year') {
|
|
2383
|
+
this.currentView = 'year';
|
|
2384
|
+
}
|
|
2095
2385
|
this.generateDays();
|
|
2096
2386
|
this.generateYears();
|
|
2097
2387
|
}
|
|
2388
|
+
// Format helpers
|
|
2389
|
+
formatMonthYear(date, type) {
|
|
2390
|
+
if (type === 'month' && this.formatMonthFn) {
|
|
2391
|
+
return this.formatMonthFn(date);
|
|
2392
|
+
}
|
|
2393
|
+
if (type === 'year' && this.formatYearFn) {
|
|
2394
|
+
return this.formatYearFn(date);
|
|
2395
|
+
}
|
|
2396
|
+
return type === 'month' ? format(date, 'MMMM') : format(date, 'yyyy');
|
|
2397
|
+
}
|
|
2398
|
+
formatDate(date, type) {
|
|
2399
|
+
if (type === 'day' && this.formatDateFn) {
|
|
2400
|
+
return this.formatDateFn(date);
|
|
2401
|
+
}
|
|
2402
|
+
return format(date, type === 'day' ? 'd' : type === 'month' ? 'MMM' : 'yyyy');
|
|
2403
|
+
}
|
|
2098
2404
|
generateDays() {
|
|
2405
|
+
if (this.mode !== 'date')
|
|
2406
|
+
return;
|
|
2099
2407
|
const start = startOfWeek(startOfMonth(this.viewDate));
|
|
2100
2408
|
const end = endOfWeek(endOfMonth(this.viewDate));
|
|
2101
2409
|
this.daysInMonth = eachDayOfInterval({ start, end });
|
|
2102
2410
|
}
|
|
2103
2411
|
generateYears() {
|
|
2104
2412
|
const currentYear = this.viewDate.getFullYear();
|
|
2105
|
-
|
|
2106
|
-
|
|
2413
|
+
if (this.mode === 'year') {
|
|
2414
|
+
// For year picker, show a 12-year grid
|
|
2415
|
+
this.years = Array.from({ length: 12 }, (_, i) => this.yearRangeStart + i);
|
|
2416
|
+
}
|
|
2417
|
+
else {
|
|
2418
|
+
// For date mode year selector, show 16 years centered on current
|
|
2419
|
+
this.years = Array.from({ length: 16 }, (_, i) => currentYear - 6 + i);
|
|
2420
|
+
}
|
|
2107
2421
|
}
|
|
2108
2422
|
setView(view) {
|
|
2109
2423
|
this.currentView = view;
|
|
2110
|
-
// If switching to year view, ensure the year grid is centered on current view year
|
|
2111
2424
|
if (view === 'year') {
|
|
2112
2425
|
this.generateYears();
|
|
2113
2426
|
}
|
|
2114
2427
|
}
|
|
2115
2428
|
prev() {
|
|
2116
|
-
if (this.
|
|
2117
|
-
|
|
2118
|
-
|
|
2429
|
+
if (this.mode === 'date') {
|
|
2430
|
+
if (this.currentView === 'date') {
|
|
2431
|
+
this.viewDate = subMonths(this.viewDate, 1);
|
|
2432
|
+
this.generateDays();
|
|
2433
|
+
}
|
|
2434
|
+
else if (this.currentView === 'year') {
|
|
2435
|
+
this.viewDate = subYears(this.viewDate, 16);
|
|
2436
|
+
this.generateYears();
|
|
2437
|
+
}
|
|
2438
|
+
else if (this.currentView === 'month') {
|
|
2439
|
+
this.viewDate = subYears(this.viewDate, 1);
|
|
2440
|
+
}
|
|
2119
2441
|
}
|
|
2120
|
-
else if (this.
|
|
2121
|
-
this.viewDate = subYears(this.viewDate,
|
|
2442
|
+
else if (this.mode === 'month') {
|
|
2443
|
+
this.viewDate = subYears(this.viewDate, 1);
|
|
2444
|
+
}
|
|
2445
|
+
else if (this.mode === 'year') {
|
|
2446
|
+
this.yearRangeStart -= 12;
|
|
2122
2447
|
this.generateYears();
|
|
2123
2448
|
}
|
|
2124
|
-
else if (this.
|
|
2125
|
-
|
|
2449
|
+
else if (this.mode === 'month-year') {
|
|
2450
|
+
if (this.currentView === 'month') {
|
|
2451
|
+
this.viewDate = subYears(this.viewDate, 1);
|
|
2452
|
+
}
|
|
2453
|
+
else {
|
|
2454
|
+
this.yearRangeStart -= 12;
|
|
2455
|
+
this.generateYears();
|
|
2456
|
+
}
|
|
2126
2457
|
}
|
|
2127
2458
|
}
|
|
2128
2459
|
next() {
|
|
2129
|
-
if (this.
|
|
2130
|
-
|
|
2131
|
-
|
|
2460
|
+
if (this.mode === 'date') {
|
|
2461
|
+
if (this.currentView === 'date') {
|
|
2462
|
+
this.viewDate = addMonths(this.viewDate, 1);
|
|
2463
|
+
this.generateDays();
|
|
2464
|
+
}
|
|
2465
|
+
else if (this.currentView === 'year') {
|
|
2466
|
+
this.viewDate = addYears(this.viewDate, 16);
|
|
2467
|
+
this.generateYears();
|
|
2468
|
+
}
|
|
2469
|
+
else if (this.currentView === 'month') {
|
|
2470
|
+
this.viewDate = addYears(this.viewDate, 1);
|
|
2471
|
+
}
|
|
2132
2472
|
}
|
|
2133
|
-
else if (this.
|
|
2134
|
-
this.viewDate = addYears(this.viewDate,
|
|
2473
|
+
else if (this.mode === 'month') {
|
|
2474
|
+
this.viewDate = addYears(this.viewDate, 1);
|
|
2475
|
+
}
|
|
2476
|
+
else if (this.mode === 'year') {
|
|
2477
|
+
this.yearRangeStart += 12;
|
|
2135
2478
|
this.generateYears();
|
|
2136
2479
|
}
|
|
2137
|
-
else if (this.
|
|
2138
|
-
|
|
2480
|
+
else if (this.mode === 'month-year') {
|
|
2481
|
+
if (this.currentView === 'month') {
|
|
2482
|
+
this.viewDate = addYears(this.viewDate, 1);
|
|
2483
|
+
}
|
|
2484
|
+
else {
|
|
2485
|
+
this.yearRangeStart += 12;
|
|
2486
|
+
this.generateYears();
|
|
2487
|
+
}
|
|
2139
2488
|
}
|
|
2140
2489
|
}
|
|
2490
|
+
prevYears() {
|
|
2491
|
+
this.yearRangeStart -= 12;
|
|
2492
|
+
this.generateYears();
|
|
2493
|
+
}
|
|
2494
|
+
nextYears() {
|
|
2495
|
+
this.yearRangeStart += 12;
|
|
2496
|
+
this.generateYears();
|
|
2497
|
+
}
|
|
2141
2498
|
selectDate(date) {
|
|
2142
2499
|
if (this.isDateDisabled(date))
|
|
2143
2500
|
return;
|
|
2144
2501
|
this.selectedDate = date;
|
|
2145
|
-
if (!isSameMonth(date, this.viewDate)) {
|
|
2146
|
-
this.viewDate = date;
|
|
2147
|
-
this.generateDays();
|
|
2148
|
-
}
|
|
2149
2502
|
this.onChange(date);
|
|
2150
2503
|
this.onTouched();
|
|
2504
|
+
this.dateSelect.emit(date);
|
|
2151
2505
|
}
|
|
2152
2506
|
selectMonth(monthIndex) {
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2507
|
+
if (this.mode === 'date') {
|
|
2508
|
+
this.viewDate = setMonth(this.viewDate, monthIndex);
|
|
2509
|
+
this.currentView = 'date';
|
|
2510
|
+
this.generateDays();
|
|
2511
|
+
}
|
|
2512
|
+
else if (this.mode === 'month') {
|
|
2513
|
+
this.viewDate = setMonth(this.viewDate, monthIndex);
|
|
2514
|
+
this.selectedDate = this.viewDate;
|
|
2515
|
+
this.onChange(this.viewDate);
|
|
2516
|
+
this.onTouched();
|
|
2517
|
+
this.dateSelect.emit(this.viewDate);
|
|
2518
|
+
}
|
|
2156
2519
|
}
|
|
2157
2520
|
selectYear(year) {
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2521
|
+
if (this.mode === 'date') {
|
|
2522
|
+
this.viewDate = setYear(this.viewDate, year);
|
|
2523
|
+
this.currentView = 'date';
|
|
2524
|
+
this.generateDays();
|
|
2525
|
+
}
|
|
2526
|
+
else if (this.mode === 'year' || this.mode === 'month') {
|
|
2527
|
+
this.viewDate = setYear(this.viewDate, year);
|
|
2528
|
+
this.selectedDate = this.viewDate;
|
|
2529
|
+
this.onChange(this.viewDate);
|
|
2530
|
+
this.onTouched();
|
|
2531
|
+
this.dateSelect.emit(this.viewDate);
|
|
2532
|
+
}
|
|
2161
2533
|
}
|
|
2162
2534
|
getDayClass(date) {
|
|
2163
2535
|
const isSelected = this.selectedDate && isSameDay(date, this.selectedDate);
|
|
2164
2536
|
const isTodayDate = isToday(date);
|
|
2165
2537
|
const isOutside = !isSameMonth(date, this.viewDate);
|
|
2166
2538
|
const isDisabled = this.isDateDisabled(date);
|
|
2167
|
-
return cn('h-9 w-9 p-0 font-normal text-sm rounded-md transition-all flex items-center justify-center', !isSelected && !isDisabled && 'hover:bg-accent hover:text-accent-foreground', isSelected && 'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground
|
|
2539
|
+
return cn('h-9 w-9 p-0 font-normal text-sm rounded-md transition-all flex items-center justify-center', !isSelected && !isDisabled && 'hover:bg-accent hover:text-accent-foreground', isSelected && 'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground', !isSelected && isTodayDate && 'bg-accent text-accent-foreground', (isOutside || isDisabled) && 'text-muted-foreground opacity-50', isDisabled && 'cursor-not-allowed');
|
|
2540
|
+
}
|
|
2541
|
+
getMonthClass(monthIndex) {
|
|
2542
|
+
const isSelected = this.selectedDate &&
|
|
2543
|
+
this.selectedDate.getMonth() === monthIndex &&
|
|
2544
|
+
this.selectedDate.getFullYear() === this.viewDate.getFullYear();
|
|
2545
|
+
const isCurrent = new Date().getMonth() === monthIndex &&
|
|
2546
|
+
new Date().getFullYear() === this.viewDate.getFullYear();
|
|
2547
|
+
return cn('text-sm py-2.5 rounded-md transition-colors', isSelected ? 'bg-primary text-primary-foreground hover:bg-primary' :
|
|
2548
|
+
isCurrent ? 'border border-primary/30 text-primary' :
|
|
2549
|
+
'hover:bg-accent hover:text-accent-foreground');
|
|
2550
|
+
}
|
|
2551
|
+
getYearClass(year) {
|
|
2552
|
+
const isSelected = this.selectedDate &&
|
|
2553
|
+
this.selectedDate.getFullYear() === year;
|
|
2554
|
+
const isCurrent = new Date().getFullYear() === year;
|
|
2555
|
+
return cn('text-sm py-2 rounded-md transition-colors', isSelected ? 'bg-primary text-primary-foreground hover:bg-primary' :
|
|
2556
|
+
isCurrent ? 'border border-primary/30 text-primary' :
|
|
2557
|
+
'hover:bg-accent hover:text-accent-foreground');
|
|
2168
2558
|
}
|
|
2169
2559
|
isDateDisabled(date) {
|
|
2170
|
-
|
|
2560
|
+
if (this.disablePastDates && isBefore(date, startOfDay(new Date()))) {
|
|
2561
|
+
return true;
|
|
2562
|
+
}
|
|
2563
|
+
if (this.minDate && isBefore(date, this.minDate)) {
|
|
2564
|
+
return true;
|
|
2565
|
+
}
|
|
2566
|
+
return !!(this.maxDate && isBefore(this.maxDate, date));
|
|
2567
|
+
}
|
|
2568
|
+
isTodayDisabled() {
|
|
2569
|
+
return this.isDateDisabled(new Date());
|
|
2570
|
+
}
|
|
2571
|
+
selectToday() {
|
|
2572
|
+
if (!this.isTodayDisabled()) {
|
|
2573
|
+
this.selectDate(new Date());
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
clear() {
|
|
2577
|
+
this.selectedDate = null;
|
|
2578
|
+
this.onChange(null);
|
|
2579
|
+
this.onTouched();
|
|
2580
|
+
this.dateSelect.emit(null);
|
|
2171
2581
|
}
|
|
2172
2582
|
// CVA Implementation
|
|
2173
2583
|
writeValue(obj) {
|
|
@@ -2184,27 +2594,26 @@ class CalendarComponent {
|
|
|
2184
2594
|
registerOnChange(fn) { this.onChange = fn; }
|
|
2185
2595
|
registerOnTouched(fn) { this.onTouched = fn; }
|
|
2186
2596
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2187
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: CalendarComponent, isStandalone: true, selector: "tolle-calendar", inputs: { class: "class", disablePastDates: "disablePastDates" }, providers: [
|
|
2597
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: CalendarComponent, isStandalone: true, selector: "tolle-calendar", inputs: { class: "class", mode: "mode", disablePastDates: "disablePastDates", showQuickActions: "showQuickActions", minDate: "minDate", maxDate: "maxDate", formatMonthFn: "formatMonthFn", formatYearFn: "formatYearFn", formatDateFn: "formatDateFn" }, outputs: { dateSelect: "dateSelect" }, providers: [
|
|
2188
2598
|
{
|
|
2189
2599
|
provide: NG_VALUE_ACCESSOR,
|
|
2190
2600
|
useExisting: forwardRef(() => CalendarComponent),
|
|
2191
2601
|
multi: true
|
|
2192
2602
|
}
|
|
2193
2603
|
], ngImport: i0, template: `
|
|
2194
|
-
<div [class]="cn('p-3 border rounded-md bg-background text-popover-foreground shadow-sm inline-block w-fit', class)">
|
|
2195
|
-
|
|
2604
|
+
<div [class]="cn('p-3 border rounded-md bg-background text-popover-foreground shadow-sm inline-block min-w-fit', class)">
|
|
2605
|
+
<!-- Header with Navigation -->
|
|
2196
2606
|
<div class="flex items-center justify-between pt-1 pb-4 gap-2">
|
|
2197
|
-
|
|
2607
|
+
<!-- View Selector -->
|
|
2198
2608
|
<div class="flex items-center gap-1">
|
|
2199
|
-
<button
|
|
2609
|
+
<button *ngIf="mode !== 'year'"
|
|
2200
2610
|
type="button"
|
|
2201
2611
|
(click)="setView('month')"
|
|
2202
2612
|
[class]="cn(
|
|
2203
2613
|
'text-sm font-semibold px-2 py-1 rounded transition-colors',
|
|
2204
2614
|
currentView === 'month' ? 'bg-secondary text-secondary-foreground' : 'hover:bg-accent hover:text-accent-foreground'
|
|
2205
|
-
)"
|
|
2206
|
-
|
|
2207
|
-
{{ viewDate | date: 'MMMM' }}
|
|
2615
|
+
)">
|
|
2616
|
+
{{ formatMonthYear(viewDate, 'month') }}
|
|
2208
2617
|
</button>
|
|
2209
2618
|
|
|
2210
2619
|
<button
|
|
@@ -2213,12 +2622,12 @@ class CalendarComponent {
|
|
|
2213
2622
|
[class]="cn(
|
|
2214
2623
|
'text-sm font-semibold px-2 py-1 rounded transition-colors',
|
|
2215
2624
|
currentView === 'year' ? 'bg-secondary text-secondary-foreground' : 'hover:bg-accent hover:text-accent-foreground'
|
|
2216
|
-
)"
|
|
2217
|
-
|
|
2218
|
-
{{ viewDate | date: 'yyyy' }}
|
|
2625
|
+
)">
|
|
2626
|
+
{{ formatMonthYear(viewDate, 'year') }}
|
|
2219
2627
|
</button>
|
|
2220
2628
|
</div>
|
|
2221
2629
|
|
|
2630
|
+
<!-- Navigation Buttons -->
|
|
2222
2631
|
<div class="flex items-center space-x-1">
|
|
2223
2632
|
<button type="button" (click)="prev()" [class]="navBtnClass">
|
|
2224
2633
|
<i class="ri-arrow-left-s-line text-lg"></i>
|
|
@@ -2229,7 +2638,8 @@ class CalendarComponent {
|
|
|
2229
2638
|
</div>
|
|
2230
2639
|
</div>
|
|
2231
2640
|
|
|
2232
|
-
|
|
2641
|
+
<!-- DATE MODE -->
|
|
2642
|
+
<div *ngIf="currentView === 'date' && mode === 'date'" class="space-y-2 animate-in fade-in zoom-in-95 duration-200">
|
|
2233
2643
|
<div class="grid grid-cols-7 gap-1 w-full">
|
|
2234
2644
|
<span *ngFor="let day of weekDays" class="text-[0.8rem] text-muted-foreground font-normal text-center w-9">
|
|
2235
2645
|
{{ day }}
|
|
@@ -2243,47 +2653,66 @@ class CalendarComponent {
|
|
|
2243
2653
|
[disabled]="isDateDisabled(date)"
|
|
2244
2654
|
[class]="getDayClass(date)"
|
|
2245
2655
|
>
|
|
2246
|
-
{{ date
|
|
2656
|
+
{{ formatDate(date, 'day') }}
|
|
2247
2657
|
</button>
|
|
2248
2658
|
</div>
|
|
2249
2659
|
</div>
|
|
2250
2660
|
|
|
2251
|
-
|
|
2661
|
+
<!-- MONTH SELECTOR (for date mode and month mode) -->
|
|
2662
|
+
<div *ngIf="(currentView === 'month')"
|
|
2663
|
+
class="grid grid-cols-3 gap-2 w-64 animate-in fade-in zoom-in-95 duration-200">
|
|
2252
2664
|
<button
|
|
2253
2665
|
*ngFor="let month of months; let i = index"
|
|
2254
2666
|
type="button"
|
|
2255
2667
|
(click)="selectMonth(i)"
|
|
2256
|
-
[class]="
|
|
2257
|
-
'text-sm py-2.5 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors',
|
|
2258
|
-
i === viewDate.getMonth() ? 'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground' : ''
|
|
2259
|
-
)"
|
|
2668
|
+
[class]="getMonthClass(i)"
|
|
2260
2669
|
>
|
|
2261
2670
|
{{ month }}
|
|
2262
2671
|
</button>
|
|
2263
2672
|
</div>
|
|
2264
2673
|
|
|
2265
|
-
|
|
2674
|
+
<!-- YEAR SELECTOR (for date mode and year mode) -->
|
|
2675
|
+
<div *ngIf="(currentView === 'year') "
|
|
2676
|
+
class="grid grid-cols-4 gap-2 w-64 animate-in fade-in zoom-in-95 duration-200">
|
|
2266
2677
|
<button
|
|
2267
2678
|
*ngFor="let year of years"
|
|
2268
2679
|
type="button"
|
|
2269
2680
|
(click)="selectYear(year)"
|
|
2270
|
-
[class]="
|
|
2271
|
-
'text-sm py-2 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors',
|
|
2272
|
-
year === viewDate.getFullYear() ? 'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground' : ''
|
|
2273
|
-
)"
|
|
2681
|
+
[class]="getYearClass(year)"
|
|
2274
2682
|
>
|
|
2275
2683
|
{{ year }}
|
|
2276
2684
|
</button>
|
|
2277
2685
|
</div>
|
|
2686
|
+
|
|
2687
|
+
<!-- Quick Actions -->
|
|
2688
|
+
<div *ngIf="showQuickActions" class="border-t pt-3 mt-3">
|
|
2689
|
+
<div class="flex items-center justify-between gap-2">
|
|
2690
|
+
<button
|
|
2691
|
+
type="button"
|
|
2692
|
+
(click)="selectToday()"
|
|
2693
|
+
[class]="quickActionBtnClass"
|
|
2694
|
+
[disabled]="isTodayDisabled()"
|
|
2695
|
+
>
|
|
2696
|
+
Today
|
|
2697
|
+
</button>
|
|
2698
|
+
<button
|
|
2699
|
+
type="button"
|
|
2700
|
+
(click)="clear()"
|
|
2701
|
+
[class]="quickActionBtnClass"
|
|
2702
|
+
>
|
|
2703
|
+
Clear
|
|
2704
|
+
</button>
|
|
2705
|
+
</div>
|
|
2706
|
+
</div>
|
|
2278
2707
|
</div>
|
|
2279
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "
|
|
2708
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }] });
|
|
2280
2709
|
}
|
|
2281
2710
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CalendarComponent, decorators: [{
|
|
2282
2711
|
type: Component,
|
|
2283
2712
|
args: [{
|
|
2284
2713
|
selector: 'tolle-calendar',
|
|
2285
2714
|
standalone: true,
|
|
2286
|
-
imports: [CommonModule],
|
|
2715
|
+
imports: [CommonModule, FormsModule],
|
|
2287
2716
|
providers: [
|
|
2288
2717
|
{
|
|
2289
2718
|
provide: NG_VALUE_ACCESSOR,
|
|
@@ -2292,20 +2721,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
2292
2721
|
}
|
|
2293
2722
|
],
|
|
2294
2723
|
template: `
|
|
2295
|
-
<div [class]="cn('p-3 border rounded-md bg-background text-popover-foreground shadow-sm inline-block w-fit', class)">
|
|
2296
|
-
|
|
2724
|
+
<div [class]="cn('p-3 border rounded-md bg-background text-popover-foreground shadow-sm inline-block min-w-fit', class)">
|
|
2725
|
+
<!-- Header with Navigation -->
|
|
2297
2726
|
<div class="flex items-center justify-between pt-1 pb-4 gap-2">
|
|
2298
|
-
|
|
2727
|
+
<!-- View Selector -->
|
|
2299
2728
|
<div class="flex items-center gap-1">
|
|
2300
|
-
<button
|
|
2729
|
+
<button *ngIf="mode !== 'year'"
|
|
2301
2730
|
type="button"
|
|
2302
2731
|
(click)="setView('month')"
|
|
2303
2732
|
[class]="cn(
|
|
2304
2733
|
'text-sm font-semibold px-2 py-1 rounded transition-colors',
|
|
2305
2734
|
currentView === 'month' ? 'bg-secondary text-secondary-foreground' : 'hover:bg-accent hover:text-accent-foreground'
|
|
2306
|
-
)"
|
|
2307
|
-
|
|
2308
|
-
{{ viewDate | date: 'MMMM' }}
|
|
2735
|
+
)">
|
|
2736
|
+
{{ formatMonthYear(viewDate, 'month') }}
|
|
2309
2737
|
</button>
|
|
2310
2738
|
|
|
2311
2739
|
<button
|
|
@@ -2314,12 +2742,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
2314
2742
|
[class]="cn(
|
|
2315
2743
|
'text-sm font-semibold px-2 py-1 rounded transition-colors',
|
|
2316
2744
|
currentView === 'year' ? 'bg-secondary text-secondary-foreground' : 'hover:bg-accent hover:text-accent-foreground'
|
|
2317
|
-
)"
|
|
2318
|
-
|
|
2319
|
-
{{ viewDate | date: 'yyyy' }}
|
|
2745
|
+
)">
|
|
2746
|
+
{{ formatMonthYear(viewDate, 'year') }}
|
|
2320
2747
|
</button>
|
|
2321
2748
|
</div>
|
|
2322
2749
|
|
|
2750
|
+
<!-- Navigation Buttons -->
|
|
2323
2751
|
<div class="flex items-center space-x-1">
|
|
2324
2752
|
<button type="button" (click)="prev()" [class]="navBtnClass">
|
|
2325
2753
|
<i class="ri-arrow-left-s-line text-lg"></i>
|
|
@@ -2330,7 +2758,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
2330
2758
|
</div>
|
|
2331
2759
|
</div>
|
|
2332
2760
|
|
|
2333
|
-
|
|
2761
|
+
<!-- DATE MODE -->
|
|
2762
|
+
<div *ngIf="currentView === 'date' && mode === 'date'" class="space-y-2 animate-in fade-in zoom-in-95 duration-200">
|
|
2334
2763
|
<div class="grid grid-cols-7 gap-1 w-full">
|
|
2335
2764
|
<span *ngFor="let day of weekDays" class="text-[0.8rem] text-muted-foreground font-normal text-center w-9">
|
|
2336
2765
|
{{ day }}
|
|
@@ -2344,45 +2773,80 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
2344
2773
|
[disabled]="isDateDisabled(date)"
|
|
2345
2774
|
[class]="getDayClass(date)"
|
|
2346
2775
|
>
|
|
2347
|
-
{{ date
|
|
2776
|
+
{{ formatDate(date, 'day') }}
|
|
2348
2777
|
</button>
|
|
2349
2778
|
</div>
|
|
2350
2779
|
</div>
|
|
2351
2780
|
|
|
2352
|
-
|
|
2781
|
+
<!-- MONTH SELECTOR (for date mode and month mode) -->
|
|
2782
|
+
<div *ngIf="(currentView === 'month')"
|
|
2783
|
+
class="grid grid-cols-3 gap-2 w-64 animate-in fade-in zoom-in-95 duration-200">
|
|
2353
2784
|
<button
|
|
2354
2785
|
*ngFor="let month of months; let i = index"
|
|
2355
2786
|
type="button"
|
|
2356
2787
|
(click)="selectMonth(i)"
|
|
2357
|
-
[class]="
|
|
2358
|
-
'text-sm py-2.5 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors',
|
|
2359
|
-
i === viewDate.getMonth() ? 'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground' : ''
|
|
2360
|
-
)"
|
|
2788
|
+
[class]="getMonthClass(i)"
|
|
2361
2789
|
>
|
|
2362
2790
|
{{ month }}
|
|
2363
2791
|
</button>
|
|
2364
2792
|
</div>
|
|
2365
2793
|
|
|
2366
|
-
|
|
2794
|
+
<!-- YEAR SELECTOR (for date mode and year mode) -->
|
|
2795
|
+
<div *ngIf="(currentView === 'year') "
|
|
2796
|
+
class="grid grid-cols-4 gap-2 w-64 animate-in fade-in zoom-in-95 duration-200">
|
|
2367
2797
|
<button
|
|
2368
2798
|
*ngFor="let year of years"
|
|
2369
2799
|
type="button"
|
|
2370
2800
|
(click)="selectYear(year)"
|
|
2371
|
-
[class]="
|
|
2372
|
-
'text-sm py-2 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors',
|
|
2373
|
-
year === viewDate.getFullYear() ? 'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground' : ''
|
|
2374
|
-
)"
|
|
2801
|
+
[class]="getYearClass(year)"
|
|
2375
2802
|
>
|
|
2376
2803
|
{{ year }}
|
|
2377
2804
|
</button>
|
|
2378
2805
|
</div>
|
|
2806
|
+
|
|
2807
|
+
<!-- Quick Actions -->
|
|
2808
|
+
<div *ngIf="showQuickActions" class="border-t pt-3 mt-3">
|
|
2809
|
+
<div class="flex items-center justify-between gap-2">
|
|
2810
|
+
<button
|
|
2811
|
+
type="button"
|
|
2812
|
+
(click)="selectToday()"
|
|
2813
|
+
[class]="quickActionBtnClass"
|
|
2814
|
+
[disabled]="isTodayDisabled()"
|
|
2815
|
+
>
|
|
2816
|
+
Today
|
|
2817
|
+
</button>
|
|
2818
|
+
<button
|
|
2819
|
+
type="button"
|
|
2820
|
+
(click)="clear()"
|
|
2821
|
+
[class]="quickActionBtnClass"
|
|
2822
|
+
>
|
|
2823
|
+
Clear
|
|
2824
|
+
</button>
|
|
2825
|
+
</div>
|
|
2826
|
+
</div>
|
|
2379
2827
|
</div>
|
|
2380
2828
|
`
|
|
2381
2829
|
}]
|
|
2382
|
-
}], propDecorators: { class: [{
|
|
2830
|
+
}], ctorParameters: () => [], propDecorators: { class: [{
|
|
2831
|
+
type: Input
|
|
2832
|
+
}], mode: [{
|
|
2383
2833
|
type: Input
|
|
2384
2834
|
}], disablePastDates: [{
|
|
2385
2835
|
type: Input
|
|
2836
|
+
}], showQuickActions: [{
|
|
2837
|
+
type: Input
|
|
2838
|
+
}], minDate: [{
|
|
2839
|
+
type: Input
|
|
2840
|
+
}], maxDate: [{
|
|
2841
|
+
type: Input
|
|
2842
|
+
}], formatMonthFn: [{
|
|
2843
|
+
type: Input
|
|
2844
|
+
}], formatYearFn: [{
|
|
2845
|
+
type: Input
|
|
2846
|
+
}], formatDateFn: [{
|
|
2847
|
+
type: Input
|
|
2848
|
+
}], dateSelect: [{
|
|
2849
|
+
type: Output
|
|
2386
2850
|
}] } });
|
|
2387
2851
|
|
|
2388
2852
|
class MaskedInputComponent {
|
|
@@ -2728,6 +3192,15 @@ class DatePickerComponent {
|
|
|
2728
3192
|
disabled = false;
|
|
2729
3193
|
class = '';
|
|
2730
3194
|
disablePastDates = false;
|
|
3195
|
+
showClear = true;
|
|
3196
|
+
showQuickActions = true;
|
|
3197
|
+
minDate;
|
|
3198
|
+
maxDate;
|
|
3199
|
+
mode = 'date';
|
|
3200
|
+
formatMonthFn;
|
|
3201
|
+
formatYearFn;
|
|
3202
|
+
// Format functions for display
|
|
3203
|
+
displayFormat;
|
|
2731
3204
|
triggerContainer;
|
|
2732
3205
|
popover;
|
|
2733
3206
|
value = null;
|
|
@@ -2737,12 +3210,56 @@ class DatePickerComponent {
|
|
|
2737
3210
|
constructor(cdr) {
|
|
2738
3211
|
this.cdr = cdr;
|
|
2739
3212
|
}
|
|
2740
|
-
|
|
3213
|
+
getMask() {
|
|
3214
|
+
switch (this.mode) {
|
|
3215
|
+
case 'date': return '00/00/0000';
|
|
3216
|
+
case 'month': return '00/0000';
|
|
3217
|
+
case 'year': return '0000';
|
|
3218
|
+
default: return '00/00/0000';
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3221
|
+
getPlaceholder() {
|
|
3222
|
+
switch (this.mode) {
|
|
3223
|
+
case 'date': return 'MM/DD/YYYY';
|
|
3224
|
+
case 'month': return 'MM/YYYY';
|
|
3225
|
+
case 'year': return 'YYYY';
|
|
3226
|
+
default: return 'MM/DD/YYYY';
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3229
|
+
getFormatString() {
|
|
3230
|
+
switch (this.mode) {
|
|
3231
|
+
case 'date': return 'MM/dd/yyyy';
|
|
3232
|
+
case 'month': return 'MM/yyyy';
|
|
3233
|
+
case 'year': return 'yyyy';
|
|
3234
|
+
default: return 'MM/dd/yyyy';
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
formatDate(date) {
|
|
3238
|
+
if (this.displayFormat) {
|
|
3239
|
+
return this.displayFormat(date, this.mode);
|
|
3240
|
+
}
|
|
3241
|
+
switch (this.mode) {
|
|
3242
|
+
case 'date': return format(date, 'MM/dd/yyyy');
|
|
3243
|
+
case 'month': return format(date, 'MM/yyyy');
|
|
3244
|
+
case 'year': return format(date, 'yyyy');
|
|
3245
|
+
default: return format(date, 'MM/dd/yyyy');
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
parseDate(str) {
|
|
3249
|
+
try {
|
|
3250
|
+
const parsed = parse(str, this.getFormatString(), new Date());
|
|
3251
|
+
return isValid(parsed) ? startOfDay(parsed) : null;
|
|
3252
|
+
}
|
|
3253
|
+
catch {
|
|
3254
|
+
return null;
|
|
3255
|
+
}
|
|
3256
|
+
}
|
|
2741
3257
|
onInputChange(str) {
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
3258
|
+
const expectedLength = this.getFormatString().replace(/[^0]/g, '').length;
|
|
3259
|
+
if (str?.length === expectedLength) {
|
|
3260
|
+
const parsed = this.parseDate(str);
|
|
3261
|
+
if (parsed) {
|
|
3262
|
+
this.value = parsed;
|
|
2746
3263
|
this.onChange(this.value);
|
|
2747
3264
|
}
|
|
2748
3265
|
}
|
|
@@ -2753,12 +3270,17 @@ class DatePickerComponent {
|
|
|
2753
3270
|
}
|
|
2754
3271
|
onCalendarChange(date) {
|
|
2755
3272
|
this.value = date;
|
|
2756
|
-
|
|
3273
|
+
if (date) {
|
|
3274
|
+
this.inputValue = this.formatDate(date);
|
|
3275
|
+
}
|
|
3276
|
+
else {
|
|
3277
|
+
this.inputValue = '';
|
|
3278
|
+
}
|
|
2757
3279
|
this.onChange(this.value);
|
|
2758
3280
|
this.close();
|
|
2759
3281
|
}
|
|
2760
3282
|
togglePopover(event) {
|
|
2761
|
-
event.stopPropagation();
|
|
3283
|
+
event.stopPropagation();
|
|
2762
3284
|
if (this.disabled)
|
|
2763
3285
|
return;
|
|
2764
3286
|
this.isOpen ? this.close() : this.open();
|
|
@@ -2773,22 +3295,27 @@ class DatePickerComponent {
|
|
|
2773
3295
|
this.cleanupAutoUpdate();
|
|
2774
3296
|
}
|
|
2775
3297
|
clear(event) {
|
|
2776
|
-
event.stopPropagation();
|
|
3298
|
+
event.stopPropagation();
|
|
2777
3299
|
this.value = null;
|
|
2778
3300
|
this.inputValue = '';
|
|
2779
3301
|
this.onChange(null);
|
|
2780
3302
|
this.cdr.markForCheck();
|
|
2781
3303
|
}
|
|
2782
|
-
// --- Positioning ---
|
|
2783
3304
|
updatePosition() {
|
|
2784
3305
|
if (!this.triggerContainer || !this.popover)
|
|
2785
3306
|
return;
|
|
2786
3307
|
this.cleanupAutoUpdate = autoUpdate(this.triggerContainer.nativeElement, this.popover.nativeElement, () => {
|
|
2787
3308
|
computePosition(this.triggerContainer.nativeElement, this.popover.nativeElement, {
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
3309
|
+
strategy: 'fixed', // ADDED: Fixed strategy
|
|
3310
|
+
placement: 'bottom-start', // Changed to bottom-start to align with input left edge
|
|
3311
|
+
middleware: [
|
|
3312
|
+
offset(4),
|
|
3313
|
+
flip(),
|
|
3314
|
+
shift({ padding: 8 })
|
|
3315
|
+
],
|
|
3316
|
+
}).then(({ x, y, strategy }) => {
|
|
2791
3317
|
Object.assign(this.popover.nativeElement.style, {
|
|
3318
|
+
position: strategy,
|
|
2792
3319
|
left: `${x}px`,
|
|
2793
3320
|
top: `${y}px`,
|
|
2794
3321
|
visibility: 'visible',
|
|
@@ -2803,7 +3330,7 @@ class DatePickerComponent {
|
|
|
2803
3330
|
this.close();
|
|
2804
3331
|
}
|
|
2805
3332
|
}
|
|
2806
|
-
//
|
|
3333
|
+
// CVA Implementation
|
|
2807
3334
|
onChange = () => { };
|
|
2808
3335
|
onTouched = () => { };
|
|
2809
3336
|
writeValue(val) {
|
|
@@ -2811,7 +3338,7 @@ class DatePickerComponent {
|
|
|
2811
3338
|
const date = new Date(val);
|
|
2812
3339
|
if (isValid(date)) {
|
|
2813
3340
|
this.value = startOfDay(date);
|
|
2814
|
-
this.inputValue =
|
|
3341
|
+
this.inputValue = this.formatDate(this.value);
|
|
2815
3342
|
}
|
|
2816
3343
|
}
|
|
2817
3344
|
else {
|
|
@@ -2825,7 +3352,7 @@ class DatePickerComponent {
|
|
|
2825
3352
|
setDisabledState(isDisabled) { this.disabled = isDisabled; }
|
|
2826
3353
|
cn = cn;
|
|
2827
3354
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DatePickerComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
2828
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: DatePickerComponent, isStandalone: true, selector: "tolle-date-picker", inputs: { placeholder: "placeholder", disabled: "disabled", class: "class", disablePastDates: "disablePastDates" }, host: { listeners: { "document:mousedown": "onClickOutside($event)" } }, providers: [
|
|
3355
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: DatePickerComponent, isStandalone: true, selector: "tolle-date-picker", inputs: { placeholder: "placeholder", disabled: "disabled", class: "class", disablePastDates: "disablePastDates", showClear: "showClear", showQuickActions: "showQuickActions", minDate: "minDate", maxDate: "maxDate", mode: "mode", formatMonthFn: "formatMonthFn", formatYearFn: "formatYearFn", displayFormat: "displayFormat" }, host: { listeners: { "document:mousedown": "onClickOutside($event)" } }, providers: [
|
|
2829
3356
|
{
|
|
2830
3357
|
provide: NG_VALUE_ACCESSOR,
|
|
2831
3358
|
useExisting: forwardRef(() => DatePickerComponent),
|
|
@@ -2835,8 +3362,8 @@ class DatePickerComponent {
|
|
|
2835
3362
|
<div class="relative w-full" #triggerContainer>
|
|
2836
3363
|
<tolle-masked-input
|
|
2837
3364
|
#maskInput
|
|
2838
|
-
[mask]="
|
|
2839
|
-
[placeholder]="
|
|
3365
|
+
[mask]="getMask()"
|
|
3366
|
+
[placeholder]="getPlaceholder()"
|
|
2840
3367
|
[disabled]="disabled"
|
|
2841
3368
|
[(ngModel)]="inputValue"
|
|
2842
3369
|
(ngModelChange)="onInputChange($event)"
|
|
@@ -2844,14 +3371,17 @@ class DatePickerComponent {
|
|
|
2844
3371
|
>
|
|
2845
3372
|
<div suffix class="flex items-center gap-1.5 cursor-pointer">
|
|
2846
3373
|
<i
|
|
2847
|
-
*ngIf="value && !disabled"
|
|
3374
|
+
*ngIf="value && !disabled && showClear"
|
|
2848
3375
|
(click)="clear($event)"
|
|
2849
3376
|
class="ri-close-line cursor-pointer text-muted-foreground hover:text-foreground transition-colors"
|
|
2850
3377
|
></i>
|
|
2851
3378
|
|
|
2852
3379
|
<i
|
|
2853
3380
|
(click)="togglePopover($event)"
|
|
2854
|
-
class="
|
|
3381
|
+
[class]="cn(
|
|
3382
|
+
'cursor-pointer text-muted-foreground transition-colors',
|
|
3383
|
+
'ri-calendar-line'
|
|
3384
|
+
)"
|
|
2855
3385
|
></i>
|
|
2856
3386
|
</div>
|
|
2857
3387
|
</tolle-masked-input>
|
|
@@ -2859,17 +3389,23 @@ class DatePickerComponent {
|
|
|
2859
3389
|
<div
|
|
2860
3390
|
#popover
|
|
2861
3391
|
*ngIf="isOpen"
|
|
2862
|
-
class="
|
|
3392
|
+
class="fixed z-[50]"
|
|
2863
3393
|
style="visibility: hidden; top: 0; left: 0;"
|
|
2864
3394
|
>
|
|
2865
|
-
<tolle-calendar
|
|
3395
|
+
<tolle-calendar class="shadow-lg"
|
|
2866
3396
|
[(ngModel)]="value"
|
|
2867
3397
|
(ngModelChange)="onCalendarChange($event)"
|
|
3398
|
+
[mode]="mode"
|
|
2868
3399
|
[disablePastDates]="disablePastDates"
|
|
3400
|
+
[minDate]="minDate"
|
|
3401
|
+
[maxDate]="maxDate"
|
|
3402
|
+
[showQuickActions]="showQuickActions"
|
|
3403
|
+
[formatMonthFn]="formatMonthFn"
|
|
3404
|
+
[formatYearFn]="formatYearFn"
|
|
2869
3405
|
></tolle-calendar>
|
|
2870
3406
|
</div>
|
|
2871
3407
|
</div>
|
|
2872
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MaskedInputComponent, selector: "tolle-masked-input", inputs: ["id", "label", "hint", "errorMessage", "mask", "placeholder", "type", "disabled", "readonly", "class", "containerClass", "error", "size", "returnRaw", "hideHintOnFocus"] }, { kind: "component", type: CalendarComponent, selector: "tolle-calendar", inputs: ["class", "disablePastDates"] }] });
|
|
3408
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MaskedInputComponent, selector: "tolle-masked-input", inputs: ["id", "label", "hint", "errorMessage", "mask", "placeholder", "type", "disabled", "readonly", "class", "containerClass", "error", "size", "returnRaw", "hideHintOnFocus"] }, { kind: "component", type: CalendarComponent, selector: "tolle-calendar", inputs: ["class", "mode", "disablePastDates", "showQuickActions", "minDate", "maxDate", "formatMonthFn", "formatYearFn", "formatDateFn"], outputs: ["dateSelect"] }] });
|
|
2873
3409
|
}
|
|
2874
3410
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DatePickerComponent, decorators: [{
|
|
2875
3411
|
type: Component,
|
|
@@ -2888,8 +3424,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
2888
3424
|
<div class="relative w-full" #triggerContainer>
|
|
2889
3425
|
<tolle-masked-input
|
|
2890
3426
|
#maskInput
|
|
2891
|
-
[mask]="
|
|
2892
|
-
[placeholder]="
|
|
3427
|
+
[mask]="getMask()"
|
|
3428
|
+
[placeholder]="getPlaceholder()"
|
|
2893
3429
|
[disabled]="disabled"
|
|
2894
3430
|
[(ngModel)]="inputValue"
|
|
2895
3431
|
(ngModelChange)="onInputChange($event)"
|
|
@@ -2897,14 +3433,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
2897
3433
|
>
|
|
2898
3434
|
<div suffix class="flex items-center gap-1.5 cursor-pointer">
|
|
2899
3435
|
<i
|
|
2900
|
-
*ngIf="value && !disabled"
|
|
3436
|
+
*ngIf="value && !disabled && showClear"
|
|
2901
3437
|
(click)="clear($event)"
|
|
2902
3438
|
class="ri-close-line cursor-pointer text-muted-foreground hover:text-foreground transition-colors"
|
|
2903
3439
|
></i>
|
|
2904
3440
|
|
|
2905
3441
|
<i
|
|
2906
3442
|
(click)="togglePopover($event)"
|
|
2907
|
-
class="
|
|
3443
|
+
[class]="cn(
|
|
3444
|
+
'cursor-pointer text-muted-foreground transition-colors',
|
|
3445
|
+
'ri-calendar-line'
|
|
3446
|
+
)"
|
|
2908
3447
|
></i>
|
|
2909
3448
|
</div>
|
|
2910
3449
|
</tolle-masked-input>
|
|
@@ -2912,13 +3451,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
2912
3451
|
<div
|
|
2913
3452
|
#popover
|
|
2914
3453
|
*ngIf="isOpen"
|
|
2915
|
-
class="
|
|
3454
|
+
class="fixed z-[50]"
|
|
2916
3455
|
style="visibility: hidden; top: 0; left: 0;"
|
|
2917
3456
|
>
|
|
2918
|
-
<tolle-calendar
|
|
3457
|
+
<tolle-calendar class="shadow-lg"
|
|
2919
3458
|
[(ngModel)]="value"
|
|
2920
3459
|
(ngModelChange)="onCalendarChange($event)"
|
|
3460
|
+
[mode]="mode"
|
|
2921
3461
|
[disablePastDates]="disablePastDates"
|
|
3462
|
+
[minDate]="minDate"
|
|
3463
|
+
[maxDate]="maxDate"
|
|
3464
|
+
[showQuickActions]="showQuickActions"
|
|
3465
|
+
[formatMonthFn]="formatMonthFn"
|
|
3466
|
+
[formatYearFn]="formatYearFn"
|
|
2922
3467
|
></tolle-calendar>
|
|
2923
3468
|
</div>
|
|
2924
3469
|
</div>
|
|
@@ -2932,6 +3477,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
2932
3477
|
type: Input
|
|
2933
3478
|
}], disablePastDates: [{
|
|
2934
3479
|
type: Input
|
|
3480
|
+
}], showClear: [{
|
|
3481
|
+
type: Input
|
|
3482
|
+
}], showQuickActions: [{
|
|
3483
|
+
type: Input
|
|
3484
|
+
}], minDate: [{
|
|
3485
|
+
type: Input
|
|
3486
|
+
}], maxDate: [{
|
|
3487
|
+
type: Input
|
|
3488
|
+
}], mode: [{
|
|
3489
|
+
type: Input
|
|
3490
|
+
}], formatMonthFn: [{
|
|
3491
|
+
type: Input
|
|
3492
|
+
}], formatYearFn: [{
|
|
3493
|
+
type: Input
|
|
3494
|
+
}], displayFormat: [{
|
|
3495
|
+
type: Input
|
|
2935
3496
|
}], triggerContainer: [{
|
|
2936
3497
|
type: ViewChild,
|
|
2937
3498
|
args: ['triggerContainer']
|
|
@@ -3113,7 +3674,7 @@ class PaginationComponent {
|
|
|
3113
3674
|
</div>
|
|
3114
3675
|
</div>
|
|
3115
3676
|
</div>
|
|
3116
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: SelectComponent, selector: "tolle-select", inputs: ["placeholder", "class", "disabled", "searchable", "size", "readonly"] }, { kind: "component", type: SelectItemComponent, selector: "tolle-select-item", inputs: ["value", "class", "selected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3677
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: SelectComponent, selector: "tolle-select", inputs: ["placeholder", "class", "disabled", "searchable", "size", "readonly"] }, { kind: "component", type: SelectItemComponent, selector: "tolle-select-item", inputs: ["value", "class", "selected", "disabled", "multiSelect"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3117
3678
|
}
|
|
3118
3679
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PaginationComponent, decorators: [{
|
|
3119
3680
|
type: Component,
|
|
@@ -4248,7 +4809,6 @@ class DateRangePickerComponent {
|
|
|
4248
4809
|
placeholder = 'Pick a date range';
|
|
4249
4810
|
class = '';
|
|
4250
4811
|
disablePastDates = false;
|
|
4251
|
-
// Standardized Sizes
|
|
4252
4812
|
size = 'default';
|
|
4253
4813
|
triggerContainer;
|
|
4254
4814
|
popover;
|
|
@@ -4261,7 +4821,7 @@ class DateRangePickerComponent {
|
|
|
4261
4821
|
get displayValue() {
|
|
4262
4822
|
if (!this.value.start)
|
|
4263
4823
|
return '';
|
|
4264
|
-
const startStr = format(this.value.start, 'MMM dd, yyyy');
|
|
4824
|
+
const startStr = format(this.value.start, 'MMM dd, yyyy');
|
|
4265
4825
|
if (!this.value.end)
|
|
4266
4826
|
return startStr;
|
|
4267
4827
|
const endStr = format(this.value.end, 'MMM dd, yyyy');
|
|
@@ -4272,12 +4832,11 @@ class DateRangePickerComponent {
|
|
|
4272
4832
|
this.onChange(this.value);
|
|
4273
4833
|
// Close only if range is complete
|
|
4274
4834
|
if (range.start && range.end) {
|
|
4275
|
-
this.onChange(this.value);
|
|
4276
|
-
// Small delay for UX
|
|
4277
4835
|
setTimeout(() => this.close(), 150);
|
|
4278
4836
|
}
|
|
4279
4837
|
}
|
|
4280
|
-
togglePopover(
|
|
4838
|
+
togglePopover(event) {
|
|
4839
|
+
event.stopPropagation();
|
|
4281
4840
|
if (this.disabled)
|
|
4282
4841
|
return;
|
|
4283
4842
|
this.isOpen ? this.close() : this.open();
|
|
@@ -4288,39 +4847,75 @@ class DateRangePickerComponent {
|
|
|
4288
4847
|
}
|
|
4289
4848
|
close() {
|
|
4290
4849
|
this.isOpen = false;
|
|
4291
|
-
if (this.cleanupAutoUpdate)
|
|
4850
|
+
if (this.cleanupAutoUpdate) {
|
|
4292
4851
|
this.cleanupAutoUpdate();
|
|
4852
|
+
this.cleanupAutoUpdate = undefined;
|
|
4853
|
+
}
|
|
4293
4854
|
}
|
|
4294
4855
|
clear(event) {
|
|
4295
|
-
event.stopPropagation();
|
|
4856
|
+
event.stopPropagation();
|
|
4296
4857
|
this.value = { start: null, end: null };
|
|
4297
4858
|
this.onChange(this.value);
|
|
4859
|
+
this.cdr.markForCheck();
|
|
4298
4860
|
}
|
|
4299
|
-
// --- Floating UI Positioning ---
|
|
4861
|
+
// --- Floating UI Positioning with Fixed Strategy ---
|
|
4300
4862
|
updatePosition() {
|
|
4301
4863
|
if (!this.triggerContainer || !this.popover)
|
|
4302
4864
|
return;
|
|
4303
4865
|
this.cleanupAutoUpdate = autoUpdate(this.triggerContainer.nativeElement, this.popover.nativeElement, () => {
|
|
4304
4866
|
computePosition(this.triggerContainer.nativeElement, this.popover.nativeElement, {
|
|
4305
|
-
placement: 'bottom-
|
|
4306
|
-
|
|
4307
|
-
|
|
4867
|
+
placement: 'bottom-end',
|
|
4868
|
+
strategy: 'fixed', // Use fixed to escape column layout
|
|
4869
|
+
middleware: [
|
|
4870
|
+
offset(4),
|
|
4871
|
+
flip({
|
|
4872
|
+
fallbackAxisSideDirection: 'start',
|
|
4873
|
+
padding: 8
|
|
4874
|
+
}),
|
|
4875
|
+
shift({ padding: 8 }),
|
|
4876
|
+
size({
|
|
4877
|
+
apply({ rects, elements, availableHeight }) {
|
|
4878
|
+
// Constrain popover to available space
|
|
4879
|
+
Object.assign(elements.floating.style, {
|
|
4880
|
+
maxHeight: `${Math.min(400, availableHeight)}px`,
|
|
4881
|
+
minWidth: `${Math.max(rects.reference.width, 320)}px`, // Calendar minimum width
|
|
4882
|
+
});
|
|
4883
|
+
}
|
|
4884
|
+
})
|
|
4885
|
+
],
|
|
4886
|
+
}).then(({ x, y, placement }) => {
|
|
4308
4887
|
Object.assign(this.popover.nativeElement.style, {
|
|
4309
4888
|
left: `${x}px`,
|
|
4310
4889
|
top: `${y}px`,
|
|
4311
4890
|
visibility: 'visible',
|
|
4312
4891
|
});
|
|
4892
|
+
// Optional: Add placement class for styling
|
|
4893
|
+
this.popover.nativeElement.classList.remove('calendar-top', 'calendar-bottom');
|
|
4894
|
+
if (placement.includes('top')) {
|
|
4895
|
+
this.popover.nativeElement.classList.add('calendar-top');
|
|
4896
|
+
}
|
|
4897
|
+
else {
|
|
4898
|
+
this.popover.nativeElement.classList.add('calendar-bottom');
|
|
4899
|
+
}
|
|
4313
4900
|
});
|
|
4314
4901
|
});
|
|
4315
4902
|
}
|
|
4316
4903
|
onClickOutside(event) {
|
|
4317
4904
|
if (this.isOpen &&
|
|
4318
4905
|
!this.triggerContainer.nativeElement.contains(event.target) &&
|
|
4319
|
-
!this.popover
|
|
4906
|
+
!this.popover?.nativeElement.contains(event.target)) {
|
|
4320
4907
|
this.close();
|
|
4321
4908
|
}
|
|
4322
4909
|
}
|
|
4323
|
-
|
|
4910
|
+
onWindowResize() {
|
|
4911
|
+
if (this.isOpen) {
|
|
4912
|
+
this.close(); // Close on resize for simplicity
|
|
4913
|
+
}
|
|
4914
|
+
}
|
|
4915
|
+
onWindowScroll() {
|
|
4916
|
+
// Floating-UI's autoUpdate handles scroll repositioning
|
|
4917
|
+
}
|
|
4918
|
+
// --- Control Value Accessor ---
|
|
4324
4919
|
onChange = () => { };
|
|
4325
4920
|
onTouched = () => { };
|
|
4326
4921
|
writeValue(val) {
|
|
@@ -4337,7 +4932,7 @@ class DateRangePickerComponent {
|
|
|
4337
4932
|
setDisabledState(isDisabled) { this.disabled = isDisabled; }
|
|
4338
4933
|
cn = cn;
|
|
4339
4934
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DateRangePickerComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
4340
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: DateRangePickerComponent, isStandalone: true, selector: "tolle-date-range-picker", inputs: { disabled: "disabled", placeholder: "placeholder", class: "class", disablePastDates: "disablePastDates", size: "size" }, host: { listeners: { "document:mousedown": "onClickOutside($event)" } }, providers: [
|
|
4935
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: DateRangePickerComponent, isStandalone: true, selector: "tolle-date-range-picker", inputs: { disabled: "disabled", placeholder: "placeholder", class: "class", disablePastDates: "disablePastDates", size: "size" }, host: { listeners: { "document:mousedown": "onClickOutside($event)", "window:resize": "onWindowResize()", "window:scroll": "onWindowScroll()" } }, providers: [
|
|
4341
4936
|
{
|
|
4342
4937
|
provide: NG_VALUE_ACCESSOR,
|
|
4343
4938
|
useExisting: forwardRef(() => DateRangePickerComponent),
|
|
@@ -4345,7 +4940,12 @@ class DateRangePickerComponent {
|
|
|
4345
4940
|
}
|
|
4346
4941
|
], viewQueries: [{ propertyName: "triggerContainer", first: true, predicate: ["triggerContainer"], descendants: true }, { propertyName: "popover", first: true, predicate: ["popover"], descendants: true }], ngImport: i0, template: `
|
|
4347
4942
|
<div class="relative w-full" #triggerContainer>
|
|
4348
|
-
<tolle-input
|
|
4943
|
+
<tolle-input
|
|
4944
|
+
[placeholder]="placeholder"
|
|
4945
|
+
[disabled]="disabled"
|
|
4946
|
+
[ngModel]="displayValue"
|
|
4947
|
+
[class]="class"
|
|
4948
|
+
>
|
|
4349
4949
|
<div suffix class="flex items-center gap-1.5 cursor-pointer">
|
|
4350
4950
|
<i
|
|
4351
4951
|
*ngIf="(value.start || value.end) && !disabled"
|
|
@@ -4359,13 +4959,14 @@ class DateRangePickerComponent {
|
|
|
4359
4959
|
></i>
|
|
4360
4960
|
</div>
|
|
4361
4961
|
</tolle-input>
|
|
4962
|
+
|
|
4362
4963
|
<div
|
|
4363
4964
|
#popover
|
|
4364
4965
|
*ngIf="isOpen"
|
|
4365
|
-
class="
|
|
4366
|
-
style="visibility: hidden;
|
|
4966
|
+
class="fixed z-50"
|
|
4967
|
+
style="visibility: hidden;"
|
|
4367
4968
|
>
|
|
4368
|
-
<tolle-range-calendar
|
|
4969
|
+
<tolle-range-calendar class="shadow-lg"
|
|
4369
4970
|
[ngModel]="value"
|
|
4370
4971
|
(rangeSelect)="onCalendarSelect($event)"
|
|
4371
4972
|
[disablePastDates]="disablePastDates"
|
|
@@ -4389,7 +4990,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
4389
4990
|
],
|
|
4390
4991
|
template: `
|
|
4391
4992
|
<div class="relative w-full" #triggerContainer>
|
|
4392
|
-
<tolle-input
|
|
4993
|
+
<tolle-input
|
|
4994
|
+
[placeholder]="placeholder"
|
|
4995
|
+
[disabled]="disabled"
|
|
4996
|
+
[ngModel]="displayValue"
|
|
4997
|
+
[class]="class"
|
|
4998
|
+
>
|
|
4393
4999
|
<div suffix class="flex items-center gap-1.5 cursor-pointer">
|
|
4394
5000
|
<i
|
|
4395
5001
|
*ngIf="(value.start || value.end) && !disabled"
|
|
@@ -4403,13 +5009,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
4403
5009
|
></i>
|
|
4404
5010
|
</div>
|
|
4405
5011
|
</tolle-input>
|
|
5012
|
+
|
|
4406
5013
|
<div
|
|
4407
5014
|
#popover
|
|
4408
5015
|
*ngIf="isOpen"
|
|
4409
|
-
class="
|
|
4410
|
-
style="visibility: hidden;
|
|
5016
|
+
class="fixed z-50"
|
|
5017
|
+
style="visibility: hidden;"
|
|
4411
5018
|
>
|
|
4412
|
-
<tolle-range-calendar
|
|
5019
|
+
<tolle-range-calendar class="shadow-lg"
|
|
4413
5020
|
[ngModel]="value"
|
|
4414
5021
|
(rangeSelect)="onCalendarSelect($event)"
|
|
4415
5022
|
[disablePastDates]="disablePastDates"
|
|
@@ -4437,6 +5044,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
4437
5044
|
}], onClickOutside: [{
|
|
4438
5045
|
type: HostListener,
|
|
4439
5046
|
args: ['document:mousedown', ['$event']]
|
|
5047
|
+
}], onWindowResize: [{
|
|
5048
|
+
type: HostListener,
|
|
5049
|
+
args: ['window:resize']
|
|
5050
|
+
}], onWindowScroll: [{
|
|
5051
|
+
type: HostListener,
|
|
5052
|
+
args: ['window:scroll']
|
|
4440
5053
|
}] } });
|
|
4441
5054
|
|
|
4442
5055
|
class DropdownItemComponent {
|
|
@@ -5831,6 +6444,192 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
5831
6444
|
type: Input
|
|
5832
6445
|
}] } });
|
|
5833
6446
|
|
|
6447
|
+
class SegmentedComponent {
|
|
6448
|
+
cdr;
|
|
6449
|
+
items = [];
|
|
6450
|
+
class = '';
|
|
6451
|
+
disabled = false;
|
|
6452
|
+
itemTemplate; // Allow custom content
|
|
6453
|
+
value = null;
|
|
6454
|
+
gliderLeft = 0;
|
|
6455
|
+
gliderWidth = 0;
|
|
6456
|
+
hasValue = false;
|
|
6457
|
+
itemElements;
|
|
6458
|
+
onChange = () => { };
|
|
6459
|
+
onTouched = () => { };
|
|
6460
|
+
constructor(cdr) {
|
|
6461
|
+
this.cdr = cdr;
|
|
6462
|
+
}
|
|
6463
|
+
ngAfterViewInit() {
|
|
6464
|
+
setTimeout(() => this.updateGlider());
|
|
6465
|
+
}
|
|
6466
|
+
ngOnChanges(changes) {
|
|
6467
|
+
// Recalculate if items change or if value changes externally
|
|
6468
|
+
if (changes['items'] && !changes['items'].firstChange) {
|
|
6469
|
+
setTimeout(() => this.updateGlider());
|
|
6470
|
+
}
|
|
6471
|
+
}
|
|
6472
|
+
select(val) {
|
|
6473
|
+
if (this.disabled)
|
|
6474
|
+
return;
|
|
6475
|
+
const item = this.items.find(i => i.value === val);
|
|
6476
|
+
if (item?.disabled)
|
|
6477
|
+
return;
|
|
6478
|
+
this.value = val;
|
|
6479
|
+
this.onChange(val);
|
|
6480
|
+
this.onTouched();
|
|
6481
|
+
this.updateGlider();
|
|
6482
|
+
}
|
|
6483
|
+
updateGlider() {
|
|
6484
|
+
if (!this.itemElements || !this.items.length)
|
|
6485
|
+
return;
|
|
6486
|
+
const index = this.items.findIndex(i => i.value === this.value);
|
|
6487
|
+
if (index === -1) {
|
|
6488
|
+
this.hasValue = false;
|
|
6489
|
+
this.gliderWidth = 0;
|
|
6490
|
+
return;
|
|
6491
|
+
}
|
|
6492
|
+
const activeElement = this.itemElements.get(index)?.nativeElement;
|
|
6493
|
+
if (activeElement) {
|
|
6494
|
+
this.hasValue = true;
|
|
6495
|
+
this.gliderLeft = activeElement.offsetLeft;
|
|
6496
|
+
this.gliderWidth = activeElement.offsetWidth;
|
|
6497
|
+
this.cdr.detectChanges();
|
|
6498
|
+
}
|
|
6499
|
+
}
|
|
6500
|
+
// CVA Implementation
|
|
6501
|
+
writeValue(val) {
|
|
6502
|
+
this.value = val;
|
|
6503
|
+
setTimeout(() => this.updateGlider());
|
|
6504
|
+
}
|
|
6505
|
+
registerOnChange(fn) { this.onChange = fn; }
|
|
6506
|
+
registerOnTouched(fn) { this.onTouched = fn; }
|
|
6507
|
+
setDisabledState(isDisabled) {
|
|
6508
|
+
this.disabled = isDisabled;
|
|
6509
|
+
this.cdr.markForCheck();
|
|
6510
|
+
}
|
|
6511
|
+
cn = cn;
|
|
6512
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SegmentedComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
6513
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: SegmentedComponent, isStandalone: true, selector: "tolle-segment", inputs: { items: "items", class: "class", disabled: "disabled", itemTemplate: "itemTemplate" }, providers: [
|
|
6514
|
+
{
|
|
6515
|
+
provide: NG_VALUE_ACCESSOR,
|
|
6516
|
+
useExisting: forwardRef(() => SegmentedComponent),
|
|
6517
|
+
multi: true
|
|
6518
|
+
}
|
|
6519
|
+
], viewQueries: [{ propertyName: "itemElements", predicate: ["itemEls"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
6520
|
+
<div
|
|
6521
|
+
#container
|
|
6522
|
+
[class]="cn(
|
|
6523
|
+
'relative flex items-center p-1 bg-muted rounded-lg select-none w-full gap-1',
|
|
6524
|
+
class
|
|
6525
|
+
)"
|
|
6526
|
+
role="tablist"
|
|
6527
|
+
>
|
|
6528
|
+
<div
|
|
6529
|
+
class="absolute top-1 bottom-1 bg-background shadow-sm rounded-md transition-all duration-300 ease-[cubic-bezier(0.2,0.0,0.2,1)]"
|
|
6530
|
+
[style.left.px]="gliderLeft"
|
|
6531
|
+
[style.width.px]="gliderWidth"
|
|
6532
|
+
[class.opacity-0]="!hasValue"
|
|
6533
|
+
></div>
|
|
6534
|
+
|
|
6535
|
+
<button
|
|
6536
|
+
*ngFor="let item of items"
|
|
6537
|
+
#itemEls
|
|
6538
|
+
type="button"
|
|
6539
|
+
role="tab"
|
|
6540
|
+
[disabled]="item.disabled || disabled"
|
|
6541
|
+
[attr.aria-selected]="value === item.value"
|
|
6542
|
+
(click)="select(item.value)"
|
|
6543
|
+
[class]="cn(
|
|
6544
|
+
'relative z-10 flex-1 px-3 py-1.5 text-sm font-medium transition-colors duration-200 rounded-md text-center focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
|
|
6545
|
+
'flex items-center justify-center gap-2',
|
|
6546
|
+
value === item.value
|
|
6547
|
+
? 'text-foreground'
|
|
6548
|
+
: 'text-muted-foreground hover:text-foreground/70',
|
|
6549
|
+
item.disabled && 'opacity-50 cursor-not-allowed',
|
|
6550
|
+
item.class
|
|
6551
|
+
)"
|
|
6552
|
+
>
|
|
6553
|
+
<ng-container *ngIf="itemTemplate; else defaultContent">
|
|
6554
|
+
<ng-container *ngTemplateOutlet="itemTemplate; context: { $implicit: item, selected: value === item.value }">
|
|
6555
|
+
</ng-container>
|
|
6556
|
+
</ng-container>
|
|
6557
|
+
|
|
6558
|
+
<ng-template #defaultContent>
|
|
6559
|
+
<i *ngIf="item.icon" [class]="item.icon"></i>
|
|
6560
|
+
<span class="truncate">{{ item.label }}</span>
|
|
6561
|
+
</ng-template>
|
|
6562
|
+
</button>
|
|
6563
|
+
</div>
|
|
6564
|
+
`, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }] });
|
|
6565
|
+
}
|
|
6566
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SegmentedComponent, decorators: [{
|
|
6567
|
+
type: Component,
|
|
6568
|
+
args: [{ selector: 'tolle-segment', standalone: true, imports: [CommonModule, FormsModule], providers: [
|
|
6569
|
+
{
|
|
6570
|
+
provide: NG_VALUE_ACCESSOR,
|
|
6571
|
+
useExisting: forwardRef(() => SegmentedComponent),
|
|
6572
|
+
multi: true
|
|
6573
|
+
}
|
|
6574
|
+
], template: `
|
|
6575
|
+
<div
|
|
6576
|
+
#container
|
|
6577
|
+
[class]="cn(
|
|
6578
|
+
'relative flex items-center p-1 bg-muted rounded-lg select-none w-full gap-1',
|
|
6579
|
+
class
|
|
6580
|
+
)"
|
|
6581
|
+
role="tablist"
|
|
6582
|
+
>
|
|
6583
|
+
<div
|
|
6584
|
+
class="absolute top-1 bottom-1 bg-background shadow-sm rounded-md transition-all duration-300 ease-[cubic-bezier(0.2,0.0,0.2,1)]"
|
|
6585
|
+
[style.left.px]="gliderLeft"
|
|
6586
|
+
[style.width.px]="gliderWidth"
|
|
6587
|
+
[class.opacity-0]="!hasValue"
|
|
6588
|
+
></div>
|
|
6589
|
+
|
|
6590
|
+
<button
|
|
6591
|
+
*ngFor="let item of items"
|
|
6592
|
+
#itemEls
|
|
6593
|
+
type="button"
|
|
6594
|
+
role="tab"
|
|
6595
|
+
[disabled]="item.disabled || disabled"
|
|
6596
|
+
[attr.aria-selected]="value === item.value"
|
|
6597
|
+
(click)="select(item.value)"
|
|
6598
|
+
[class]="cn(
|
|
6599
|
+
'relative z-10 flex-1 px-3 py-1.5 text-sm font-medium transition-colors duration-200 rounded-md text-center focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
|
|
6600
|
+
'flex items-center justify-center gap-2',
|
|
6601
|
+
value === item.value
|
|
6602
|
+
? 'text-foreground'
|
|
6603
|
+
: 'text-muted-foreground hover:text-foreground/70',
|
|
6604
|
+
item.disabled && 'opacity-50 cursor-not-allowed',
|
|
6605
|
+
item.class
|
|
6606
|
+
)"
|
|
6607
|
+
>
|
|
6608
|
+
<ng-container *ngIf="itemTemplate; else defaultContent">
|
|
6609
|
+
<ng-container *ngTemplateOutlet="itemTemplate; context: { $implicit: item, selected: value === item.value }">
|
|
6610
|
+
</ng-container>
|
|
6611
|
+
</ng-container>
|
|
6612
|
+
|
|
6613
|
+
<ng-template #defaultContent>
|
|
6614
|
+
<i *ngIf="item.icon" [class]="item.icon"></i>
|
|
6615
|
+
<span class="truncate">{{ item.label }}</span>
|
|
6616
|
+
</ng-template>
|
|
6617
|
+
</button>
|
|
6618
|
+
</div>
|
|
6619
|
+
`, styles: [":host{display:block}\n"] }]
|
|
6620
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { items: [{
|
|
6621
|
+
type: Input
|
|
6622
|
+
}], class: [{
|
|
6623
|
+
type: Input
|
|
6624
|
+
}], disabled: [{
|
|
6625
|
+
type: Input
|
|
6626
|
+
}], itemTemplate: [{
|
|
6627
|
+
type: Input
|
|
6628
|
+
}], itemElements: [{
|
|
6629
|
+
type: ViewChildren,
|
|
6630
|
+
args: ['itemEls']
|
|
6631
|
+
}] } });
|
|
6632
|
+
|
|
5834
6633
|
/*
|
|
5835
6634
|
* Public API Surface of tolle
|
|
5836
6635
|
*/
|
|
@@ -5839,5 +6638,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
5839
6638
|
* Generated bundle index. Do not edit.
|
|
5840
6639
|
*/
|
|
5841
6640
|
|
|
5842
|
-
export { AccordionComponent, AccordionItemComponent, AlertComponent, AvatarComponent, AvatarFallbackComponent, BadgeComponent, BreadcrumbComponent, BreadcrumbItemComponent, BreadcrumbLinkComponent, BreadcrumbSeparatorComponent, ButtonComponent, ButtonGroupComponent, CalendarComponent, CardComponent, CardContentComponent, CardFooterComponent, CardHeaderComponent, CardTitleComponent, CheckboxComponent, DataTableComponent, DatePickerComponent, DateRangePickerComponent, DropdownItemComponent, DropdownLabelComponent, DropdownMenuComponent, DropdownSeparatorComponent, DropdownTriggerDirective, EmptyStateComponent, InputComponent, MaskedInputComponent, Modal, ModalComponent, ModalRef, ModalService, ModalStackService, MultiSelectComponent, OtpComponent, OtpGroupComponent, OtpSlotComponent, PaginationComponent, PopoverComponent, PopoverContentComponent, RadioGroupComponent, RadioItemComponent, RangeCalendarComponent, SelectComponent, SelectGroupComponent, SelectItemComponent, SelectSeparatorComponent, SkeletonComponent, SwitchComponent, TOLLE_CONFIG, TextareaComponent, ThemeService, ToastContainerComponent, ToastService, TolleCellDirective, TooltipDirective, cn, provideTolleConfig };
|
|
6641
|
+
export { AccordionComponent, AccordionItemComponent, AlertComponent, AvatarComponent, AvatarFallbackComponent, BadgeComponent, BreadcrumbComponent, BreadcrumbItemComponent, BreadcrumbLinkComponent, BreadcrumbSeparatorComponent, ButtonComponent, ButtonGroupComponent, CalendarComponent, CardComponent, CardContentComponent, CardFooterComponent, CardHeaderComponent, CardTitleComponent, CheckboxComponent, DataTableComponent, DatePickerComponent, DateRangePickerComponent, DropdownItemComponent, DropdownLabelComponent, DropdownMenuComponent, DropdownSeparatorComponent, DropdownTriggerDirective, EmptyStateComponent, InputComponent, MaskedInputComponent, Modal, ModalComponent, ModalRef, ModalService, ModalStackService, MultiSelectComponent, OtpComponent, OtpGroupComponent, OtpSlotComponent, PaginationComponent, PopoverComponent, PopoverContentComponent, RadioGroupComponent, RadioItemComponent, RangeCalendarComponent, SegmentedComponent, SelectComponent, SelectGroupComponent, SelectItemComponent, SelectSeparatorComponent, SkeletonComponent, SwitchComponent, TOLLE_CONFIG, TextareaComponent, ThemeService, ToastContainerComponent, ToastService, TolleCellDirective, TooltipDirective, cn, provideTolleConfig };
|
|
5843
6642
|
//# sourceMappingURL=tolle-ui.mjs.map
|