@tolle_/tolle-ui 0.0.18-beta → 0.0.21-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 (60) 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/badge.component.mjs +4 -4
  5. package/esm2022/lib/breadcrumb-item.component.mjs +19 -0
  6. package/esm2022/lib/breadcrumb-link.component.mjs +60 -0
  7. package/esm2022/lib/breadcrumb-separator.component.mjs +23 -0
  8. package/esm2022/lib/breadcrumb.component.mjs +28 -0
  9. package/esm2022/lib/button.component.mjs +20 -24
  10. package/esm2022/lib/card.component.mjs +3 -3
  11. package/esm2022/lib/data-table.component.mjs +1 -1
  12. package/esm2022/lib/date-picker.component.mjs +2 -2
  13. package/esm2022/lib/date-range-picker.component.mjs +1 -1
  14. package/esm2022/lib/empty-state.component.mjs +111 -0
  15. package/esm2022/lib/input.component.mjs +125 -32
  16. package/esm2022/lib/masked-input.component.mjs +210 -46
  17. package/esm2022/lib/multi-select.component.mjs +1 -1
  18. package/esm2022/lib/otp-group.component.mjs +15 -0
  19. package/esm2022/lib/otp-slot.component.mjs +74 -0
  20. package/esm2022/lib/otp.component.mjs +127 -0
  21. package/esm2022/lib/popover-content.component.mjs +44 -0
  22. package/esm2022/lib/popover.component.mjs +105 -0
  23. package/esm2022/lib/radio-group.component.mjs +78 -0
  24. package/esm2022/lib/radio-item.component.mjs +112 -0
  25. package/esm2022/lib/radio-service.mjs +23 -0
  26. package/esm2022/lib/select.component.mjs +38 -9
  27. package/esm2022/lib/textarea.component.mjs +130 -26
  28. package/esm2022/lib/theme.service.mjs +227 -56
  29. package/esm2022/public-api.mjs +16 -1
  30. package/esm2022/tolle-ui.mjs +5 -0
  31. package/fesm2022/{tolle_-tolle-ui.mjs → tolle-ui.mjs} +1730 -201
  32. package/fesm2022/tolle-ui.mjs.map +1 -0
  33. package/lib/alert.component.d.ts +25 -0
  34. package/lib/avatar-fallback.component.d.ts +5 -0
  35. package/lib/avatar.component.d.ts +17 -0
  36. package/lib/breadcrumb-item.component.d.ts +5 -0
  37. package/lib/breadcrumb-link.component.d.ts +6 -0
  38. package/lib/breadcrumb-separator.component.d.ts +5 -0
  39. package/lib/breadcrumb.component.d.ts +8 -0
  40. package/lib/button.component.d.ts +1 -4
  41. package/lib/empty-state.component.d.ts +20 -0
  42. package/lib/input.component.d.ts +11 -3
  43. package/lib/masked-input.component.d.ts +14 -1
  44. package/lib/otp-group.component.d.ts +5 -0
  45. package/lib/otp-slot.component.d.ts +13 -0
  46. package/lib/otp.component.d.ts +21 -0
  47. package/lib/popover-content.component.d.ts +8 -0
  48. package/lib/popover.component.d.ts +19 -0
  49. package/lib/radio-group.component.d.ts +23 -0
  50. package/lib/radio-item.component.d.ts +22 -0
  51. package/lib/radio-service.d.ts +11 -0
  52. package/lib/select.component.d.ts +1 -0
  53. package/lib/textarea.component.d.ts +8 -1
  54. package/lib/theme.service.d.ts +37 -3
  55. package/package.json +7 -6
  56. package/preset.js +47 -33
  57. package/public-api.d.ts +15 -0
  58. package/theme.css +208 -163
  59. package/esm2022/tolle_-tolle-ui.mjs +0 -5
  60. 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, ViewChild, Injectable, Optional, HostListener, 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';
@@ -18,56 +18,48 @@ function cn(...inputs) {
18
18
  return twMerge(clsx(inputs));
19
19
  }
20
20
 
21
- const buttonVariants = cva("inline-flex items-center justify-center rounded-md text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background active:scale-[0.98]", {
21
+ const buttonVariants = cva("tolle-button-base inline-flex items-center justify-center rounded-md text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background active:scale-[0.98]", {
22
22
  variants: {
23
23
  variant: {
24
24
  default: "bg-primary text-primary-foreground hover:bg-primary/90",
25
25
  destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
26
- outline: "border border-input hover:bg-accent hover:text-accent-foreground",
26
+ outline: "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
27
27
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
28
28
  ghost: "hover:bg-accent hover:text-accent-foreground",
29
- link: "underline-offset-4 hover:underline text-primary",
29
+ link: "text-primary underline-offset-4 hover:underline",
30
30
  },
31
31
  size: {
32
32
  default: "h-10 px-4 py-2",
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
- busy: { true: "relative !cursor-wait !pointer-events-none" }
41
+ busy: { true: "tolle-button--busy 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
- readonly = false;
59
54
  get computedClass() {
60
55
  return cn(buttonVariants({
61
56
  variant: this.variant,
62
57
  size: this.size,
63
- block: this.block,
64
58
  busy: this.busy
65
- }),
66
- // Adds 'size-icon-sm', 'size-xs', etc. for the CSS selectors to work
67
- 'size-' + this.size, this.class);
59
+ }), this.class);
68
60
  }
69
61
  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: `
62
+ 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" }, host: { classAttribute: "tolle-button-wrapper inline-block align-middle" }, ngImport: i0, template: `
71
63
  <button
72
64
  [class]="computedClass"
73
65
  [disabled]="disabled || busy"
@@ -80,15 +72,19 @@ class ButtonComponent {
80
72
  </svg>
81
73
  </div>
82
74
 
83
- <span class="flex items-center justify-center w-full h-full" [class.invisible]="busy">
75
+ <span class="flex items-center justify-center w-full h-full pointer-events-none" [class.invisible]="busy">
84
76
  <ng-content></ng-content>
85
77
  </span>
86
78
  </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"] }] });
79
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
88
80
  }
89
81
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ButtonComponent, decorators: [{
90
82
  type: Component,
91
- args: [{ selector: 'tolle-button', standalone: true, imports: [CommonModule], template: `
83
+ args: [{
84
+ selector: 'tolle-button',
85
+ standalone: true,
86
+ imports: [CommonModule],
87
+ template: `
92
88
  <button
93
89
  [class]="computedClass"
94
90
  [disabled]="disabled || busy"
@@ -101,29 +97,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
101
97
  </svg>
102
98
  </div>
103
99
 
104
- <span class="flex items-center justify-center w-full h-full" [class.invisible]="busy">
100
+ <span class="flex items-center justify-center w-full h-full pointer-events-none" [class.invisible]="busy">
105
101
  <ng-content></ng-content>
106
102
  </span>
107
103
  </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"] }]
104
+ `,
105
+ host: {
106
+ 'class': 'tolle-button-wrapper inline-block align-middle'
107
+ }
108
+ }]
109
109
  }], propDecorators: { class: [{
110
110
  type: Input
111
111
  }], variant: [{
112
112
  type: Input
113
113
  }], size: [{
114
114
  type: Input
115
- }], block: [{
116
- type: Input
117
115
  }], disabled: [{
118
116
  type: Input
119
117
  }], busy: [{
120
118
  type: Input
121
- }], readonly: [{
122
- type: Input
123
119
  }] } });
124
120
 
125
121
  class InputComponent {
126
122
  cdr;
123
+ inputElement;
127
124
  id = `input-${Math.random().toString(36).substr(2, 9)}`;
128
125
  label = '';
129
126
  hint = '';
@@ -137,12 +134,20 @@ class InputComponent {
137
134
  disabled = false;
138
135
  readonly = false;
139
136
  error = false;
137
+ // Focus behavior
138
+ hideHintOnFocus = true;
140
139
  value = '';
141
140
  onChange = () => { };
142
141
  onTouched = () => { };
142
+ isFocused = false;
143
143
  constructor(cdr) {
144
144
  this.cdr = cdr;
145
145
  }
146
+ ngAfterViewInit() {
147
+ if (this.inputElement?.nativeElement.hasAttribute('autofocus')) {
148
+ setTimeout(() => this.inputElement.nativeElement.focus());
149
+ }
150
+ }
146
151
  writeValue(value) {
147
152
  this.value = value;
148
153
  this.cdr.markForCheck();
@@ -160,66 +165,132 @@ class InputComponent {
160
165
  this.value = val;
161
166
  this.onChange(val);
162
167
  }
168
+ onFocus() {
169
+ this.isFocused = true;
170
+ }
171
+ onBlur() {
172
+ this.isFocused = false;
173
+ this.onTouched();
174
+ }
175
+ focusInput() {
176
+ if (!this.disabled && this.inputElement) {
177
+ this.inputElement.nativeElement.focus();
178
+ }
179
+ }
163
180
  cn = cn;
181
+ get computedLabelClass() {
182
+ return cn("text-sm font-medium text-foreground leading-none transition-opacity duration-200", this.disabled && "opacity-50");
183
+ }
164
184
  get computedContainerClass() {
165
- return cn("group relative flex items-center w-full rounded-md border transition-all shadow-sm", "bg-background ring-offset-background",
185
+ return cn(
186
+ // Base styles
187
+ "group relative flex items-center w-full rounded-md border transition-all duration-200", "bg-background",
188
+ // Border and shadow
189
+ "border-input shadow-sm",
166
190
  // Sizing
167
- 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",
168
- // Interaction States (Focus ring disabled for Readonly/Disabled)
169
- !(this.readonly || this.disabled) && "focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-1",
170
- // Colors & Borders
171
- this.error ? "border-destructive focus-within:ring-destructive" : "border-input",
172
- // 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);
191
+ this.size === 'xs' && "h-8 px-2 gap-1.5 text-xs", this.size === 'sm' && "h-9 px-3 gap-2 text-sm", this.size === 'default' && "h-10 px-3 gap-2 text-sm", this.size === 'lg' && "h-11 px-4 gap-3 text-base",
192
+ // Focus state - SIMPLE AND ELEGANT LIKE ZARDUI
193
+ // The magic happens in CSS: border darkens automatically on focus
194
+ !(this.readonly || this.disabled) && [
195
+ "focus-within:border-primary/80",
196
+ "focus-within:ring-4",
197
+ "focus-within:ring-ring/30",
198
+ "focus-within:ring-offset-0",
199
+ "focus-within:shadow-none",
200
+ ],
201
+ // Error state
202
+ this.error && [
203
+ "border-destructive",
204
+ !(this.readonly || this.disabled) && [
205
+ "focus-within:border-destructive/80",
206
+ "focus-within:ring-destructive/30"
207
+ ]
208
+ ],
209
+ // Disabled state
210
+ this.disabled && [
211
+ "cursor-not-allowed opacity-50",
212
+ "border-opacity-50"
213
+ ],
214
+ // Readonly state
215
+ this.readonly && [
216
+ "cursor-default",
217
+ "border-dashed",
218
+ !this.disabled && "focus-within:ring-0 focus-within:border-opacity-100"
219
+ ], this.containerClass);
174
220
  }
175
221
  get computedInputClass() {
176
- 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);
222
+ return cn(
223
+ // Base styles
224
+ "flex-1 bg-transparent border-none p-0", "placeholder:text-muted-foreground",
225
+ // Remove all default focus styles
226
+ "focus:outline-none focus:ring-0 focus:shadow-none",
227
+ // Text sizing
228
+ this.size === 'xs' && "text-xs", this.size === 'sm' && "text-sm", this.size === 'default' && "text-sm", this.size === 'lg' && "text-base",
229
+ // Cursor states
230
+ this.disabled && "cursor-not-allowed", this.readonly && "cursor-default",
231
+ // Text color
232
+ "text-foreground",
233
+ // Selection color
234
+ "selection:bg-primary/20 selection:text-foreground", this.class);
177
235
  }
178
236
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: InputComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
179
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: InputComponent, isStandalone: true, selector: "tolle-input", inputs: { id: "id", label: "label", hint: "hint", errorMessage: "errorMessage", type: "type", placeholder: "placeholder", size: "size", containerClass: "containerClass", class: "class", disabled: "disabled", readonly: "readonly", error: "error" }, providers: [
237
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: InputComponent, isStandalone: true, selector: "tolle-input", inputs: { id: "id", label: "label", hint: "hint", errorMessage: "errorMessage", type: "type", placeholder: "placeholder", size: "size", containerClass: "containerClass", class: "class", disabled: "disabled", readonly: "readonly", error: "error", hideHintOnFocus: "hideHintOnFocus" }, providers: [
180
238
  {
181
239
  provide: NG_VALUE_ACCESSOR,
182
240
  useExisting: forwardRef(() => InputComponent),
183
241
  multi: true
184
242
  }
185
- ], ngImport: i0, template: `
243
+ ], viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["inputElement"], descendants: true }], ngImport: i0, template: `
186
244
  <div class="flex flex-col gap-1.5 w-full">
187
245
  <label
188
246
  *ngIf="label"
189
247
  [for]="id"
190
- [class.opacity-50]="disabled"
191
- class="text-sm font-medium text-foreground leading-none transition-opacity"
192
- >
248
+ [class]="computedLabelClass">
193
249
  {{ label }}
194
250
  </label>
195
251
 
196
- <div [class]="computedContainerClass">
197
- <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors">
252
+ <div
253
+ [class]="computedContainerClass"
254
+ (click)="focusInput()"
255
+ >
256
+ <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors duration-200">
198
257
  <ng-content select="[prefix]"></ng-content>
199
258
  </div>
200
259
 
201
260
  <input
261
+ #inputElement
202
262
  [id]="id"
203
263
  [type]="type"
204
264
  [placeholder]="placeholder"
205
265
  [disabled]="disabled"
206
266
  [readOnly]="readonly"
207
267
  [(ngModel)]="value"
208
- (blur)="onTouched()"
268
+ (blur)="onBlur()"
269
+ (focus)="onFocus()"
209
270
  (input)="onInputChange($event)"
210
271
  [class]="computedInputClass"
272
+ [attr.aria-invalid]="error"
273
+ [attr.aria-describedby]="error && errorMessage ? id + '-error' : null"
211
274
  />
212
275
 
213
- <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors">
276
+ <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors duration-200">
214
277
  <ng-content select="[suffix]"></ng-content>
215
278
  </div>
216
279
  </div>
217
280
 
218
281
  <ng-container *ngIf="!disabled">
219
- <p *ngIf="hint && !error" class="text-xs text-muted-foreground px-1">
282
+ <p
283
+ *ngIf="hint && !error"
284
+ class="text-xs text-muted-foreground px-1 transition-opacity duration-200"
285
+ [class.opacity-0]="isFocused && hideHintOnFocus"
286
+ >
220
287
  {{ hint }}
221
288
  </p>
222
- <p *ngIf="error && errorMessage" class="text-xs text-destructive px-1">
289
+ <p
290
+ *ngIf="error && errorMessage"
291
+ [id]="id + '-error'"
292
+ class="text-xs text-destructive px-1"
293
+ >
223
294
  {{ errorMessage }}
224
295
  </p>
225
296
  </ng-container>
@@ -244,46 +315,62 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
244
315
  <label
245
316
  *ngIf="label"
246
317
  [for]="id"
247
- [class.opacity-50]="disabled"
248
- class="text-sm font-medium text-foreground leading-none transition-opacity"
249
- >
318
+ [class]="computedLabelClass">
250
319
  {{ label }}
251
320
  </label>
252
321
 
253
- <div [class]="computedContainerClass">
254
- <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors">
322
+ <div
323
+ [class]="computedContainerClass"
324
+ (click)="focusInput()"
325
+ >
326
+ <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors duration-200">
255
327
  <ng-content select="[prefix]"></ng-content>
256
328
  </div>
257
329
 
258
330
  <input
331
+ #inputElement
259
332
  [id]="id"
260
333
  [type]="type"
261
334
  [placeholder]="placeholder"
262
335
  [disabled]="disabled"
263
336
  [readOnly]="readonly"
264
337
  [(ngModel)]="value"
265
- (blur)="onTouched()"
338
+ (blur)="onBlur()"
339
+ (focus)="onFocus()"
266
340
  (input)="onInputChange($event)"
267
341
  [class]="computedInputClass"
342
+ [attr.aria-invalid]="error"
343
+ [attr.aria-describedby]="error && errorMessage ? id + '-error' : null"
268
344
  />
269
345
 
270
- <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors">
346
+ <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors duration-200">
271
347
  <ng-content select="[suffix]"></ng-content>
272
348
  </div>
273
349
  </div>
274
350
 
275
351
  <ng-container *ngIf="!disabled">
276
- <p *ngIf="hint && !error" class="text-xs text-muted-foreground px-1">
352
+ <p
353
+ *ngIf="hint && !error"
354
+ class="text-xs text-muted-foreground px-1 transition-opacity duration-200"
355
+ [class.opacity-0]="isFocused && hideHintOnFocus"
356
+ >
277
357
  {{ hint }}
278
358
  </p>
279
- <p *ngIf="error && errorMessage" class="text-xs text-destructive px-1">
359
+ <p
360
+ *ngIf="error && errorMessage"
361
+ [id]="id + '-error'"
362
+ class="text-xs text-destructive px-1"
363
+ >
280
364
  {{ errorMessage }}
281
365
  </p>
282
366
  </ng-container>
283
367
  </div>
284
368
  `,
285
369
  }]
286
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { id: [{
370
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { inputElement: [{
371
+ type: ViewChild,
372
+ args: ['inputElement']
373
+ }], id: [{
287
374
  type: Input
288
375
  }], label: [{
289
376
  type: Input
@@ -307,6 +394,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
307
394
  type: Input
308
395
  }], error: [{
309
396
  type: Input
397
+ }], hideHintOnFocus: [{
398
+ type: Input
310
399
  }] } });
311
400
 
312
401
  class CardComponent {
@@ -314,7 +403,7 @@ class CardComponent {
314
403
  cn = cn;
315
404
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
316
405
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: CardComponent, isStandalone: true, selector: "tolle-card", inputs: { class: "class" }, ngImport: i0, template: `
317
- <div [class]="cn('rounded-xl border border-border bg-card text-card-foreground shadow', class)">
406
+ <div [class]="cn('rounded-md border border-border bg-card text-card-foreground shadow', class)">
318
407
  <ng-content></ng-content>
319
408
  </div>
320
409
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
@@ -326,7 +415,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
326
415
  standalone: true,
327
416
  imports: [CommonModule],
328
417
  template: `
329
- <div [class]="cn('rounded-xl border border-border bg-card text-card-foreground shadow', class)">
418
+ <div [class]="cn('rounded-md border border-border bg-card text-card-foreground shadow', class)">
330
419
  <ng-content></ng-content>
331
420
  </div>
332
421
  `,
@@ -505,6 +594,7 @@ class SelectComponent {
505
594
  readonly = false;
506
595
  trigger;
507
596
  popover;
597
+ container;
508
598
  items;
509
599
  sub = new Subscription();
510
600
  searchQuery = '';
@@ -528,15 +618,38 @@ class SelectComponent {
528
618
  this.close();
529
619
  }));
530
620
  }
531
- // UPDATED: Centralized sizing logic for the trigger
621
+ // SIMPLIFIED: Zardui-inspired trigger styling
532
622
  get computedTriggerClass() {
533
- return cn('flex w-full items-center justify-between rounded-md border transition-all shadow-sm', 'bg-background ring-offset-background placeholder:text-muted-foreground',
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',
534
628
  // Sizing
535
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',
536
- // Interaction States (Focus ring disabled for Readonly/Disabled)
537
- !(this.readonly || this.disabled) && 'focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1',
538
- // Colors & Borders (Matching your Hex-based theme logic)
539
- this.disabled && 'cursor-not-allowed opacity-50 bg-muted/30 border-input', this.readonly && 'cursor-default bg-muted/10 border-dashed border-input focus:ring-0', !this.disabled && !this.readonly && 'border-input hover:border-accent cursor-pointer', this.class);
630
+ // Focus state - SIMPLE LIKE ZARDUI
631
+ !(this.readonly || this.disabled) && [
632
+ 'focus:outline-none',
633
+ 'focus:ring-4',
634
+ 'focus:ring-ring/30',
635
+ 'focus:ring-offset-0',
636
+ 'focus:shadow-none',
637
+ // Border darkens on focus automatically
638
+ 'focus:border-primary/80'
639
+ ],
640
+ // Hover state
641
+ !(this.readonly || this.disabled) && 'hover:border-accent',
642
+ // Disabled state
643
+ this.disabled && [
644
+ 'cursor-not-allowed opacity-50',
645
+ 'border-opacity-50'
646
+ ],
647
+ // Readonly state
648
+ this.readonly && [
649
+ 'cursor-default',
650
+ 'border-dashed',
651
+ !this.disabled && 'focus:ring-0 focus:border-opacity-100'
652
+ ], this.class);
540
653
  }
541
654
  // UPDATED: Dynamic icon sizing relative to the trigger size
542
655
  get iconClass() {
@@ -562,6 +675,8 @@ class SelectComponent {
562
675
  }
563
676
  open() {
564
677
  this.isOpen = true;
678
+ // Trigger focus on the button for focus styling
679
+ this.trigger.nativeElement.focus();
565
680
  // Tick to ensure DOM is rendered before positioning
566
681
  setTimeout(() => this.updatePosition());
567
682
  }
@@ -630,7 +745,7 @@ class SelectComponent {
630
745
  useExisting: forwardRef(() => SelectComponent),
631
746
  multi: true
632
747
  }
633
- ], 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: `
748
+ ], 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: `
634
749
  <div [class]="cn('w-full', 'size-' + size)" #container>
635
750
  <button
636
751
  type="button"
@@ -670,7 +785,7 @@ class SelectComponent {
670
785
  </div>
671
786
  </div>
672
787
  </div>
673
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { 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"] }] });
788
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { 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"] }] });
674
789
  }
675
790
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SelectComponent, decorators: [{
676
791
  type: Component,
@@ -746,6 +861,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
746
861
  }], popover: [{
747
862
  type: ViewChild,
748
863
  args: ['popover']
864
+ }], container: [{
865
+ type: ViewChild,
866
+ args: ['container']
749
867
  }], items: [{
750
868
  type: ContentChildren,
751
869
  args: [SelectItemComponent, { descendants: true }]
@@ -938,7 +1056,7 @@ class BadgeComponent {
938
1056
  get computedClass() {
939
1057
  return cn(
940
1058
  // Base styles - Pills are always rounded-full
941
- 'inline-flex items-center justify-center rounded-full border px-2 py-0.5 font-medium transition-colors gap-1',
1059
+ 'inline-flex items-center justify-center rounded-md border px-2 py-0.5 font-medium transition-colors gap-1',
942
1060
  // Variants (Google Dark Mode theme)
943
1061
  this.variant === 'default' && 'border-transparent bg-primary text-primary-foreground', this.variant === 'secondary' && 'border-transparent bg-secondary text-secondary-foreground', this.variant === 'outline' && 'text-foreground border-border bg-transparent', this.variant === 'destructive' && 'border-transparent bg-destructive text-destructive-foreground',
944
1062
  // Sizing
@@ -956,7 +1074,7 @@ class BadgeComponent {
956
1074
  <button
957
1075
  *ngIf="removable"
958
1076
  (click)="onRemove.emit($event)"
959
- class="ml-1 -mr-1 rounded-full p-0.5 hover:bg-foreground/20 transition-colors outline-none focus:ring-1 focus:ring-ring"
1077
+ class="ml-1 -mr-1 rounded-md p-0.5 hover:bg-foreground/20 transition-colors outline-none focus:ring-1 focus:ring-ring"
960
1078
  >
961
1079
  <i class="ri-close-line text-[1.1em]"></i>
962
1080
  </button>
@@ -980,7 +1098,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
980
1098
  <button
981
1099
  *ngIf="removable"
982
1100
  (click)="onRemove.emit($event)"
983
- class="ml-1 -mr-1 rounded-full p-0.5 hover:bg-foreground/20 transition-colors outline-none focus:ring-1 focus:ring-ring"
1101
+ class="ml-1 -mr-1 rounded-md p-0.5 hover:bg-foreground/20 transition-colors outline-none focus:ring-1 focus:ring-ring"
984
1102
  >
985
1103
  <i class="ri-close-line text-[1.1em]"></i>
986
1104
  </button>
@@ -1365,93 +1483,212 @@ class ThemeService {
1365
1483
  else {
1366
1484
  this.disableDarkMode();
1367
1485
  }
1368
- // 2. Apply Brand Config - This will generate full palette
1369
- if (this.config) {
1370
- this.applyBrandConfig(this.config);
1486
+ const savedPrimary = localStorage.getItem('tolle-primary-color');
1487
+ if (savedPrimary) {
1488
+ this.setPrimaryColor(savedPrimary, false);
1489
+ }
1490
+ else if (this.config?.primaryColor) {
1491
+ this.setPrimaryColor(this.config.primaryColor, false);
1492
+ }
1493
+ // Set radius from config
1494
+ if (this.config?.radius) {
1495
+ this.setRadius(this.config.radius, false);
1371
1496
  }
1372
1497
  }
1373
1498
  /**
1374
- * Applies the brand identity variables with full shade palette
1499
+ * Sets the border radius for all components
1375
1500
  */
1376
- applyBrandConfig(config) {
1501
+ setRadius(radius, persist = true) {
1377
1502
  if (!isPlatformBrowser(this.platformId))
1378
1503
  return;
1379
1504
  const root = this.document.documentElement;
1380
- // Set primary color if provided
1381
- if (config.primaryColor) {
1382
- this.renderer.setStyle(root, '--primary', config.primaryColor);
1383
- this.generatePrimaryShades(config.primaryColor);
1505
+ // Set the CSS variable
1506
+ this.renderer.setStyle(root, '--radius', radius);
1507
+ // Also update the dynamic styles to include radius calculations
1508
+ this.updateRadiusInDynamicStyles(radius);
1509
+ // Persist if needed
1510
+ if (persist) {
1511
+ localStorage.setItem('tolle-radius', radius);
1384
1512
  }
1385
- // Set border radius if provided
1386
- if (config.radius) {
1387
- this.renderer.setStyle(root, '--radius', config.radius);
1513
+ }
1514
+ /**
1515
+ * Updates the radius calculations in dynamic styles
1516
+ */
1517
+ updateRadiusInDynamicStyles(radius) {
1518
+ const existingStyle = this.document.getElementById(this.styleId);
1519
+ if (existingStyle) {
1520
+ let css = existingStyle.textContent || '';
1521
+ // Update or add radius calculations
1522
+ if (css.includes('--radius:')) {
1523
+ // Replace existing radius declarations
1524
+ css = css.replace(/--radius:[^;]+;/g, `--radius: ${radius};`);
1525
+ }
1526
+ else {
1527
+ // Add radius to the beginning of :root
1528
+ css = css.replace(/:root\s*{/, `:root {\n --radius: ${radius};`);
1529
+ }
1530
+ // Update the calculated radius values in the CSS
1531
+ const radiusCalcRegex = /calc\(var\(--radius[^)]+\)/g;
1532
+ css = css.replace(radiusCalcRegex, (match) => {
1533
+ if (match.includes('- 2px')) {
1534
+ return `calc(${radius} - 2px)`;
1535
+ }
1536
+ else if (match.includes('- 4px')) {
1537
+ return `calc(${radius} - 4px)`;
1538
+ }
1539
+ return match;
1540
+ });
1541
+ existingStyle.textContent = css;
1388
1542
  }
1389
1543
  }
1390
1544
  /**
1391
1545
  * Generates full primary color palette (50-900) based on base color
1392
- * Uses color-mix() for consistency with your existing approach
1393
1546
  */
1394
1547
  generatePrimaryShades(baseColor) {
1548
+ // Convert hex to RGB
1549
+ const rgb = this.hexToRgb(baseColor);
1550
+ const rgbString = rgb ? `${rgb.r} ${rgb.g} ${rgb.b}` : '37 99 235';
1551
+ // Create lighter ring colors in RGB
1552
+ const ringLight = this.lightenColor(baseColor, 40);
1553
+ const ringLightRgb = this.hexToRgb(ringLight);
1554
+ const ringLightRgbString = ringLightRgb ? `${ringLightRgb.r} ${ringLightRgb.g} ${ringLightRgb.b}` : '96 165 250';
1555
+ const ringDark = this.lightenColor(baseColor, 20);
1556
+ const ringDarkRgb = this.hexToRgb(ringDark);
1557
+ const ringDarkRgbString = ringDarkRgb ? `${ringDarkRgb.r} ${ringDarkRgb.g} ${ringDarkRgb.b}` : '147 197 253';
1558
+ // Get current radius or use default
1559
+ const root = this.document.documentElement;
1560
+ const currentRadius = getComputedStyle(root).getPropertyValue('--radius').trim() || '0.5rem';
1395
1561
  const css = `
1562
+ /* Override primary colors - this needs to come AFTER your main CSS */
1396
1563
  :root {
1397
- /* Primary Shades */
1398
- --primary-50: color-mix(in srgb, ${baseColor}, white 90%);
1399
- --primary-100: color-mix(in srgb, ${baseColor}, white 80%);
1400
- --primary-200: color-mix(in srgb, ${baseColor}, white 60%);
1401
- --primary-300: color-mix(in srgb, ${baseColor}, white 40%);
1402
- --primary-400: color-mix(in srgb, ${baseColor}, white 20%);
1403
- --primary-500: ${baseColor};
1404
- --primary-600: color-mix(in srgb, ${baseColor}, black 20%);
1405
- --primary-700: color-mix(in srgb, ${baseColor}, black 40%);
1406
- --primary-800: color-mix(in srgb, ${baseColor}, black 60%);
1407
- --primary-900: color-mix(in srgb, ${baseColor}, black 80%);
1408
-
1409
- /* Your existing derived colors - updated to use new shades */
1410
- --primary-foreground: white;
1411
- --secondary: color-mix(in srgb, var(--primary-200), transparent 40%);
1412
- --secondary-foreground: var(--primary-900);
1413
- --muted: color-mix(in srgb, var(--primary-50), #f3f4f6 50%);
1414
- --muted-foreground: color-mix(in srgb, var(--primary-400), #4b5563 60%);
1415
- --accent: color-mix(in srgb, var(--primary-100), transparent 70%);
1416
- --accent-foreground: var(--primary-700);
1417
- --ring: color-mix(in srgb, var(--primary-300), transparent 50%);
1564
+ /* Primary in RGB format for Tailwind opacity support */
1565
+ --primary: ${rgbString};
1566
+ --primary-foreground: ${this.getContrastColorRgb(baseColor)};
1567
+
1568
+ /* Radius */
1569
+ --radius: ${currentRadius};
1570
+
1571
+ /* Primary shades for light mode */
1572
+ --primary-50: ${this.hexToRgbString(this.lightenColor(baseColor, 90))};
1573
+ --primary-100: ${this.hexToRgbString(this.lightenColor(baseColor, 80))};
1574
+ --primary-200: ${this.hexToRgbString(this.lightenColor(baseColor, 60))};
1575
+ --primary-300: ${this.hexToRgbString(this.lightenColor(baseColor, 40))};
1576
+ --primary-400: ${this.hexToRgbString(this.lightenColor(baseColor, 20))};
1577
+ --primary-500: ${rgbString};
1578
+ --primary-600: ${this.hexToRgbString(this.darkenColor(baseColor, 20))};
1579
+ --primary-700: ${this.hexToRgbString(this.darkenColor(baseColor, 40))};
1580
+ --primary-800: ${this.hexToRgbString(this.darkenColor(baseColor, 60))};
1581
+ --primary-900: ${this.hexToRgbString(this.darkenColor(baseColor, 80))};
1582
+
1583
+ /* Update ring color to be lighter */
1584
+ --ring: ${ringLightRgbString};
1418
1585
  }
1419
1586
 
1420
1587
  .dark {
1421
- /* Dark mode variants */
1422
- --primary-50: color-mix(in srgb, ${baseColor}, black 85%);
1423
- --primary-100: color-mix(in srgb, ${baseColor}, black 75%);
1424
- --primary-200: color-mix(in srgb, ${baseColor}, black 65%);
1425
- --primary-300: color-mix(in srgb, ${baseColor}, black 55%);
1426
- --primary-400: color-mix(in srgb, ${baseColor}, black 45%);
1427
- --primary-500: ${baseColor};
1428
- --primary-600: color-mix(in srgb, ${baseColor}, white 20%);
1429
- --primary-700: color-mix(in srgb, ${baseColor}, white 35%);
1430
- --primary-800: color-mix(in srgb, ${baseColor}, white 50%);
1431
- --primary-900: color-mix(in srgb, ${baseColor}, white 65%);
1432
-
1433
- /* Dark mode derived colors */
1434
- --primary-foreground: color-mix(in srgb, ${baseColor}, white 90%);
1435
- --secondary: color-mix(in srgb, var(--primary-900), transparent 70%);
1436
- --secondary-foreground: var(--primary-100);
1437
- --muted: color-mix(in srgb, var(--primary-950), #1f2937 50%);
1438
- --muted-foreground: color-mix(in srgb, var(--primary-300), #9ca3af 40%);
1439
- --accent: color-mix(in srgb, var(--primary-800), transparent 80%);
1440
- --accent-foreground: var(--primary-200);
1441
- --ring: color-mix(in srgb, var(--primary-600), transparent 60%);
1588
+ /* For dark mode, we keep the primary color but adjust shades */
1589
+ --primary: ${rgbString};
1590
+ --primary-foreground: ${this.getContrastColorRgb(baseColor)};
1591
+
1592
+ /* Dark mode shades */
1593
+ --primary-50: ${this.hexToRgbString(this.darkenColor(baseColor, 85))};
1594
+ --primary-100: ${this.hexToRgbString(this.darkenColor(baseColor, 75))};
1595
+ --primary-200: ${this.hexToRgbString(this.darkenColor(baseColor, 65))};
1596
+ --primary-300: ${this.hexToRgbString(this.darkenColor(baseColor, 55))};
1597
+ --primary-400: ${this.hexToRgbString(this.darkenColor(baseColor, 45))};
1598
+ --primary-500: ${rgbString};
1599
+ --primary-600: ${this.hexToRgbString(this.lightenColor(baseColor, 20))};
1600
+ --primary-700: ${this.hexToRgbString(this.lightenColor(baseColor, 35))};
1601
+ --primary-800: ${this.hexToRgbString(this.lightenColor(baseColor, 50))};
1602
+ --primary-900: ${this.hexToRgbString(this.lightenColor(baseColor, 65))};
1603
+
1604
+ /* Update ring color for dark mode - lighter variant */
1605
+ --ring: ${ringDarkRgbString};
1442
1606
  }
1443
1607
  `;
1444
1608
  this.injectDynamicStyles(css);
1445
1609
  }
1610
+ /**
1611
+ * Convert hex color to RGB object
1612
+ */
1613
+ hexToRgb(hex) {
1614
+ // Remove # if present
1615
+ const cleanedHex = hex.replace('#', '');
1616
+ let r = 0, g = 0, b = 0;
1617
+ if (cleanedHex.length === 3) {
1618
+ r = parseInt(cleanedHex[0] + cleanedHex[0], 16);
1619
+ g = parseInt(cleanedHex[1] + cleanedHex[1], 16);
1620
+ b = parseInt(cleanedHex[2] + cleanedHex[2], 16);
1621
+ return { r, g, b };
1622
+ }
1623
+ if (cleanedHex.length === 6) {
1624
+ r = parseInt(cleanedHex.substring(0, 2), 16);
1625
+ g = parseInt(cleanedHex.substring(2, 4), 16);
1626
+ b = parseInt(cleanedHex.substring(4, 6), 16);
1627
+ return { r, g, b };
1628
+ }
1629
+ return null;
1630
+ }
1631
+ /**
1632
+ * Convert hex to RGB string format for CSS (space-separated)
1633
+ */
1634
+ hexToRgbString(hexColor) {
1635
+ const rgb = this.hexToRgb(hexColor);
1636
+ return rgb ? `${rgb.r} ${rgb.g} ${rgb.b}` : '37 99 235';
1637
+ }
1638
+ /**
1639
+ * Get contrast color in RGB format
1640
+ */
1641
+ getContrastColorRgb(hexColor) {
1642
+ const contrast = this.getContrastColor(hexColor);
1643
+ const rgb = this.hexToRgb(contrast);
1644
+ return rgb ? `${rgb.r} ${rgb.g} ${rgb.b}` : '255 255 255';
1645
+ }
1646
+ /**
1647
+ * Lighten a hex color by a percentage
1648
+ */
1649
+ lightenColor(color, percent) {
1650
+ const rgb = this.hexToRgb(color);
1651
+ if (!rgb)
1652
+ return color;
1653
+ // Lighten by percentage
1654
+ const r = Math.min(255, Math.floor(rgb.r + (255 - rgb.r) * (percent / 100)));
1655
+ const g = Math.min(255, Math.floor(rgb.g + (255 - rgb.g) * (percent / 100)));
1656
+ const b = Math.min(255, Math.floor(rgb.b + (255 - rgb.b) * (percent / 100)));
1657
+ // Convert back to hex
1658
+ return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
1659
+ }
1660
+ /**
1661
+ * Darken a hex color by a percentage
1662
+ */
1663
+ darkenColor(color, percent) {
1664
+ const rgb = this.hexToRgb(color);
1665
+ if (!rgb)
1666
+ return color;
1667
+ const factor = 1 - (percent / 100);
1668
+ const r = Math.max(0, Math.floor(rgb.r * factor));
1669
+ const g = Math.max(0, Math.floor(rgb.g * factor));
1670
+ const b = Math.max(0, Math.floor(rgb.b * factor));
1671
+ return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
1672
+ }
1673
+ /**
1674
+ * Calculate contrast color (black or white) based on background color
1675
+ */
1676
+ getContrastColor(hexColor) {
1677
+ const rgb = this.hexToRgb(hexColor);
1678
+ if (!rgb)
1679
+ return '#ffffff';
1680
+ // Calculate relative luminance
1681
+ const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255;
1682
+ // Return black for light colors, white for dark colors
1683
+ return luminance > 0.5 ? '#000000' : '#ffffff';
1684
+ }
1446
1685
  injectDynamicStyles(css) {
1447
1686
  if (!isPlatformBrowser(this.platformId))
1448
1687
  return;
1449
- // Remove existing dynamic styles
1450
1688
  const existingStyle = this.document.getElementById(this.styleId);
1451
1689
  if (existingStyle) {
1452
1690
  existingStyle.remove();
1453
1691
  }
1454
- // Create and inject new styles
1455
1692
  const styleElement = this.document.createElement('style');
1456
1693
  styleElement.id = this.styleId;
1457
1694
  styleElement.textContent = css;
@@ -1471,9 +1708,61 @@ class ThemeService {
1471
1708
  localStorage.setItem('tolle-theme', 'light');
1472
1709
  this.isDarkSubject.next(false);
1473
1710
  }
1711
+ setPrimaryColor(color, persist = true) {
1712
+ if (!isPlatformBrowser(this.platformId))
1713
+ return;
1714
+ this.generatePrimaryShades(color);
1715
+ // Also set inline for immediate update
1716
+ const rgb = this.hexToRgb(color);
1717
+ if (rgb) {
1718
+ this.renderer.setStyle(this.document.documentElement, '--primary', `${rgb.r} ${rgb.g} ${rgb.b}`);
1719
+ }
1720
+ if (persist) {
1721
+ localStorage.setItem('tolle-primary-color', color);
1722
+ }
1723
+ }
1474
1724
  get currentTheme() {
1475
1725
  return this.isDarkSubject.value ? 'dark' : 'light';
1476
1726
  }
1727
+ get primaryColor() {
1728
+ if (!isPlatformBrowser(this.platformId))
1729
+ return null;
1730
+ const root = this.document.documentElement;
1731
+ const cssValue = getComputedStyle(root).getPropertyValue('--primary').trim();
1732
+ if (cssValue && cssValue !== '') {
1733
+ // Convert RGB string back to hex for external use
1734
+ const rgbParts = cssValue.split(' ').map(Number);
1735
+ if (rgbParts.length === 3) {
1736
+ return `#${rgbParts[0].toString(16).padStart(2, '0')}${rgbParts[1].toString(16).padStart(2, '0')}${rgbParts[2].toString(16).padStart(2, '0')}`;
1737
+ }
1738
+ }
1739
+ return localStorage.getItem('tolle-primary-color');
1740
+ }
1741
+ get radius() {
1742
+ if (!isPlatformBrowser(this.platformId))
1743
+ return null;
1744
+ const root = this.document.documentElement;
1745
+ const cssValue = getComputedStyle(root).getPropertyValue('--radius').trim();
1746
+ if (cssValue && cssValue !== '') {
1747
+ return cssValue;
1748
+ }
1749
+ return localStorage.getItem('tolle-radius') || '0.5rem';
1750
+ }
1751
+ /**
1752
+ * Applies the brand identity variables with full shade palette
1753
+ */
1754
+ applyBrandConfig(config) {
1755
+ if (!isPlatformBrowser(this.platformId))
1756
+ return;
1757
+ // Set primary color if provided
1758
+ if (config.primaryColor) {
1759
+ this.setPrimaryColor(config.primaryColor, false);
1760
+ }
1761
+ // Set border radius if provided
1762
+ if (config.radius) {
1763
+ this.setRadius(config.radius, false);
1764
+ }
1765
+ }
1477
1766
  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
1767
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ThemeService, providedIn: 'root' });
1479
1768
  }
@@ -1655,7 +1944,7 @@ class MultiSelectComponent {
1655
1944
  </div>
1656
1945
  </div>
1657
1946
  </div>
1658
- `, 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: BadgeComponent, selector: "tolle-badge", inputs: ["variant", "size", "removable", "class"], outputs: ["onRemove"] }, { kind: "component", type: InputComponent, selector: "tolle-input", inputs: ["id", "label", "hint", "errorMessage", "type", "placeholder", "size", "containerClass", "class", "disabled", "readonly", "error"] }] });
1947
+ `, 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: BadgeComponent, selector: "tolle-badge", inputs: ["variant", "size", "removable", "class"], outputs: ["onRemove"] }, { kind: "component", type: InputComponent, selector: "tolle-input", inputs: ["id", "label", "hint", "errorMessage", "type", "placeholder", "size", "containerClass", "class", "disabled", "readonly", "error", "hideHintOnFocus"] }] });
1659
1948
  }
1660
1949
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MultiSelectComponent, decorators: [{
1661
1950
  type: Component,
@@ -2038,18 +2327,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
2038
2327
  class MaskedInputComponent {
2039
2328
  el;
2040
2329
  cdr;
2330
+ id = `masked-input-${Math.random().toString(36).substr(2, 9)}`;
2331
+ label = '';
2332
+ hint = '';
2333
+ errorMessage = '';
2041
2334
  mask = '';
2042
2335
  placeholder = '';
2043
2336
  type = 'text';
2044
2337
  disabled = false;
2338
+ readonly = false;
2045
2339
  class = '';
2340
+ containerClass = '';
2046
2341
  error = false;
2047
2342
  size = 'default';
2048
2343
  returnRaw = false;
2344
+ hideHintOnFocus = true;
2049
2345
  inputEl;
2050
2346
  hasPrefix = false;
2051
2347
  hasSuffix = false;
2052
2348
  displayValue = '';
2349
+ isFocused = false;
2053
2350
  tokens = {
2054
2351
  '0': /\d/, '9': /\d/, 'a': /[a-z]/i, 'A': /[a-z]/i, '*': /[a-z0-9]/i
2055
2352
  };
@@ -2059,7 +2356,6 @@ class MaskedInputComponent {
2059
2356
  this.el = el;
2060
2357
  this.cdr = cdr;
2061
2358
  }
2062
- // FIXED DETECTION: Check the actual DOM nodes projected into the component
2063
2359
  ngAfterContentChecked() {
2064
2360
  const prefix = this.el.nativeElement.querySelector('[prefix]');
2065
2361
  const suffix = this.el.nativeElement.querySelector('[suffix]');
@@ -2069,11 +2365,76 @@ class MaskedInputComponent {
2069
2365
  this.cdr.detectChanges();
2070
2366
  }
2071
2367
  }
2368
+ get computedLabelClass() {
2369
+ return cn("text-sm font-medium text-foreground leading-none transition-opacity duration-200", this.disabled && "opacity-50");
2370
+ }
2371
+ get computedContainerClass() {
2372
+ return cn(
2373
+ // Base styles
2374
+ "group relative flex items-center w-full rounded-md border transition-all duration-200", "bg-background",
2375
+ // Border and shadow
2376
+ "border-input shadow-sm",
2377
+ // Sizing
2378
+ this.size === 'xs' && "h-8 px-2 gap-1.5 text-xs", this.size === 'sm' && "h-9 px-3 gap-2 text-sm", this.size === 'default' && "h-10 px-3 gap-2 text-sm", this.size === 'lg' && "h-11 px-4 gap-3 text-base",
2379
+ // Focus state - SIMPLE LIKE ZARDUI
2380
+ !(this.readonly || this.disabled) && [
2381
+ "focus-within:border-primary/80",
2382
+ "focus-within:ring-4",
2383
+ "focus-within:ring-ring/30",
2384
+ "focus-within:ring-offset-0",
2385
+ "focus-within:shadow-none",
2386
+ ],
2387
+ // Error state
2388
+ this.error && [
2389
+ "border-destructive",
2390
+ !(this.readonly || this.disabled) && [
2391
+ "focus-within:border-destructive/80",
2392
+ "focus-within:ring-destructive/30"
2393
+ ]
2394
+ ],
2395
+ // Disabled state
2396
+ this.disabled && [
2397
+ "cursor-not-allowed opacity-50",
2398
+ "border-opacity-50"
2399
+ ],
2400
+ // Readonly state
2401
+ this.readonly && [
2402
+ "cursor-default",
2403
+ "border-dashed",
2404
+ !this.disabled && "focus-within:ring-0 focus-within:border-opacity-100"
2405
+ ], this.containerClass);
2406
+ }
2072
2407
  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);
2408
+ return cn(
2409
+ // Base styles
2410
+ "flex-1 bg-transparent border-none p-0", "placeholder:text-muted-foreground",
2411
+ // Remove all default focus styles
2412
+ "focus:outline-none focus:ring-0 focus:shadow-none",
2413
+ // Text sizing
2414
+ this.size === 'xs' && "text-xs", this.size === 'sm' && "text-sm", this.size === 'default' && "text-sm", this.size === 'lg' && "text-base",
2415
+ // Cursor states
2416
+ this.disabled && "cursor-not-allowed", this.readonly && "cursor-default",
2417
+ // Text color
2418
+ "text-foreground",
2419
+ // Selection color
2420
+ "selection:bg-primary/20 selection:text-foreground", this.class);
2421
+ }
2422
+ focusInput() {
2423
+ if (!this.disabled && this.inputEl) {
2424
+ this.inputEl.nativeElement.focus();
2425
+ }
2426
+ }
2427
+ onFocus() {
2428
+ this.isFocused = true;
2429
+ }
2430
+ onBlur() {
2431
+ this.isFocused = false;
2432
+ this.onTouched();
2074
2433
  }
2075
2434
  // --- Masking Logic ---
2076
2435
  onInput(event) {
2436
+ if (this.readonly || this.disabled)
2437
+ return;
2077
2438
  const input = event.target;
2078
2439
  const raw = this.unmask(input.value);
2079
2440
  const masked = this.applyMask(raw);
@@ -2107,47 +2468,90 @@ class MaskedInputComponent {
2107
2468
  }
2108
2469
  return formatted;
2109
2470
  }
2110
- unmask(val) { return val.replace(/[^a-zA-Z0-9]/g, ''); }
2471
+ unmask(val) {
2472
+ return val.replace(/[^a-zA-Z0-9]/g, '');
2473
+ }
2111
2474
  writeValue(value) {
2112
2475
  this.displayValue = value ? this.applyMask(this.unmask(value.toString())) : '';
2113
2476
  this.cdr.markForCheck();
2114
2477
  }
2115
- registerOnChange(fn) { this.onChange = fn; }
2116
- registerOnTouched(fn) { this.onTouched = fn; }
2117
- setDisabledState(isDisabled) { this.disabled = isDisabled; }
2478
+ registerOnChange(fn) {
2479
+ this.onChange = fn;
2480
+ }
2481
+ registerOnTouched(fn) {
2482
+ this.onTouched = fn;
2483
+ }
2484
+ setDisabledState(isDisabled) {
2485
+ this.disabled = isDisabled;
2486
+ this.cdr.markForCheck();
2487
+ }
2118
2488
  cn = cn;
2119
2489
  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: [
2490
+ 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", hideHintOnFocus: "hideHintOnFocus" }, providers: [
2121
2491
  {
2122
2492
  provide: NG_VALUE_ACCESSOR,
2123
2493
  useExisting: forwardRef(() => MaskedInputComponent),
2124
2494
  multi: true
2125
2495
  }
2126
2496
  ], 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)">
2497
+ <div class="flex flex-col gap-1.5 w-full">
2498
+ <label
2499
+ *ngIf="label"
2500
+ [for]="id"
2501
+ [class]="computedLabelClass"
2502
+ >
2503
+ {{ label }}
2504
+ </label>
2128
2505
 
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>
2506
+ <div
2507
+ [class]="computedContainerClass"
2508
+ (click)="focusInput()"
2509
+ >
2510
+ <!-- Prefix Icon -->
2511
+ <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors duration-200">
2512
+ <ng-content select="[prefix]"></ng-content>
2513
+ </div>
2133
2514
 
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
- />
2515
+ <input
2516
+ #inputEl
2517
+ [id]="id"
2518
+ [type]="type"
2519
+ [placeholder]="placeholder"
2520
+ [disabled]="disabled"
2521
+ [readOnly]="readonly"
2522
+ [value]="displayValue"
2523
+ (input)="onInput($event)"
2524
+ (blur)="onBlur()"
2525
+ (focus)="onFocus()"
2526
+ [class]="computedInputClass"
2527
+ [attr.aria-invalid]="error"
2528
+ [attr.aria-describedby]="error && errorMessage ? id + '-error' : null"
2529
+ />
2144
2530
 
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>
2531
+ <!-- Suffix Icon -->
2532
+ <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors duration-200">
2533
+ <ng-content select="[suffix]"></ng-content>
2534
+ </div>
2148
2535
  </div>
2536
+
2537
+ <ng-container *ngIf="!disabled">
2538
+ <p
2539
+ *ngIf="hint && !error"
2540
+ class="text-xs text-muted-foreground px-1 transition-opacity duration-200"
2541
+ [class.opacity-0]="isFocused && hideHintOnFocus"
2542
+ >
2543
+ {{ hint }}
2544
+ </p>
2545
+ <p
2546
+ *ngIf="error && errorMessage"
2547
+ [id]="id + '-error'"
2548
+ class="text-xs text-destructive px-1"
2549
+ >
2550
+ {{ errorMessage }}
2551
+ </p>
2552
+ </ng-container>
2149
2553
  </div>
2150
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }] });
2554
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }] });
2151
2555
  }
2152
2556
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MaskedInputComponent, decorators: [{
2153
2557
  type: Component,
@@ -2163,32 +2567,74 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
2163
2567
  }
2164
2568
  ],
2165
2569
  template: `
2166
- <div [class]="cn('relative flex items-center w-full group', 'size-' + size, class)">
2570
+ <div class="flex flex-col gap-1.5 w-full">
2571
+ <label
2572
+ *ngIf="label"
2573
+ [for]="id"
2574
+ [class]="computedLabelClass"
2575
+ >
2576
+ {{ label }}
2577
+ </label>
2167
2578
 
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>
2579
+ <div
2580
+ [class]="computedContainerClass"
2581
+ (click)="focusInput()"
2582
+ >
2583
+ <!-- Prefix Icon -->
2584
+ <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors duration-200">
2585
+ <ng-content select="[prefix]"></ng-content>
2586
+ </div>
2172
2587
 
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
- />
2588
+ <input
2589
+ #inputEl
2590
+ [id]="id"
2591
+ [type]="type"
2592
+ [placeholder]="placeholder"
2593
+ [disabled]="disabled"
2594
+ [readOnly]="readonly"
2595
+ [value]="displayValue"
2596
+ (input)="onInput($event)"
2597
+ (blur)="onBlur()"
2598
+ (focus)="onFocus()"
2599
+ [class]="computedInputClass"
2600
+ [attr.aria-invalid]="error"
2601
+ [attr.aria-describedby]="error && errorMessage ? id + '-error' : null"
2602
+ />
2183
2603
 
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>
2604
+ <!-- Suffix Icon -->
2605
+ <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors duration-200">
2606
+ <ng-content select="[suffix]"></ng-content>
2607
+ </div>
2187
2608
  </div>
2609
+
2610
+ <ng-container *ngIf="!disabled">
2611
+ <p
2612
+ *ngIf="hint && !error"
2613
+ class="text-xs text-muted-foreground px-1 transition-opacity duration-200"
2614
+ [class.opacity-0]="isFocused && hideHintOnFocus"
2615
+ >
2616
+ {{ hint }}
2617
+ </p>
2618
+ <p
2619
+ *ngIf="error && errorMessage"
2620
+ [id]="id + '-error'"
2621
+ class="text-xs text-destructive px-1"
2622
+ >
2623
+ {{ errorMessage }}
2624
+ </p>
2625
+ </ng-container>
2188
2626
  </div>
2189
2627
  `
2190
2628
  }]
2191
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { mask: [{
2629
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { id: [{
2630
+ type: Input
2631
+ }], label: [{
2632
+ type: Input
2633
+ }], hint: [{
2634
+ type: Input
2635
+ }], errorMessage: [{
2636
+ type: Input
2637
+ }], mask: [{
2192
2638
  type: Input
2193
2639
  }], placeholder: [{
2194
2640
  type: Input
@@ -2196,14 +2642,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
2196
2642
  type: Input
2197
2643
  }], disabled: [{
2198
2644
  type: Input
2645
+ }], readonly: [{
2646
+ type: Input
2199
2647
  }], class: [{
2200
2648
  type: Input
2649
+ }], containerClass: [{
2650
+ type: Input
2201
2651
  }], error: [{
2202
2652
  type: Input
2203
2653
  }], size: [{
2204
2654
  type: Input
2205
2655
  }], returnRaw: [{
2206
2656
  type: Input
2657
+ }], hideHintOnFocus: [{
2658
+ type: Input
2207
2659
  }], inputEl: [{
2208
2660
  type: ViewChild,
2209
2661
  args: ['inputEl', { static: true }]
@@ -2356,7 +2808,7 @@ class DatePickerComponent {
2356
2808
  ></tolle-calendar>
2357
2809
  </div>
2358
2810
  </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"] }] });
2811
+ `, 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"] }] });
2360
2812
  }
2361
2813
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DatePickerComponent, decorators: [{
2362
2814
  type: Component,
@@ -2948,7 +3400,7 @@ class DataTableComponent {
2948
3400
  (onPageSizeChange)="updatePage()"
2949
3401
  ></tolle-pagination>
2950
3402
  </div>
2951
- `, 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: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { 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: PaginationComponent, selector: "tolle-pagination", inputs: ["class", "showPageLinks", "showPageOptions", "showCurrentPageInfo", "currentPageInfoTemplate", "totalRecords", "currentPageSize", "currentPage", "pageSizeOptions"], outputs: ["onPageNumberChange", "onPageSizeChange"] }, { kind: "component", type: InputComponent, selector: "tolle-input", inputs: ["id", "label", "hint", "errorMessage", "type", "placeholder", "size", "containerClass", "class", "disabled", "readonly", "error"] }] });
3403
+ `, 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: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { 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: PaginationComponent, selector: "tolle-pagination", inputs: ["class", "showPageLinks", "showPageOptions", "showCurrentPageInfo", "currentPageInfoTemplate", "totalRecords", "currentPageSize", "currentPage", "pageSizeOptions"], outputs: ["onPageNumberChange", "onPageSizeChange"] }, { kind: "component", type: InputComponent, selector: "tolle-input", inputs: ["id", "label", "hint", "errorMessage", "type", "placeholder", "size", "containerClass", "class", "disabled", "readonly", "error", "hideHintOnFocus"] }] });
2952
3404
  }
2953
3405
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DataTableComponent, decorators: [{
2954
3406
  type: Component,
@@ -3858,7 +4310,7 @@ class DateRangePickerComponent {
3858
4310
  ></tolle-range-calendar>
3859
4311
  </div>
3860
4312
  </div>
3861
- `, 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: RangeCalendarComponent, selector: "tolle-range-calendar", inputs: ["class", "disablePastDates"], outputs: ["rangeSelect"] }, { kind: "component", type: InputComponent, selector: "tolle-input", inputs: ["id", "label", "hint", "errorMessage", "type", "placeholder", "size", "containerClass", "class", "disabled", "readonly", "error"] }] });
4313
+ `, 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: RangeCalendarComponent, selector: "tolle-range-calendar", inputs: ["class", "disablePastDates"], outputs: ["rangeSelect"] }, { kind: "component", type: InputComponent, selector: "tolle-input", inputs: ["id", "label", "hint", "errorMessage", "type", "placeholder", "size", "containerClass", "class", "disabled", "readonly", "error", "hideHintOnFocus"] }] });
3862
4314
  }
3863
4315
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DateRangePickerComponent, decorators: [{
3864
4316
  type: Component,
@@ -4076,30 +4528,69 @@ class TextareaComponent {
4076
4528
  label = '';
4077
4529
  placeholder = '';
4078
4530
  hint = '';
4531
+ errorMessage = '';
4079
4532
  rows = 3;
4080
4533
  maxLength;
4081
4534
  showCharacterCount = false;
4082
4535
  autoGrow = false;
4083
4536
  error = false;
4084
4537
  className = '';
4538
+ // Focus behavior
4539
+ hideHintOnFocus = true;
4540
+ hideCharacterCountOnFocus = false;
4085
4541
  // New States
4086
4542
  disabled = false;
4087
4543
  readonly = false;
4088
4544
  value = '';
4545
+ isFocused = false;
4089
4546
  onChange = () => { };
4090
4547
  onTouched = () => { };
4091
4548
  ngAfterViewInit() {
4092
4549
  if (this.autoGrow)
4093
4550
  this.resize();
4094
4551
  }
4552
+ get computedLabelClass() {
4553
+ return cn("text-sm font-medium text-foreground leading-none transition-opacity duration-200", this.disabled && "opacity-50");
4554
+ }
4095
4555
  get textareaClasses() {
4096
- return cn('flex w-full rounded-md border bg-background px-3 py-2 text-sm ring-offset-background transition-all duration-200 shadow-sm', 'placeholder:text-muted-foreground focus-visible:outline-none',
4097
- // Focus States (Disabled only when readonly or disabled is true)
4098
- !(this.readonly || this.disabled) && 'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',
4099
- // Border colors
4100
- this.error ? 'border-destructive' : 'border-input',
4101
- // 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);
4556
+ return cn(
4557
+ // Base styles
4558
+ 'flex w-full rounded-md border bg-background px-3 py-2 text-sm', 'ring-offset-background transition-all duration-200', 'placeholder:text-muted-foreground',
4559
+ // Border and shadow
4560
+ 'border-input shadow-sm',
4561
+ // Minimum height
4562
+ 'min-h-[80px]',
4563
+ // Focus state - SIMPLE LIKE ZARDUI
4564
+ !(this.readonly || this.disabled) && [
4565
+ 'focus:outline-none',
4566
+ 'focus:ring-4',
4567
+ 'focus:ring-ring/30',
4568
+ 'focus:ring-offset-0',
4569
+ 'focus:shadow-none',
4570
+ // Border darkens on focus automatically
4571
+ 'focus:border-primary/80'
4572
+ ],
4573
+ // Error state
4574
+ this.error && [
4575
+ 'border-destructive',
4576
+ !(this.readonly || this.disabled) && [
4577
+ 'focus:border-destructive/80',
4578
+ 'focus:ring-destructive/30'
4579
+ ]
4580
+ ],
4581
+ // Disabled state
4582
+ this.disabled && [
4583
+ 'cursor-not-allowed opacity-50',
4584
+ 'border-opacity-50'
4585
+ ],
4586
+ // Readonly state
4587
+ this.readonly && [
4588
+ 'cursor-default',
4589
+ 'border-dashed',
4590
+ !this.disabled && 'focus:ring-0 focus:border-opacity-100'
4591
+ ],
4592
+ // Scrollbar styling
4593
+ 'scrollbar-thin scrollbar-thumb-muted scrollbar-track-transparent', this.className);
4103
4594
  }
4104
4595
  handleInput(event) {
4105
4596
  if (this.readonly || this.disabled)
@@ -4110,6 +4601,13 @@ class TextareaComponent {
4110
4601
  if (this.autoGrow)
4111
4602
  this.resize();
4112
4603
  }
4604
+ onFocus() {
4605
+ this.isFocused = true;
4606
+ }
4607
+ onBlur() {
4608
+ this.isFocused = false;
4609
+ this.onTouched();
4610
+ }
4113
4611
  resize() {
4114
4612
  const textarea = this.textareaElement.nativeElement;
4115
4613
  textarea.style.height = 'auto';
@@ -4120,11 +4618,17 @@ class TextareaComponent {
4120
4618
  if (this.autoGrow)
4121
4619
  setTimeout(() => this.resize());
4122
4620
  }
4123
- registerOnChange(fn) { this.onChange = fn; }
4124
- registerOnTouched(fn) { this.onTouched = fn; }
4125
- setDisabledState(isDisabled) { this.disabled = isDisabled; }
4621
+ registerOnChange(fn) {
4622
+ this.onChange = fn;
4623
+ }
4624
+ registerOnTouched(fn) {
4625
+ this.onTouched = fn;
4626
+ }
4627
+ setDisabledState(isDisabled) {
4628
+ this.disabled = isDisabled;
4629
+ }
4126
4630
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TextareaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4127
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: TextareaComponent, isStandalone: true, selector: "tolle-textarea", inputs: { id: "id", label: "label", placeholder: "placeholder", hint: "hint", rows: "rows", maxLength: "maxLength", showCharacterCount: "showCharacterCount", autoGrow: "autoGrow", error: "error", className: "className", disabled: "disabled", readonly: "readonly" }, providers: [
4631
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: TextareaComponent, isStandalone: true, selector: "tolle-textarea", inputs: { id: "id", label: "label", placeholder: "placeholder", hint: "hint", errorMessage: "errorMessage", rows: "rows", maxLength: "maxLength", showCharacterCount: "showCharacterCount", autoGrow: "autoGrow", error: "error", className: "className", hideHintOnFocus: "hideHintOnFocus", hideCharacterCountOnFocus: "hideCharacterCountOnFocus", disabled: "disabled", readonly: "readonly" }, providers: [
4128
4632
  {
4129
4633
  provide: NG_VALUE_ACCESSOR,
4130
4634
  useExisting: forwardRef(() => TextareaComponent),
@@ -4132,9 +4636,11 @@ class TextareaComponent {
4132
4636
  }
4133
4637
  ], viewQueries: [{ propertyName: "textareaElement", first: true, predicate: ["textareaElement"], descendants: true }], ngImport: i0, template: `
4134
4638
  <div class="flex flex-col gap-1.5 w-full">
4135
- <label *ngIf="label" [for]="id"
4136
- [class.opacity-50]="disabled"
4137
- class="text-sm font-medium text-foreground leading-none transition-opacity">
4639
+ <label
4640
+ *ngIf="label"
4641
+ [for]="id"
4642
+ [class]="computedLabelClass"
4643
+ >
4138
4644
  {{ label }}
4139
4645
  </label>
4140
4646
 
@@ -4148,16 +4654,37 @@ class TextareaComponent {
4148
4654
  [rows]="rows"
4149
4655
  [(ngModel)]="value"
4150
4656
  (input)="handleInput($event)"
4151
- (blur)="onTouched()"
4657
+ (blur)="onBlur()"
4658
+ (focus)="onFocus()"
4152
4659
  [class]="textareaClasses"
4153
4660
  [style.resize]="(autoGrow || readonly || disabled) ? 'none' : 'vertical'"
4154
4661
  [style.overflow]="autoGrow ? 'hidden' : 'auto'"
4662
+ [attr.aria-invalid]="error"
4663
+ [attr.aria-describedby]="error && errorMessage ? id + '-error' : null"
4664
+ [attr.maxlength]="maxLength"
4155
4665
  ></textarea>
4156
4666
  </div>
4157
4667
 
4158
- <div *ngIf="(showCharacterCount || hint) && !disabled" class="flex justify-between items-center px-1">
4159
- <p *ngIf="hint" class="text-xs text-muted-foreground">{{ hint }}</p>
4160
- <p *ngIf="showCharacterCount" class="text-[10px] uppercase tracking-wider text-muted-foreground ml-auto font-medium">
4668
+ <div *ngIf="(showCharacterCount || hint || errorMessage) && !disabled" class="flex justify-between items-center px-1">
4669
+ <p
4670
+ *ngIf="hint && !error"
4671
+ class="text-xs text-muted-foreground transition-opacity duration-200"
4672
+ [class.opacity-0]="isFocused && hideHintOnFocus"
4673
+ >
4674
+ {{ hint }}
4675
+ </p>
4676
+ <p
4677
+ *ngIf="error && errorMessage"
4678
+ [id]="id + '-error'"
4679
+ class="text-xs text-destructive"
4680
+ >
4681
+ {{ errorMessage }}
4682
+ </p>
4683
+ <p
4684
+ *ngIf="showCharacterCount"
4685
+ class="text-[10px] uppercase tracking-wider text-muted-foreground ml-auto font-medium transition-opacity duration-200"
4686
+ [class.opacity-0]="isFocused && hideCharacterCountOnFocus"
4687
+ >
4161
4688
  {{ value.length || 0 }}{{ maxLength ? ' / ' + maxLength : '' }}
4162
4689
  </p>
4163
4690
  </div>
@@ -4179,9 +4706,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
4179
4706
  ],
4180
4707
  template: `
4181
4708
  <div class="flex flex-col gap-1.5 w-full">
4182
- <label *ngIf="label" [for]="id"
4183
- [class.opacity-50]="disabled"
4184
- class="text-sm font-medium text-foreground leading-none transition-opacity">
4709
+ <label
4710
+ *ngIf="label"
4711
+ [for]="id"
4712
+ [class]="computedLabelClass"
4713
+ >
4185
4714
  {{ label }}
4186
4715
  </label>
4187
4716
 
@@ -4195,16 +4724,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
4195
4724
  [rows]="rows"
4196
4725
  [(ngModel)]="value"
4197
4726
  (input)="handleInput($event)"
4198
- (blur)="onTouched()"
4727
+ (blur)="onBlur()"
4728
+ (focus)="onFocus()"
4199
4729
  [class]="textareaClasses"
4200
4730
  [style.resize]="(autoGrow || readonly || disabled) ? 'none' : 'vertical'"
4201
4731
  [style.overflow]="autoGrow ? 'hidden' : 'auto'"
4732
+ [attr.aria-invalid]="error"
4733
+ [attr.aria-describedby]="error && errorMessage ? id + '-error' : null"
4734
+ [attr.maxlength]="maxLength"
4202
4735
  ></textarea>
4203
4736
  </div>
4204
4737
 
4205
- <div *ngIf="(showCharacterCount || hint) && !disabled" class="flex justify-between items-center px-1">
4206
- <p *ngIf="hint" class="text-xs text-muted-foreground">{{ hint }}</p>
4207
- <p *ngIf="showCharacterCount" class="text-[10px] uppercase tracking-wider text-muted-foreground ml-auto font-medium">
4738
+ <div *ngIf="(showCharacterCount || hint || errorMessage) && !disabled" class="flex justify-between items-center px-1">
4739
+ <p
4740
+ *ngIf="hint && !error"
4741
+ class="text-xs text-muted-foreground transition-opacity duration-200"
4742
+ [class.opacity-0]="isFocused && hideHintOnFocus"
4743
+ >
4744
+ {{ hint }}
4745
+ </p>
4746
+ <p
4747
+ *ngIf="error && errorMessage"
4748
+ [id]="id + '-error'"
4749
+ class="text-xs text-destructive"
4750
+ >
4751
+ {{ errorMessage }}
4752
+ </p>
4753
+ <p
4754
+ *ngIf="showCharacterCount"
4755
+ class="text-[10px] uppercase tracking-wider text-muted-foreground ml-auto font-medium transition-opacity duration-200"
4756
+ [class.opacity-0]="isFocused && hideCharacterCountOnFocus"
4757
+ >
4208
4758
  {{ value.length || 0 }}{{ maxLength ? ' / ' + maxLength : '' }}
4209
4759
  </p>
4210
4760
  </div>
@@ -4222,6 +4772,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
4222
4772
  type: Input
4223
4773
  }], hint: [{
4224
4774
  type: Input
4775
+ }], errorMessage: [{
4776
+ type: Input
4225
4777
  }], rows: [{
4226
4778
  type: Input
4227
4779
  }], maxLength: [{
@@ -4234,12 +4786,989 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
4234
4786
  type: Input
4235
4787
  }], className: [{
4236
4788
  type: Input
4789
+ }], hideHintOnFocus: [{
4790
+ type: Input
4791
+ }], hideCharacterCountOnFocus: [{
4792
+ type: Input
4237
4793
  }], disabled: [{
4238
4794
  type: Input
4239
4795
  }], readonly: [{
4240
4796
  type: Input
4241
4797
  }] } });
4242
4798
 
4799
+ 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", {
4800
+ variants: {
4801
+ variant: {
4802
+ default: "bg-background text-foreground",
4803
+ destructive: "border-destructive/50 text-destructive dark:border-destructive [&>i]:text-destructive",
4804
+ success: "border-emerald-500/50 text-emerald-700 dark:text-emerald-400 [&>i]:text-emerald-600",
4805
+ warning: "border-amber-500/50 text-amber-700 dark:text-amber-400 [&>i]:text-amber-600",
4806
+ },
4807
+ },
4808
+ defaultVariants: {
4809
+ variant: "default",
4810
+ },
4811
+ });
4812
+ class AlertComponent {
4813
+ variant = 'default';
4814
+ title;
4815
+ class = '';
4816
+ dismissible = false;
4817
+ onClose = new EventEmitter();
4818
+ dismissed = false;
4819
+ isDismissing = false;
4820
+ alertVariants = alertVariants;
4821
+ cn = cn;
4822
+ dismiss() {
4823
+ this.isDismissing = true;
4824
+ // Wait for animation to finish before removing from DOM
4825
+ setTimeout(() => {
4826
+ this.dismissed = true;
4827
+ this.onClose.emit();
4828
+ }, 300);
4829
+ }
4830
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4831
+ 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: `
4832
+ <div
4833
+ *ngIf="!dismissed"
4834
+ [class]="cn(alertVariants({ variant }), class)"
4835
+ [class.opacity-0]="isDismissing"
4836
+ [class.scale-95]="isDismissing"
4837
+ role="alert"
4838
+ >
4839
+ <ng-content select="[icon]"></ng-content>
4840
+
4841
+ <button
4842
+ *ngIf="dismissible"
4843
+ (click)="dismiss()"
4844
+ 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"
4845
+ [class.opacity-100]="dismissible"
4846
+ >
4847
+ <i class="ri-close-line text-lg"></i>
4848
+ </button>
4849
+
4850
+ <div>
4851
+ <h5 *ngIf="title" class="mb-1 font-medium leading-none tracking-tight">
4852
+ {{ title }}
4853
+ </h5>
4854
+ <div class="text-sm [&_p]:leading-relaxed">
4855
+ <ng-content></ng-content>
4856
+ </div>
4857
+ </div>
4858
+ </div>
4859
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
4860
+ }
4861
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AlertComponent, decorators: [{
4862
+ type: Component,
4863
+ args: [{
4864
+ selector: 'tolle-alert',
4865
+ standalone: true,
4866
+ imports: [CommonModule],
4867
+ template: `
4868
+ <div
4869
+ *ngIf="!dismissed"
4870
+ [class]="cn(alertVariants({ variant }), class)"
4871
+ [class.opacity-0]="isDismissing"
4872
+ [class.scale-95]="isDismissing"
4873
+ role="alert"
4874
+ >
4875
+ <ng-content select="[icon]"></ng-content>
4876
+
4877
+ <button
4878
+ *ngIf="dismissible"
4879
+ (click)="dismiss()"
4880
+ 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"
4881
+ [class.opacity-100]="dismissible"
4882
+ >
4883
+ <i class="ri-close-line text-lg"></i>
4884
+ </button>
4885
+
4886
+ <div>
4887
+ <h5 *ngIf="title" class="mb-1 font-medium leading-none tracking-tight">
4888
+ {{ title }}
4889
+ </h5>
4890
+ <div class="text-sm [&_p]:leading-relaxed">
4891
+ <ng-content></ng-content>
4892
+ </div>
4893
+ </div>
4894
+ </div>
4895
+ `,
4896
+ }]
4897
+ }], propDecorators: { variant: [{
4898
+ type: Input
4899
+ }], title: [{
4900
+ type: Input
4901
+ }], class: [{
4902
+ type: Input
4903
+ }], dismissible: [{
4904
+ type: Input
4905
+ }], onClose: [{
4906
+ type: Output
4907
+ }] } });
4908
+
4909
+ class AvatarComponent {
4910
+ cdr;
4911
+ src;
4912
+ alt = '';
4913
+ size = 'default';
4914
+ shape = 'circle';
4915
+ // We remove @Input() class because standard class="" attributes
4916
+ // on the tag will now work automatically with the host bindings.
4917
+ isLoading = true;
4918
+ hasError = false;
4919
+ constructor(cdr) {
4920
+ this.cdr = cdr;
4921
+ }
4922
+ onLoad() {
4923
+ this.isLoading = false;
4924
+ this.cdr.detectChanges();
4925
+ }
4926
+ onError() {
4927
+ this.isLoading = false;
4928
+ this.hasError = true;
4929
+ this.cdr.detectChanges();
4930
+ }
4931
+ // Apply styles directly to the <tolle-avatar> tag
4932
+ get hostClasses() {
4933
+ return cn(
4934
+ // Layout & Shape
4935
+ "relative flex shrink-0 overflow-hidden bg-muted", this.shape === 'circle' ? 'rounded-full' : 'rounded-md',
4936
+ // Sizes
4937
+ 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");
4938
+ }
4939
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AvatarComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
4940
+ 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: `
4941
+ <!-- Image Layer -->
4942
+ <img *ngIf="src && !hasError"
4943
+ [src]="src"
4944
+ [alt]="alt"
4945
+ (load)="onLoad()"
4946
+ (error)="onError()"
4947
+ [class.opacity-0]="isLoading"
4948
+ class="h-full w-full object-cover transition-opacity duration-300" />
4949
+
4950
+ <!-- Fallback Layer -->
4951
+ <div *ngIf="hasError || !src || isLoading" class="flex h-full w-full items-center justify-center bg-muted">
4952
+ <ng-content></ng-content>
4953
+ </div>
4954
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
4955
+ }
4956
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AvatarComponent, decorators: [{
4957
+ type: Component,
4958
+ args: [{
4959
+ selector: 'tolle-avatar',
4960
+ standalone: true,
4961
+ imports: [NgIf],
4962
+ template: `
4963
+ <!-- Image Layer -->
4964
+ <img *ngIf="src && !hasError"
4965
+ [src]="src"
4966
+ [alt]="alt"
4967
+ (load)="onLoad()"
4968
+ (error)="onError()"
4969
+ [class.opacity-0]="isLoading"
4970
+ class="h-full w-full object-cover transition-opacity duration-300" />
4971
+
4972
+ <!-- Fallback Layer -->
4973
+ <div *ngIf="hasError || !src || isLoading" class="flex h-full w-full items-center justify-center bg-muted">
4974
+ <ng-content></ng-content>
4975
+ </div>
4976
+ `
4977
+ }]
4978
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { src: [{
4979
+ type: Input
4980
+ }], alt: [{
4981
+ type: Input
4982
+ }], size: [{
4983
+ type: Input
4984
+ }], shape: [{
4985
+ type: Input
4986
+ }], hostClasses: [{
4987
+ type: HostBinding,
4988
+ args: ['class']
4989
+ }] } });
4990
+
4991
+ class AvatarFallbackComponent {
4992
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AvatarFallbackComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4993
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: AvatarFallbackComponent, isStandalone: true, selector: "tolle-avatar-fallback", ngImport: i0, template: `
4994
+ <div class="flex h-full w-full items-center justify-center bg-muted text-muted-foreground font-medium uppercase">
4995
+ <ng-content></ng-content>
4996
+ </div>
4997
+ `, isInline: true, styles: [""] });
4998
+ }
4999
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AvatarFallbackComponent, decorators: [{
5000
+ type: Component,
5001
+ args: [{ selector: 'tolle-avatar-fallback', standalone: true, imports: [], template: `
5002
+ <div class="flex h-full w-full items-center justify-center bg-muted text-muted-foreground font-medium uppercase">
5003
+ <ng-content></ng-content>
5004
+ </div>
5005
+ ` }]
5006
+ }] });
5007
+
5008
+ class BreadcrumbComponent {
5009
+ class = '';
5010
+ cn = cn;
5011
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5012
+ 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: `
5013
+ <nav aria-label="breadcrumb" [class]="cn('flex flex-wrap items-center break-words text-sm text-muted-foreground', class)">
5014
+ <ol class="flex flex-wrap items-center gap-1.5 break-words">
5015
+ <ng-content></ng-content>
5016
+ </ol>
5017
+ </nav>
5018
+ `, isInline: true, styles: [""] });
5019
+ }
5020
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BreadcrumbComponent, decorators: [{
5021
+ type: Component,
5022
+ args: [{ selector: 'tolle-breadcrumb', standalone: true, imports: [], template: `
5023
+ <nav aria-label="breadcrumb" [class]="cn('flex flex-wrap items-center break-words text-sm text-muted-foreground', class)">
5024
+ <ol class="flex flex-wrap items-center gap-1.5 break-words">
5025
+ <ng-content></ng-content>
5026
+ </ol>
5027
+ </nav>
5028
+ ` }]
5029
+ }], propDecorators: { class: [{
5030
+ type: Input
5031
+ }] } });
5032
+
5033
+ class BreadcrumbLinkComponent {
5034
+ active = false;
5035
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BreadcrumbLinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5036
+ 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: `
5037
+ <ng-template #content>
5038
+ <ng-content></ng-content>
5039
+ </ng-template>
5040
+
5041
+ <ng-container *ngIf="active; else linkTemplate">
5042
+ <span
5043
+ role="link"
5044
+ aria-disabled="true"
5045
+ aria-current="page"
5046
+ class="font-normal text-foreground"
5047
+ >
5048
+ <ng-container *ngTemplateOutlet="content"></ng-container>
5049
+ </span>
5050
+ </ng-container>
5051
+
5052
+ <ng-template #linkTemplate>
5053
+ <div class="transition-colors hover:text-foreground cursor-pointer">
5054
+ <ng-container *ngTemplateOutlet="content"></ng-container>
5055
+ </div>
5056
+ </ng-template>
5057
+ `, isInline: true, styles: [""], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
5058
+ }
5059
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BreadcrumbLinkComponent, decorators: [{
5060
+ type: Component,
5061
+ args: [{ selector: 'tolle-breadcrumb-link', standalone: true, imports: [
5062
+ NgIf,
5063
+ NgTemplateOutlet
5064
+ ], template: `
5065
+ <ng-template #content>
5066
+ <ng-content></ng-content>
5067
+ </ng-template>
5068
+
5069
+ <ng-container *ngIf="active; else linkTemplate">
5070
+ <span
5071
+ role="link"
5072
+ aria-disabled="true"
5073
+ aria-current="page"
5074
+ class="font-normal text-foreground"
5075
+ >
5076
+ <ng-container *ngTemplateOutlet="content"></ng-container>
5077
+ </span>
5078
+ </ng-container>
5079
+
5080
+ <ng-template #linkTemplate>
5081
+ <div class="transition-colors hover:text-foreground cursor-pointer">
5082
+ <ng-container *ngTemplateOutlet="content"></ng-container>
5083
+ </div>
5084
+ </ng-template>
5085
+ ` }]
5086
+ }], propDecorators: { active: [{
5087
+ type: Input
5088
+ }] } });
5089
+
5090
+ class BreadcrumbSeparatorComponent {
5091
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BreadcrumbSeparatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5092
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: BreadcrumbSeparatorComponent, isStandalone: true, selector: "tolle-breadcrumb-separator", ngImport: i0, template: `
5093
+ <li role="presentation" aria-hidden="true" class="[&>i]:size-3.5">
5094
+ <ng-content>
5095
+ <i class="ri-arrow-right-s-line"></i>
5096
+ </ng-content>
5097
+ </li>
5098
+ `, isInline: true, styles: [""] });
5099
+ }
5100
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BreadcrumbSeparatorComponent, decorators: [{
5101
+ type: Component,
5102
+ args: [{ selector: 'tolle-breadcrumb-separator', standalone: true, imports: [], template: `
5103
+ <li role="presentation" aria-hidden="true" class="[&>i]:size-3.5">
5104
+ <ng-content>
5105
+ <i class="ri-arrow-right-s-line"></i>
5106
+ </ng-content>
5107
+ </li>
5108
+ ` }]
5109
+ }] });
5110
+
5111
+ class BreadcrumbItemComponent {
5112
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BreadcrumbItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5113
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: BreadcrumbItemComponent, isStandalone: true, selector: "tolle-breadcrumb-item", ngImport: i0, template: `
5114
+ <li class="inline-flex items-center gap-1.5">
5115
+ <ng-content></ng-content>
5116
+ </li>
5117
+ `, isInline: true, styles: [""] });
5118
+ }
5119
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BreadcrumbItemComponent, decorators: [{
5120
+ type: Component,
5121
+ args: [{ selector: 'tolle-breadcrumb-item', standalone: true, imports: [], template: `
5122
+ <li class="inline-flex items-center gap-1.5">
5123
+ <ng-content></ng-content>
5124
+ </li>
5125
+ ` }]
5126
+ }] });
5127
+
5128
+ const emptyStateVariants = cva("flex flex-col items-center justify-center text-center animate-in fade-in duration-500", {
5129
+ variants: {
5130
+ variant: {
5131
+ default: "min-h-[400px] rounded-md border border-dashed border-border p-8 bg-background/50",
5132
+ minimal: "p-4 min-h-[200px]",
5133
+ },
5134
+ },
5135
+ defaultVariants: {
5136
+ variant: "default",
5137
+ },
5138
+ });
5139
+ class EmptyStateComponent {
5140
+ variant = 'default';
5141
+ title = 'No items found';
5142
+ description;
5143
+ class = '';
5144
+ emptyStateVariants = emptyStateVariants;
5145
+ cn = cn;
5146
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: EmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5147
+ 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: `
5148
+ <div [class]="cn(emptyStateVariants({ variant }), class)">
5149
+
5150
+ <div [class]="cn(
5151
+ 'flex items-center justify-center rounded-full bg-muted',
5152
+ variant === 'minimal' ? 'h-12 w-12' : 'h-20 w-20'
5153
+ )">
5154
+ <ng-content select="[icon]">
5155
+ <i [class]="cn(
5156
+ 'ri-inbox-line text-muted-foreground/60',
5157
+ variant === 'minimal' ? 'text-xl' : 'text-3xl'
5158
+ )"></i>
5159
+ </ng-content>
5160
+ </div>
5161
+
5162
+ <h3 [class]="cn(
5163
+ 'font-semibold text-foreground',
5164
+ variant === 'minimal' ? 'mt-2 text-sm' : 'mt-4 text-lg'
5165
+ )">
5166
+ {{ title }}
5167
+ </h3>
5168
+
5169
+ <p *ngIf="description" [class]="cn(
5170
+ 'text-muted-foreground',
5171
+ variant === 'minimal' ? 'mt-1 text-xs' : 'mb-6 mt-2 max-w-sm text-sm'
5172
+ )">
5173
+ {{ description }}
5174
+ </p>
5175
+
5176
+ <div *ngIf="variant !== 'minimal'" class="flex items-center justify-center gap-3">
5177
+ <ng-content select="[actions]"></ng-content>
5178
+ </div>
5179
+ </div>
5180
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
5181
+ }
5182
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: EmptyStateComponent, decorators: [{
5183
+ type: Component,
5184
+ args: [{
5185
+ selector: 'tolle-empty-state',
5186
+ standalone: true,
5187
+ imports: [CommonModule],
5188
+ template: `
5189
+ <div [class]="cn(emptyStateVariants({ variant }), class)">
5190
+
5191
+ <div [class]="cn(
5192
+ 'flex items-center justify-center rounded-full bg-muted',
5193
+ variant === 'minimal' ? 'h-12 w-12' : 'h-20 w-20'
5194
+ )">
5195
+ <ng-content select="[icon]">
5196
+ <i [class]="cn(
5197
+ 'ri-inbox-line text-muted-foreground/60',
5198
+ variant === 'minimal' ? 'text-xl' : 'text-3xl'
5199
+ )"></i>
5200
+ </ng-content>
5201
+ </div>
5202
+
5203
+ <h3 [class]="cn(
5204
+ 'font-semibold text-foreground',
5205
+ variant === 'minimal' ? 'mt-2 text-sm' : 'mt-4 text-lg'
5206
+ )">
5207
+ {{ title }}
5208
+ </h3>
5209
+
5210
+ <p *ngIf="description" [class]="cn(
5211
+ 'text-muted-foreground',
5212
+ variant === 'minimal' ? 'mt-1 text-xs' : 'mb-6 mt-2 max-w-sm text-sm'
5213
+ )">
5214
+ {{ description }}
5215
+ </p>
5216
+
5217
+ <div *ngIf="variant !== 'minimal'" class="flex items-center justify-center gap-3">
5218
+ <ng-content select="[actions]"></ng-content>
5219
+ </div>
5220
+ </div>
5221
+ `
5222
+ }]
5223
+ }], propDecorators: { variant: [{
5224
+ type: Input
5225
+ }], title: [{
5226
+ type: Input
5227
+ }], description: [{
5228
+ type: Input
5229
+ }], class: [{
5230
+ type: Input
5231
+ }] } });
5232
+
5233
+ class OtpComponent {
5234
+ cdr;
5235
+ length = 6;
5236
+ disabled = false;
5237
+ auto = false; // The toggle for automatic slot generation
5238
+ value = '';
5239
+ isFocused = false;
5240
+ onChange = () => { };
5241
+ onTouched = () => { };
5242
+ constructor(cdr) {
5243
+ this.cdr = cdr;
5244
+ }
5245
+ onInputChange(event) {
5246
+ const val = event.target.value.replace(/\D/g, '');
5247
+ this.value = val;
5248
+ this.onChange(val);
5249
+ this.cdr.markForCheck();
5250
+ }
5251
+ // Visual logic for the automated slots
5252
+ getSlotClass(index) {
5253
+ const isActive = this.isFocused && this.value.length === index;
5254
+ 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');
5255
+ }
5256
+ writeValue(value) { this.value = value || ''; this.cdr.markForCheck(); }
5257
+ registerOnChange(fn) { this.onChange = fn; }
5258
+ registerOnTouched(fn) { this.onTouched = fn; }
5259
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OtpComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
5260
+ 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: [{
5261
+ provide: NG_VALUE_ACCESSOR,
5262
+ useExisting: forwardRef(() => OtpComponent),
5263
+ multi: true
5264
+ }], ngImport: i0, template: `
5265
+ <div class="relative flex items-center gap-2">
5266
+ <input
5267
+ #hiddenInput
5268
+ type="text"
5269
+ inputmode="numeric"
5270
+ autocomplete="one-time-code"
5271
+ [maxLength]="length"
5272
+ class="absolute inset-0 opacity-0 cursor-default z-20"
5273
+ [(ngModel)]="value"
5274
+ (input)="onInputChange($event)"
5275
+ (focus)="isFocused = true"
5276
+ (blur)="isFocused = false"
5277
+ [disabled]="disabled"
5278
+ />
5279
+
5280
+ <div *ngIf="auto" class="flex items-center gap-2 pointer-events-none">
5281
+ <div class="flex items-center">
5282
+ <div *ngFor="let _ of [].constructor(length); let i = index"
5283
+ [class]="getSlotClass(i)"
5284
+ >
5285
+ {{ value[i] || '' }}
5286
+ <div *ngIf="isFocused && value.length === i" class="absolute inset-0 flex items-center justify-center">
5287
+ <div class="h-4 w-px animate-caret-blink bg-foreground duration-1000"></div>
5288
+ </div>
5289
+ </div>
5290
+ </div>
5291
+ </div>
5292
+
5293
+ <div *ngIf="!auto" class="flex items-center gap-2 pointer-events-none">
5294
+ <ng-content></ng-content>
5295
+ </div>
5296
+ </div>
5297
+ `, 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"] }] });
5298
+ }
5299
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OtpComponent, decorators: [{
5300
+ type: Component,
5301
+ args: [{
5302
+ selector: 'tolle-otp',
5303
+ standalone: true,
5304
+ imports: [CommonModule, FormsModule],
5305
+ providers: [{
5306
+ provide: NG_VALUE_ACCESSOR,
5307
+ useExisting: forwardRef(() => OtpComponent),
5308
+ multi: true
5309
+ }],
5310
+ template: `
5311
+ <div class="relative flex items-center gap-2">
5312
+ <input
5313
+ #hiddenInput
5314
+ type="text"
5315
+ inputmode="numeric"
5316
+ autocomplete="one-time-code"
5317
+ [maxLength]="length"
5318
+ class="absolute inset-0 opacity-0 cursor-default z-20"
5319
+ [(ngModel)]="value"
5320
+ (input)="onInputChange($event)"
5321
+ (focus)="isFocused = true"
5322
+ (blur)="isFocused = false"
5323
+ [disabled]="disabled"
5324
+ />
5325
+
5326
+ <div *ngIf="auto" class="flex items-center gap-2 pointer-events-none">
5327
+ <div class="flex items-center">
5328
+ <div *ngFor="let _ of [].constructor(length); let i = index"
5329
+ [class]="getSlotClass(i)"
5330
+ >
5331
+ {{ value[i] || '' }}
5332
+ <div *ngIf="isFocused && value.length === i" class="absolute inset-0 flex items-center justify-center">
5333
+ <div class="h-4 w-px animate-caret-blink bg-foreground duration-1000"></div>
5334
+ </div>
5335
+ </div>
5336
+ </div>
5337
+ </div>
5338
+
5339
+ <div *ngIf="!auto" class="flex items-center gap-2 pointer-events-none">
5340
+ <ng-content></ng-content>
5341
+ </div>
5342
+ </div>
5343
+ `
5344
+ }]
5345
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { length: [{
5346
+ type: Input
5347
+ }], disabled: [{
5348
+ type: Input
5349
+ }], auto: [{
5350
+ type: Input
5351
+ }] } });
5352
+
5353
+ class OtpSlotComponent {
5354
+ char = '';
5355
+ isActive = false;
5356
+ isFirst = false;
5357
+ isLast = false;
5358
+ class = '';
5359
+ cn = cn;
5360
+ get computedClass() {
5361
+ return cn(
5362
+ // Base styles (matching input container)
5363
+ 'relative flex h-10 w-10 items-center justify-center', 'transition-all duration-200', 'text-center font-medium select-none',
5364
+ // Border styling - exactly like input
5365
+ 'border border-input shadow-sm bg-background',
5366
+ // FOCUS STYLING - EXACTLY LIKE INPUT COMPONENT
5367
+ this.isActive && [
5368
+ // Darker border on focus
5369
+ 'border-primary/80',
5370
+ // Remove shadow on focus
5371
+ 'shadow-none',
5372
+ // Focus ring with same styling as input
5373
+ 'ring-4',
5374
+ 'ring-ring/30',
5375
+ 'ring-offset-0',
5376
+ // Ensure it's above other slots
5377
+ 'z-10'
5378
+ ],
5379
+ // Filled state
5380
+ this.char && !this.isActive && 'border-primary/60',
5381
+ // Border radius
5382
+ this.isFirst && 'rounded-l-md', this.isLast && 'rounded-r-md',
5383
+ // Remove left border for all but first slot
5384
+ !this.isFirst && '-ml-px', this.class);
5385
+ }
5386
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OtpSlotComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5387
+ 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: `
5388
+ <div [class]="computedClass">
5389
+ <span class="text-lg font-medium">{{ char || '' }}</span>
5390
+ <div *ngIf="isActive && !char" class="pointer-events-none absolute inset-0 flex items-center justify-center">
5391
+ <div class="h-6 w-0.5 animate-caret-blink bg-foreground"></div>
5392
+ </div>
5393
+ </div>
5394
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
5395
+ }
5396
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OtpSlotComponent, decorators: [{
5397
+ type: Component,
5398
+ args: [{
5399
+ selector: 'tolle-otp-slot',
5400
+ standalone: true,
5401
+ imports: [NgIf],
5402
+ template: `
5403
+ <div [class]="computedClass">
5404
+ <span class="text-lg font-medium">{{ char || '' }}</span>
5405
+ <div *ngIf="isActive && !char" class="pointer-events-none absolute inset-0 flex items-center justify-center">
5406
+ <div class="h-6 w-0.5 animate-caret-blink bg-foreground"></div>
5407
+ </div>
5408
+ </div>
5409
+ `
5410
+ }]
5411
+ }], propDecorators: { char: [{
5412
+ type: Input
5413
+ }], isActive: [{
5414
+ type: Input
5415
+ }], isFirst: [{
5416
+ type: Input
5417
+ }], isLast: [{
5418
+ type: Input
5419
+ }], class: [{
5420
+ type: Input
5421
+ }] } });
5422
+
5423
+ class OtpGroupComponent {
5424
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OtpGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5425
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: OtpGroupComponent, isStandalone: true, selector: "tolle-otp-group", ngImport: i0, template: `
5426
+ <div class="flex items-center"><ng-content></ng-content></div>
5427
+ `, isInline: true, styles: [""] });
5428
+ }
5429
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OtpGroupComponent, decorators: [{
5430
+ type: Component,
5431
+ args: [{ selector: 'tolle-otp-group', standalone: true, imports: [], template: `
5432
+ <div class="flex items-center"><ng-content></ng-content></div>
5433
+ ` }]
5434
+ }] });
5435
+
5436
+ class PopoverComponent {
5437
+ placement = 'bottom';
5438
+ onOpen = new EventEmitter();
5439
+ onClose = new EventEmitter();
5440
+ triggerEl;
5441
+ popoverEl;
5442
+ isOpen = false;
5443
+ cleanup;
5444
+ toggle() {
5445
+ this.isOpen ? this.close() : this.open();
5446
+ }
5447
+ open() {
5448
+ this.isOpen = true;
5449
+ this.onOpen.emit();
5450
+ setTimeout(() => this.updatePosition());
5451
+ }
5452
+ close() {
5453
+ this.isOpen = false;
5454
+ this.onClose.emit();
5455
+ if (this.cleanup)
5456
+ this.cleanup();
5457
+ }
5458
+ updatePosition() {
5459
+ if (!this.triggerEl || !this.popoverEl)
5460
+ return;
5461
+ this.cleanup = autoUpdate(this.triggerEl.nativeElement, this.popoverEl.nativeElement, () => {
5462
+ computePosition(this.triggerEl.nativeElement, this.popoverEl.nativeElement, {
5463
+ placement: this.placement,
5464
+ middleware: [offset(8), flip(), shift({ padding: 8 })],
5465
+ }).then(({ x, y }) => {
5466
+ Object.assign(this.popoverEl.nativeElement.style, {
5467
+ left: `${x}px`,
5468
+ top: `${y}px`,
5469
+ });
5470
+ });
5471
+ });
5472
+ }
5473
+ onClickOutside(event) {
5474
+ if (this.isOpen &&
5475
+ !this.triggerEl.nativeElement.contains(event.target) &&
5476
+ !this.popoverEl?.nativeElement.contains(event.target)) {
5477
+ this.close();
5478
+ }
5479
+ }
5480
+ ngOnDestroy() {
5481
+ if (this.cleanup)
5482
+ this.cleanup();
5483
+ }
5484
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5485
+ 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: `
5486
+ <div class="inline-block" #trigger (click)="toggle()">
5487
+ <ng-content select="[trigger]"></ng-content>
5488
+ </div>
5489
+
5490
+ <div
5491
+ *ngIf="isOpen"
5492
+ #popover
5493
+ class="absolute top-0 left-0 w-max z-[9999]"
5494
+ >
5495
+ <ng-content></ng-content>
5496
+ </div>
5497
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
5498
+ }
5499
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PopoverComponent, decorators: [{
5500
+ type: Component,
5501
+ args: [{
5502
+ selector: 'tolle-popover',
5503
+ standalone: true,
5504
+ imports: [CommonModule],
5505
+ template: `
5506
+ <div class="inline-block" #trigger (click)="toggle()">
5507
+ <ng-content select="[trigger]"></ng-content>
5508
+ </div>
5509
+
5510
+ <div
5511
+ *ngIf="isOpen"
5512
+ #popover
5513
+ class="absolute top-0 left-0 w-max z-[9999]"
5514
+ >
5515
+ <ng-content></ng-content>
5516
+ </div>
5517
+ `,
5518
+ }]
5519
+ }], propDecorators: { placement: [{
5520
+ type: Input
5521
+ }], onOpen: [{
5522
+ type: Output
5523
+ }], onClose: [{
5524
+ type: Output
5525
+ }], triggerEl: [{
5526
+ type: ViewChild,
5527
+ args: ['trigger']
5528
+ }], popoverEl: [{
5529
+ type: ViewChild,
5530
+ args: ['popover']
5531
+ }], onClickOutside: [{
5532
+ type: HostListener,
5533
+ args: ['document:mousedown', ['$event']]
5534
+ }] } });
5535
+
5536
+ class PopoverContentComponent {
5537
+ class = '';
5538
+ cn = cn;
5539
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PopoverContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5540
+ 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: `
5541
+ <div
5542
+ [class]="cn(
5543
+ 'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none',
5544
+ 'animate-in fade-in zoom-in-95 duration-200',
5545
+ class
5546
+ )"
5547
+ role="dialog"
5548
+ >
5549
+ <ng-content></ng-content>
5550
+ </div>
5551
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
5552
+ }
5553
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PopoverContentComponent, decorators: [{
5554
+ type: Component,
5555
+ args: [{
5556
+ selector: 'tolle-popover-content',
5557
+ standalone: true,
5558
+ imports: [CommonModule],
5559
+ template: `
5560
+ <div
5561
+ [class]="cn(
5562
+ 'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none',
5563
+ 'animate-in fade-in zoom-in-95 duration-200',
5564
+ class
5565
+ )"
5566
+ role="dialog"
5567
+ >
5568
+ <ng-content></ng-content>
5569
+ </div>
5570
+ `
5571
+ }]
5572
+ }], propDecorators: { class: [{
5573
+ type: Input
5574
+ }] } });
5575
+
5576
+ class RadioService {
5577
+ selectedValueSource = new BehaviorSubject(null);
5578
+ selectedValue$ = this.selectedValueSource.asObservable();
5579
+ disabledSource = new BehaviorSubject(false);
5580
+ disabled$ = this.disabledSource.asObservable();
5581
+ select(value) {
5582
+ if (!this.disabledSource.value) {
5583
+ this.selectedValueSource.next(value);
5584
+ }
5585
+ }
5586
+ setDisabled(isDisabled) {
5587
+ this.disabledSource.next(isDisabled);
5588
+ }
5589
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RadioService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
5590
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RadioService });
5591
+ }
5592
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RadioService, decorators: [{
5593
+ type: Injectable
5594
+ }] });
5595
+
5596
+ class RadioGroupComponent {
5597
+ radioService;
5598
+ class = '';
5599
+ disabled = false;
5600
+ name = `radio-group-${Math.random().toString(36).substring(2, 9)}`;
5601
+ value;
5602
+ onChange = () => { };
5603
+ onTouched = () => { };
5604
+ constructor(radioService) {
5605
+ this.radioService = radioService;
5606
+ this.radioService.selectedValue$.subscribe(val => {
5607
+ this.value = val;
5608
+ this.onChange(val);
5609
+ });
5610
+ }
5611
+ setDisabledState(isDisabled) {
5612
+ this.disabled = isDisabled;
5613
+ this.radioService.setDisabled(isDisabled);
5614
+ }
5615
+ ngOnChanges() {
5616
+ this.radioService.setDisabled(this.disabled);
5617
+ }
5618
+ writeValue(value) {
5619
+ this.value = value;
5620
+ this.radioService.select(value);
5621
+ }
5622
+ registerOnChange(fn) { this.onChange = fn; }
5623
+ registerOnTouched(fn) { this.onTouched = fn; }
5624
+ cn = cn;
5625
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RadioGroupComponent, deps: [{ token: RadioService }], target: i0.ɵɵFactoryTarget.Component });
5626
+ 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: [
5627
+ RadioService,
5628
+ {
5629
+ provide: NG_VALUE_ACCESSOR,
5630
+ useExisting: forwardRef(() => RadioGroupComponent),
5631
+ multi: true
5632
+ }
5633
+ ], usesOnChanges: true, ngImport: i0, template: `
5634
+ <div [class]="cn('grid gap-2', class)" role="radiogroup">
5635
+ <ng-content></ng-content>
5636
+ </div>
5637
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
5638
+ }
5639
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RadioGroupComponent, decorators: [{
5640
+ type: Component,
5641
+ args: [{
5642
+ selector: 'tolle-radio-group',
5643
+ standalone: true,
5644
+ imports: [CommonModule],
5645
+ providers: [
5646
+ RadioService,
5647
+ {
5648
+ provide: NG_VALUE_ACCESSOR,
5649
+ useExisting: forwardRef(() => RadioGroupComponent),
5650
+ multi: true
5651
+ }
5652
+ ],
5653
+ template: `
5654
+ <div [class]="cn('grid gap-2', class)" role="radiogroup">
5655
+ <ng-content></ng-content>
5656
+ </div>
5657
+ `
5658
+ }]
5659
+ }], ctorParameters: () => [{ type: RadioService }], propDecorators: { class: [{
5660
+ type: Input
5661
+ }], disabled: [{
5662
+ type: Input
5663
+ }], name: [{
5664
+ type: Input
5665
+ }] } });
5666
+
5667
+ class RadioItemComponent {
5668
+ radioService;
5669
+ cdr;
5670
+ value;
5671
+ disabled = false;
5672
+ class = '';
5673
+ isSelected = false;
5674
+ groupDisabled = false;
5675
+ sub = new Subscription();
5676
+ get isEffectiveDisabled() {
5677
+ return this.disabled || this.groupDisabled;
5678
+ }
5679
+ // Inject ChangeDetectorRef to ensure UI updates when service emits
5680
+ constructor(radioService, cdr) {
5681
+ this.radioService = radioService;
5682
+ this.cdr = cdr;
5683
+ }
5684
+ ngOnInit() {
5685
+ // Listen for selection changes
5686
+ this.sub.add(this.radioService.selectedValue$.subscribe(val => {
5687
+ this.isSelected = (val === this.value);
5688
+ this.cdr.markForCheck(); // Trigger UI refresh
5689
+ }));
5690
+ // Listen for group-level disabled state
5691
+ this.sub.add(this.radioService.disabled$.subscribe(dis => {
5692
+ this.groupDisabled = dis;
5693
+ this.cdr.markForCheck(); // Trigger UI refresh
5694
+ }));
5695
+ }
5696
+ select() {
5697
+ this.radioService.select(this.value);
5698
+ }
5699
+ ngOnDestroy() {
5700
+ this.sub.unsubscribe(); // Clean up subscriptions
5701
+ }
5702
+ cn = cn;
5703
+ 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 });
5704
+ 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: `
5705
+ <div
5706
+ (click)="!isEffectiveDisabled && select()"
5707
+ [class]="cn(
5708
+ 'flex items-center space-x-2 group py-1',
5709
+ isEffectiveDisabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'
5710
+ )"
5711
+ >
5712
+ <div [class]="cn(
5713
+ 'aspect-square h-4 w-4 rounded-full border border-primary text-primary transition-all flex items-center justify-center',
5714
+ 'ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
5715
+ !isEffectiveDisabled && 'group-hover:border-primary/70',
5716
+ isSelected ? 'bg-background' : 'bg-transparent',
5717
+ class
5718
+ )">
5719
+ <div
5720
+ *ngIf="isSelected"
5721
+ class="h-2.5 w-2.5 rounded-full bg-primary animate-in zoom-in-50 duration-200"
5722
+ ></div>
5723
+ </div>
5724
+
5725
+ <label class="text-sm font-medium leading-none select-none" [class.cursor-pointer]="!isEffectiveDisabled">
5726
+ <ng-content></ng-content>
5727
+ </label>
5728
+ </div>
5729
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
5730
+ }
5731
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RadioItemComponent, decorators: [{
5732
+ type: Component,
5733
+ args: [{
5734
+ selector: 'tolle-radio-item',
5735
+ standalone: true,
5736
+ imports: [CommonModule],
5737
+ template: `
5738
+ <div
5739
+ (click)="!isEffectiveDisabled && select()"
5740
+ [class]="cn(
5741
+ 'flex items-center space-x-2 group py-1',
5742
+ isEffectiveDisabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'
5743
+ )"
5744
+ >
5745
+ <div [class]="cn(
5746
+ 'aspect-square h-4 w-4 rounded-full border border-primary text-primary transition-all flex items-center justify-center',
5747
+ 'ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
5748
+ !isEffectiveDisabled && 'group-hover:border-primary/70',
5749
+ isSelected ? 'bg-background' : 'bg-transparent',
5750
+ class
5751
+ )">
5752
+ <div
5753
+ *ngIf="isSelected"
5754
+ class="h-2.5 w-2.5 rounded-full bg-primary animate-in zoom-in-50 duration-200"
5755
+ ></div>
5756
+ </div>
5757
+
5758
+ <label class="text-sm font-medium leading-none select-none" [class.cursor-pointer]="!isEffectiveDisabled">
5759
+ <ng-content></ng-content>
5760
+ </label>
5761
+ </div>
5762
+ `
5763
+ }]
5764
+ }], ctorParameters: () => [{ type: RadioService }, { type: i0.ChangeDetectorRef }], propDecorators: { value: [{
5765
+ type: Input
5766
+ }], disabled: [{
5767
+ type: Input
5768
+ }], class: [{
5769
+ type: Input
5770
+ }] } });
5771
+
4243
5772
  /*
4244
5773
  * Public API Surface of tolle
4245
5774
  */
@@ -4248,5 +5777,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
4248
5777
  * Generated bundle index. Do not edit.
4249
5778
  */
4250
5779
 
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
5780
+ 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 };
5781
+ //# sourceMappingURL=tolle-ui.mjs.map