@tolle_/tolle-ui 0.0.15-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.
@@ -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']
@@ -1568,7 +1639,7 @@ class MultiSelectComponent {
1568
1639
  </div>
1569
1640
  </div>
1570
1641
  </div>
1571
- `, 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"] }] });
1572
1643
  }
1573
1644
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MultiSelectComponent, decorators: [{
1574
1645
  type: Component,
@@ -2513,7 +2584,7 @@ class PaginationComponent {
2513
2584
  </div>
2514
2585
  </div>
2515
2586
  </div>
2516
- `, 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 });
2517
2588
  }
2518
2589
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PaginationComponent, decorators: [{
2519
2590
  type: Component,
@@ -2642,6 +2713,16 @@ class DataTableComponent {
2642
2713
  pageSize = 10;
2643
2714
  expandable = false;
2644
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
+ }
2645
2726
  // Track which rows are open
2646
2727
  expandedRows = new Set();
2647
2728
  // Use ContentChildren to grab the tolleCell templates from the user's HTML
@@ -2687,11 +2768,25 @@ class DataTableComponent {
2687
2768
  if (changes['data']) {
2688
2769
  this.refreshTable();
2689
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
+ });
2690
2782
  }
2691
2783
  // --- Search & Sort & Page Logic ---
2692
2784
  // (Your existing implementation of applySearch, applySort, and updatePage goes here)
2693
2785
  refreshTable() { this.applySearch(); this.applySort(); this.updatePage(); }
2694
2786
  onSearch() { this.currentPage = 1; this.refreshTable(); }
2787
+ toggleColumn(key) {
2788
+ this.columnVisibility[key] = !this.columnVisibility[key];
2789
+ }
2695
2790
  applySearch() {
2696
2791
  if (!this.searchTerm) {
2697
2792
  this.filteredData = [...this.data];
@@ -2749,7 +2844,7 @@ class DataTableComponent {
2749
2844
  return this.cellTemplates?.find(t => t.name === key);
2750
2845
  }
2751
2846
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DataTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2752
- 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: `
2753
2848
  <div class="space-y-4">
2754
2849
  <div *ngIf="searchable" class="flex items-center py-2">
2755
2850
  <tolle-input
@@ -2837,7 +2932,7 @@ class DataTableComponent {
2837
2932
  (onPageSizeChange)="updatePage()"
2838
2933
  ></tolle-pagination>
2839
2934
  </div>
2840
- `, 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"] }] });
2841
2936
  }
2842
2937
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DataTableComponent, decorators: [{
2843
2938
  type: Component,
@@ -2949,6 +3044,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
2949
3044
  type: Input
2950
3045
  }], size: [{
2951
3046
  type: Input
3047
+ }], allowColumnHiding: [{
3048
+ type: Input
3049
+ }], showSettings: [{
3050
+ type: Input
2952
3051
  }], cellTemplates: [{
2953
3052
  type: ContentChildren,
2954
3053
  args: [TolleCellDirective]
@@ -3743,7 +3842,7 @@ class DateRangePickerComponent {
3743
3842
  ></tolle-range-calendar>
3744
3843
  </div>
3745
3844
  </div>
3746
- `, 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"] }] });
3747
3846
  }
3748
3847
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DateRangePickerComponent, decorators: [{
3749
3848
  type: Component,
@@ -3955,6 +4054,176 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
3955
4054
  args: ['click']
3956
4055
  }] } });
3957
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
+
3958
4227
  /*
3959
4228
  * Public API Surface of tolle
3960
4229
  */
@@ -3963,5 +4232,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
3963
4232
  * Generated bundle index. Do not edit.
3964
4233
  */
3965
4234
 
3966
- 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, ToastContainerComponent, 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 };
3967
4236
  //# sourceMappingURL=tolle_-tolle-ui.mjs.map