@tolle_/tolle-ui 0.0.18-beta → 0.0.19-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.
Files changed (50) hide show
  1. package/esm2022/lib/alert.component.mjs +116 -0
  2. package/esm2022/lib/avatar-fallback.component.mjs +19 -0
  3. package/esm2022/lib/avatar.component.mjs +86 -0
  4. package/esm2022/lib/breadcrumb-item.component.mjs +19 -0
  5. package/esm2022/lib/breadcrumb-link.component.mjs +60 -0
  6. package/esm2022/lib/breadcrumb-separator.component.mjs +23 -0
  7. package/esm2022/lib/breadcrumb.component.mjs +28 -0
  8. package/esm2022/lib/button.component.mjs +7 -16
  9. package/esm2022/lib/date-picker.component.mjs +2 -2
  10. package/esm2022/lib/empty-state.component.mjs +111 -0
  11. package/esm2022/lib/input.component.mjs +2 -2
  12. package/esm2022/lib/masked-input.component.mjs +119 -43
  13. package/esm2022/lib/otp-group.component.mjs +15 -0
  14. package/esm2022/lib/otp-slot.component.mjs +62 -0
  15. package/esm2022/lib/otp.component.mjs +127 -0
  16. package/esm2022/lib/popover-content.component.mjs +44 -0
  17. package/esm2022/lib/popover.component.mjs +105 -0
  18. package/esm2022/lib/radio-group.component.mjs +78 -0
  19. package/esm2022/lib/radio-item.component.mjs +112 -0
  20. package/esm2022/lib/radio-service.mjs +23 -0
  21. package/esm2022/lib/textarea.component.mjs +2 -2
  22. package/esm2022/lib/theme.service.mjs +25 -1
  23. package/esm2022/public-api.mjs +16 -1
  24. package/esm2022/tolle-ui.mjs +5 -0
  25. package/fesm2022/{tolle_-tolle-ui.mjs → tolle-ui.mjs} +1115 -64
  26. package/fesm2022/tolle-ui.mjs.map +1 -0
  27. package/lib/alert.component.d.ts +25 -0
  28. package/lib/avatar-fallback.component.d.ts +5 -0
  29. package/lib/avatar.component.d.ts +17 -0
  30. package/lib/breadcrumb-item.component.d.ts +5 -0
  31. package/lib/breadcrumb-link.component.d.ts +6 -0
  32. package/lib/breadcrumb-separator.component.d.ts +5 -0
  33. package/lib/breadcrumb.component.d.ts +8 -0
  34. package/lib/button.component.d.ts +1 -3
  35. package/lib/empty-state.component.d.ts +20 -0
  36. package/lib/masked-input.component.d.ts +8 -1
  37. package/lib/otp-group.component.d.ts +5 -0
  38. package/lib/otp-slot.component.d.ts +12 -0
  39. package/lib/otp.component.d.ts +21 -0
  40. package/lib/popover-content.component.d.ts +8 -0
  41. package/lib/popover.component.d.ts +19 -0
  42. package/lib/radio-group.component.d.ts +23 -0
  43. package/lib/radio-item.component.d.ts +22 -0
  44. package/lib/radio-service.d.ts +11 -0
  45. package/lib/theme.service.d.ts +2 -0
  46. package/package.json +7 -6
  47. package/public-api.d.ts +15 -0
  48. package/theme.css +9 -0
  49. package/esm2022/tolle_-tolle-ui.mjs +0 -5
  50. package/fesm2022/tolle_-tolle-ui.mjs.map +0 -1
@@ -1,9 +1,9 @@
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, Injectable, Optional, HostListener, ViewChild, ContentChildren, EventEmitter, Output, Directive, inject, PLATFORM_ID, Inject, InjectionToken, APP_INITIALIZER, ChangeDetectorRef, ChangeDetectionStrategy, TemplateRef, Injector } from '@angular/core';
4
+ import { Component, Input, forwardRef, Injectable, Optional, HostListener, ViewChild, ContentChildren, EventEmitter, Output, Directive, inject, PLATFORM_ID, Inject, InjectionToken, APP_INITIALIZER, ChangeDetectorRef, ChangeDetectionStrategy, TemplateRef, Injector, HostBinding } from '@angular/core';
5
5
  import * as i1 from '@angular/common';
6
- import { CommonModule, isPlatformBrowser, DOCUMENT } from '@angular/common';
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';
@@ -33,26 +33,22 @@ const buttonVariants = cva("inline-flex items-center justify-center rounded-md t
33
33
  xs: "h-8 px-2 py-1 text-xs",
34
34
  sm: "h-9 rounded-md px-3",
35
35
  lg: "h-11 rounded-md px-8",
36
- // RESTORED: Square icon button variants
37
36
  "icon-xs": "h-8 w-8",
38
37
  "icon-sm": "h-9 w-9",
39
38
  icon: "h-10 w-10",
40
39
  "icon-lg": "h-11 w-11",
41
40
  },
42
- block: { true: "w-full flex" },
43
41
  busy: { true: "relative !cursor-wait !pointer-events-none" }
44
42
  },
45
43
  defaultVariants: {
46
44
  variant: "default",
47
45
  size: "default",
48
- block: false,
49
46
  },
50
47
  });
51
48
  class ButtonComponent {
52
49
  class = '';
53
50
  variant = 'default';
54
51
  size = 'default';
55
- block = false;
56
52
  disabled = false;
57
53
  busy = false;
58
54
  readonly = false;
@@ -60,14 +56,11 @@ class ButtonComponent {
60
56
  return cn(buttonVariants({
61
57
  variant: this.variant,
62
58
  size: this.size,
63
- block: this.block,
64
59
  busy: this.busy
65
- }),
66
- // Adds 'size-icon-sm', 'size-xs', etc. for the CSS selectors to work
67
- 'size-' + this.size, this.class);
60
+ }), 'size-' + this.size, this.class);
68
61
  }
69
62
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
70
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ButtonComponent, isStandalone: true, selector: "tolle-button", inputs: { class: "class", variant: "variant", size: "size", block: "block", disabled: "disabled", busy: "busy", readonly: "readonly" }, ngImport: i0, template: `
63
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ButtonComponent, isStandalone: true, selector: "tolle-button", inputs: { class: "class", variant: "variant", size: "size", disabled: "disabled", busy: "busy", readonly: "readonly" }, ngImport: i0, template: `
71
64
  <button
72
65
  [class]="computedClass"
73
66
  [disabled]="disabled || busy"
@@ -80,11 +73,11 @@ class ButtonComponent {
80
73
  </svg>
81
74
  </div>
82
75
 
83
- <span class="flex items-center justify-center w-full h-full" [class.invisible]="busy">
76
+ <span class="flex items-center justify-center w-full h-full pointer-events-none" [class.invisible]="busy">
84
77
  <ng-content></ng-content>
85
78
  </span>
86
79
  </button>
87
- `, isInline: true, styles: [":host{display:inline-block}:host(.w-full){display:block}:host ::ng-deep i{display:inline-flex;align-items:center;justify-content:center;line-height:1}:host-context(.size-xs) ::ng-deep i,:host-context(.size-icon-xs) ::ng-deep i,:host-context(.size-sm) ::ng-deep i,:host-context(.size-icon-sm) ::ng-deep i{font-size:1rem}:host-context(.size-default) ::ng-deep i,:host-context(.size-icon) ::ng-deep i,:host-context(.size-lg) ::ng-deep i,:host-context(.size-icon-lg) ::ng-deep i{font-size:1.2rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
80
+ `, isInline: true, styles: [":host{display:inline-block;vertical-align:middle}:host ::ng-deep i{display:inline-flex;align-items:center;justify-content:center;line-height:1}:host-context(.size-xs) ::ng-deep i,:host-context(.size-icon-xs) ::ng-deep i,:host-context(.size-sm) ::ng-deep i,:host-context(.size-icon-sm) ::ng-deep i{font-size:1rem}:host-context(.size-default) ::ng-deep i,:host-context(.size-icon) ::ng-deep i,:host-context(.size-lg) ::ng-deep i,:host-context(.size-icon-lg) ::ng-deep i{font-size:1.2rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
88
81
  }
89
82
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ButtonComponent, decorators: [{
90
83
  type: Component,
@@ -101,19 +94,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
101
94
  </svg>
102
95
  </div>
103
96
 
104
- <span class="flex items-center justify-center w-full h-full" [class.invisible]="busy">
97
+ <span class="flex items-center justify-center w-full h-full pointer-events-none" [class.invisible]="busy">
105
98
  <ng-content></ng-content>
106
99
  </span>
107
100
  </button>
108
- `, styles: [":host{display:inline-block}:host(.w-full){display:block}:host ::ng-deep i{display:inline-flex;align-items:center;justify-content:center;line-height:1}:host-context(.size-xs) ::ng-deep i,:host-context(.size-icon-xs) ::ng-deep i,:host-context(.size-sm) ::ng-deep i,:host-context(.size-icon-sm) ::ng-deep i{font-size:1rem}:host-context(.size-default) ::ng-deep i,:host-context(.size-icon) ::ng-deep i,:host-context(.size-lg) ::ng-deep i,:host-context(.size-icon-lg) ::ng-deep i{font-size:1.2rem}\n"] }]
101
+ `, styles: [":host{display:inline-block;vertical-align:middle}:host ::ng-deep i{display:inline-flex;align-items:center;justify-content:center;line-height:1}:host-context(.size-xs) ::ng-deep i,:host-context(.size-icon-xs) ::ng-deep i,:host-context(.size-sm) ::ng-deep i,:host-context(.size-icon-sm) ::ng-deep i{font-size:1rem}:host-context(.size-default) ::ng-deep i,:host-context(.size-icon) ::ng-deep i,:host-context(.size-lg) ::ng-deep i,:host-context(.size-icon-lg) ::ng-deep i{font-size:1.2rem}\n"] }]
109
102
  }], propDecorators: { class: [{
110
103
  type: Input
111
104
  }], variant: [{
112
105
  type: Input
113
106
  }], size: [{
114
107
  type: Input
115
- }], block: [{
116
- type: Input
117
108
  }], disabled: [{
118
109
  type: Input
119
110
  }], busy: [{
@@ -170,7 +161,7 @@ class InputComponent {
170
161
  // Colors & Borders
171
162
  this.error ? "border-destructive focus-within:ring-destructive" : "border-input",
172
163
  // Disabled vs Readonly styling
173
- this.disabled && "cursor-not-allowed opacity-50 bg-muted/30", this.readonly && "cursor-default bg-muted/10 border-dashed focus-within:ring-0", this.containerClass);
164
+ this.disabled && "cursor-not-allowed opacity-50", this.readonly && "cursor-default border-dashed focus-within:ring-0", this.containerClass);
174
165
  }
175
166
  get computedInputClass() {
176
167
  return cn("flex-1 bg-transparent border-none p-0 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-0", this.size === 'xs' && "text-xs", this.size === 'lg' && "text-base", this.disabled && "cursor-not-allowed", this.readonly && "cursor-default", this.class);
@@ -1365,6 +1356,16 @@ class ThemeService {
1365
1356
  else {
1366
1357
  this.disableDarkMode();
1367
1358
  }
1359
+ const savedPrimary = localStorage.getItem('tolle-primary-color');
1360
+ if (savedPrimary) {
1361
+ this.setPrimaryColor(savedPrimary, false);
1362
+ }
1363
+ else if (this.config?.primaryColor) {
1364
+ this.setPrimaryColor(this.config.primaryColor, false);
1365
+ }
1366
+ if (this.config?.radius) {
1367
+ this.renderer.setStyle(this.document.documentElement, '--radius', this.config.radius);
1368
+ }
1368
1369
  // 2. Apply Brand Config - This will generate full palette
1369
1370
  if (this.config) {
1370
1371
  this.applyBrandConfig(this.config);
@@ -1471,9 +1472,23 @@ class ThemeService {
1471
1472
  localStorage.setItem('tolle-theme', 'light');
1472
1473
  this.isDarkSubject.next(false);
1473
1474
  }
1475
+ setPrimaryColor(color, persist = true) {
1476
+ if (!isPlatformBrowser(this.platformId))
1477
+ return;
1478
+ // Update CSS variables + palette
1479
+ this.renderer.setStyle(this.document.documentElement, '--primary', color);
1480
+ this.generatePrimaryShades(color);
1481
+ // Persist user preference
1482
+ if (persist) {
1483
+ localStorage.setItem('tolle-primary-color', color);
1484
+ }
1485
+ }
1474
1486
  get currentTheme() {
1475
1487
  return this.isDarkSubject.value ? 'dark' : 'light';
1476
1488
  }
1489
+ get primaryColor() {
1490
+ return localStorage.getItem('tolle-primary-color');
1491
+ }
1477
1492
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ThemeService, deps: [{ token: DOCUMENT }, { token: PLATFORM_ID }, { token: TOLLE_CONFIG, optional: true }, { token: i0.RendererFactory2 }], target: i0.ɵɵFactoryTarget.Injectable });
1478
1493
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ThemeService, providedIn: 'root' });
1479
1494
  }
@@ -2038,11 +2053,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
2038
2053
  class MaskedInputComponent {
2039
2054
  el;
2040
2055
  cdr;
2056
+ id = `masked-input-${Math.random().toString(36).substr(2, 9)}`;
2057
+ label = '';
2058
+ hint = '';
2059
+ errorMessage = '';
2041
2060
  mask = '';
2042
2061
  placeholder = '';
2043
2062
  type = 'text';
2044
2063
  disabled = false;
2064
+ readonly = false;
2045
2065
  class = '';
2066
+ containerClass = '';
2046
2067
  error = false;
2047
2068
  size = 'default';
2048
2069
  returnRaw = false;
@@ -2059,7 +2080,6 @@ class MaskedInputComponent {
2059
2080
  this.el = el;
2060
2081
  this.cdr = cdr;
2061
2082
  }
2062
- // FIXED DETECTION: Check the actual DOM nodes projected into the component
2063
2083
  ngAfterContentChecked() {
2064
2084
  const prefix = this.el.nativeElement.querySelector('[prefix]');
2065
2085
  const suffix = this.el.nativeElement.querySelector('[suffix]');
@@ -2069,11 +2089,24 @@ class MaskedInputComponent {
2069
2089
  this.cdr.detectChanges();
2070
2090
  }
2071
2091
  }
2092
+ get computedContainerClass() {
2093
+ return cn("group relative flex items-center w-full rounded-md border transition-all shadow-sm", "bg-background ring-offset-background",
2094
+ // Sizing
2095
+ this.size === 'xs' && "h-8 px-2 gap-1.5", this.size === 'sm' && "h-9 px-3 gap-2", this.size === 'default' && "h-10 px-3 gap-2", this.size === 'lg' && "h-11 px-4 gap-3",
2096
+ // Interaction States (Inherited from Input focus style)
2097
+ !(this.readonly || this.disabled) && "focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-1",
2098
+ // Colors & Borders
2099
+ this.error ? "border-destructive focus-within:ring-destructive" : "border-input",
2100
+ // Disabled vs Readonly styling
2101
+ this.disabled && "cursor-not-allowed opacity-50", this.readonly && "cursor-default border-dashed focus-within:ring-0", this.containerClass);
2102
+ }
2072
2103
  get computedInputClass() {
2073
- return cn("flex w-full rounded-md border border-input bg-background text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring focus-visible:ring-ring focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 transition-all", 'disabled:opacity-50 shadow-sm transition-shadow', this.size === 'xs' && "h-8 text-xs px-2", this.size === 'sm' && "h-9 px-3", this.size === 'default' && "h-10 px-3", this.size === 'lg' && "h-11 px-4 text-base", "group-has-[[prefix]]:pl-10 group-has-[[suffix]]:pr-10", this.size === 'xs' && "group-has-[[prefix]]:pl-8 group-has-[[suffix]]:pr-8", this.error && "border-destructive focus-visible:ring-destructive", this.class);
2104
+ return cn("flex-1 bg-transparent border-none p-0 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-0", this.size === 'xs' && "text-xs", this.size === 'lg' && "text-base", this.disabled && "cursor-not-allowed", this.readonly && "cursor-default", this.class);
2074
2105
  }
2075
2106
  // --- Masking Logic ---
2076
2107
  onInput(event) {
2108
+ if (this.readonly || this.disabled)
2109
+ return;
2077
2110
  const input = event.target;
2078
2111
  const raw = this.unmask(input.value);
2079
2112
  const masked = this.applyMask(raw);
@@ -2114,40 +2147,64 @@ class MaskedInputComponent {
2114
2147
  }
2115
2148
  registerOnChange(fn) { this.onChange = fn; }
2116
2149
  registerOnTouched(fn) { this.onTouched = fn; }
2117
- setDisabledState(isDisabled) { this.disabled = isDisabled; }
2150
+ setDisabledState(isDisabled) {
2151
+ this.disabled = isDisabled;
2152
+ this.cdr.markForCheck();
2153
+ }
2118
2154
  cn = cn;
2119
2155
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MaskedInputComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2120
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: MaskedInputComponent, isStandalone: true, selector: "tolle-masked-input", inputs: { mask: "mask", placeholder: "placeholder", type: "type", disabled: "disabled", class: "class", error: "error", size: "size", returnRaw: "returnRaw" }, providers: [
2156
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: MaskedInputComponent, isStandalone: true, selector: "tolle-masked-input", inputs: { id: "id", label: "label", hint: "hint", errorMessage: "errorMessage", mask: "mask", placeholder: "placeholder", type: "type", disabled: "disabled", readonly: "readonly", class: "class", containerClass: "containerClass", error: "error", size: "size", returnRaw: "returnRaw" }, providers: [
2121
2157
  {
2122
2158
  provide: NG_VALUE_ACCESSOR,
2123
2159
  useExisting: forwardRef(() => MaskedInputComponent),
2124
2160
  multi: true
2125
2161
  }
2126
2162
  ], viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["inputEl"], descendants: true, static: true }], ngImport: i0, template: `
2127
- <div [class]="cn('relative flex items-center w-full group', 'size-' + size, class)">
2163
+ <div class="flex flex-col gap-1.5 w-full">
2164
+ <label
2165
+ *ngIf="label"
2166
+ [for]="id"
2167
+ [class.opacity-50]="disabled"
2168
+ class="text-sm font-medium text-foreground leading-none transition-opacity"
2169
+ >
2170
+ {{ label }}
2171
+ </label>
2128
2172
 
2129
- <div class="absolute left-3 flex items-center justify-center text-muted-foreground group-focus-within:text-primary transition-colors"
2130
- [class.left-2.5]="size === 'xs'">
2131
- <ng-content select="[prefix]"></ng-content>
2132
- </div>
2173
+ <div [class]="computedContainerClass">
2174
+ <!-- Prefix Icon -->
2175
+ <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors">
2176
+ <ng-content select="[prefix]"></ng-content>
2177
+ </div>
2133
2178
 
2134
- <input
2135
- #inputEl
2136
- [type]="type"
2137
- [placeholder]="placeholder"
2138
- [disabled]="disabled"
2139
- [value]="displayValue"
2140
- (input)="onInput($event)"
2141
- (blur)="onTouched()"
2142
- [class]="computedInputClass"
2143
- />
2179
+ <input
2180
+ #inputEl
2181
+ [id]="id"
2182
+ [type]="type"
2183
+ [placeholder]="placeholder"
2184
+ [disabled]="disabled"
2185
+ [readOnly]="readonly"
2186
+ [value]="displayValue"
2187
+ (input)="onInput($event)"
2188
+ (blur)="onTouched()"
2189
+ [class]="computedInputClass"
2190
+ />
2144
2191
 
2145
- <div class="absolute right-3 flex items-center justify-center text-muted-foreground group-focus-within:text-primary transition-colors"
2146
- [class.right-2.5]="size === 'xs'">
2147
- <ng-content select="[suffix]"></ng-content>
2192
+ <!-- Suffix Icon -->
2193
+ <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors">
2194
+ <ng-content select="[suffix]"></ng-content>
2195
+ </div>
2148
2196
  </div>
2197
+
2198
+ <ng-container *ngIf="!disabled">
2199
+ <p *ngIf="hint && !error" class="text-xs text-muted-foreground px-1">
2200
+ {{ hint }}
2201
+ </p>
2202
+ <p *ngIf="error && errorMessage" class="text-xs text-destructive px-1">
2203
+ {{ errorMessage }}
2204
+ </p>
2205
+ </ng-container>
2149
2206
  </div>
2150
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }] });
2207
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }] });
2151
2208
  }
2152
2209
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MaskedInputComponent, decorators: [{
2153
2210
  type: Component,
@@ -2163,32 +2220,61 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
2163
2220
  }
2164
2221
  ],
2165
2222
  template: `
2166
- <div [class]="cn('relative flex items-center w-full group', 'size-' + size, class)">
2223
+ <div class="flex flex-col gap-1.5 w-full">
2224
+ <label
2225
+ *ngIf="label"
2226
+ [for]="id"
2227
+ [class.opacity-50]="disabled"
2228
+ class="text-sm font-medium text-foreground leading-none transition-opacity"
2229
+ >
2230
+ {{ label }}
2231
+ </label>
2167
2232
 
2168
- <div class="absolute left-3 flex items-center justify-center text-muted-foreground group-focus-within:text-primary transition-colors"
2169
- [class.left-2.5]="size === 'xs'">
2170
- <ng-content select="[prefix]"></ng-content>
2171
- </div>
2233
+ <div [class]="computedContainerClass">
2234
+ <!-- Prefix Icon -->
2235
+ <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors">
2236
+ <ng-content select="[prefix]"></ng-content>
2237
+ </div>
2172
2238
 
2173
- <input
2174
- #inputEl
2175
- [type]="type"
2176
- [placeholder]="placeholder"
2177
- [disabled]="disabled"
2178
- [value]="displayValue"
2179
- (input)="onInput($event)"
2180
- (blur)="onTouched()"
2181
- [class]="computedInputClass"
2182
- />
2239
+ <input
2240
+ #inputEl
2241
+ [id]="id"
2242
+ [type]="type"
2243
+ [placeholder]="placeholder"
2244
+ [disabled]="disabled"
2245
+ [readOnly]="readonly"
2246
+ [value]="displayValue"
2247
+ (input)="onInput($event)"
2248
+ (blur)="onTouched()"
2249
+ [class]="computedInputClass"
2250
+ />
2183
2251
 
2184
- <div class="absolute right-3 flex items-center justify-center text-muted-foreground group-focus-within:text-primary transition-colors"
2185
- [class.right-2.5]="size === 'xs'">
2186
- <ng-content select="[suffix]"></ng-content>
2252
+ <!-- Suffix Icon -->
2253
+ <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors">
2254
+ <ng-content select="[suffix]"></ng-content>
2255
+ </div>
2187
2256
  </div>
2257
+
2258
+ <ng-container *ngIf="!disabled">
2259
+ <p *ngIf="hint && !error" class="text-xs text-muted-foreground px-1">
2260
+ {{ hint }}
2261
+ </p>
2262
+ <p *ngIf="error && errorMessage" class="text-xs text-destructive px-1">
2263
+ {{ errorMessage }}
2264
+ </p>
2265
+ </ng-container>
2188
2266
  </div>
2189
2267
  `
2190
2268
  }]
2191
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { mask: [{
2269
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { id: [{
2270
+ type: Input
2271
+ }], label: [{
2272
+ type: Input
2273
+ }], hint: [{
2274
+ type: Input
2275
+ }], errorMessage: [{
2276
+ type: Input
2277
+ }], mask: [{
2192
2278
  type: Input
2193
2279
  }], placeholder: [{
2194
2280
  type: Input
@@ -2196,8 +2282,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
2196
2282
  type: Input
2197
2283
  }], disabled: [{
2198
2284
  type: Input
2285
+ }], readonly: [{
2286
+ type: Input
2199
2287
  }], class: [{
2200
2288
  type: Input
2289
+ }], containerClass: [{
2290
+ type: Input
2201
2291
  }], error: [{
2202
2292
  type: Input
2203
2293
  }], size: [{
@@ -2356,7 +2446,7 @@ class DatePickerComponent {
2356
2446
  ></tolle-calendar>
2357
2447
  </div>
2358
2448
  </div>
2359
- `, 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: ["mask", "placeholder", "type", "disabled", "class", "error", "size", "returnRaw"] }, { kind: "component", type: CalendarComponent, selector: "tolle-calendar", inputs: ["class", "disablePastDates"] }] });
2449
+ `, 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"] }, { kind: "component", type: CalendarComponent, selector: "tolle-calendar", inputs: ["class", "disablePastDates"] }] });
2360
2450
  }
2361
2451
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DatePickerComponent, decorators: [{
2362
2452
  type: Component,
@@ -4099,7 +4189,7 @@ class TextareaComponent {
4099
4189
  // Border colors
4100
4190
  this.error ? 'border-destructive' : 'border-input',
4101
4191
  // Disabled vs Readonly styles
4102
- this.disabled && 'cursor-not-allowed opacity-50 bg-muted/30', this.readonly && 'cursor-default bg-muted/10 border-dashed focus-visible:ring-0', 'scrollbar-thin scrollbar-thumb-muted scrollbar-track-transparent', 'min-h-[80px]', this.className);
4192
+ this.disabled && 'cursor-not-allowed opacity-50', this.readonly && 'cursor-default border-dashed focus-visible:ring-0', 'scrollbar-thin scrollbar-thumb-muted scrollbar-track-transparent', 'min-h-[80px]', this.className);
4103
4193
  }
4104
4194
  handleInput(event) {
4105
4195
  if (this.readonly || this.disabled)
@@ -4240,6 +4330,967 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
4240
4330
  type: Input
4241
4331
  }] } });
4242
4332
 
4333
+ const alertVariants = cva("relative w-full rounded-lg border p-4 transition-all duration-300 [&>i~div]:pl-7 [&>i]:absolute [&>i]:left-4 [&>i]:top-4 [&>i]:text-foreground", {
4334
+ variants: {
4335
+ variant: {
4336
+ default: "bg-background text-foreground",
4337
+ destructive: "border-destructive/50 text-destructive dark:border-destructive [&>i]:text-destructive",
4338
+ success: "border-emerald-500/50 text-emerald-700 dark:text-emerald-400 [&>i]:text-emerald-600",
4339
+ warning: "border-amber-500/50 text-amber-700 dark:text-amber-400 [&>i]:text-amber-600",
4340
+ },
4341
+ },
4342
+ defaultVariants: {
4343
+ variant: "default",
4344
+ },
4345
+ });
4346
+ class AlertComponent {
4347
+ variant = 'default';
4348
+ title;
4349
+ class = '';
4350
+ dismissible = false;
4351
+ onClose = new EventEmitter();
4352
+ dismissed = false;
4353
+ isDismissing = false;
4354
+ alertVariants = alertVariants;
4355
+ cn = cn;
4356
+ dismiss() {
4357
+ this.isDismissing = true;
4358
+ // Wait for animation to finish before removing from DOM
4359
+ setTimeout(() => {
4360
+ this.dismissed = true;
4361
+ this.onClose.emit();
4362
+ }, 300);
4363
+ }
4364
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4365
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: AlertComponent, isStandalone: true, selector: "tolle-alert", inputs: { variant: "variant", title: "title", class: "class", dismissible: "dismissible" }, outputs: { onClose: "onClose" }, ngImport: i0, template: `
4366
+ <div
4367
+ *ngIf="!dismissed"
4368
+ [class]="cn(alertVariants({ variant }), class)"
4369
+ [class.opacity-0]="isDismissing"
4370
+ [class.scale-95]="isDismissing"
4371
+ role="alert"
4372
+ >
4373
+ <ng-content select="[icon]"></ng-content>
4374
+
4375
+ <button
4376
+ *ngIf="dismissible"
4377
+ (click)="dismiss()"
4378
+ class="absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 group-hover:opacity-100"
4379
+ [class.opacity-100]="dismissible"
4380
+ >
4381
+ <i class="ri-close-line text-lg"></i>
4382
+ </button>
4383
+
4384
+ <div>
4385
+ <h5 *ngIf="title" class="mb-1 font-medium leading-none tracking-tight">
4386
+ {{ title }}
4387
+ </h5>
4388
+ <div class="text-sm [&_p]:leading-relaxed">
4389
+ <ng-content></ng-content>
4390
+ </div>
4391
+ </div>
4392
+ </div>
4393
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
4394
+ }
4395
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AlertComponent, decorators: [{
4396
+ type: Component,
4397
+ args: [{
4398
+ selector: 'tolle-alert',
4399
+ standalone: true,
4400
+ imports: [CommonModule],
4401
+ template: `
4402
+ <div
4403
+ *ngIf="!dismissed"
4404
+ [class]="cn(alertVariants({ variant }), class)"
4405
+ [class.opacity-0]="isDismissing"
4406
+ [class.scale-95]="isDismissing"
4407
+ role="alert"
4408
+ >
4409
+ <ng-content select="[icon]"></ng-content>
4410
+
4411
+ <button
4412
+ *ngIf="dismissible"
4413
+ (click)="dismiss()"
4414
+ class="absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 group-hover:opacity-100"
4415
+ [class.opacity-100]="dismissible"
4416
+ >
4417
+ <i class="ri-close-line text-lg"></i>
4418
+ </button>
4419
+
4420
+ <div>
4421
+ <h5 *ngIf="title" class="mb-1 font-medium leading-none tracking-tight">
4422
+ {{ title }}
4423
+ </h5>
4424
+ <div class="text-sm [&_p]:leading-relaxed">
4425
+ <ng-content></ng-content>
4426
+ </div>
4427
+ </div>
4428
+ </div>
4429
+ `,
4430
+ }]
4431
+ }], propDecorators: { variant: [{
4432
+ type: Input
4433
+ }], title: [{
4434
+ type: Input
4435
+ }], class: [{
4436
+ type: Input
4437
+ }], dismissible: [{
4438
+ type: Input
4439
+ }], onClose: [{
4440
+ type: Output
4441
+ }] } });
4442
+
4443
+ class AvatarComponent {
4444
+ cdr;
4445
+ src;
4446
+ alt = '';
4447
+ size = 'default';
4448
+ shape = 'circle';
4449
+ // We remove @Input() class because standard class="" attributes
4450
+ // on the tag will now work automatically with the host bindings.
4451
+ isLoading = true;
4452
+ hasError = false;
4453
+ constructor(cdr) {
4454
+ this.cdr = cdr;
4455
+ }
4456
+ onLoad() {
4457
+ this.isLoading = false;
4458
+ this.cdr.detectChanges();
4459
+ }
4460
+ onError() {
4461
+ this.isLoading = false;
4462
+ this.hasError = true;
4463
+ this.cdr.detectChanges();
4464
+ }
4465
+ // Apply styles directly to the <tolle-avatar> tag
4466
+ get hostClasses() {
4467
+ return cn(
4468
+ // Layout & Shape
4469
+ "relative flex shrink-0 overflow-hidden bg-muted", this.shape === 'circle' ? 'rounded-full' : 'rounded-md',
4470
+ // Sizes
4471
+ this.size === 'sm' && "h-8 w-8 text-xs", this.size === 'default' && "h-10 w-10", this.size === 'lg' && "h-16 w-16 text-lg", this.size === 'xl' && "h-24 w-24 text-xl");
4472
+ }
4473
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AvatarComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
4474
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: AvatarComponent, isStandalone: true, selector: "tolle-avatar", inputs: { src: "src", alt: "alt", size: "size", shape: "shape" }, host: { properties: { "class": "this.hostClasses" } }, ngImport: i0, template: `
4475
+ <!-- Image Layer -->
4476
+ <img *ngIf="src && !hasError"
4477
+ [src]="src"
4478
+ [alt]="alt"
4479
+ (load)="onLoad()"
4480
+ (error)="onError()"
4481
+ [class.opacity-0]="isLoading"
4482
+ class="h-full w-full object-cover transition-opacity duration-300" />
4483
+
4484
+ <!-- Fallback Layer -->
4485
+ <div *ngIf="hasError || !src || isLoading" class="flex h-full w-full items-center justify-center bg-muted">
4486
+ <ng-content></ng-content>
4487
+ </div>
4488
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
4489
+ }
4490
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AvatarComponent, decorators: [{
4491
+ type: Component,
4492
+ args: [{
4493
+ selector: 'tolle-avatar',
4494
+ standalone: true,
4495
+ imports: [NgIf],
4496
+ template: `
4497
+ <!-- Image Layer -->
4498
+ <img *ngIf="src && !hasError"
4499
+ [src]="src"
4500
+ [alt]="alt"
4501
+ (load)="onLoad()"
4502
+ (error)="onError()"
4503
+ [class.opacity-0]="isLoading"
4504
+ class="h-full w-full object-cover transition-opacity duration-300" />
4505
+
4506
+ <!-- Fallback Layer -->
4507
+ <div *ngIf="hasError || !src || isLoading" class="flex h-full w-full items-center justify-center bg-muted">
4508
+ <ng-content></ng-content>
4509
+ </div>
4510
+ `
4511
+ }]
4512
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { src: [{
4513
+ type: Input
4514
+ }], alt: [{
4515
+ type: Input
4516
+ }], size: [{
4517
+ type: Input
4518
+ }], shape: [{
4519
+ type: Input
4520
+ }], hostClasses: [{
4521
+ type: HostBinding,
4522
+ args: ['class']
4523
+ }] } });
4524
+
4525
+ class AvatarFallbackComponent {
4526
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AvatarFallbackComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4527
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: AvatarFallbackComponent, isStandalone: true, selector: "tolle-avatar-fallback", ngImport: i0, template: `
4528
+ <div class="flex h-full w-full items-center justify-center bg-muted text-muted-foreground font-medium uppercase">
4529
+ <ng-content></ng-content>
4530
+ </div>
4531
+ `, isInline: true, styles: [""] });
4532
+ }
4533
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AvatarFallbackComponent, decorators: [{
4534
+ type: Component,
4535
+ args: [{ selector: 'tolle-avatar-fallback', standalone: true, imports: [], template: `
4536
+ <div class="flex h-full w-full items-center justify-center bg-muted text-muted-foreground font-medium uppercase">
4537
+ <ng-content></ng-content>
4538
+ </div>
4539
+ ` }]
4540
+ }] });
4541
+
4542
+ class BreadcrumbComponent {
4543
+ class = '';
4544
+ cn = cn;
4545
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4546
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: BreadcrumbComponent, isStandalone: true, selector: "tolle-breadcrumb", inputs: { class: "class" }, ngImport: i0, template: `
4547
+ <nav aria-label="breadcrumb" [class]="cn('flex flex-wrap items-center break-words text-sm text-muted-foreground', class)">
4548
+ <ol class="flex flex-wrap items-center gap-1.5 break-words">
4549
+ <ng-content></ng-content>
4550
+ </ol>
4551
+ </nav>
4552
+ `, isInline: true, styles: [""] });
4553
+ }
4554
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BreadcrumbComponent, decorators: [{
4555
+ type: Component,
4556
+ args: [{ selector: 'tolle-breadcrumb', standalone: true, imports: [], template: `
4557
+ <nav aria-label="breadcrumb" [class]="cn('flex flex-wrap items-center break-words text-sm text-muted-foreground', class)">
4558
+ <ol class="flex flex-wrap items-center gap-1.5 break-words">
4559
+ <ng-content></ng-content>
4560
+ </ol>
4561
+ </nav>
4562
+ ` }]
4563
+ }], propDecorators: { class: [{
4564
+ type: Input
4565
+ }] } });
4566
+
4567
+ class BreadcrumbLinkComponent {
4568
+ active = false;
4569
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BreadcrumbLinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4570
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: BreadcrumbLinkComponent, isStandalone: true, selector: "tolle-breadcrumb-link", inputs: { active: "active" }, ngImport: i0, template: `
4571
+ <ng-template #content>
4572
+ <ng-content></ng-content>
4573
+ </ng-template>
4574
+
4575
+ <ng-container *ngIf="active; else linkTemplate">
4576
+ <span
4577
+ role="link"
4578
+ aria-disabled="true"
4579
+ aria-current="page"
4580
+ class="font-normal text-foreground"
4581
+ >
4582
+ <ng-container *ngTemplateOutlet="content"></ng-container>
4583
+ </span>
4584
+ </ng-container>
4585
+
4586
+ <ng-template #linkTemplate>
4587
+ <div class="transition-colors hover:text-foreground cursor-pointer">
4588
+ <ng-container *ngTemplateOutlet="content"></ng-container>
4589
+ </div>
4590
+ </ng-template>
4591
+ `, isInline: true, styles: [""], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
4592
+ }
4593
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BreadcrumbLinkComponent, decorators: [{
4594
+ type: Component,
4595
+ args: [{ selector: 'tolle-breadcrumb-link', standalone: true, imports: [
4596
+ NgIf,
4597
+ NgTemplateOutlet
4598
+ ], template: `
4599
+ <ng-template #content>
4600
+ <ng-content></ng-content>
4601
+ </ng-template>
4602
+
4603
+ <ng-container *ngIf="active; else linkTemplate">
4604
+ <span
4605
+ role="link"
4606
+ aria-disabled="true"
4607
+ aria-current="page"
4608
+ class="font-normal text-foreground"
4609
+ >
4610
+ <ng-container *ngTemplateOutlet="content"></ng-container>
4611
+ </span>
4612
+ </ng-container>
4613
+
4614
+ <ng-template #linkTemplate>
4615
+ <div class="transition-colors hover:text-foreground cursor-pointer">
4616
+ <ng-container *ngTemplateOutlet="content"></ng-container>
4617
+ </div>
4618
+ </ng-template>
4619
+ ` }]
4620
+ }], propDecorators: { active: [{
4621
+ type: Input
4622
+ }] } });
4623
+
4624
+ class BreadcrumbSeparatorComponent {
4625
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BreadcrumbSeparatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4626
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: BreadcrumbSeparatorComponent, isStandalone: true, selector: "tolle-breadcrumb-separator", ngImport: i0, template: `
4627
+ <li role="presentation" aria-hidden="true" class="[&>i]:size-3.5">
4628
+ <ng-content>
4629
+ <i class="ri-arrow-right-s-line"></i>
4630
+ </ng-content>
4631
+ </li>
4632
+ `, isInline: true, styles: [""] });
4633
+ }
4634
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BreadcrumbSeparatorComponent, decorators: [{
4635
+ type: Component,
4636
+ args: [{ selector: 'tolle-breadcrumb-separator', standalone: true, imports: [], template: `
4637
+ <li role="presentation" aria-hidden="true" class="[&>i]:size-3.5">
4638
+ <ng-content>
4639
+ <i class="ri-arrow-right-s-line"></i>
4640
+ </ng-content>
4641
+ </li>
4642
+ ` }]
4643
+ }] });
4644
+
4645
+ class BreadcrumbItemComponent {
4646
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BreadcrumbItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4647
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: BreadcrumbItemComponent, isStandalone: true, selector: "tolle-breadcrumb-item", ngImport: i0, template: `
4648
+ <li class="inline-flex items-center gap-1.5">
4649
+ <ng-content></ng-content>
4650
+ </li>
4651
+ `, isInline: true, styles: [""] });
4652
+ }
4653
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BreadcrumbItemComponent, decorators: [{
4654
+ type: Component,
4655
+ args: [{ selector: 'tolle-breadcrumb-item', standalone: true, imports: [], template: `
4656
+ <li class="inline-flex items-center gap-1.5">
4657
+ <ng-content></ng-content>
4658
+ </li>
4659
+ ` }]
4660
+ }] });
4661
+
4662
+ const emptyStateVariants = cva("flex flex-col items-center justify-center text-center animate-in fade-in duration-500", {
4663
+ variants: {
4664
+ variant: {
4665
+ default: "min-h-[400px] rounded-md border border-dashed border-border p-8 bg-background/50",
4666
+ minimal: "p-4 min-h-[200px]",
4667
+ },
4668
+ },
4669
+ defaultVariants: {
4670
+ variant: "default",
4671
+ },
4672
+ });
4673
+ class EmptyStateComponent {
4674
+ variant = 'default';
4675
+ title = 'No items found';
4676
+ description;
4677
+ class = '';
4678
+ emptyStateVariants = emptyStateVariants;
4679
+ cn = cn;
4680
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: EmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4681
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: EmptyStateComponent, isStandalone: true, selector: "tolle-empty-state", inputs: { variant: "variant", title: "title", description: "description", class: "class" }, ngImport: i0, template: `
4682
+ <div [class]="cn(emptyStateVariants({ variant }), class)">
4683
+
4684
+ <div [class]="cn(
4685
+ 'flex items-center justify-center rounded-full bg-muted',
4686
+ variant === 'minimal' ? 'h-12 w-12' : 'h-20 w-20'
4687
+ )">
4688
+ <ng-content select="[icon]">
4689
+ <i [class]="cn(
4690
+ 'ri-inbox-line text-muted-foreground/60',
4691
+ variant === 'minimal' ? 'text-xl' : 'text-3xl'
4692
+ )"></i>
4693
+ </ng-content>
4694
+ </div>
4695
+
4696
+ <h3 [class]="cn(
4697
+ 'font-semibold text-foreground',
4698
+ variant === 'minimal' ? 'mt-2 text-sm' : 'mt-4 text-lg'
4699
+ )">
4700
+ {{ title }}
4701
+ </h3>
4702
+
4703
+ <p *ngIf="description" [class]="cn(
4704
+ 'text-muted-foreground',
4705
+ variant === 'minimal' ? 'mt-1 text-xs' : 'mb-6 mt-2 max-w-sm text-sm'
4706
+ )">
4707
+ {{ description }}
4708
+ </p>
4709
+
4710
+ <div *ngIf="variant !== 'minimal'" class="flex items-center justify-center gap-3">
4711
+ <ng-content select="[actions]"></ng-content>
4712
+ </div>
4713
+ </div>
4714
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
4715
+ }
4716
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: EmptyStateComponent, decorators: [{
4717
+ type: Component,
4718
+ args: [{
4719
+ selector: 'tolle-empty-state',
4720
+ standalone: true,
4721
+ imports: [CommonModule],
4722
+ template: `
4723
+ <div [class]="cn(emptyStateVariants({ variant }), class)">
4724
+
4725
+ <div [class]="cn(
4726
+ 'flex items-center justify-center rounded-full bg-muted',
4727
+ variant === 'minimal' ? 'h-12 w-12' : 'h-20 w-20'
4728
+ )">
4729
+ <ng-content select="[icon]">
4730
+ <i [class]="cn(
4731
+ 'ri-inbox-line text-muted-foreground/60',
4732
+ variant === 'minimal' ? 'text-xl' : 'text-3xl'
4733
+ )"></i>
4734
+ </ng-content>
4735
+ </div>
4736
+
4737
+ <h3 [class]="cn(
4738
+ 'font-semibold text-foreground',
4739
+ variant === 'minimal' ? 'mt-2 text-sm' : 'mt-4 text-lg'
4740
+ )">
4741
+ {{ title }}
4742
+ </h3>
4743
+
4744
+ <p *ngIf="description" [class]="cn(
4745
+ 'text-muted-foreground',
4746
+ variant === 'minimal' ? 'mt-1 text-xs' : 'mb-6 mt-2 max-w-sm text-sm'
4747
+ )">
4748
+ {{ description }}
4749
+ </p>
4750
+
4751
+ <div *ngIf="variant !== 'minimal'" class="flex items-center justify-center gap-3">
4752
+ <ng-content select="[actions]"></ng-content>
4753
+ </div>
4754
+ </div>
4755
+ `
4756
+ }]
4757
+ }], propDecorators: { variant: [{
4758
+ type: Input
4759
+ }], title: [{
4760
+ type: Input
4761
+ }], description: [{
4762
+ type: Input
4763
+ }], class: [{
4764
+ type: Input
4765
+ }] } });
4766
+
4767
+ class OtpComponent {
4768
+ cdr;
4769
+ length = 6;
4770
+ disabled = false;
4771
+ auto = false; // The toggle for automatic slot generation
4772
+ value = '';
4773
+ isFocused = false;
4774
+ onChange = () => { };
4775
+ onTouched = () => { };
4776
+ constructor(cdr) {
4777
+ this.cdr = cdr;
4778
+ }
4779
+ onInputChange(event) {
4780
+ const val = event.target.value.replace(/\D/g, '');
4781
+ this.value = val;
4782
+ this.onChange(val);
4783
+ this.cdr.markForCheck();
4784
+ }
4785
+ // Visual logic for the automated slots
4786
+ getSlotClass(index) {
4787
+ const isActive = this.isFocused && this.value.length === index;
4788
+ return cn('relative flex h-10 w-10 items-center justify-center border-y border-r border-input text-sm transition-all bg-background', index === 0 && 'rounded-l-md border-l', index === this.length - 1 && 'rounded-r-md', isActive && 'z-30 ring-2 ring-ring ring-offset-background');
4789
+ }
4790
+ writeValue(value) { this.value = value || ''; this.cdr.markForCheck(); }
4791
+ registerOnChange(fn) { this.onChange = fn; }
4792
+ registerOnTouched(fn) { this.onTouched = fn; }
4793
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OtpComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
4794
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: OtpComponent, isStandalone: true, selector: "tolle-otp", inputs: { length: "length", disabled: "disabled", auto: "auto" }, providers: [{
4795
+ provide: NG_VALUE_ACCESSOR,
4796
+ useExisting: forwardRef(() => OtpComponent),
4797
+ multi: true
4798
+ }], ngImport: i0, template: `
4799
+ <div class="relative flex items-center gap-2">
4800
+ <input
4801
+ #hiddenInput
4802
+ type="text"
4803
+ inputmode="numeric"
4804
+ autocomplete="one-time-code"
4805
+ [maxLength]="length"
4806
+ class="absolute inset-0 opacity-0 cursor-default z-20"
4807
+ [(ngModel)]="value"
4808
+ (input)="onInputChange($event)"
4809
+ (focus)="isFocused = true"
4810
+ (blur)="isFocused = false"
4811
+ [disabled]="disabled"
4812
+ />
4813
+
4814
+ <div *ngIf="auto" class="flex items-center gap-2 pointer-events-none">
4815
+ <div class="flex items-center">
4816
+ <div *ngFor="let _ of [].constructor(length); let i = index"
4817
+ [class]="getSlotClass(i)"
4818
+ >
4819
+ {{ value[i] || '' }}
4820
+ <div *ngIf="isFocused && value.length === i" class="absolute inset-0 flex items-center justify-center">
4821
+ <div class="h-4 w-px animate-caret-blink bg-foreground duration-1000"></div>
4822
+ </div>
4823
+ </div>
4824
+ </div>
4825
+ </div>
4826
+
4827
+ <div *ngIf="!auto" class="flex items-center gap-2 pointer-events-none">
4828
+ <ng-content></ng-content>
4829
+ </div>
4830
+ </div>
4831
+ `, 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.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { 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"] }] });
4832
+ }
4833
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OtpComponent, decorators: [{
4834
+ type: Component,
4835
+ args: [{
4836
+ selector: 'tolle-otp',
4837
+ standalone: true,
4838
+ imports: [CommonModule, FormsModule],
4839
+ providers: [{
4840
+ provide: NG_VALUE_ACCESSOR,
4841
+ useExisting: forwardRef(() => OtpComponent),
4842
+ multi: true
4843
+ }],
4844
+ template: `
4845
+ <div class="relative flex items-center gap-2">
4846
+ <input
4847
+ #hiddenInput
4848
+ type="text"
4849
+ inputmode="numeric"
4850
+ autocomplete="one-time-code"
4851
+ [maxLength]="length"
4852
+ class="absolute inset-0 opacity-0 cursor-default z-20"
4853
+ [(ngModel)]="value"
4854
+ (input)="onInputChange($event)"
4855
+ (focus)="isFocused = true"
4856
+ (blur)="isFocused = false"
4857
+ [disabled]="disabled"
4858
+ />
4859
+
4860
+ <div *ngIf="auto" class="flex items-center gap-2 pointer-events-none">
4861
+ <div class="flex items-center">
4862
+ <div *ngFor="let _ of [].constructor(length); let i = index"
4863
+ [class]="getSlotClass(i)"
4864
+ >
4865
+ {{ value[i] || '' }}
4866
+ <div *ngIf="isFocused && value.length === i" class="absolute inset-0 flex items-center justify-center">
4867
+ <div class="h-4 w-px animate-caret-blink bg-foreground duration-1000"></div>
4868
+ </div>
4869
+ </div>
4870
+ </div>
4871
+ </div>
4872
+
4873
+ <div *ngIf="!auto" class="flex items-center gap-2 pointer-events-none">
4874
+ <ng-content></ng-content>
4875
+ </div>
4876
+ </div>
4877
+ `
4878
+ }]
4879
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { length: [{
4880
+ type: Input
4881
+ }], disabled: [{
4882
+ type: Input
4883
+ }], auto: [{
4884
+ type: Input
4885
+ }] } });
4886
+
4887
+ class OtpSlotComponent {
4888
+ char = '';
4889
+ isActive = false;
4890
+ isFirst = false; // New Input
4891
+ isLast = false; // New Input
4892
+ class = '';
4893
+ cn = cn;
4894
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OtpSlotComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4895
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: OtpSlotComponent, isStandalone: true, selector: "tolle-otp-slot", inputs: { char: "char", isActive: "isActive", isFirst: "isFirst", isLast: "isLast", class: "class" }, ngImport: i0, template: `
4896
+ <div [class]="cn(
4897
+ 'relative flex h-10 w-10 items-center justify-center border-y border-r border-input text-sm transition-all',
4898
+ 'bg-background',
4899
+ isFirst ? 'rounded-l-md border-l' : '',
4900
+ isLast ? 'rounded-r-md' : '',
4901
+ isActive ? 'z-10 ring-2 ring-ring ring-offset-background' : '',
4902
+ class
4903
+ )">
4904
+ {{ char || '' }}
4905
+ <div *ngIf="isActive && !char" class="pointer-events-none absolute inset-0 flex items-center justify-center">
4906
+ <div class="h-4 w-px animate-caret-blink bg-foreground duration-1000"></div>
4907
+ </div>
4908
+ </div>
4909
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
4910
+ }
4911
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OtpSlotComponent, decorators: [{
4912
+ type: Component,
4913
+ args: [{
4914
+ selector: 'tolle-otp-slot',
4915
+ standalone: true,
4916
+ imports: [NgIf],
4917
+ template: `
4918
+ <div [class]="cn(
4919
+ 'relative flex h-10 w-10 items-center justify-center border-y border-r border-input text-sm transition-all',
4920
+ 'bg-background',
4921
+ isFirst ? 'rounded-l-md border-l' : '',
4922
+ isLast ? 'rounded-r-md' : '',
4923
+ isActive ? 'z-10 ring-2 ring-ring ring-offset-background' : '',
4924
+ class
4925
+ )">
4926
+ {{ char || '' }}
4927
+ <div *ngIf="isActive && !char" class="pointer-events-none absolute inset-0 flex items-center justify-center">
4928
+ <div class="h-4 w-px animate-caret-blink bg-foreground duration-1000"></div>
4929
+ </div>
4930
+ </div>
4931
+ `
4932
+ }]
4933
+ }], propDecorators: { char: [{
4934
+ type: Input
4935
+ }], isActive: [{
4936
+ type: Input
4937
+ }], isFirst: [{
4938
+ type: Input
4939
+ }], isLast: [{
4940
+ type: Input
4941
+ }], class: [{
4942
+ type: Input
4943
+ }] } });
4944
+
4945
+ class OtpGroupComponent {
4946
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OtpGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4947
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: OtpGroupComponent, isStandalone: true, selector: "tolle-otp-group", ngImport: i0, template: `
4948
+ <div class="flex items-center"><ng-content></ng-content></div>
4949
+ `, isInline: true, styles: [""] });
4950
+ }
4951
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OtpGroupComponent, decorators: [{
4952
+ type: Component,
4953
+ args: [{ selector: 'tolle-otp-group', standalone: true, imports: [], template: `
4954
+ <div class="flex items-center"><ng-content></ng-content></div>
4955
+ ` }]
4956
+ }] });
4957
+
4958
+ class PopoverComponent {
4959
+ placement = 'bottom';
4960
+ onOpen = new EventEmitter();
4961
+ onClose = new EventEmitter();
4962
+ triggerEl;
4963
+ popoverEl;
4964
+ isOpen = false;
4965
+ cleanup;
4966
+ toggle() {
4967
+ this.isOpen ? this.close() : this.open();
4968
+ }
4969
+ open() {
4970
+ this.isOpen = true;
4971
+ this.onOpen.emit();
4972
+ setTimeout(() => this.updatePosition());
4973
+ }
4974
+ close() {
4975
+ this.isOpen = false;
4976
+ this.onClose.emit();
4977
+ if (this.cleanup)
4978
+ this.cleanup();
4979
+ }
4980
+ updatePosition() {
4981
+ if (!this.triggerEl || !this.popoverEl)
4982
+ return;
4983
+ this.cleanup = autoUpdate(this.triggerEl.nativeElement, this.popoverEl.nativeElement, () => {
4984
+ computePosition(this.triggerEl.nativeElement, this.popoverEl.nativeElement, {
4985
+ placement: this.placement,
4986
+ middleware: [offset(8), flip(), shift({ padding: 8 })],
4987
+ }).then(({ x, y }) => {
4988
+ Object.assign(this.popoverEl.nativeElement.style, {
4989
+ left: `${x}px`,
4990
+ top: `${y}px`,
4991
+ });
4992
+ });
4993
+ });
4994
+ }
4995
+ onClickOutside(event) {
4996
+ if (this.isOpen &&
4997
+ !this.triggerEl.nativeElement.contains(event.target) &&
4998
+ !this.popoverEl?.nativeElement.contains(event.target)) {
4999
+ this.close();
5000
+ }
5001
+ }
5002
+ ngOnDestroy() {
5003
+ if (this.cleanup)
5004
+ this.cleanup();
5005
+ }
5006
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5007
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: PopoverComponent, isStandalone: true, selector: "tolle-popover", inputs: { placement: "placement" }, outputs: { onOpen: "onOpen", onClose: "onClose" }, host: { listeners: { "document:mousedown": "onClickOutside($event)" } }, viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["trigger"], descendants: true }, { propertyName: "popoverEl", first: true, predicate: ["popover"], descendants: true }], ngImport: i0, template: `
5008
+ <div class="inline-block" #trigger (click)="toggle()">
5009
+ <ng-content select="[trigger]"></ng-content>
5010
+ </div>
5011
+
5012
+ <div
5013
+ *ngIf="isOpen"
5014
+ #popover
5015
+ class="absolute top-0 left-0 w-max z-[9999]"
5016
+ >
5017
+ <ng-content></ng-content>
5018
+ </div>
5019
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
5020
+ }
5021
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PopoverComponent, decorators: [{
5022
+ type: Component,
5023
+ args: [{
5024
+ selector: 'tolle-popover',
5025
+ standalone: true,
5026
+ imports: [CommonModule],
5027
+ template: `
5028
+ <div class="inline-block" #trigger (click)="toggle()">
5029
+ <ng-content select="[trigger]"></ng-content>
5030
+ </div>
5031
+
5032
+ <div
5033
+ *ngIf="isOpen"
5034
+ #popover
5035
+ class="absolute top-0 left-0 w-max z-[9999]"
5036
+ >
5037
+ <ng-content></ng-content>
5038
+ </div>
5039
+ `,
5040
+ }]
5041
+ }], propDecorators: { placement: [{
5042
+ type: Input
5043
+ }], onOpen: [{
5044
+ type: Output
5045
+ }], onClose: [{
5046
+ type: Output
5047
+ }], triggerEl: [{
5048
+ type: ViewChild,
5049
+ args: ['trigger']
5050
+ }], popoverEl: [{
5051
+ type: ViewChild,
5052
+ args: ['popover']
5053
+ }], onClickOutside: [{
5054
+ type: HostListener,
5055
+ args: ['document:mousedown', ['$event']]
5056
+ }] } });
5057
+
5058
+ class PopoverContentComponent {
5059
+ class = '';
5060
+ cn = cn;
5061
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PopoverContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5062
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: PopoverContentComponent, isStandalone: true, selector: "tolle-popover-content", inputs: { class: "class" }, ngImport: i0, template: `
5063
+ <div
5064
+ [class]="cn(
5065
+ 'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none',
5066
+ 'animate-in fade-in zoom-in-95 duration-200',
5067
+ class
5068
+ )"
5069
+ role="dialog"
5070
+ >
5071
+ <ng-content></ng-content>
5072
+ </div>
5073
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
5074
+ }
5075
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PopoverContentComponent, decorators: [{
5076
+ type: Component,
5077
+ args: [{
5078
+ selector: 'tolle-popover-content',
5079
+ standalone: true,
5080
+ imports: [CommonModule],
5081
+ template: `
5082
+ <div
5083
+ [class]="cn(
5084
+ 'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none',
5085
+ 'animate-in fade-in zoom-in-95 duration-200',
5086
+ class
5087
+ )"
5088
+ role="dialog"
5089
+ >
5090
+ <ng-content></ng-content>
5091
+ </div>
5092
+ `
5093
+ }]
5094
+ }], propDecorators: { class: [{
5095
+ type: Input
5096
+ }] } });
5097
+
5098
+ class RadioService {
5099
+ selectedValueSource = new BehaviorSubject(null);
5100
+ selectedValue$ = this.selectedValueSource.asObservable();
5101
+ disabledSource = new BehaviorSubject(false);
5102
+ disabled$ = this.disabledSource.asObservable();
5103
+ select(value) {
5104
+ if (!this.disabledSource.value) {
5105
+ this.selectedValueSource.next(value);
5106
+ }
5107
+ }
5108
+ setDisabled(isDisabled) {
5109
+ this.disabledSource.next(isDisabled);
5110
+ }
5111
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RadioService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
5112
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RadioService });
5113
+ }
5114
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RadioService, decorators: [{
5115
+ type: Injectable
5116
+ }] });
5117
+
5118
+ class RadioGroupComponent {
5119
+ radioService;
5120
+ class = '';
5121
+ disabled = false;
5122
+ name = `radio-group-${Math.random().toString(36).substring(2, 9)}`;
5123
+ value;
5124
+ onChange = () => { };
5125
+ onTouched = () => { };
5126
+ constructor(radioService) {
5127
+ this.radioService = radioService;
5128
+ this.radioService.selectedValue$.subscribe(val => {
5129
+ this.value = val;
5130
+ this.onChange(val);
5131
+ });
5132
+ }
5133
+ setDisabledState(isDisabled) {
5134
+ this.disabled = isDisabled;
5135
+ this.radioService.setDisabled(isDisabled);
5136
+ }
5137
+ ngOnChanges() {
5138
+ this.radioService.setDisabled(this.disabled);
5139
+ }
5140
+ writeValue(value) {
5141
+ this.value = value;
5142
+ this.radioService.select(value);
5143
+ }
5144
+ registerOnChange(fn) { this.onChange = fn; }
5145
+ registerOnTouched(fn) { this.onTouched = fn; }
5146
+ cn = cn;
5147
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RadioGroupComponent, deps: [{ token: RadioService }], target: i0.ɵɵFactoryTarget.Component });
5148
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: RadioGroupComponent, isStandalone: true, selector: "tolle-radio-group", inputs: { class: "class", disabled: "disabled", name: "name" }, providers: [
5149
+ RadioService,
5150
+ {
5151
+ provide: NG_VALUE_ACCESSOR,
5152
+ useExisting: forwardRef(() => RadioGroupComponent),
5153
+ multi: true
5154
+ }
5155
+ ], usesOnChanges: true, ngImport: i0, template: `
5156
+ <div [class]="cn('grid gap-2', class)" role="radiogroup">
5157
+ <ng-content></ng-content>
5158
+ </div>
5159
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
5160
+ }
5161
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RadioGroupComponent, decorators: [{
5162
+ type: Component,
5163
+ args: [{
5164
+ selector: 'tolle-radio-group',
5165
+ standalone: true,
5166
+ imports: [CommonModule],
5167
+ providers: [
5168
+ RadioService,
5169
+ {
5170
+ provide: NG_VALUE_ACCESSOR,
5171
+ useExisting: forwardRef(() => RadioGroupComponent),
5172
+ multi: true
5173
+ }
5174
+ ],
5175
+ template: `
5176
+ <div [class]="cn('grid gap-2', class)" role="radiogroup">
5177
+ <ng-content></ng-content>
5178
+ </div>
5179
+ `
5180
+ }]
5181
+ }], ctorParameters: () => [{ type: RadioService }], propDecorators: { class: [{
5182
+ type: Input
5183
+ }], disabled: [{
5184
+ type: Input
5185
+ }], name: [{
5186
+ type: Input
5187
+ }] } });
5188
+
5189
+ class RadioItemComponent {
5190
+ radioService;
5191
+ cdr;
5192
+ value;
5193
+ disabled = false;
5194
+ class = '';
5195
+ isSelected = false;
5196
+ groupDisabled = false;
5197
+ sub = new Subscription();
5198
+ get isEffectiveDisabled() {
5199
+ return this.disabled || this.groupDisabled;
5200
+ }
5201
+ // Inject ChangeDetectorRef to ensure UI updates when service emits
5202
+ constructor(radioService, cdr) {
5203
+ this.radioService = radioService;
5204
+ this.cdr = cdr;
5205
+ }
5206
+ ngOnInit() {
5207
+ // Listen for selection changes
5208
+ this.sub.add(this.radioService.selectedValue$.subscribe(val => {
5209
+ this.isSelected = (val === this.value);
5210
+ this.cdr.markForCheck(); // Trigger UI refresh
5211
+ }));
5212
+ // Listen for group-level disabled state
5213
+ this.sub.add(this.radioService.disabled$.subscribe(dis => {
5214
+ this.groupDisabled = dis;
5215
+ this.cdr.markForCheck(); // Trigger UI refresh
5216
+ }));
5217
+ }
5218
+ select() {
5219
+ this.radioService.select(this.value);
5220
+ }
5221
+ ngOnDestroy() {
5222
+ this.sub.unsubscribe(); // Clean up subscriptions
5223
+ }
5224
+ cn = cn;
5225
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RadioItemComponent, deps: [{ token: RadioService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
5226
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: RadioItemComponent, isStandalone: true, selector: "tolle-radio-item", inputs: { value: "value", disabled: "disabled", class: "class" }, ngImport: i0, template: `
5227
+ <div
5228
+ (click)="!isEffectiveDisabled && select()"
5229
+ [class]="cn(
5230
+ 'flex items-center space-x-2 group py-1',
5231
+ isEffectiveDisabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'
5232
+ )"
5233
+ >
5234
+ <div [class]="cn(
5235
+ 'aspect-square h-4 w-4 rounded-full border border-primary text-primary transition-all flex items-center justify-center',
5236
+ 'ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
5237
+ !isEffectiveDisabled && 'group-hover:border-primary/70',
5238
+ isSelected ? 'bg-background' : 'bg-transparent',
5239
+ class
5240
+ )">
5241
+ <div
5242
+ *ngIf="isSelected"
5243
+ class="h-2.5 w-2.5 rounded-full bg-primary animate-in zoom-in-50 duration-200"
5244
+ ></div>
5245
+ </div>
5246
+
5247
+ <label class="text-sm font-medium leading-none select-none" [class.cursor-pointer]="!isEffectiveDisabled">
5248
+ <ng-content></ng-content>
5249
+ </label>
5250
+ </div>
5251
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
5252
+ }
5253
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RadioItemComponent, decorators: [{
5254
+ type: Component,
5255
+ args: [{
5256
+ selector: 'tolle-radio-item',
5257
+ standalone: true,
5258
+ imports: [CommonModule],
5259
+ template: `
5260
+ <div
5261
+ (click)="!isEffectiveDisabled && select()"
5262
+ [class]="cn(
5263
+ 'flex items-center space-x-2 group py-1',
5264
+ isEffectiveDisabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'
5265
+ )"
5266
+ >
5267
+ <div [class]="cn(
5268
+ 'aspect-square h-4 w-4 rounded-full border border-primary text-primary transition-all flex items-center justify-center',
5269
+ 'ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
5270
+ !isEffectiveDisabled && 'group-hover:border-primary/70',
5271
+ isSelected ? 'bg-background' : 'bg-transparent',
5272
+ class
5273
+ )">
5274
+ <div
5275
+ *ngIf="isSelected"
5276
+ class="h-2.5 w-2.5 rounded-full bg-primary animate-in zoom-in-50 duration-200"
5277
+ ></div>
5278
+ </div>
5279
+
5280
+ <label class="text-sm font-medium leading-none select-none" [class.cursor-pointer]="!isEffectiveDisabled">
5281
+ <ng-content></ng-content>
5282
+ </label>
5283
+ </div>
5284
+ `
5285
+ }]
5286
+ }], ctorParameters: () => [{ type: RadioService }, { type: i0.ChangeDetectorRef }], propDecorators: { value: [{
5287
+ type: Input
5288
+ }], disabled: [{
5289
+ type: Input
5290
+ }], class: [{
5291
+ type: Input
5292
+ }] } });
5293
+
4243
5294
  /*
4244
5295
  * Public API Surface of tolle
4245
5296
  */
@@ -4248,5 +5299,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
4248
5299
  * Generated bundle index. Do not edit.
4249
5300
  */
4250
5301
 
4251
- export { AccordionComponent, AccordionItemComponent, BadgeComponent, ButtonComponent, ButtonGroupComponent, CalendarComponent, CardComponent, CardContentComponent, CardFooterComponent, CardHeaderComponent, CardTitleComponent, CheckboxComponent, DataTableComponent, DatePickerComponent, DateRangePickerComponent, DropdownItemComponent, DropdownLabelComponent, DropdownMenuComponent, DropdownSeparatorComponent, DropdownTriggerDirective, InputComponent, MaskedInputComponent, Modal, ModalComponent, ModalRef, ModalService, ModalStackService, MultiSelectComponent, PaginationComponent, RangeCalendarComponent, SelectComponent, SelectGroupComponent, SelectItemComponent, SelectSeparatorComponent, SkeletonComponent, SwitchComponent, TOLLE_CONFIG, TextareaComponent, ThemeService, ToastContainerComponent, ToastService, TolleCellDirective, TooltipDirective, cn, provideTolleConfig };
4252
- //# sourceMappingURL=tolle_-tolle-ui.mjs.map
5302
+ 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 };
5303
+ //# sourceMappingURL=tolle-ui.mjs.map