ng-blatui 1.30.0 → 1.31.0

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.
@@ -174,8 +174,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
174
174
  }]
175
175
  }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
176
176
 
177
- const BASE$2 = 'inline-flex items-center justify-center rounded-md border font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden';
178
- const SIZES$6 = {
177
+ const BASE$1 = 'inline-flex items-center justify-center rounded-md border font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden';
178
+ const SIZES$4 = {
179
179
  sm: 'px-1.5 py-px text-[0.625rem]',
180
180
  default: 'px-2 py-0.5 text-xs',
181
181
  lg: 'px-3 py-1 text-sm [&>svg]:size-3.5',
@@ -252,7 +252,7 @@ class BuiBadge {
252
252
  computedClass = computed(() => {
253
253
  const tone = this.tone();
254
254
  const toneOrVariant = tone === null ? brandClass(this.variant()) : TONES$2[tone][intensityFor(this.variant())];
255
- return cn(BASE$2, SIZES$6[this.size()], toneOrVariant, this.userClass());
255
+ return cn(BASE$1, SIZES$4[this.size()], toneOrVariant, this.userClass());
256
256
  }, /* @ts-ignore */
257
257
  ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
258
258
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiBadge, deps: [], target: i0.ɵɵFactoryTarget.Directive });
@@ -558,16 +558,36 @@ const TEXTAREA_SIZES = {
558
558
  default: 'min-h-16 px-3 py-2 text-base md:text-sm',
559
559
  lg: 'min-h-20 px-4 py-2.5 text-base',
560
560
  };
561
- /** Applies BlatUI textarea styling to a native `<textarea>` (auto-grows via field-sizing). */
561
+ // Vertical padding (top + bottom) baked into each size preset, used to compute the `maxRows`
562
+ // height cap. Mirrors the `py-*` utilities in TEXTAREA_SIZES.
563
+ const TEXTAREA_PADDING_Y = {
564
+ sm: '0.75rem',
565
+ default: '1rem',
566
+ lg: '1.25rem',
567
+ };
568
+ /**
569
+ * Applies BlatUI textarea styling to a native `<textarea>`. Auto-grows with its content via CSS
570
+ * `field-sizing-content` (no JS). Set `[maxRows]` to cap the growth — past it the field scrolls.
571
+ */
562
572
  class BuiTextarea {
563
573
  /** Size preset controlling minimum height, padding and text size. */
564
574
  size = input('default', /* @ts-ignore */
565
575
  ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
576
+ /** Maximum number of rows before the textarea scrolls instead of growing (null = unlimited). */
577
+ maxRows = input(null, /* @ts-ignore */
578
+ ...(ngDevMode ? [{ debugName: "maxRows" }] : /* istanbul ignore next */ []));
566
579
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
567
580
  computedClass = computed(() => cn(TEXTAREA_BASE, TEXTAREA_SIZES[this.size()], this.userClass()), /* @ts-ignore */
568
581
  ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
582
+ // Cap the auto-grow at `maxRows` lines using the `lh` unit (one line-height) plus the size's
583
+ // vertical padding and the 1px borders — purely declarative, so it stays SSR-safe.
584
+ maxHeight = computed(() => {
585
+ const rows = this.maxRows();
586
+ return rows === null ? null : `calc(${rows} * 1lh + ${TEXTAREA_PADDING_Y[this.size()]} + 2px)`;
587
+ }, /* @ts-ignore */
588
+ ...(ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []));
569
589
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiTextarea, deps: [], target: i0.ɵɵFactoryTarget.Directive });
570
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: BuiTextarea, isStandalone: true, selector: "textarea[buiTextarea]", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "textarea" }, properties: { "attr.data-size": "size()", "class": "computedClass()" } }, ngImport: i0 });
590
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: BuiTextarea, isStandalone: true, selector: "textarea[buiTextarea]", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, maxRows: { classPropertyName: "maxRows", publicName: "maxRows", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "textarea" }, properties: { "attr.data-size": "size()", "class": "computedClass()", "style.max-height": "maxHeight()", "style.overflow-y": "maxRows() === null ? null : 'auto'" } }, ngImport: i0 });
571
591
  }
572
592
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiTextarea, decorators: [{
573
593
  type: Directive,
@@ -577,9 +597,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
577
597
  'data-slot': 'textarea',
578
598
  '[attr.data-size]': 'size()',
579
599
  '[class]': 'computedClass()',
600
+ '[style.max-height]': 'maxHeight()',
601
+ '[style.overflow-y]': "maxRows() === null ? null : 'auto'",
580
602
  },
581
603
  }]
582
- }], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
604
+ }], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], maxRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRows", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
583
605
 
584
606
  /**
585
607
  * BlatUI linear progress bar. Exposes the full `progressbar` ARIA contract
@@ -2720,7 +2742,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
2720
2742
  }]
2721
2743
  }], propDecorators: { userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
2722
2744
 
2723
- const SIZES$5 = {
2745
+ const SIZES$3 = {
2724
2746
  sm: 'max-w-3xl',
2725
2747
  md: 'max-w-5xl',
2726
2748
  lg: 'max-w-6xl',
@@ -2734,7 +2756,7 @@ class BuiContainer {
2734
2756
  size = input('lg', /* @ts-ignore */
2735
2757
  ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
2736
2758
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
2737
- computedClass = computed(() => cn('mx-auto w-full px-4 sm:px-6 lg:px-8', SIZES$5[this.size()], this.userClass()), /* @ts-ignore */
2759
+ computedClass = computed(() => cn('mx-auto w-full px-4 sm:px-6 lg:px-8', SIZES$3[this.size()], this.userClass()), /* @ts-ignore */
2738
2760
  ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
2739
2761
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiContainer, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2740
2762
  static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: BuiContainer, isStandalone: true, selector: "[buiContainer]", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "container" }, properties: { "class": "computedClass()" } }, ngImport: i0 });
@@ -3477,7 +3499,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
3477
3499
  }]
3478
3500
  }], propDecorators: { userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
3479
3501
 
3480
- const SIZES$4 = {
3502
+ const SIZES$2 = {
3481
3503
  sm: { box: 'size-6', overlap: '-ms-2', ring: 'ring-1', text: 'text-xs' },
3482
3504
  default: { box: 'size-8', overlap: '-ms-2.5', ring: 'ring-2', text: 'text-sm' },
3483
3505
  lg: { box: 'size-12', overlap: '-ms-3', ring: 'ring-2', text: 'text-base' },
@@ -3512,11 +3534,11 @@ class BuiAvatarGroup {
3512
3534
  ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
3513
3535
  toInitials = initials;
3514
3536
  itemClass(index) {
3515
- const size = SIZES$4[this.size()];
3537
+ const size = SIZES$2[this.size()];
3516
3538
  return cn(size.box, size.ring, 'ring-background', index > 0 && size.overlap);
3517
3539
  }
3518
3540
  moreClass() {
3519
- const size = SIZES$4[this.size()];
3541
+ const size = SIZES$2[this.size()];
3520
3542
  return cn('relative z-10 flex shrink-0 items-center justify-center rounded-full bg-muted font-medium text-foreground', size.box, size.ring, 'ring-background', size.text, this.shown().length > 0 && size.overlap);
3521
3543
  }
3522
3544
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiAvatarGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
@@ -5024,7 +5046,13 @@ const BTN_SIZE$1 = {
5024
5046
  lg: 'w-9 [&_svg]:size-4',
5025
5047
  };
5026
5048
  const FIELD_WIDTH = { sm: 'w-9', default: 'w-10', lg: 'w-12' };
5027
- /** A compact − [n] + quantity stepper (`role="group"` with a `spinbutton` field). */
5049
+ /**
5050
+ * @deprecated Use `<bui-number-input [min]="1" size="sm">` instead — it is the same numeric
5051
+ * stepper, so this duplicate was dropped from the registry and docs. Still exported as a thin
5052
+ * compatibility shim; existing usages keep working.
5053
+ *
5054
+ * A compact − [n] + quantity stepper (`role="group"` with a `spinbutton` field).
5055
+ */
5028
5056
  class BuiQuantitySelector {
5029
5057
  /** Current quantity. Two-way bindable with `[(value)]`. */
5030
5058
  value = model(1, /* @ts-ignore */
@@ -5314,71 +5342,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
5314
5342
  }]
5315
5343
  }], propDecorators: { userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
5316
5344
 
5317
- const BASE$1 = 'border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 flex w-full resize-none overflow-hidden rounded-md border bg-transparent shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50';
5318
- const SIZES$3 = {
5319
- sm: 'min-h-14 px-2.5 py-1.5 text-sm',
5320
- default: 'min-h-16 px-3 py-2 text-base md:text-sm',
5321
- lg: 'min-h-20 px-4 py-2.5 text-base',
5322
- };
5323
5345
  /**
5324
- * A textarea that grows with its content. SSR-safe the height is measured only in the
5325
- * browser (via `afterNextRender` and the `input` event).
5346
+ * @deprecated Use `<textarea buiTextarea [maxRows]="…">` instead`buiTextarea` already auto-grows
5347
+ * (CSS `field-sizing-content`) and now supports `maxRows`. Kept as a thin alias so existing
5348
+ * `buiAutosizeTextarea` markup keeps working; it inherits every input from {@link BuiTextarea}.
5349
+ *
5350
+ * A textarea that grows with its content, capped at `maxRows`.
5326
5351
  */
5327
- class BuiAutosizeTextarea {
5328
- /** Size preset controlling minimum height, padding and text size. */
5329
- size = input('default', /* @ts-ignore */
5330
- ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
5331
- /** Maximum number of rows before the textarea scrolls instead of growing (null = unlimited). */
5332
- maxRows = input(null, /* @ts-ignore */
5333
- ...(ngDevMode ? [{ debugName: "maxRows" }] : /* istanbul ignore next */ []));
5334
- userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
5335
- host = inject(ElementRef);
5336
- computedClass = computed(() => cn(BASE$1, SIZES$3[this.size()], this.userClass()), /* @ts-ignore */
5337
- ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
5338
- constructor() {
5339
- afterNextRender(() => {
5340
- this.resize();
5341
- });
5342
- }
5343
- resize() {
5344
- const element = this.host.nativeElement;
5345
- element.style.height = 'auto';
5346
- let target = element.scrollHeight;
5347
- const maxRows = this.maxRows();
5348
- if (maxRows !== null) {
5349
- const styles = getComputedStyle(element);
5350
- let lineHeight = Number.parseFloat(styles.lineHeight);
5351
- if (Number.isNaN(lineHeight)) {
5352
- lineHeight = Number.parseFloat(styles.fontSize) * 1.2;
5353
- }
5354
- const padding = Number.parseFloat(styles.paddingTop) + Number.parseFloat(styles.paddingBottom);
5355
- const border = Number.parseFloat(styles.borderTopWidth) + Number.parseFloat(styles.borderBottomWidth);
5356
- const cap = lineHeight * maxRows + padding + border;
5357
- if (target > cap) {
5358
- target = cap;
5359
- element.style.overflowY = 'auto';
5360
- }
5361
- else {
5362
- element.style.overflowY = 'hidden';
5363
- }
5364
- }
5365
- element.style.height = `${target}px`;
5366
- }
5367
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiAutosizeTextarea, deps: [], target: i0.ɵɵFactoryTarget.Directive });
5368
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: BuiAutosizeTextarea, isStandalone: true, selector: "textarea[buiAutosizeTextarea]", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, maxRows: { classPropertyName: "maxRows", publicName: "maxRows", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "autosize-textarea" }, listeners: { "input": "resize()" }, properties: { "attr.data-size": "size()", "class": "computedClass()" } }, ngImport: i0 });
5352
+ class BuiAutosizeTextarea extends BuiTextarea {
5353
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiAutosizeTextarea, deps: null, target: i0.ɵɵFactoryTarget.Directive });
5354
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.2", type: BuiAutosizeTextarea, isStandalone: true, selector: "textarea[buiAutosizeTextarea]", host: { attributes: { "data-slot": "autosize-textarea" } }, usesInheritance: true, ngImport: i0 });
5369
5355
  }
5370
5356
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiAutosizeTextarea, decorators: [{
5371
5357
  type: Directive,
5372
5358
  args: [{
5373
5359
  selector: 'textarea[buiAutosizeTextarea]',
5374
- host: {
5375
- 'data-slot': 'autosize-textarea',
5376
- '[attr.data-size]': 'size()',
5377
- '[class]': 'computedClass()',
5378
- '(input)': 'resize()',
5379
- },
5360
+ host: { 'data-slot': 'autosize-textarea' },
5380
5361
  }]
5381
- }], ctorParameters: () => [], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], maxRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRows", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
5362
+ }] });
5382
5363
 
5383
5364
  class BuiDropdownMenu {
5384
5365
  menu = inject(Menu);
@@ -7431,7 +7412,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
7431
7412
  }]
7432
7413
  }], propDecorators: { author: [{ type: i0.Input, args: [{ isSignal: true, alias: "author", required: false }] }], role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: false }] }], avatar: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatar", required: false }] }], cite: [{ type: i0.Input, args: [{ isSignal: true, alias: "cite", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
7433
7414
 
7434
- const SIZES$2 = { sm: 'text-sm', default: 'text-base', lg: 'text-2xl' };
7415
+ const SIZES$1 = { sm: 'text-sm', default: 'text-base', lg: 'text-2xl' };
7435
7416
  const COMPARE_SIZES = { sm: 'text-xs', default: 'text-sm', lg: 'text-base' };
7436
7417
  /** A price display with optional compare-at (strikethrough) and a discount badge. */
7437
7418
  class BuiPrice {
@@ -7463,7 +7444,7 @@ class BuiPrice {
7463
7444
  : 0;
7464
7445
  }, /* @ts-ignore */
7465
7446
  ...(ngDevMode ? [{ debugName: "discount" }] : /* istanbul ignore next */ []));
7466
- currentClass = computed(() => cn(SIZES$2[this.size()], this.onSale() ? 'text-emerald-700 dark:text-emerald-400' : 'text-foreground'), /* @ts-ignore */
7447
+ currentClass = computed(() => cn(SIZES$1[this.size()], this.onSale() ? 'text-emerald-700 dark:text-emerald-400' : 'text-foreground'), /* @ts-ignore */
7467
7448
  ...(ngDevMode ? [{ debugName: "currentClass" }] : /* istanbul ignore next */ []));
7468
7449
  compareClass = computed(() => cn(COMPARE_SIZES[this.size()], 'text-muted-foreground'), /* @ts-ignore */
7469
7450
  ...(ngDevMode ? [{ debugName: "compareClass" }] : /* istanbul ignore next */ []));
@@ -7626,7 +7607,7 @@ const COLORS = {
7626
7607
  offline: 'bg-gray-400',
7627
7608
  };
7628
7609
  const LABELS = { online: 'Online', away: 'Away', busy: 'Busy', offline: 'Offline' };
7629
- const SIZES$1 = { sm: 'size-2', default: 'size-2.5', lg: 'size-3' };
7610
+ const SIZES = { sm: 'size-2', default: 'size-2.5', lg: 'size-3' };
7630
7611
  /** A small status dot (online/away/busy/offline). Status is never colour-only — the label is always present. */
7631
7612
  class BuiPresence {
7632
7613
  /** Presence state, which sets the dot color and default label. */
@@ -7647,7 +7628,7 @@ class BuiPresence {
7647
7628
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
7648
7629
  colorClass = computed(() => COLORS[this.status()], /* @ts-ignore */
7649
7630
  ...(ngDevMode ? [{ debugName: "colorClass" }] : /* istanbul ignore next */ []));
7650
- sizeClass = computed(() => SIZES$1[this.size()], /* @ts-ignore */
7631
+ sizeClass = computed(() => SIZES[this.size()], /* @ts-ignore */
7651
7632
  ...(ngDevMode ? [{ debugName: "sizeClass" }] : /* istanbul ignore next */ []));
7652
7633
  labelText = computed(() => this.label() || LABELS[this.status()], /* @ts-ignore */
7653
7634
  ...(ngDevMode ? [{ debugName: "labelText" }] : /* istanbul ignore next */ []));
@@ -8563,7 +8544,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
8563
8544
  }]
8564
8545
  }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], area: [{ type: i0.Input, args: [{ isSignal: true, alias: "area", required: false }] }], strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
8565
8546
 
8566
- const SIZES = { default: 'h-9 px-4 py-2', sm: 'h-8 gap-1.5 px-3', lg: 'h-10 px-6' };
8567
8547
  /** A stateful add-to-cart button: idle → adding → added → idle. Emits `triggered` on click. */
8568
8548
  class BuiAddToCart {
8569
8549
  /** Button text shown in the idle and adding states. */
@@ -8581,9 +8561,9 @@ class BuiAddToCart {
8581
8561
  state = signal('idle', /* @ts-ignore */
8582
8562
  ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
8583
8563
  timers = [];
8584
- btnClass = computed(() => cn('inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium transition-all outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:opacity-90', SIZES[this.size()], this.state() === 'added'
8585
- ? 'bg-emerald-600 text-white'
8586
- : 'bg-primary text-primary-foreground hover:bg-primary/90', this.userClass()), /* @ts-ignore */
8564
+ // Composes the button's styling (single source of truth via `buttonVariants`); the busy/added
8565
+ // states only recolor on top — tailwind-merge drops the conflicting base background.
8566
+ btnClass = computed(() => cn(buttonVariants({ size: this.size() }), 'disabled:opacity-90', this.state() === 'added' ? 'bg-emerald-600 text-white hover:bg-emerald-600' : '', this.userClass()), /* @ts-ignore */
8587
8567
  ...(ngDevMode ? [{ debugName: "btnClass" }] : /* istanbul ignore next */ []));
8588
8568
  add() {
8589
8569
  if (this.state() !== 'idle') {
@@ -18556,11 +18536,11 @@ class BuiMentionInput {
18556
18536
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiMentionInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
18557
18537
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiMentionInput, isStandalone: true, selector: "bui-mention-input", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, mentions: { classPropertyName: "mentions", publicName: "mentions", isSignal: true, isRequired: false, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { attributes: { "data-slot": "mention-input" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
18558
18538
  <textarea
18539
+ buiTextarea
18559
18540
  [value]="value()"
18560
18541
  [placeholder]="placeholder()"
18561
18542
  [rows]="rows()"
18562
18543
  [attr.name]="name() || null"
18563
- class="w-full resize-y rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50"
18564
18544
  (input)="onInput($event)"
18565
18545
  (keydown)="onKeydown($event)"
18566
18546
  ></textarea>
@@ -18583,20 +18563,21 @@ class BuiMentionInput {
18583
18563
  }
18584
18564
  </ul>
18585
18565
  }
18586
- `, isInline: true });
18566
+ `, isInline: true, dependencies: [{ kind: "directive", type: BuiTextarea, selector: "textarea[buiTextarea]", inputs: ["size", "maxRows", "class"] }] });
18587
18567
  }
18588
18568
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiMentionInput, decorators: [{
18589
18569
  type: Component,
18590
18570
  args: [{
18591
18571
  selector: 'bui-mention-input',
18592
18572
  host: { 'data-slot': 'mention-input', '[class]': 'computedClass()' },
18573
+ imports: [BuiTextarea],
18593
18574
  template: `
18594
18575
  <textarea
18576
+ buiTextarea
18595
18577
  [value]="value()"
18596
18578
  [placeholder]="placeholder()"
18597
18579
  [rows]="rows()"
18598
18580
  [attr.name]="name() || null"
18599
- class="w-full resize-y rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50"
18600
18581
  (input)="onInput($event)"
18601
18582
  (keydown)="onKeydown($event)"
18602
18583
  ></textarea>