ng-blatui 1.9.0 → 1.11.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.
@@ -81,7 +81,7 @@ const VARIANTS = {
81
81
  destructive: 'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
82
82
  outline: 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground',
83
83
  };
84
- const TONES$1 = {
84
+ const TONES$2 = {
85
85
  success: {
86
86
  soft: 'border-transparent bg-success/10 text-success dark:bg-success/15',
87
87
  solid: 'border-transparent bg-success text-success-foreground',
@@ -143,7 +143,7 @@ class BuiBadge {
143
143
  userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
144
144
  computedClass = computed(() => {
145
145
  const tone = this.tone();
146
- const toneOrVariant = tone === null ? brandClass(this.variant()) : TONES$1[tone][intensityFor(this.variant())];
146
+ const toneOrVariant = tone === null ? brandClass(this.variant()) : TONES$2[tone][intensityFor(this.variant())];
147
147
  return cn(BASE, SIZES$2[this.size()], toneOrVariant, this.userClass());
148
148
  }, /* @ts-ignore */
149
149
  ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
@@ -2801,7 +2801,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
2801
2801
  }]
2802
2802
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
2803
2803
 
2804
- const TONES = {
2804
+ const TONES$1 = {
2805
2805
  default: 'bg-muted text-foreground border-border',
2806
2806
  primary: 'bg-primary text-primary-foreground border-transparent',
2807
2807
  info: 'bg-info/10 text-info border-info/25',
@@ -2824,7 +2824,7 @@ class BuiBanner {
2824
2824
  show = signal(true, /* @ts-ignore */
2825
2825
  ...(ngDevMode ? [{ debugName: "show" }] : /* istanbul ignore next */ []));
2826
2826
  isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
2827
- computedClass = computed(() => cn('relative flex w-full items-center gap-3 border-b px-4 py-2.5 text-sm', TONES[this.tone()], this.userClass()), /* @ts-ignore */
2827
+ computedClass = computed(() => cn('relative flex w-full items-center gap-3 border-b px-4 py-2.5 text-sm', TONES$1[this.tone()], this.userClass()), /* @ts-ignore */
2828
2828
  ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
2829
2829
  ngOnInit() {
2830
2830
  const key = this.persistKey();
@@ -3613,6 +3613,388 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
3613
3613
  }]
3614
3614
  }], 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 }] }] } });
3615
3615
 
3616
+ /** Visually hides content while keeping it available to assistive tech (sr-only). */
3617
+ class BuiVisuallyHidden {
3618
+ focusable = input(false, /* @ts-ignore */
3619
+ ...(ngDevMode ? [{ debugName: "focusable" }] : /* istanbul ignore next */ []));
3620
+ userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
3621
+ computedClass = computed(() => cn('sr-only', this.focusable() &&
3622
+ 'focus:not-sr-only focus:fixed focus:start-4 focus:top-4 focus:z-50 focus:rounded-md focus:bg-primary focus:px-4 focus:py-2 focus:text-primary-foreground focus:shadow-md', this.userClass()), /* @ts-ignore */
3623
+ ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
3624
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiVisuallyHidden, deps: [], target: i0.ɵɵFactoryTarget.Directive });
3625
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: BuiVisuallyHidden, isStandalone: true, selector: "[buiVisuallyHidden]", inputs: { focusable: { classPropertyName: "focusable", publicName: "focusable", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "visually-hidden" }, properties: { "class": "computedClass()" } }, ngImport: i0 });
3626
+ }
3627
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiVisuallyHidden, decorators: [{
3628
+ type: Directive,
3629
+ args: [{
3630
+ selector: '[buiVisuallyHidden]',
3631
+ host: { 'data-slot': 'visually-hidden', '[class]': 'computedClass()' },
3632
+ }]
3633
+ }], propDecorators: { focusable: [{ type: i0.Input, args: [{ isSignal: true, alias: "focusable", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
3634
+
3635
+ const TONES = {
3636
+ good: 'bg-emerald-600',
3637
+ warning: 'bg-amber-500',
3638
+ danger: 'bg-destructive',
3639
+ default: 'bg-primary',
3640
+ };
3641
+ /** A labelled meter (`role="meter"`) for a measurement within a known range. */
3642
+ class BuiMeter {
3643
+ value = input(0, /* @ts-ignore */
3644
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
3645
+ min = input(0, /* @ts-ignore */
3646
+ ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
3647
+ max = input(100, /* @ts-ignore */
3648
+ ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
3649
+ label = input(null, /* @ts-ignore */
3650
+ ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
3651
+ tone = input('default', /* @ts-ignore */
3652
+ ...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
3653
+ showValue = input(true, /* @ts-ignore */
3654
+ ...(ngDevMode ? [{ debugName: "showValue" }] : /* istanbul ignore next */ []));
3655
+ unit = input('%', /* @ts-ignore */
3656
+ ...(ngDevMode ? [{ debugName: "unit" }] : /* istanbul ignore next */ []));
3657
+ userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
3658
+ clamped = computed(() => Math.max(this.min(), Math.min(this.max(), this.value())), /* @ts-ignore */
3659
+ ...(ngDevMode ? [{ debugName: "clamped" }] : /* istanbul ignore next */ []));
3660
+ pct = computed(() => {
3661
+ const range = this.max() - this.min() || 1;
3662
+ return ((this.clamped() - this.min()) / range) * 100;
3663
+ }, /* @ts-ignore */
3664
+ ...(ngDevMode ? [{ debugName: "pct" }] : /* istanbul ignore next */ []));
3665
+ valueText = computed(() => `${this.value()}${this.unit()}`, /* @ts-ignore */
3666
+ ...(ngDevMode ? [{ debugName: "valueText" }] : /* istanbul ignore next */ []));
3667
+ fillClass = computed(() => TONES[this.tone()], /* @ts-ignore */
3668
+ ...(ngDevMode ? [{ debugName: "fillClass" }] : /* istanbul ignore next */ []));
3669
+ computedClass = computed(() => cn('grid w-full gap-1.5', this.userClass()), /* @ts-ignore */
3670
+ ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
3671
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiMeter, deps: [], target: i0.ɵɵFactoryTarget.Component });
3672
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiMeter, isStandalone: true, selector: "bui-meter", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null }, showValue: { classPropertyName: "showValue", publicName: "showValue", isSignal: true, isRequired: false, transformFunction: null }, unit: { classPropertyName: "unit", publicName: "unit", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "meter" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
3673
+ @if (label() || showValue()) {
3674
+ <div class="flex items-center justify-between gap-2 text-sm">
3675
+ @if (label()) {
3676
+ <span class="font-medium text-foreground">{{ label() }}</span>
3677
+ } @else {
3678
+ <span aria-hidden="true"></span>
3679
+ }
3680
+ @if (showValue()) {
3681
+ <span class="text-muted-foreground tabular-nums">{{ valueText() }}</span>
3682
+ }
3683
+ </div>
3684
+ }
3685
+ <div
3686
+ role="meter"
3687
+ [attr.aria-label]="label() ?? 'Meter'"
3688
+ [attr.aria-valuenow]="clamped()"
3689
+ [attr.aria-valuemin]="min()"
3690
+ [attr.aria-valuemax]="max()"
3691
+ [attr.aria-valuetext]="valueText()"
3692
+ class="relative h-2 w-full overflow-hidden rounded-full bg-muted"
3693
+ >
3694
+ <div
3695
+ class="absolute inset-y-0 start-0 rounded-full transition-[width] duration-500 ease-out"
3696
+ [class]="fillClass()"
3697
+ [style.width.%]="pct()"
3698
+ ></div>
3699
+ </div>
3700
+ `, isInline: true });
3701
+ }
3702
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiMeter, decorators: [{
3703
+ type: Component,
3704
+ args: [{
3705
+ selector: 'bui-meter',
3706
+ host: { 'data-slot': 'meter', '[class]': 'computedClass()' },
3707
+ template: `
3708
+ @if (label() || showValue()) {
3709
+ <div class="flex items-center justify-between gap-2 text-sm">
3710
+ @if (label()) {
3711
+ <span class="font-medium text-foreground">{{ label() }}</span>
3712
+ } @else {
3713
+ <span aria-hidden="true"></span>
3714
+ }
3715
+ @if (showValue()) {
3716
+ <span class="text-muted-foreground tabular-nums">{{ valueText() }}</span>
3717
+ }
3718
+ </div>
3719
+ }
3720
+ <div
3721
+ role="meter"
3722
+ [attr.aria-label]="label() ?? 'Meter'"
3723
+ [attr.aria-valuenow]="clamped()"
3724
+ [attr.aria-valuemin]="min()"
3725
+ [attr.aria-valuemax]="max()"
3726
+ [attr.aria-valuetext]="valueText()"
3727
+ class="relative h-2 w-full overflow-hidden rounded-full bg-muted"
3728
+ >
3729
+ <div
3730
+ class="absolute inset-y-0 start-0 rounded-full transition-[width] duration-500 ease-out"
3731
+ [class]="fillClass()"
3732
+ [style.width.%]="pct()"
3733
+ ></div>
3734
+ </div>
3735
+ `,
3736
+ }]
3737
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], unit: [{ type: i0.Input, args: [{ isSignal: true, alias: "unit", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
3738
+
3739
+ const TREND_CLASS = {
3740
+ up: 'text-emerald-600 font-medium',
3741
+ down: 'text-destructive font-medium',
3742
+ neutral: 'text-muted-foreground font-medium',
3743
+ };
3744
+ /** A KPI / statistic card: label, big value, and a trend-coloured change. */
3745
+ class BuiStat {
3746
+ label = input(null, /* @ts-ignore */
3747
+ ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
3748
+ value = input('', /* @ts-ignore */
3749
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
3750
+ change = input(null, /* @ts-ignore */
3751
+ ...(ngDevMode ? [{ debugName: "change" }] : /* istanbul ignore next */ []));
3752
+ trend = input(null, /* @ts-ignore */
3753
+ ...(ngDevMode ? [{ debugName: "trend" }] : /* istanbul ignore next */ []));
3754
+ caption = input(null, /* @ts-ignore */
3755
+ ...(ngDevMode ? [{ debugName: "caption" }] : /* istanbul ignore next */ []));
3756
+ userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
3757
+ resolvedTrend = computed(() => {
3758
+ const explicit = this.trend();
3759
+ if (explicit) {
3760
+ return explicit;
3761
+ }
3762
+ const change = (this.change() ?? '').trim();
3763
+ if (change.startsWith('+')) {
3764
+ return 'up';
3765
+ }
3766
+ if (change.startsWith('-') || change.startsWith('−')) {
3767
+ return 'down';
3768
+ }
3769
+ return 'neutral';
3770
+ }, /* @ts-ignore */
3771
+ ...(ngDevMode ? [{ debugName: "resolvedTrend" }] : /* istanbul ignore next */ []));
3772
+ trendClass = computed(() => TREND_CLASS[this.resolvedTrend()], /* @ts-ignore */
3773
+ ...(ngDevMode ? [{ debugName: "trendClass" }] : /* istanbul ignore next */ []));
3774
+ computedClass = computed(() => cn('flex flex-col gap-1 rounded-lg border bg-card p-4', this.userClass()), /* @ts-ignore */
3775
+ ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
3776
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiStat, deps: [], target: i0.ɵɵFactoryTarget.Component });
3777
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiStat, isStandalone: true, selector: "bui-stat", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, change: { classPropertyName: "change", publicName: "change", isSignal: true, isRequired: false, transformFunction: null }, trend: { classPropertyName: "trend", publicName: "trend", isSignal: true, isRequired: false, transformFunction: null }, caption: { classPropertyName: "caption", publicName: "caption", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "stat" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
3778
+ @if (label()) {
3779
+ <span class="text-sm font-medium text-muted-foreground">{{ label() }}</span>
3780
+ }
3781
+ <span class="text-2xl font-semibold tabular-nums">{{ value() }}</span>
3782
+ @if (change()) {
3783
+ <span class="flex items-center gap-1.5 text-sm">
3784
+ <span [class]="trendClass()">{{ change() }}</span>
3785
+ @if (caption()) {
3786
+ <span class="text-muted-foreground">{{ caption() }}</span>
3787
+ }
3788
+ </span>
3789
+ }
3790
+ `, isInline: true });
3791
+ }
3792
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiStat, decorators: [{
3793
+ type: Component,
3794
+ args: [{
3795
+ selector: 'bui-stat',
3796
+ host: { 'data-slot': 'stat', '[class]': 'computedClass()' },
3797
+ template: `
3798
+ @if (label()) {
3799
+ <span class="text-sm font-medium text-muted-foreground">{{ label() }}</span>
3800
+ }
3801
+ <span class="text-2xl font-semibold tabular-nums">{{ value() }}</span>
3802
+ @if (change()) {
3803
+ <span class="flex items-center gap-1.5 text-sm">
3804
+ <span [class]="trendClass()">{{ change() }}</span>
3805
+ @if (caption()) {
3806
+ <span class="text-muted-foreground">{{ caption() }}</span>
3807
+ }
3808
+ </span>
3809
+ }
3810
+ `,
3811
+ }]
3812
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], change: [{ type: i0.Input, args: [{ isSignal: true, alias: "change", required: false }] }], trend: [{ type: i0.Input, args: [{ isSignal: true, alias: "trend", required: false }] }], caption: [{ type: i0.Input, args: [{ isSignal: true, alias: "caption", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
3813
+
3814
+ /**
3815
+ * Hover-triggered card on the Angular CDK overlay. Opens on hover/focus after a delay
3816
+ * and stays open while the pointer is over the card. SSR-safe (browser-only, on hover).
3817
+ */
3818
+ class BuiHoverCard {
3819
+ content = input.required({ ...(ngDevMode ? { debugName: "content" } : /* istanbul ignore next */ {}), alias: 'buiHoverCard' });
3820
+ openDelay = input(400, /* @ts-ignore */
3821
+ ...(ngDevMode ? [{ debugName: "openDelay" }] : /* istanbul ignore next */ []));
3822
+ closeDelay = input(100, /* @ts-ignore */
3823
+ ...(ngDevMode ? [{ debugName: "closeDelay" }] : /* istanbul ignore next */ []));
3824
+ overlay = inject(Overlay);
3825
+ host = inject(ElementRef);
3826
+ viewContainerRef = inject(ViewContainerRef);
3827
+ overlayRef = null;
3828
+ timer;
3829
+ scheduleOpen() {
3830
+ this.clearTimer();
3831
+ this.timer = setTimeout(() => {
3832
+ this.open();
3833
+ }, this.openDelay());
3834
+ }
3835
+ scheduleClose() {
3836
+ this.clearTimer();
3837
+ this.timer = setTimeout(() => {
3838
+ this.close();
3839
+ }, this.closeDelay());
3840
+ }
3841
+ clearTimer() {
3842
+ if (this.timer === undefined) {
3843
+ return;
3844
+ }
3845
+ clearTimeout(this.timer);
3846
+ this.timer = undefined;
3847
+ }
3848
+ open() {
3849
+ if (this.overlayRef) {
3850
+ return;
3851
+ }
3852
+ const positionStrategy = this.overlay
3853
+ .position()
3854
+ .flexibleConnectedTo(this.host)
3855
+ .withPositions([
3856
+ { originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top', offsetY: 4 },
3857
+ { originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom', offsetY: -4 },
3858
+ ]);
3859
+ const overlayReference = this.overlay.create({
3860
+ positionStrategy,
3861
+ scrollStrategy: this.overlay.scrollStrategies.reposition(),
3862
+ });
3863
+ overlayReference.attach(new TemplatePortal(this.content(), this.viewContainerRef));
3864
+ overlayReference.overlayElement.addEventListener('mouseenter', () => {
3865
+ this.clearTimer();
3866
+ });
3867
+ overlayReference.overlayElement.addEventListener('mouseleave', () => {
3868
+ this.scheduleClose();
3869
+ });
3870
+ this.overlayRef = overlayReference;
3871
+ }
3872
+ close() {
3873
+ this.overlayRef?.dispose();
3874
+ this.overlayRef = null;
3875
+ }
3876
+ ngOnDestroy() {
3877
+ this.clearTimer();
3878
+ this.close();
3879
+ }
3880
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiHoverCard, deps: [], target: i0.ɵɵFactoryTarget.Directive });
3881
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: BuiHoverCard, isStandalone: true, selector: "[buiHoverCard]", inputs: { content: { classPropertyName: "content", publicName: "buiHoverCard", isSignal: true, isRequired: true, transformFunction: null }, openDelay: { classPropertyName: "openDelay", publicName: "openDelay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "scheduleOpen()", "mouseleave": "scheduleClose()", "focusin": "scheduleOpen()", "focusout": "scheduleClose()" } }, ngImport: i0 });
3882
+ }
3883
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiHoverCard, decorators: [{
3884
+ type: Directive,
3885
+ args: [{
3886
+ selector: '[buiHoverCard]',
3887
+ host: {
3888
+ '(mouseenter)': 'scheduleOpen()',
3889
+ '(mouseleave)': 'scheduleClose()',
3890
+ '(focusin)': 'scheduleOpen()',
3891
+ '(focusout)': 'scheduleClose()',
3892
+ },
3893
+ }]
3894
+ }], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "buiHoverCard", required: true }] }], openDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "openDelay", required: false }] }], closeDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeDelay", required: false }] }] } });
3895
+ /** Styling for the hover-card content root (inside the bound template). */
3896
+ class BuiHoverCardContent {
3897
+ userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
3898
+ computedClass = computed(() => cn('z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none', this.userClass()), /* @ts-ignore */
3899
+ ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
3900
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiHoverCardContent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
3901
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: BuiHoverCardContent, isStandalone: true, selector: "[buiHoverCardContent]", inputs: { userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "hover-card-content", "tabindex": "-1" }, properties: { "class": "computedClass()" } }, ngImport: i0 });
3902
+ }
3903
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiHoverCardContent, decorators: [{
3904
+ type: Directive,
3905
+ args: [{
3906
+ selector: '[buiHoverCardContent]',
3907
+ host: { 'data-slot': 'hover-card-content', tabindex: '-1', '[class]': 'computedClass()' },
3908
+ }]
3909
+ }], propDecorators: { userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
3910
+
3911
+ /** A dark code panel with an optional filename header and a copy button. */
3912
+ class BuiCodeBlock {
3913
+ code = input('', /* @ts-ignore */
3914
+ ...(ngDevMode ? [{ debugName: "code" }] : /* istanbul ignore next */ []));
3915
+ filename = input(null, /* @ts-ignore */
3916
+ ...(ngDevMode ? [{ debugName: "filename" }] : /* istanbul ignore next */ []));
3917
+ userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
3918
+ copied = signal(false, /* @ts-ignore */
3919
+ ...(ngDevMode ? [{ debugName: "copied" }] : /* istanbul ignore next */ []));
3920
+ computedClass = computed(() => cn('group/code-block relative block overflow-hidden rounded-lg border border-zinc-800 bg-zinc-950 text-zinc-100', this.userClass()), /* @ts-ignore */
3921
+ ...(ngDevMode ? [{ debugName: "computedClass" }] : /* istanbul ignore next */ []));
3922
+ async copy() {
3923
+ try {
3924
+ await navigator.clipboard.writeText(this.code());
3925
+ this.copied.set(true);
3926
+ setTimeout(() => {
3927
+ this.copied.set(false);
3928
+ }, 1600);
3929
+ }
3930
+ catch {
3931
+ // Clipboard unavailable — ignore.
3932
+ }
3933
+ }
3934
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiCodeBlock, deps: [], target: i0.ɵɵFactoryTarget.Component });
3935
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BuiCodeBlock, isStandalone: true, selector: "bui-code-block", inputs: { code: { classPropertyName: "code", publicName: "code", isSignal: true, isRequired: false, transformFunction: null }, filename: { classPropertyName: "filename", publicName: "filename", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-slot": "code-block" }, properties: { "class": "computedClass()" } }, ngImport: i0, template: `
3936
+ @if (filename()) {
3937
+ <div class="flex items-center justify-between border-b border-white/10 px-4 py-2">
3938
+ <span class="font-mono text-xs text-zinc-400">{{ filename() }}</span>
3939
+ <button
3940
+ type="button"
3941
+ aria-label="Copy code"
3942
+ class="text-xs text-zinc-400 transition-colors hover:text-zinc-100"
3943
+ (click)="copy()"
3944
+ >
3945
+ {{ copied() ? 'Copied' : 'Copy' }}
3946
+ </button>
3947
+ </div>
3948
+ } @else {
3949
+ <button
3950
+ type="button"
3951
+ aria-label="Copy code"
3952
+ class="absolute end-2 top-2 z-10 rounded-md px-1.5 py-1 text-xs text-zinc-400 opacity-0 transition-all group-hover/code-block:opacity-100 hover:bg-white/10 hover:text-zinc-100 focus-visible:opacity-100"
3953
+ (click)="copy()"
3954
+ >
3955
+ {{ copied() ? 'Copied' : 'Copy' }}
3956
+ </button>
3957
+ }
3958
+ <pre
3959
+ class="overflow-x-auto p-4 text-[13px] leading-relaxed"
3960
+ ><code class="font-mono">{{ code() }}</code></pre>
3961
+ `, isInline: true });
3962
+ }
3963
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BuiCodeBlock, decorators: [{
3964
+ type: Component,
3965
+ args: [{
3966
+ selector: 'bui-code-block',
3967
+ host: { 'data-slot': 'code-block', '[class]': 'computedClass()' },
3968
+ template: `
3969
+ @if (filename()) {
3970
+ <div class="flex items-center justify-between border-b border-white/10 px-4 py-2">
3971
+ <span class="font-mono text-xs text-zinc-400">{{ filename() }}</span>
3972
+ <button
3973
+ type="button"
3974
+ aria-label="Copy code"
3975
+ class="text-xs text-zinc-400 transition-colors hover:text-zinc-100"
3976
+ (click)="copy()"
3977
+ >
3978
+ {{ copied() ? 'Copied' : 'Copy' }}
3979
+ </button>
3980
+ </div>
3981
+ } @else {
3982
+ <button
3983
+ type="button"
3984
+ aria-label="Copy code"
3985
+ class="absolute end-2 top-2 z-10 rounded-md px-1.5 py-1 text-xs text-zinc-400 opacity-0 transition-all group-hover/code-block:opacity-100 hover:bg-white/10 hover:text-zinc-100 focus-visible:opacity-100"
3986
+ (click)="copy()"
3987
+ >
3988
+ {{ copied() ? 'Copied' : 'Copy' }}
3989
+ </button>
3990
+ }
3991
+ <pre
3992
+ class="overflow-x-auto p-4 text-[13px] leading-relaxed"
3993
+ ><code class="font-mono">{{ code() }}</code></pre>
3994
+ `,
3995
+ }]
3996
+ }], propDecorators: { code: [{ type: i0.Input, args: [{ isSignal: true, alias: "code", required: false }] }], filename: [{ type: i0.Input, args: [{ isSignal: true, alias: "filename", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
3997
+
3616
3998
  /*
3617
3999
  * Public API Surface of ng-blatui
3618
4000
  */
@@ -3621,5 +4003,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
3621
4003
  * Generated bundle index. Do not edit.
3622
4004
  */
3623
4005
 
3624
- export { BuiAccordion, BuiAccordionContent, BuiAccordionItem, BuiAccordionTrigger, BuiAlert, BuiAlertDescription, BuiAlertTitle, BuiAspectRatio, BuiAvatar, BuiAvatarGroup, BuiBadge, BuiBanner, BuiBreadcrumb, BuiBreadcrumbEllipsis, BuiBreadcrumbItem, BuiBreadcrumbLink, BuiBreadcrumbList, BuiBreadcrumbPage, BuiBreadcrumbSeparator, BuiButton, BuiButtonGroup, BuiButtonGroupText, BuiCard, BuiCardAction, BuiCardContent, BuiCardDescription, BuiCardFooter, BuiCardHeader, BuiCardTitle, BuiCheckbox, BuiCollapsible, BuiCollapsibleContent, BuiCollapsibleTrigger, BuiContainer, BuiCopyButton, BuiDialogContent, BuiDialogDescription, BuiDialogFooter, BuiDialogHeader, BuiDialogTitle, BuiEmpty, BuiEmptyContent, BuiEmptyDescription, BuiEmptyHeader, BuiEmptyMedia, BuiEmptyTitle, BuiField, BuiFieldContent, BuiFieldDescription, BuiFieldError, BuiFieldGroup, BuiFieldLabel, BuiFieldLegend, BuiFieldSeparator, BuiFieldSet, BuiFieldTitle, BuiInput, BuiInputGroup, BuiInputGroupAddon, BuiInputGroupButton, BuiInputGroupInput, BuiInputGroupText, BuiItem, BuiItemActions, BuiItemContent, BuiItemDescription, BuiItemGroup, BuiItemMedia, BuiItemTitle, BuiKbd, BuiLabel, BuiPagination, BuiPaginationContent, BuiPaginationEllipsis, BuiPaginationItem, BuiPaginationLink, BuiPopover, BuiPopoverContent, BuiProgress, BuiRadioGroup, BuiRadioGroupItem, BuiScrollArea, BuiSeparator, BuiSkeleton, BuiSpinner, BuiSwitch, BuiTabList, BuiTabPanel, BuiTabTrigger, BuiTable, BuiTableBody, BuiTableCaption, BuiTableCell, BuiTableContainer, BuiTableFooter, BuiTableHead, BuiTableHeader, BuiTableRow, BuiTabs, BuiTextarea, BuiThemeCustomizer, BuiToggle, BuiTooltip, BuiTooltipContent, THEME_TOKENS, ThemeStore, buttonVariants, cn, toggleVariants };
4006
+ export { BuiAccordion, BuiAccordionContent, BuiAccordionItem, BuiAccordionTrigger, BuiAlert, BuiAlertDescription, BuiAlertTitle, BuiAspectRatio, BuiAvatar, BuiAvatarGroup, BuiBadge, BuiBanner, BuiBreadcrumb, BuiBreadcrumbEllipsis, BuiBreadcrumbItem, BuiBreadcrumbLink, BuiBreadcrumbList, BuiBreadcrumbPage, BuiBreadcrumbSeparator, BuiButton, BuiButtonGroup, BuiButtonGroupText, BuiCard, BuiCardAction, BuiCardContent, BuiCardDescription, BuiCardFooter, BuiCardHeader, BuiCardTitle, BuiCheckbox, BuiCodeBlock, BuiCollapsible, BuiCollapsibleContent, BuiCollapsibleTrigger, BuiContainer, BuiCopyButton, BuiDialogContent, BuiDialogDescription, BuiDialogFooter, BuiDialogHeader, BuiDialogTitle, BuiEmpty, BuiEmptyContent, BuiEmptyDescription, BuiEmptyHeader, BuiEmptyMedia, BuiEmptyTitle, BuiField, BuiFieldContent, BuiFieldDescription, BuiFieldError, BuiFieldGroup, BuiFieldLabel, BuiFieldLegend, BuiFieldSeparator, BuiFieldSet, BuiFieldTitle, BuiHoverCard, BuiHoverCardContent, BuiInput, BuiInputGroup, BuiInputGroupAddon, BuiInputGroupButton, BuiInputGroupInput, BuiInputGroupText, BuiItem, BuiItemActions, BuiItemContent, BuiItemDescription, BuiItemGroup, BuiItemMedia, BuiItemTitle, BuiKbd, BuiLabel, BuiMeter, BuiPagination, BuiPaginationContent, BuiPaginationEllipsis, BuiPaginationItem, BuiPaginationLink, BuiPopover, BuiPopoverContent, BuiProgress, BuiRadioGroup, BuiRadioGroupItem, BuiScrollArea, BuiSeparator, BuiSkeleton, BuiSpinner, BuiStat, BuiSwitch, BuiTabList, BuiTabPanel, BuiTabTrigger, BuiTable, BuiTableBody, BuiTableCaption, BuiTableCell, BuiTableContainer, BuiTableFooter, BuiTableHead, BuiTableHeader, BuiTableRow, BuiTabs, BuiTextarea, BuiThemeCustomizer, BuiToggle, BuiTooltip, BuiTooltipContent, BuiVisuallyHidden, THEME_TOKENS, ThemeStore, buttonVariants, cn, toggleVariants };
3625
4007
  //# sourceMappingURL=ng-blatui.mjs.map