@tolle_/tolle-ui 0.0.14-beta → 0.0.17-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.
@@ -1,7 +1,7 @@
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, PLATFORM_ID, Inject, InjectionToken, APP_INITIALIZER, inject, ChangeDetectorRef, ChangeDetectionStrategy, TemplateRef, Injector } from '@angular/core';
4
+ import { Component, Input, forwardRef, Injectable, Optional, HostListener, ViewChild, ContentChildren, EventEmitter, Output, Directive, inject, PLATFORM_ID, Inject, InjectionToken, APP_INITIALIZER, ChangeDetectorRef, ChangeDetectionStrategy, TemplateRef, Injector } from '@angular/core';
5
5
  import * as i1 from '@angular/common';
6
6
  import { CommonModule, isPlatformBrowser, DOCUMENT } from '@angular/common';
7
7
  import { cva } from 'class-variance-authority';
@@ -108,78 +108,107 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
108
108
 
109
109
  class InputComponent {
110
110
  cdr;
111
+ id = `input-${Math.random().toString(36).substr(2, 9)}`;
112
+ label = '';
113
+ hint = '';
114
+ errorMessage = '';
111
115
  type = 'text';
112
116
  placeholder = '';
113
- disabled = false;
114
- error = false;
115
117
  size = 'default';
116
118
  containerClass = '';
117
119
  class = '';
118
- // Internal State
120
+ // New States
121
+ disabled = false;
122
+ readonly = false;
123
+ error = false;
119
124
  value = '';
120
- // CVA Callbacks
121
125
  onChange = () => { };
122
126
  onTouched = () => { };
123
127
  constructor(cdr) {
124
128
  this.cdr = cdr;
125
129
  }
126
- // --- ControlValueAccessor Implementation ---
127
130
  writeValue(value) {
128
131
  this.value = value;
129
132
  this.cdr.markForCheck();
130
133
  }
131
- registerOnChange(fn) {
132
- this.onChange = fn;
133
- }
134
- registerOnTouched(fn) {
135
- this.onTouched = fn;
136
- }
134
+ registerOnChange(fn) { this.onChange = fn; }
135
+ registerOnTouched(fn) { this.onTouched = fn; }
137
136
  setDisabledState(isDisabled) {
138
137
  this.disabled = isDisabled;
139
138
  this.cdr.markForCheck();
140
139
  }
141
140
  onInputChange(event) {
141
+ if (this.readonly || this.disabled)
142
+ return;
142
143
  const val = event.target.value;
143
144
  this.value = val;
144
145
  this.onChange(val);
145
146
  }
146
- // --- Styling Logic ---
147
147
  cn = cn;
148
148
  get computedContainerClass() {
149
- return cn("group relative flex items-center w-full rounded-md border border-input bg-background ring-offset-background transition-all focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-1 shadow-sm", 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", this.disabled && "cursor-not-allowed opacity-50", this.error && "border-destructive focus-within:ring-destructive", this.containerClass);
149
+ return cn("group relative flex items-center w-full rounded-md border transition-all shadow-sm", "bg-background ring-offset-background",
150
+ // Sizing
151
+ 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",
152
+ // Interaction States (Focus ring disabled for Readonly/Disabled)
153
+ !(this.readonly || this.disabled) && "focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-1",
154
+ // Colors & Borders
155
+ this.error ? "border-destructive focus-within:ring-destructive" : "border-input",
156
+ // Disabled vs Readonly styling
157
+ 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);
150
158
  }
151
159
  get computedInputClass() {
152
- return cn("flex-1 bg-transparent border-none p-0 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-0 disabled:cursor-not-allowed", this.size === 'xs' && "text-xs", this.size === 'lg' && "text-base", this.class);
160
+ 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);
153
161
  }
154
162
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: InputComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
155
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: InputComponent, isStandalone: true, selector: "tolle-input", inputs: { type: "type", placeholder: "placeholder", disabled: "disabled", error: "error", size: "size", containerClass: "containerClass", class: "class" }, providers: [
163
+ 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: [
156
164
  {
157
165
  provide: NG_VALUE_ACCESSOR,
158
166
  useExisting: forwardRef(() => InputComponent),
159
167
  multi: true
160
168
  }
161
169
  ], ngImport: i0, template: `
162
- <div [class]="computedContainerClass">
170
+ <div class="flex flex-col gap-1.5 w-full">
171
+ <label
172
+ *ngIf="label"
173
+ [for]="id"
174
+ [class.opacity-50]="disabled"
175
+ class="text-sm font-medium text-foreground leading-none transition-opacity"
176
+ >
177
+ {{ label }}
178
+ </label>
163
179
 
164
- <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors">
165
- <ng-content select="[prefix]"></ng-content>
166
- </div>
180
+ <div [class]="computedContainerClass">
181
+ <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors">
182
+ <ng-content select="[prefix]"></ng-content>
183
+ </div>
167
184
 
168
- <input
169
- [type]="type"
170
- [placeholder]="placeholder"
171
- [disabled]="disabled"
172
- [(ngModel)]="value"
173
- (blur)="onTouched()"
174
- (input)="onInputChange($event)"
175
- [class]="computedInputClass"
176
- />
185
+ <input
186
+ [id]="id"
187
+ [type]="type"
188
+ [placeholder]="placeholder"
189
+ [disabled]="disabled"
190
+ [readOnly]="readonly"
191
+ [(ngModel)]="value"
192
+ (blur)="onTouched()"
193
+ (input)="onInputChange($event)"
194
+ [class]="computedInputClass"
195
+ />
177
196
 
178
- <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors">
179
- <ng-content select="[suffix]"></ng-content>
197
+ <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors">
198
+ <ng-content select="[suffix]"></ng-content>
199
+ </div>
180
200
  </div>
201
+
202
+ <ng-container *ngIf="!disabled">
203
+ <p *ngIf="hint && !error" class="text-xs text-muted-foreground px-1">
204
+ {{ hint }}
205
+ </p>
206
+ <p *ngIf="error && errorMessage" class="text-xs text-destructive px-1">
207
+ {{ errorMessage }}
208
+ </p>
209
+ </ng-container>
181
210
  </div>
182
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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"] }] });
211
+ `, 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.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"] }] });
183
212
  }
184
213
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: InputComponent, decorators: [{
185
214
  type: Component,
@@ -195,35 +224,60 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
195
224
  }
196
225
  ],
197
226
  template: `
198
- <div [class]="computedContainerClass">
227
+ <div class="flex flex-col gap-1.5 w-full">
228
+ <label
229
+ *ngIf="label"
230
+ [for]="id"
231
+ [class.opacity-50]="disabled"
232
+ class="text-sm font-medium text-foreground leading-none transition-opacity"
233
+ >
234
+ {{ label }}
235
+ </label>
199
236
 
200
- <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors">
201
- <ng-content select="[prefix]"></ng-content>
202
- </div>
237
+ <div [class]="computedContainerClass">
238
+ <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors">
239
+ <ng-content select="[prefix]"></ng-content>
240
+ </div>
203
241
 
204
- <input
205
- [type]="type"
206
- [placeholder]="placeholder"
207
- [disabled]="disabled"
208
- [(ngModel)]="value"
209
- (blur)="onTouched()"
210
- (input)="onInputChange($event)"
211
- [class]="computedInputClass"
212
- />
242
+ <input
243
+ [id]="id"
244
+ [type]="type"
245
+ [placeholder]="placeholder"
246
+ [disabled]="disabled"
247
+ [readOnly]="readonly"
248
+ [(ngModel)]="value"
249
+ (blur)="onTouched()"
250
+ (input)="onInputChange($event)"
251
+ [class]="computedInputClass"
252
+ />
213
253
 
214
- <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors">
215
- <ng-content select="[suffix]"></ng-content>
254
+ <div class="flex items-center text-muted-foreground group-focus-within:text-primary transition-colors">
255
+ <ng-content select="[suffix]"></ng-content>
256
+ </div>
216
257
  </div>
258
+
259
+ <ng-container *ngIf="!disabled">
260
+ <p *ngIf="hint && !error" class="text-xs text-muted-foreground px-1">
261
+ {{ hint }}
262
+ </p>
263
+ <p *ngIf="error && errorMessage" class="text-xs text-destructive px-1">
264
+ {{ errorMessage }}
265
+ </p>
266
+ </ng-container>
217
267
  </div>
218
268
  `,
219
269
  }]
220
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { type: [{
270
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { id: [{
221
271
  type: Input
222
- }], placeholder: [{
272
+ }], label: [{
223
273
  type: Input
224
- }], disabled: [{
274
+ }], hint: [{
225
275
  type: Input
226
- }], error: [{
276
+ }], errorMessage: [{
277
+ type: Input
278
+ }], type: [{
279
+ type: Input
280
+ }], placeholder: [{
227
281
  type: Input
228
282
  }], size: [{
229
283
  type: Input
@@ -231,6 +285,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
231
285
  type: Input
232
286
  }], class: [{
233
287
  type: Input
288
+ }], disabled: [{
289
+ type: Input
290
+ }], readonly: [{
291
+ type: Input
292
+ }], error: [{
293
+ type: Input
234
294
  }] } });
235
295
 
236
296
  class CardComponent {
@@ -426,6 +486,7 @@ class SelectComponent {
426
486
  disabled = false;
427
487
  searchable = false;
428
488
  size = 'default';
489
+ readonly = false;
429
490
  trigger;
430
491
  popover;
431
492
  items;
@@ -453,11 +514,19 @@ class SelectComponent {
453
514
  }
454
515
  // UPDATED: Centralized sizing logic for the trigger
455
516
  get computedTriggerClass() {
456
- return cn('flex w-full items-center justify-between rounded-md border border-input bg-background ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring focus:ring-ring focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 transition-all', 'disabled:opacity-50 shadow-sm transition-shadow', this.size === 'xs' && 'h-8 px-2 text-xs', this.size === 'sm' && 'h-9 px-3 text-sm', this.size === 'default' && 'h-10 px-3 text-sm', this.size === 'lg' && 'h-11 px-4 text-base', this.class);
517
+ 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',
518
+ // Sizing
519
+ 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',
520
+ // Interaction States (Focus ring disabled for Readonly/Disabled)
521
+ !(this.readonly || this.disabled) && 'focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1',
522
+ // Colors & Borders (Matching your Hex-based theme logic)
523
+ 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);
457
524
  }
458
525
  // UPDATED: Dynamic icon sizing relative to the trigger size
459
526
  get iconClass() {
460
- return cn('ri-arrow-down-s-line text-muted-foreground ml-2 transition-transform duration-200', this.isOpen ? 'rotate-180' : '', (this.size === 'xs' || this.size === 'sm') ? 'text-[14px]' : 'text-[18px]');
527
+ return cn('ri-arrow-down-s-line text-muted-foreground ml-2 transition-transform duration-200', this.isOpen ? 'rotate-180' : '', (this.size === 'xs' || this.size === 'sm') ? 'text-[14px]' : 'text-[18px]',
528
+ // Hide or fade icon when interaction is blocked
529
+ (this.disabled || this.readonly) && 'opacity-30');
461
530
  }
462
531
  ngAfterContentInit() {
463
532
  this.updateItemSelection();
@@ -471,7 +540,7 @@ class SelectComponent {
471
540
  }
472
541
  }
473
542
  toggle() {
474
- if (this.disabled)
543
+ if (this.disabled || this.readonly)
475
544
  return;
476
545
  this.isOpen ? this.close() : this.open();
477
546
  }
@@ -538,7 +607,7 @@ class SelectComponent {
538
607
  this.cleanupAutoUpdate();
539
608
  }
540
609
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SelectComponent, deps: [{ token: SelectService }], target: i0.ɵɵFactoryTarget.Component });
541
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: SelectComponent, isStandalone: true, selector: "tolle-select", inputs: { placeholder: "placeholder", class: "class", disabled: "disabled", searchable: "searchable", size: "size" }, host: { listeners: { "document:mousedown": "onDocumentClick($event)" } }, providers: [
610
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: SelectComponent, isStandalone: true, selector: "tolle-select", inputs: { placeholder: "placeholder", class: "class", disabled: "disabled", searchable: "searchable", size: "size", readonly: "readonly" }, host: { listeners: { "document:mousedown": "onDocumentClick($event)" } }, providers: [
542
611
  SelectService,
543
612
  {
544
613
  provide: NG_VALUE_ACCESSOR,
@@ -585,7 +654,7 @@ class SelectComponent {
585
654
  </div>
586
655
  </div>
587
656
  </div>
588
- `, 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: ["type", "placeholder", "disabled", "error", "size", "containerClass", "class"] }] });
657
+ `, 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"] }] });
589
658
  }
590
659
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SelectComponent, decorators: [{
591
660
  type: Component,
@@ -653,6 +722,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
653
722
  type: Input
654
723
  }], size: [{
655
724
  type: Input
725
+ }], readonly: [{
726
+ type: Input
656
727
  }], trigger: [{
657
728
  type: ViewChild,
658
729
  args: ['trigger']
@@ -1159,6 +1230,94 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
1159
1230
  args: [{ providedIn: 'root' }]
1160
1231
  }], ctorParameters: () => [] });
1161
1232
 
1233
+ // projects/tolle/src/lib/toast-container.component.ts
1234
+ class ToastContainerComponent {
1235
+ toastService = inject(ToastService);
1236
+ position = 'bottom-right';
1237
+ toasts$ = this.toastService.toasts$;
1238
+ get positionClasses() {
1239
+ const pos = {
1240
+ 'top-right': 'top-0 right-0 flex-col-reverse',
1241
+ 'top-left': 'top-0 left-0 flex-col-reverse',
1242
+ 'bottom-right': 'bottom-0 right-0',
1243
+ 'bottom-left': 'bottom-0 left-0',
1244
+ 'top-center': 'top-0 left-1/2 -translate-x-1/2 flex-col-reverse',
1245
+ 'bottom-center': 'bottom-0 left-1/2 -translate-x-1/2'
1246
+ };
1247
+ return pos[this.position];
1248
+ }
1249
+ cn = cn;
1250
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ToastContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1251
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ToastContainerComponent, isStandalone: true, selector: "tolle-toaster", inputs: { position: "position" }, ngImport: i0, template: `
1252
+ <div [class]="cn('fixed z-[100] flex flex-col gap-2 w-full max-w-[380px] p-4', positionClasses)">
1253
+ <div
1254
+ *ngFor="let toast of toasts$ | async"
1255
+ (mouseenter)="toastService.setPaused(toast.id, true)"
1256
+ (mouseleave)="toastService.setPaused(toast.id, false)"
1257
+ [class]="cn(
1258
+ 'relative overflow-hidden p-4 rounded-md border border-border shadow-lg flex items-start justify-between gap-4 transition-all duration-300 bg-background text-foreground',
1259
+ toast.variant === 'destructive' && 'border-destructive/50 text-destructive'
1260
+ )"
1261
+ >
1262
+ <div class="grid gap-1">
1263
+ <div *ngIf="toast.title" class="text-sm font-semibold">{{ toast.title }}</div>
1264
+ <div class="text-xs opacity-90">{{ toast.description }}</div>
1265
+ </div>
1266
+
1267
+ <button (click)="toastService.remove(toast.id)" class="opacity-50 hover:opacity-100">
1268
+ <i class="ri-close-line"></i>
1269
+ </button>
1270
+
1271
+ <div
1272
+ class="absolute bottom-0 left-0 h-1 transition-all duration-100 ease-linear"
1273
+ [style.width.%]="(toast.remainingTime / (toast.duration || 3000)) * 100"
1274
+ [class.bg-destructive]="toast.variant === 'destructive'"
1275
+ [class.bg-primary]="toast.variant !== 'destructive'"
1276
+ ></div>
1277
+ </div>
1278
+ </div>
1279
+ `, 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: "pipe", type: i1.AsyncPipe, name: "async" }] });
1280
+ }
1281
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ToastContainerComponent, decorators: [{
1282
+ type: Component,
1283
+ args: [{
1284
+ selector: 'tolle-toaster',
1285
+ standalone: true,
1286
+ imports: [CommonModule],
1287
+ template: `
1288
+ <div [class]="cn('fixed z-[100] flex flex-col gap-2 w-full max-w-[380px] p-4', positionClasses)">
1289
+ <div
1290
+ *ngFor="let toast of toasts$ | async"
1291
+ (mouseenter)="toastService.setPaused(toast.id, true)"
1292
+ (mouseleave)="toastService.setPaused(toast.id, false)"
1293
+ [class]="cn(
1294
+ 'relative overflow-hidden p-4 rounded-md border border-border shadow-lg flex items-start justify-between gap-4 transition-all duration-300 bg-background text-foreground',
1295
+ toast.variant === 'destructive' && 'border-destructive/50 text-destructive'
1296
+ )"
1297
+ >
1298
+ <div class="grid gap-1">
1299
+ <div *ngIf="toast.title" class="text-sm font-semibold">{{ toast.title }}</div>
1300
+ <div class="text-xs opacity-90">{{ toast.description }}</div>
1301
+ </div>
1302
+
1303
+ <button (click)="toastService.remove(toast.id)" class="opacity-50 hover:opacity-100">
1304
+ <i class="ri-close-line"></i>
1305
+ </button>
1306
+
1307
+ <div
1308
+ class="absolute bottom-0 left-0 h-1 transition-all duration-100 ease-linear"
1309
+ [style.width.%]="(toast.remainingTime / (toast.duration || 3000)) * 100"
1310
+ [class.bg-destructive]="toast.variant === 'destructive'"
1311
+ [class.bg-primary]="toast.variant !== 'destructive'"
1312
+ ></div>
1313
+ </div>
1314
+ </div>
1315
+ `
1316
+ }]
1317
+ }], propDecorators: { position: [{
1318
+ type: Input
1319
+ }] } });
1320
+
1162
1321
  class ThemeService {
1163
1322
  document;
1164
1323
  platformId;
@@ -1480,7 +1639,7 @@ class MultiSelectComponent {
1480
1639
  </div>
1481
1640
  </div>
1482
1641
  </div>
1483
- `, 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: ["type", "placeholder", "disabled", "error", "size", "containerClass", "class"] }] });
1642
+ `, 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"] }] });
1484
1643
  }
1485
1644
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MultiSelectComponent, decorators: [{
1486
1645
  type: Component,
@@ -2425,7 +2584,7 @@ class PaginationComponent {
2425
2584
  </div>
2426
2585
  </div>
2427
2586
  </div>
2428
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: SelectComponent, selector: "tolle-select", inputs: ["placeholder", "class", "disabled", "searchable", "size"] }, { kind: "component", type: SelectItemComponent, selector: "tolle-select-item", inputs: ["value", "class", "selected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2587
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: SelectComponent, selector: "tolle-select", inputs: ["placeholder", "class", "disabled", "searchable", "size", "readonly"] }, { kind: "component", type: SelectItemComponent, selector: "tolle-select-item", inputs: ["value", "class", "selected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2429
2588
  }
2430
2589
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PaginationComponent, decorators: [{
2431
2590
  type: Component,
@@ -2554,6 +2713,16 @@ class DataTableComponent {
2554
2713
  pageSize = 10;
2555
2714
  expandable = false;
2556
2715
  size = 'default';
2716
+ // --- NEW INPUTS FOR COLUMN HIDING ---
2717
+ allowColumnHiding = true;
2718
+ showSettings = true; // Set to false to hide the gear icon/menu entirely
2719
+ // Track visibility state: { 'columnKey': true/false }
2720
+ columnVisibility = {};
2721
+ showColumnMenu = false;
2722
+ // Filter columns based on visibility state
2723
+ get activeColumns() {
2724
+ return this.columns.filter(col => this.columnVisibility[col.key]);
2725
+ }
2557
2726
  // Track which rows are open
2558
2727
  expandedRows = new Set();
2559
2728
  // Use ContentChildren to grab the tolleCell templates from the user's HTML
@@ -2599,11 +2768,25 @@ class DataTableComponent {
2599
2768
  if (changes['data']) {
2600
2769
  this.refreshTable();
2601
2770
  }
2771
+ if (changes['columns']) {
2772
+ this.initializeVisibility();
2773
+ }
2774
+ }
2775
+ initializeVisibility() {
2776
+ // Default all columns to visible if not already set
2777
+ this.columns.forEach(col => {
2778
+ if (this.columnVisibility[col.key] === undefined) {
2779
+ this.columnVisibility[col.key] = true;
2780
+ }
2781
+ });
2602
2782
  }
2603
2783
  // --- Search & Sort & Page Logic ---
2604
2784
  // (Your existing implementation of applySearch, applySort, and updatePage goes here)
2605
2785
  refreshTable() { this.applySearch(); this.applySort(); this.updatePage(); }
2606
2786
  onSearch() { this.currentPage = 1; this.refreshTable(); }
2787
+ toggleColumn(key) {
2788
+ this.columnVisibility[key] = !this.columnVisibility[key];
2789
+ }
2607
2790
  applySearch() {
2608
2791
  if (!this.searchTerm) {
2609
2792
  this.filteredData = [...this.data];
@@ -2661,7 +2844,7 @@ class DataTableComponent {
2661
2844
  return this.cellTemplates?.find(t => t.name === key);
2662
2845
  }
2663
2846
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DataTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2664
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: DataTableComponent, isStandalone: true, selector: "tolle-data-table", inputs: { data: "data", columns: "columns", searchable: "searchable", paginate: "paginate", pageSize: "pageSize", expandable: "expandable", size: "size", expandedTemplate: "expandedTemplate" }, queries: [{ propertyName: "cellTemplates", predicate: TolleCellDirective }], usesOnChanges: true, ngImport: i0, template: `
2847
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: DataTableComponent, isStandalone: true, selector: "tolle-data-table", inputs: { data: "data", columns: "columns", searchable: "searchable", paginate: "paginate", pageSize: "pageSize", expandable: "expandable", size: "size", allowColumnHiding: "allowColumnHiding", showSettings: "showSettings", expandedTemplate: "expandedTemplate" }, queries: [{ propertyName: "cellTemplates", predicate: TolleCellDirective }], usesOnChanges: true, ngImport: i0, template: `
2665
2848
  <div class="space-y-4">
2666
2849
  <div *ngIf="searchable" class="flex items-center py-2">
2667
2850
  <tolle-input
@@ -2749,7 +2932,7 @@ class DataTableComponent {
2749
2932
  (onPageSizeChange)="updatePage()"
2750
2933
  ></tolle-pagination>
2751
2934
  </div>
2752
- `, 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: ["type", "placeholder", "disabled", "error", "size", "containerClass", "class"] }] });
2935
+ `, 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"] }] });
2753
2936
  }
2754
2937
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DataTableComponent, decorators: [{
2755
2938
  type: Component,
@@ -2861,6 +3044,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
2861
3044
  type: Input
2862
3045
  }], size: [{
2863
3046
  type: Input
3047
+ }], allowColumnHiding: [{
3048
+ type: Input
3049
+ }], showSettings: [{
3050
+ type: Input
2864
3051
  }], cellTemplates: [{
2865
3052
  type: ContentChildren,
2866
3053
  args: [TolleCellDirective]
@@ -3655,7 +3842,7 @@ class DateRangePickerComponent {
3655
3842
  ></tolle-range-calendar>
3656
3843
  </div>
3657
3844
  </div>
3658
- `, 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: ["type", "placeholder", "disabled", "error", "size", "containerClass", "class"] }] });
3845
+ `, 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"] }] });
3659
3846
  }
3660
3847
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DateRangePickerComponent, decorators: [{
3661
3848
  type: Component,
@@ -3867,6 +4054,176 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
3867
4054
  args: ['click']
3868
4055
  }] } });
3869
4056
 
4057
+ class TextareaComponent {
4058
+ textareaElement;
4059
+ id = `textarea-${Math.random().toString(36).substr(2, 9)}`;
4060
+ label = '';
4061
+ placeholder = '';
4062
+ hint = '';
4063
+ rows = 3;
4064
+ maxLength;
4065
+ showCharacterCount = false;
4066
+ autoGrow = false;
4067
+ error = false;
4068
+ className = '';
4069
+ // New States
4070
+ disabled = false;
4071
+ readonly = false;
4072
+ value = '';
4073
+ onChange = () => { };
4074
+ onTouched = () => { };
4075
+ ngAfterViewInit() {
4076
+ if (this.autoGrow)
4077
+ this.resize();
4078
+ }
4079
+ get textareaClasses() {
4080
+ 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',
4081
+ // Focus States (Disabled only when readonly or disabled is true)
4082
+ !(this.readonly || this.disabled) && 'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',
4083
+ // Border colors
4084
+ this.error ? 'border-destructive' : 'border-input',
4085
+ // Disabled vs Readonly styles
4086
+ 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);
4087
+ }
4088
+ handleInput(event) {
4089
+ if (this.readonly || this.disabled)
4090
+ return;
4091
+ const val = event.target.value;
4092
+ this.value = val;
4093
+ this.onChange(val);
4094
+ if (this.autoGrow)
4095
+ this.resize();
4096
+ }
4097
+ resize() {
4098
+ const textarea = this.textareaElement.nativeElement;
4099
+ textarea.style.height = 'auto';
4100
+ textarea.style.height = `${textarea.scrollHeight}px`;
4101
+ }
4102
+ writeValue(value) {
4103
+ this.value = value;
4104
+ if (this.autoGrow)
4105
+ setTimeout(() => this.resize());
4106
+ }
4107
+ registerOnChange(fn) { this.onChange = fn; }
4108
+ registerOnTouched(fn) { this.onTouched = fn; }
4109
+ setDisabledState(isDisabled) { this.disabled = isDisabled; }
4110
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TextareaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4111
+ 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: [
4112
+ {
4113
+ provide: NG_VALUE_ACCESSOR,
4114
+ useExisting: forwardRef(() => TextareaComponent),
4115
+ multi: true
4116
+ }
4117
+ ], viewQueries: [{ propertyName: "textareaElement", first: true, predicate: ["textareaElement"], descendants: true }], ngImport: i0, template: `
4118
+ <div class="flex flex-col gap-1.5 w-full">
4119
+ <label *ngIf="label" [for]="id"
4120
+ [class.opacity-50]="disabled"
4121
+ class="text-sm font-medium text-foreground leading-none transition-opacity">
4122
+ {{ label }}
4123
+ </label>
4124
+
4125
+ <div class="relative">
4126
+ <textarea
4127
+ #textareaElement
4128
+ [id]="id"
4129
+ [placeholder]="placeholder"
4130
+ [disabled]="disabled"
4131
+ [readOnly]="readonly"
4132
+ [rows]="rows"
4133
+ [(ngModel)]="value"
4134
+ (input)="handleInput($event)"
4135
+ (blur)="onTouched()"
4136
+ [class]="textareaClasses"
4137
+ [style.resize]="(autoGrow || readonly || disabled) ? 'none' : 'vertical'"
4138
+ [style.overflow]="autoGrow ? 'hidden' : 'auto'"
4139
+ ></textarea>
4140
+ </div>
4141
+
4142
+ <div *ngIf="(showCharacterCount || hint) && !disabled" class="flex justify-between items-center px-1">
4143
+ <p *ngIf="hint" class="text-xs text-muted-foreground">{{ hint }}</p>
4144
+ <p *ngIf="showCharacterCount" class="text-[10px] uppercase tracking-wider text-muted-foreground ml-auto font-medium">
4145
+ {{ value.length || 0 }}{{ maxLength ? ' / ' + maxLength : '' }}
4146
+ </p>
4147
+ </div>
4148
+ </div>
4149
+ `, 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.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"] }] });
4150
+ }
4151
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TextareaComponent, decorators: [{
4152
+ type: Component,
4153
+ args: [{
4154
+ selector: 'tolle-textarea',
4155
+ standalone: true,
4156
+ imports: [CommonModule, FormsModule],
4157
+ providers: [
4158
+ {
4159
+ provide: NG_VALUE_ACCESSOR,
4160
+ useExisting: forwardRef(() => TextareaComponent),
4161
+ multi: true
4162
+ }
4163
+ ],
4164
+ template: `
4165
+ <div class="flex flex-col gap-1.5 w-full">
4166
+ <label *ngIf="label" [for]="id"
4167
+ [class.opacity-50]="disabled"
4168
+ class="text-sm font-medium text-foreground leading-none transition-opacity">
4169
+ {{ label }}
4170
+ </label>
4171
+
4172
+ <div class="relative">
4173
+ <textarea
4174
+ #textareaElement
4175
+ [id]="id"
4176
+ [placeholder]="placeholder"
4177
+ [disabled]="disabled"
4178
+ [readOnly]="readonly"
4179
+ [rows]="rows"
4180
+ [(ngModel)]="value"
4181
+ (input)="handleInput($event)"
4182
+ (blur)="onTouched()"
4183
+ [class]="textareaClasses"
4184
+ [style.resize]="(autoGrow || readonly || disabled) ? 'none' : 'vertical'"
4185
+ [style.overflow]="autoGrow ? 'hidden' : 'auto'"
4186
+ ></textarea>
4187
+ </div>
4188
+
4189
+ <div *ngIf="(showCharacterCount || hint) && !disabled" class="flex justify-between items-center px-1">
4190
+ <p *ngIf="hint" class="text-xs text-muted-foreground">{{ hint }}</p>
4191
+ <p *ngIf="showCharacterCount" class="text-[10px] uppercase tracking-wider text-muted-foreground ml-auto font-medium">
4192
+ {{ value.length || 0 }}{{ maxLength ? ' / ' + maxLength : '' }}
4193
+ </p>
4194
+ </div>
4195
+ </div>
4196
+ `
4197
+ }]
4198
+ }], propDecorators: { textareaElement: [{
4199
+ type: ViewChild,
4200
+ args: ['textareaElement']
4201
+ }], id: [{
4202
+ type: Input
4203
+ }], label: [{
4204
+ type: Input
4205
+ }], placeholder: [{
4206
+ type: Input
4207
+ }], hint: [{
4208
+ type: Input
4209
+ }], rows: [{
4210
+ type: Input
4211
+ }], maxLength: [{
4212
+ type: Input
4213
+ }], showCharacterCount: [{
4214
+ type: Input
4215
+ }], autoGrow: [{
4216
+ type: Input
4217
+ }], error: [{
4218
+ type: Input
4219
+ }], className: [{
4220
+ type: Input
4221
+ }], disabled: [{
4222
+ type: Input
4223
+ }], readonly: [{
4224
+ type: Input
4225
+ }] } });
4226
+
3870
4227
  /*
3871
4228
  * Public API Surface of tolle
3872
4229
  */
@@ -3875,5 +4232,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
3875
4232
  * Generated bundle index. Do not edit.
3876
4233
  */
3877
4234
 
3878
- 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, ThemeService, ToastService, TolleCellDirective, TooltipDirective, cn, provideTolleConfig };
4235
+ 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 };
3879
4236
  //# sourceMappingURL=tolle_-tolle-ui.mjs.map