duck-dev-lib 0.0.45 → 0.0.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, HostBinding, Directive, computed, Component, output, signal, viewChildren, effect, inject, Injectable, afterNextRender, ElementRef, ChangeDetectionStrategy, ChangeDetectorRef, PLATFORM_ID, viewChild, ContentChildren } from '@angular/core';
2
+ import { input, HostBinding, Directive, computed, Component, output, signal, viewChildren, effect, inject, DestroyRef, Injectable, afterNextRender, ElementRef, ChangeDetectionStrategy, ChangeDetectorRef, PLATFORM_ID, viewChild, ContentChildren, afterRenderEffect } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
- import { NgStyle, CommonModule, JsonPipe, NgTemplateOutlet, isPlatformBrowser } from '@angular/common';
4
+ import { NgStyle, CommonModule, JsonPipe, NgTemplateOutlet, isPlatformBrowser, DOCUMENT } from '@angular/common';
5
5
  import * as i1$3 from '@jsverse/transloco';
6
6
  import { TranslocoPipe, TranslocoService, TranslocoModule } from '@jsverse/transloco';
7
7
  import * as i1$1 from '@angular/forms';
@@ -773,7 +773,16 @@ function getNeobrutalCardStyle(color) {
773
773
  }
774
774
  }
775
775
 
776
+ const RETURN_TRANSITION$1 = 'transform 180ms cubic-bezier(0.22, 1, 0.36, 1)';
777
+ const EXIT_TRANSITION$1 = 'transform 220ms cubic-bezier(0.22, 1, 0.36, 1)';
776
778
  class DuckDevCardNeobrutalPoster {
779
+ destroyRef = inject(DestroyRef);
780
+ activePointerId = null;
781
+ dragAxis = null;
782
+ dragStartX = 0;
783
+ dragStartY = 0;
784
+ cardWidth = 0;
785
+ swipeEmitTimeoutId = null;
777
786
  color = input(AccentEnumColor.Dark, { ...(ngDevMode ? { debugName: "color" } : {}) });
778
787
  railTop = input.required({ ...(ngDevMode ? { debugName: "railTop" } : {}) });
779
788
  railMiddle = input.required({ ...(ngDevMode ? { debugName: "railMiddle" } : {}) });
@@ -784,26 +793,269 @@ class DuckDevCardNeobrutalPoster {
784
793
  badge = input.required({ ...(ngDevMode ? { debugName: "badge" } : {}) });
785
794
  metricLabel = input.required({ ...(ngDevMode ? { debugName: "metricLabel" } : {}) });
786
795
  metric = input.required({ ...(ngDevMode ? { debugName: "metric" } : {}) });
796
+ swipeable = input(false, { ...(ngDevMode ? { debugName: "swipeable" } : {}) });
797
+ swipeThreshold = input(96, { ...(ngDevMode ? { debugName: "swipeThreshold" } : {}) });
798
+ swipedLeft = output();
799
+ swipedRight = output();
787
800
  cardStyle = computed(() => getNeobrutalCardStyle(this.color()), { ...(ngDevMode ? { debugName: "cardStyle" } : {}) });
801
+ isDragging = signal(false, { ...(ngDevMode ? { debugName: "isDragging" } : {}) });
802
+ dragOffsetX = signal(0, { ...(ngDevMode ? { debugName: "dragOffsetX" } : {}) });
803
+ dragTransition = signal(RETURN_TRANSITION$1, { ...(ngDevMode ? { debugName: "dragTransition" } : {}) });
804
+ rotationDeg = computed(() => this.clamp(this.dragOffsetX() / 18, -14, 14), { ...(ngDevMode ? { debugName: "rotationDeg" } : {}) });
805
+ transformStyle = computed(() => `translate3d(${this.dragOffsetX()}px, 0, 0) rotate(${this.rotationDeg()}deg)`, { ...(ngDevMode ? { debugName: "transformStyle" } : {}) });
806
+ cursorStyle = computed(() => {
807
+ if (!this.swipeable()) {
808
+ return 'default';
809
+ }
810
+ return this.isDragging() ? 'grabbing' : 'grab';
811
+ }, { ...(ngDevMode ? { debugName: "cursorStyle" } : {}) });
812
+ touchActionStyle = computed(() => (this.swipeable() ? 'pan-y' : 'auto'), { ...(ngDevMode ? { debugName: "touchActionStyle" } : {}) });
813
+ constructor() {
814
+ this.destroyRef.onDestroy(() => this.clearSwipeEmitTimeout());
815
+ }
816
+ onPointerDown(event) {
817
+ if (!this.swipeable() || this.activePointerId !== null) {
818
+ return;
819
+ }
820
+ if (event.pointerType === 'mouse' && event.button !== 0) {
821
+ return;
822
+ }
823
+ const card = event.currentTarget;
824
+ if (!(card instanceof HTMLElement)) {
825
+ return;
826
+ }
827
+ this.clearSwipeEmitTimeout();
828
+ this.activePointerId = event.pointerId;
829
+ this.dragAxis = null;
830
+ this.dragStartX = event.clientX;
831
+ this.dragStartY = event.clientY;
832
+ this.cardWidth = card.offsetWidth;
833
+ this.dragTransition.set('none');
834
+ card.setPointerCapture(event.pointerId);
835
+ }
836
+ onPointerMove(event) {
837
+ if (event.pointerId !== this.activePointerId) {
838
+ return;
839
+ }
840
+ const deltaX = event.clientX - this.dragStartX;
841
+ const deltaY = event.clientY - this.dragStartY;
842
+ if (this.dragAxis === null) {
843
+ if (Math.abs(deltaX) < 10 && Math.abs(deltaY) < 10) {
844
+ return;
845
+ }
846
+ this.dragAxis = Math.abs(deltaX) >= Math.abs(deltaY) ? 'x' : 'y';
847
+ if (this.dragAxis !== 'x') {
848
+ this.releasePointer(event);
849
+ this.resetPosition();
850
+ return;
851
+ }
852
+ }
853
+ event.preventDefault();
854
+ this.isDragging.set(true);
855
+ this.dragOffsetX.set(deltaX);
856
+ }
857
+ onPointerUp(event) {
858
+ if (event.pointerId !== this.activePointerId) {
859
+ return;
860
+ }
861
+ const deltaX = this.dragOffsetX();
862
+ const threshold = Math.max(24, this.swipeThreshold());
863
+ const shouldDismiss = this.dragAxis === 'x' && Math.abs(deltaX) >= threshold;
864
+ this.releasePointer(event);
865
+ this.dragAxis = null;
866
+ this.isDragging.set(false);
867
+ if (!shouldDismiss) {
868
+ this.resetPosition();
869
+ return;
870
+ }
871
+ const direction = deltaX >= 0 ? 1 : -1;
872
+ const exitDistance = Math.max(this.cardWidth * 1.35, 420);
873
+ this.dragTransition.set(EXIT_TRANSITION$1);
874
+ this.dragOffsetX.set(direction * exitDistance);
875
+ this.swipeEmitTimeoutId = window.setTimeout(() => {
876
+ this.swipeEmitTimeoutId = null;
877
+ if (direction > 0) {
878
+ this.swipedRight.emit();
879
+ return;
880
+ }
881
+ this.swipedLeft.emit();
882
+ }, 180);
883
+ }
884
+ onPointerCancel(event) {
885
+ if (event.pointerId !== this.activePointerId) {
886
+ return;
887
+ }
888
+ this.releasePointer(event);
889
+ this.resetPosition();
890
+ }
891
+ releasePointer(event) {
892
+ const card = event.currentTarget;
893
+ if (card instanceof HTMLElement && card.hasPointerCapture(event.pointerId)) {
894
+ card.releasePointerCapture(event.pointerId);
895
+ }
896
+ this.activePointerId = null;
897
+ }
898
+ resetPosition() {
899
+ this.dragAxis = null;
900
+ this.isDragging.set(false);
901
+ this.dragTransition.set(RETURN_TRANSITION$1);
902
+ this.dragOffsetX.set(0);
903
+ }
904
+ clearSwipeEmitTimeout() {
905
+ if (this.swipeEmitTimeoutId === null) {
906
+ return;
907
+ }
908
+ window.clearTimeout(this.swipeEmitTimeoutId);
909
+ this.swipeEmitTimeoutId = null;
910
+ }
911
+ clamp(value, min, max) {
912
+ return Math.min(Math.max(value, min), max);
913
+ }
788
914
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: DuckDevCardNeobrutalPoster, deps: [], target: i0.ɵɵFactoryTarget.Component });
789
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.1", type: DuckDevCardNeobrutalPoster, isStandalone: true, selector: "dd-card-neobrutal-poster", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, railTop: { classPropertyName: "railTop", publicName: "railTop", isSignal: true, isRequired: true, transformFunction: null }, railMiddle: { classPropertyName: "railMiddle", publicName: "railMiddle", isSignal: true, isRequired: true, transformFunction: null }, railBottom: { classPropertyName: "railBottom", publicName: "railBottom", isSignal: true, isRequired: true, transformFunction: null }, eyebrow: { classPropertyName: "eyebrow", publicName: "eyebrow", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: true, transformFunction: null }, badge: { classPropertyName: "badge", publicName: "badge", isSignal: true, isRequired: true, transformFunction: null }, metricLabel: { classPropertyName: "metricLabel", publicName: "metricLabel", isSignal: true, isRequired: true, transformFunction: null }, metric: { classPropertyName: "metric", publicName: "metric", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"dd-card-neo-poster\" [ngStyle]=\"cardStyle()\">\n <div class=\"dd-card-neo-poster__panel\">\n <div class=\"dd-card-neo-poster__meta\">\n <p class=\"dd-card-neo-poster__eyebrow\">{{ eyebrow() }}</p>\n <p class=\"dd-card-neo-poster__badge\">{{ badge() }}</p>\n </div>\n\n <div class=\"dd-card-neo-poster__content\">\n <h3 class=\"dd-card-neo-poster__title\">{{ title() }}</h3>\n <p class=\"dd-card-neo-poster__description\">{{ description() }}</p>\n </div>\n\n <div class=\"dd-card-neo-poster__metric\">\n <span class=\"dd-card-neo-poster__metric-label\">{{ metricLabel() }}</span>\n <strong class=\"dd-card-neo-poster__metric-value\">{{ metric() }}</strong>\n </div>\n </div>\n</article>\n", styles: [".dd-card-neo-poster{display:grid;grid-template-columns:92px minmax(0,1fr);background:var(--dd-neo-card-surface);border:4px solid var(--dd-neo-card-border);box-shadow:12px 12px 0 var(--dd-neo-card-shadow);color:var(--dd-neo-card-text);overflow:clip}.dd-card-neo-poster__headline span:last-child{border-bottom:0}.dd-card-neo-poster__panel{position:relative;display:grid;gap:18px;padding:24px 24px 24px 28px;background:linear-gradient(135deg,color-mix(in srgb,var(--dd-neo-card-accent) 20%,transparent) 0 17%,transparent 17% 100%),repeating-linear-gradient(-45deg,color-mix(in srgb,var(--dd-neo-card-border) 9%,transparent) 0 10px,transparent 10px 22px),var(--dd-neo-card-panel)}.dd-card-neo-poster__panel:before{content:\"\";position:absolute;top:0;bottom:0;left:0;width:8px;background:var(--dd-neo-card-border)}.dd-card-neo-poster__content{display:grid;gap:10px}.dd-card-neo-poster__meta{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.dd-card-neo-poster__eyebrow,.dd-card-neo-poster__badge,.dd-card-neo-poster__title,.dd-card-neo-poster__description,.dd-card-neo-poster__metric-label,.dd-card-neo-poster__metric-value{margin:0}.dd-card-neo-poster__eyebrow,.dd-card-neo-poster__metric-label{font-size:12px;font-weight:900;letter-spacing:.18em;line-height:1.1;text-transform:uppercase}.dd-card-neo-poster__badge{padding:7px 10px 5px;border:4px solid var(--dd-neo-card-border);background:var(--dd-neo-card-accent);box-shadow:4px 4px 0 var(--dd-neo-card-shadow);font-size:12px;font-weight:900;letter-spacing:.14em;line-height:1;text-transform:uppercase}.dd-card-neo-poster__title{max-width:11ch;font-size:clamp(30px,5vw,44px);font-weight:1000;line-height:.9;letter-spacing:-.05em;text-transform:uppercase;text-wrap:balance}.dd-card-neo-poster__description{max-width:38ch;font-size:15px;line-height:1.5;font-weight:800}.dd-card-neo-poster__metric{display:grid;justify-items:start;gap:6px;width:fit-content;padding:12px 14px 10px;border:4px solid var(--dd-neo-card-border);background:var(--dd-neo-card-surface);box-shadow:7px 7px 0 var(--dd-neo-card-shadow)}.dd-card-neo-poster__metric-value{font-size:clamp(28px,5vw,52px);font-weight:1000;line-height:.9;letter-spacing:-.07em}@media(max-width:640px){.dd-card-neo-poster{grid-template-columns:1fr;box-shadow:8px 8px 0 var(--dd-neo-card-shadow)}.dd-card-neo-poster__headline{grid-template-columns:repeat(3,1fr);border-right:0;border-bottom:4px solid var(--dd-neo-card-border)}.dd-card-neo-poster__headline span{min-height:auto;writing-mode:horizontal-tb;transform:none;border-right:4px solid var(--dd-neo-card-border);border-bottom:0}.dd-card-neo-poster__headline span:last-child{border-right:0}.dd-card-neo-poster__panel{padding:20px 20px 20px 24px}.dd-card-neo-poster__meta{flex-direction:column;align-items:flex-start}.dd-card-neo-poster__title{max-width:none}}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
915
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.1", type: DuckDevCardNeobrutalPoster, isStandalone: true, selector: "dd-card-neobrutal-poster", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, railTop: { classPropertyName: "railTop", publicName: "railTop", isSignal: true, isRequired: true, transformFunction: null }, railMiddle: { classPropertyName: "railMiddle", publicName: "railMiddle", isSignal: true, isRequired: true, transformFunction: null }, railBottom: { classPropertyName: "railBottom", publicName: "railBottom", isSignal: true, isRequired: true, transformFunction: null }, eyebrow: { classPropertyName: "eyebrow", publicName: "eyebrow", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: true, transformFunction: null }, badge: { classPropertyName: "badge", publicName: "badge", isSignal: true, isRequired: true, transformFunction: null }, metricLabel: { classPropertyName: "metricLabel", publicName: "metricLabel", isSignal: true, isRequired: true, transformFunction: null }, metric: { classPropertyName: "metric", publicName: "metric", isSignal: true, isRequired: true, transformFunction: null }, swipeable: { classPropertyName: "swipeable", publicName: "swipeable", isSignal: true, isRequired: false, transformFunction: null }, swipeThreshold: { classPropertyName: "swipeThreshold", publicName: "swipeThreshold", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { swipedLeft: "swipedLeft", swipedRight: "swipedRight" }, ngImport: i0, template: "<article\n class=\"dd-card-neo-poster\"\n [class.dd-card-neo-poster--dragging]=\"isDragging()\"\n [class.dd-card-neo-poster--swipeable]=\"swipeable()\"\n [ngStyle]=\"cardStyle()\"\n [style.cursor]=\"cursorStyle()\"\n [style.touch-action]=\"touchActionStyle()\"\n [style.transform]=\"transformStyle()\"\n [style.transition]=\"dragTransition()\"\n (pointercancel)=\"onPointerCancel($event)\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n>\n <div class=\"dd-card-neo-poster__panel\">\n <div class=\"dd-card-neo-poster__meta\">\n <p class=\"dd-card-neo-poster__eyebrow\">{{ eyebrow() }}</p>\n <p class=\"dd-card-neo-poster__badge\">{{ badge() }}</p>\n </div>\n\n <div class=\"dd-card-neo-poster__content\">\n <h3 class=\"dd-card-neo-poster__title\">{{ title() }}</h3>\n <p class=\"dd-card-neo-poster__description\">{{ description() }}</p>\n </div>\n\n <div class=\"dd-card-neo-poster__metric\">\n <span class=\"dd-card-neo-poster__metric-label\">{{ metricLabel() }}</span>\n <strong class=\"dd-card-neo-poster__metric-value\">{{ metric() }}</strong>\n </div>\n </div>\n</article>\n", styles: [".dd-card-neo-poster{display:grid;grid-template-columns:92px minmax(0,1fr);background:var(--dd-neo-card-surface);border:4px solid var(--dd-neo-card-border);box-shadow:12px 12px 0 var(--dd-neo-card-shadow);color:var(--dd-neo-card-text);overflow:clip;transform-origin:center bottom;will-change:transform}.dd-card-neo-poster.dd-card-neo-poster--swipeable{-webkit-user-select:none;user-select:none}.dd-card-neo-poster.dd-card-neo-poster--dragging{z-index:1}.dd-card-neo-poster__headline span:last-child{border-bottom:0}.dd-card-neo-poster__panel{position:relative;display:grid;gap:18px;padding:24px 24px 24px 28px;background:linear-gradient(135deg,color-mix(in srgb,var(--dd-neo-card-accent) 20%,transparent) 0 17%,transparent 17% 100%),repeating-linear-gradient(-45deg,color-mix(in srgb,var(--dd-neo-card-border) 9%,transparent) 0 10px,transparent 10px 22px),var(--dd-neo-card-panel)}.dd-card-neo-poster__panel:before{content:\"\";position:absolute;top:0;bottom:0;left:0;width:8px;background:var(--dd-neo-card-border)}.dd-card-neo-poster__content{display:grid;gap:10px}.dd-card-neo-poster__meta{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.dd-card-neo-poster__eyebrow,.dd-card-neo-poster__badge,.dd-card-neo-poster__title,.dd-card-neo-poster__description,.dd-card-neo-poster__metric-label,.dd-card-neo-poster__metric-value{margin:0}.dd-card-neo-poster__eyebrow,.dd-card-neo-poster__metric-label{font-size:12px;font-weight:900;letter-spacing:.18em;line-height:1.1;text-transform:uppercase}.dd-card-neo-poster__badge{padding:7px 10px 5px;border:4px solid var(--dd-neo-card-border);background:var(--dd-neo-card-accent);box-shadow:4px 4px 0 var(--dd-neo-card-shadow);font-size:12px;font-weight:900;letter-spacing:.14em;line-height:1;text-transform:uppercase}.dd-card-neo-poster__title{max-width:11ch;font-size:clamp(30px,5vw,44px);font-weight:1000;line-height:.9;letter-spacing:-.05em;text-transform:uppercase;text-wrap:balance}.dd-card-neo-poster__description{max-width:38ch;font-size:15px;line-height:1.5;font-weight:800}.dd-card-neo-poster__metric{display:grid;justify-items:start;gap:6px;width:fit-content;padding:12px 14px 10px;border:4px solid var(--dd-neo-card-border);background:var(--dd-neo-card-surface);box-shadow:7px 7px 0 var(--dd-neo-card-shadow)}.dd-card-neo-poster__metric-value{font-size:clamp(28px,5vw,52px);font-weight:1000;line-height:.9;letter-spacing:-.07em}@media(max-width:640px){.dd-card-neo-poster{grid-template-columns:1fr;box-shadow:8px 8px 0 var(--dd-neo-card-shadow)}.dd-card-neo-poster__headline{grid-template-columns:repeat(3,1fr);border-right:0;border-bottom:4px solid var(--dd-neo-card-border)}.dd-card-neo-poster__headline span{min-height:auto;writing-mode:horizontal-tb;transform:none;border-right:4px solid var(--dd-neo-card-border);border-bottom:0}.dd-card-neo-poster__headline span:last-child{border-right:0}.dd-card-neo-poster__panel{padding:20px 20px 20px 24px}.dd-card-neo-poster__meta{flex-direction:column;align-items:flex-start}.dd-card-neo-poster__title{max-width:none}}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
790
916
  }
791
917
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: DuckDevCardNeobrutalPoster, decorators: [{
792
918
  type: Component,
793
- args: [{ selector: 'dd-card-neobrutal-poster', standalone: true, imports: [NgStyle], template: "<article class=\"dd-card-neo-poster\" [ngStyle]=\"cardStyle()\">\n <div class=\"dd-card-neo-poster__panel\">\n <div class=\"dd-card-neo-poster__meta\">\n <p class=\"dd-card-neo-poster__eyebrow\">{{ eyebrow() }}</p>\n <p class=\"dd-card-neo-poster__badge\">{{ badge() }}</p>\n </div>\n\n <div class=\"dd-card-neo-poster__content\">\n <h3 class=\"dd-card-neo-poster__title\">{{ title() }}</h3>\n <p class=\"dd-card-neo-poster__description\">{{ description() }}</p>\n </div>\n\n <div class=\"dd-card-neo-poster__metric\">\n <span class=\"dd-card-neo-poster__metric-label\">{{ metricLabel() }}</span>\n <strong class=\"dd-card-neo-poster__metric-value\">{{ metric() }}</strong>\n </div>\n </div>\n</article>\n", styles: [".dd-card-neo-poster{display:grid;grid-template-columns:92px minmax(0,1fr);background:var(--dd-neo-card-surface);border:4px solid var(--dd-neo-card-border);box-shadow:12px 12px 0 var(--dd-neo-card-shadow);color:var(--dd-neo-card-text);overflow:clip}.dd-card-neo-poster__headline span:last-child{border-bottom:0}.dd-card-neo-poster__panel{position:relative;display:grid;gap:18px;padding:24px 24px 24px 28px;background:linear-gradient(135deg,color-mix(in srgb,var(--dd-neo-card-accent) 20%,transparent) 0 17%,transparent 17% 100%),repeating-linear-gradient(-45deg,color-mix(in srgb,var(--dd-neo-card-border) 9%,transparent) 0 10px,transparent 10px 22px),var(--dd-neo-card-panel)}.dd-card-neo-poster__panel:before{content:\"\";position:absolute;top:0;bottom:0;left:0;width:8px;background:var(--dd-neo-card-border)}.dd-card-neo-poster__content{display:grid;gap:10px}.dd-card-neo-poster__meta{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.dd-card-neo-poster__eyebrow,.dd-card-neo-poster__badge,.dd-card-neo-poster__title,.dd-card-neo-poster__description,.dd-card-neo-poster__metric-label,.dd-card-neo-poster__metric-value{margin:0}.dd-card-neo-poster__eyebrow,.dd-card-neo-poster__metric-label{font-size:12px;font-weight:900;letter-spacing:.18em;line-height:1.1;text-transform:uppercase}.dd-card-neo-poster__badge{padding:7px 10px 5px;border:4px solid var(--dd-neo-card-border);background:var(--dd-neo-card-accent);box-shadow:4px 4px 0 var(--dd-neo-card-shadow);font-size:12px;font-weight:900;letter-spacing:.14em;line-height:1;text-transform:uppercase}.dd-card-neo-poster__title{max-width:11ch;font-size:clamp(30px,5vw,44px);font-weight:1000;line-height:.9;letter-spacing:-.05em;text-transform:uppercase;text-wrap:balance}.dd-card-neo-poster__description{max-width:38ch;font-size:15px;line-height:1.5;font-weight:800}.dd-card-neo-poster__metric{display:grid;justify-items:start;gap:6px;width:fit-content;padding:12px 14px 10px;border:4px solid var(--dd-neo-card-border);background:var(--dd-neo-card-surface);box-shadow:7px 7px 0 var(--dd-neo-card-shadow)}.dd-card-neo-poster__metric-value{font-size:clamp(28px,5vw,52px);font-weight:1000;line-height:.9;letter-spacing:-.07em}@media(max-width:640px){.dd-card-neo-poster{grid-template-columns:1fr;box-shadow:8px 8px 0 var(--dd-neo-card-shadow)}.dd-card-neo-poster__headline{grid-template-columns:repeat(3,1fr);border-right:0;border-bottom:4px solid var(--dd-neo-card-border)}.dd-card-neo-poster__headline span{min-height:auto;writing-mode:horizontal-tb;transform:none;border-right:4px solid var(--dd-neo-card-border);border-bottom:0}.dd-card-neo-poster__headline span:last-child{border-right:0}.dd-card-neo-poster__panel{padding:20px 20px 20px 24px}.dd-card-neo-poster__meta{flex-direction:column;align-items:flex-start}.dd-card-neo-poster__title{max-width:none}}\n"] }]
794
- }], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], railTop: [{ type: i0.Input, args: [{ isSignal: true, alias: "railTop", required: true }] }], railMiddle: [{ type: i0.Input, args: [{ isSignal: true, alias: "railMiddle", required: true }] }], railBottom: [{ type: i0.Input, args: [{ isSignal: true, alias: "railBottom", required: true }] }], eyebrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "eyebrow", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: true }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: true }] }], metricLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "metricLabel", required: true }] }], metric: [{ type: i0.Input, args: [{ isSignal: true, alias: "metric", required: true }] }] } });
919
+ args: [{ selector: 'dd-card-neobrutal-poster', standalone: true, imports: [NgStyle], template: "<article\n class=\"dd-card-neo-poster\"\n [class.dd-card-neo-poster--dragging]=\"isDragging()\"\n [class.dd-card-neo-poster--swipeable]=\"swipeable()\"\n [ngStyle]=\"cardStyle()\"\n [style.cursor]=\"cursorStyle()\"\n [style.touch-action]=\"touchActionStyle()\"\n [style.transform]=\"transformStyle()\"\n [style.transition]=\"dragTransition()\"\n (pointercancel)=\"onPointerCancel($event)\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n>\n <div class=\"dd-card-neo-poster__panel\">\n <div class=\"dd-card-neo-poster__meta\">\n <p class=\"dd-card-neo-poster__eyebrow\">{{ eyebrow() }}</p>\n <p class=\"dd-card-neo-poster__badge\">{{ badge() }}</p>\n </div>\n\n <div class=\"dd-card-neo-poster__content\">\n <h3 class=\"dd-card-neo-poster__title\">{{ title() }}</h3>\n <p class=\"dd-card-neo-poster__description\">{{ description() }}</p>\n </div>\n\n <div class=\"dd-card-neo-poster__metric\">\n <span class=\"dd-card-neo-poster__metric-label\">{{ metricLabel() }}</span>\n <strong class=\"dd-card-neo-poster__metric-value\">{{ metric() }}</strong>\n </div>\n </div>\n</article>\n", styles: [".dd-card-neo-poster{display:grid;grid-template-columns:92px minmax(0,1fr);background:var(--dd-neo-card-surface);border:4px solid var(--dd-neo-card-border);box-shadow:12px 12px 0 var(--dd-neo-card-shadow);color:var(--dd-neo-card-text);overflow:clip;transform-origin:center bottom;will-change:transform}.dd-card-neo-poster.dd-card-neo-poster--swipeable{-webkit-user-select:none;user-select:none}.dd-card-neo-poster.dd-card-neo-poster--dragging{z-index:1}.dd-card-neo-poster__headline span:last-child{border-bottom:0}.dd-card-neo-poster__panel{position:relative;display:grid;gap:18px;padding:24px 24px 24px 28px;background:linear-gradient(135deg,color-mix(in srgb,var(--dd-neo-card-accent) 20%,transparent) 0 17%,transparent 17% 100%),repeating-linear-gradient(-45deg,color-mix(in srgb,var(--dd-neo-card-border) 9%,transparent) 0 10px,transparent 10px 22px),var(--dd-neo-card-panel)}.dd-card-neo-poster__panel:before{content:\"\";position:absolute;top:0;bottom:0;left:0;width:8px;background:var(--dd-neo-card-border)}.dd-card-neo-poster__content{display:grid;gap:10px}.dd-card-neo-poster__meta{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.dd-card-neo-poster__eyebrow,.dd-card-neo-poster__badge,.dd-card-neo-poster__title,.dd-card-neo-poster__description,.dd-card-neo-poster__metric-label,.dd-card-neo-poster__metric-value{margin:0}.dd-card-neo-poster__eyebrow,.dd-card-neo-poster__metric-label{font-size:12px;font-weight:900;letter-spacing:.18em;line-height:1.1;text-transform:uppercase}.dd-card-neo-poster__badge{padding:7px 10px 5px;border:4px solid var(--dd-neo-card-border);background:var(--dd-neo-card-accent);box-shadow:4px 4px 0 var(--dd-neo-card-shadow);font-size:12px;font-weight:900;letter-spacing:.14em;line-height:1;text-transform:uppercase}.dd-card-neo-poster__title{max-width:11ch;font-size:clamp(30px,5vw,44px);font-weight:1000;line-height:.9;letter-spacing:-.05em;text-transform:uppercase;text-wrap:balance}.dd-card-neo-poster__description{max-width:38ch;font-size:15px;line-height:1.5;font-weight:800}.dd-card-neo-poster__metric{display:grid;justify-items:start;gap:6px;width:fit-content;padding:12px 14px 10px;border:4px solid var(--dd-neo-card-border);background:var(--dd-neo-card-surface);box-shadow:7px 7px 0 var(--dd-neo-card-shadow)}.dd-card-neo-poster__metric-value{font-size:clamp(28px,5vw,52px);font-weight:1000;line-height:.9;letter-spacing:-.07em}@media(max-width:640px){.dd-card-neo-poster{grid-template-columns:1fr;box-shadow:8px 8px 0 var(--dd-neo-card-shadow)}.dd-card-neo-poster__headline{grid-template-columns:repeat(3,1fr);border-right:0;border-bottom:4px solid var(--dd-neo-card-border)}.dd-card-neo-poster__headline span{min-height:auto;writing-mode:horizontal-tb;transform:none;border-right:4px solid var(--dd-neo-card-border);border-bottom:0}.dd-card-neo-poster__headline span:last-child{border-right:0}.dd-card-neo-poster__panel{padding:20px 20px 20px 24px}.dd-card-neo-poster__meta{flex-direction:column;align-items:flex-start}.dd-card-neo-poster__title{max-width:none}}\n"] }]
920
+ }], ctorParameters: () => [], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], railTop: [{ type: i0.Input, args: [{ isSignal: true, alias: "railTop", required: true }] }], railMiddle: [{ type: i0.Input, args: [{ isSignal: true, alias: "railMiddle", required: true }] }], railBottom: [{ type: i0.Input, args: [{ isSignal: true, alias: "railBottom", required: true }] }], eyebrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "eyebrow", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: true }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: true }] }], metricLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "metricLabel", required: true }] }], metric: [{ type: i0.Input, args: [{ isSignal: true, alias: "metric", required: true }] }], swipeable: [{ type: i0.Input, args: [{ isSignal: true, alias: "swipeable", required: false }] }], swipeThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "swipeThreshold", required: false }] }], swipedLeft: [{ type: i0.Output, args: ["swipedLeft"] }], swipedRight: [{ type: i0.Output, args: ["swipedRight"] }] } });
795
921
 
922
+ const RETURN_TRANSITION = 'transform 180ms cubic-bezier(0.22, 1, 0.36, 1)';
923
+ const EXIT_TRANSITION = 'transform 220ms cubic-bezier(0.22, 1, 0.36, 1)';
796
924
  class DuckDevCardNeobrutalSlab {
925
+ destroyRef = inject(DestroyRef);
926
+ activePointerId = null;
927
+ dragAxis = null;
928
+ dragStartX = 0;
929
+ dragStartY = 0;
930
+ cardWidth = 0;
931
+ swipeEmitTimeoutId = null;
797
932
  color = input(AccentEnumColor.White, { ...(ngDevMode ? { debugName: "color" } : {}) });
798
933
  strapLabel = input.required({ ...(ngDevMode ? { debugName: "strapLabel" } : {}) });
934
+ swipeable = input(false, { ...(ngDevMode ? { debugName: "swipeable" } : {}) });
935
+ swipeThreshold = input(96, { ...(ngDevMode ? { debugName: "swipeThreshold" } : {}) });
936
+ swipedLeft = output();
937
+ swipedRight = output();
799
938
  cardStyle = computed(() => getNeobrutalCardStyle(this.color()), { ...(ngDevMode ? { debugName: "cardStyle" } : {}) });
939
+ isDragging = signal(false, { ...(ngDevMode ? { debugName: "isDragging" } : {}) });
940
+ dragOffsetX = signal(0, { ...(ngDevMode ? { debugName: "dragOffsetX" } : {}) });
941
+ dragTransition = signal(RETURN_TRANSITION, { ...(ngDevMode ? { debugName: "dragTransition" } : {}) });
942
+ rotationDeg = computed(() => this.clamp(this.dragOffsetX() / 18, -14, 14), { ...(ngDevMode ? { debugName: "rotationDeg" } : {}) });
943
+ transformStyle = computed(() => `translate3d(${this.dragOffsetX()}px, 0, 0) rotate(${this.rotationDeg()}deg)`, { ...(ngDevMode ? { debugName: "transformStyle" } : {}) });
944
+ cursorStyle = computed(() => {
945
+ if (!this.swipeable()) {
946
+ return 'default';
947
+ }
948
+ return this.isDragging() ? 'grabbing' : 'grab';
949
+ }, { ...(ngDevMode ? { debugName: "cursorStyle" } : {}) });
950
+ touchActionStyle = computed(() => (this.swipeable() ? 'pan-y' : 'auto'), { ...(ngDevMode ? { debugName: "touchActionStyle" } : {}) });
951
+ constructor() {
952
+ this.destroyRef.onDestroy(() => this.clearSwipeEmitTimeout());
953
+ }
954
+ onPointerDown(event) {
955
+ if (!this.swipeable() || this.activePointerId !== null) {
956
+ return;
957
+ }
958
+ if (event.pointerType === 'mouse' && event.button !== 0) {
959
+ return;
960
+ }
961
+ const card = event.currentTarget;
962
+ if (!(card instanceof HTMLElement)) {
963
+ return;
964
+ }
965
+ this.clearSwipeEmitTimeout();
966
+ this.activePointerId = event.pointerId;
967
+ this.dragAxis = null;
968
+ this.dragStartX = event.clientX;
969
+ this.dragStartY = event.clientY;
970
+ this.cardWidth = card.offsetWidth;
971
+ this.dragTransition.set('none');
972
+ card.setPointerCapture(event.pointerId);
973
+ }
974
+ onPointerMove(event) {
975
+ if (event.pointerId !== this.activePointerId) {
976
+ return;
977
+ }
978
+ const deltaX = event.clientX - this.dragStartX;
979
+ const deltaY = event.clientY - this.dragStartY;
980
+ if (this.dragAxis === null) {
981
+ if (Math.abs(deltaX) < 10 && Math.abs(deltaY) < 10) {
982
+ return;
983
+ }
984
+ this.dragAxis = Math.abs(deltaX) >= Math.abs(deltaY) ? 'x' : 'y';
985
+ if (this.dragAxis !== 'x') {
986
+ this.releasePointer(event);
987
+ this.resetPosition();
988
+ return;
989
+ }
990
+ }
991
+ event.preventDefault();
992
+ this.isDragging.set(true);
993
+ this.dragOffsetX.set(deltaX);
994
+ }
995
+ onPointerUp(event) {
996
+ if (event.pointerId !== this.activePointerId) {
997
+ return;
998
+ }
999
+ const deltaX = this.dragOffsetX();
1000
+ const threshold = Math.max(24, this.swipeThreshold());
1001
+ const shouldDismiss = this.dragAxis === 'x' && Math.abs(deltaX) >= threshold;
1002
+ this.releasePointer(event);
1003
+ this.dragAxis = null;
1004
+ this.isDragging.set(false);
1005
+ if (!shouldDismiss) {
1006
+ this.resetPosition();
1007
+ return;
1008
+ }
1009
+ const direction = deltaX >= 0 ? 1 : -1;
1010
+ const exitDistance = Math.max(this.cardWidth * 1.35, 420);
1011
+ this.dragTransition.set(EXIT_TRANSITION);
1012
+ this.dragOffsetX.set(direction * exitDistance);
1013
+ this.swipeEmitTimeoutId = window.setTimeout(() => {
1014
+ this.swipeEmitTimeoutId = null;
1015
+ if (direction > 0) {
1016
+ this.swipedRight.emit();
1017
+ return;
1018
+ }
1019
+ this.swipedLeft.emit();
1020
+ }, 180);
1021
+ }
1022
+ onPointerCancel(event) {
1023
+ if (event.pointerId !== this.activePointerId) {
1024
+ return;
1025
+ }
1026
+ this.releasePointer(event);
1027
+ this.resetPosition();
1028
+ }
1029
+ releasePointer(event) {
1030
+ const card = event.currentTarget;
1031
+ if (card instanceof HTMLElement && card.hasPointerCapture(event.pointerId)) {
1032
+ card.releasePointerCapture(event.pointerId);
1033
+ }
1034
+ this.activePointerId = null;
1035
+ }
1036
+ resetPosition() {
1037
+ this.dragAxis = null;
1038
+ this.isDragging.set(false);
1039
+ this.dragTransition.set(RETURN_TRANSITION);
1040
+ this.dragOffsetX.set(0);
1041
+ }
1042
+ clearSwipeEmitTimeout() {
1043
+ if (this.swipeEmitTimeoutId === null) {
1044
+ return;
1045
+ }
1046
+ window.clearTimeout(this.swipeEmitTimeoutId);
1047
+ this.swipeEmitTimeoutId = null;
1048
+ }
1049
+ clamp(value, min, max) {
1050
+ return Math.min(Math.max(value, min), max);
1051
+ }
800
1052
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: DuckDevCardNeobrutalSlab, deps: [], target: i0.ɵɵFactoryTarget.Component });
801
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.1", type: DuckDevCardNeobrutalSlab, isStandalone: true, selector: "dd-card-neobrutal-slab", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, strapLabel: { classPropertyName: "strapLabel", publicName: "strapLabel", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"dd-card-neo-slab\" [ngStyle]=\"cardStyle()\">\n <div class=\"dd-card-neo-slab__strap\" aria-hidden=\"true\">{{ strapLabel() }}</div>\n <div class=\"dd-card-neo-slab__panel\">\n <div class=\"dd-card-neo-slab__marker\" aria-hidden=\"true\"></div>\n <div class=\"dd-card-neo-slab__content\">\n <ng-content />\n </div>\n </div>\n</article>\n", styles: [".dd-card-neo-slab{position:relative;display:block;background:var(--dd-neo-card-surface);border:4px solid var(--dd-neo-card-border);box-shadow:10px 10px 0 var(--dd-neo-card-shadow);color:var(--dd-neo-card-text)}.dd-card-neo-slab__strap{position:absolute;top:-22px;left:18px;display:inline-flex;align-items:center;justify-content:center;padding:7px 12px;border:3px solid var(--dd-neo-card-border);background:var(--dd-neo-card-accent);box-shadow:4px 4px 0 var(--dd-neo-card-border);font-size:11px;font-weight:900;letter-spacing:.16em;line-height:1;text-transform:uppercase;transform:rotate(-3deg)}.dd-card-neo-slab__panel{position:relative;padding:28px 22px 22px;background:linear-gradient(135deg,color-mix(in srgb,var(--dd-neo-card-accent) 28%,transparent) 0 16%,transparent 16% 100%),var(--dd-neo-card-panel)}.dd-card-neo-slab__marker{position:absolute;top:0;right:0;width:26px;height:26px;border-left:4px solid var(--dd-neo-card-border);border-bottom:4px solid var(--dd-neo-card-border);background:var(--dd-neo-card-accent)}.dd-card-neo-slab__content{position:relative;font-size:15px;line-height:1.6;font-weight:700}.dd-card-neo-slab__content :first-child{margin-top:0}.dd-card-neo-slab__content :last-child{margin-bottom:0}@media(max-width:640px){.dd-card-neo-slab{box-shadow:7px 7px 0 var(--dd-neo-card-shadow)}}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
1053
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.1", type: DuckDevCardNeobrutalSlab, isStandalone: true, selector: "dd-card-neobrutal-slab", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, strapLabel: { classPropertyName: "strapLabel", publicName: "strapLabel", isSignal: true, isRequired: true, transformFunction: null }, swipeable: { classPropertyName: "swipeable", publicName: "swipeable", isSignal: true, isRequired: false, transformFunction: null }, swipeThreshold: { classPropertyName: "swipeThreshold", publicName: "swipeThreshold", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { swipedLeft: "swipedLeft", swipedRight: "swipedRight" }, ngImport: i0, template: "<article\n class=\"dd-card-neo-slab\"\n [class.dd-card-neo-slab--dragging]=\"isDragging()\"\n [class.dd-card-neo-slab--swipeable]=\"swipeable()\"\n [ngStyle]=\"cardStyle()\"\n [style.cursor]=\"cursorStyle()\"\n [style.touch-action]=\"touchActionStyle()\"\n [style.transform]=\"transformStyle()\"\n [style.transition]=\"dragTransition()\"\n (pointercancel)=\"onPointerCancel($event)\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n>\n <div class=\"dd-card-neo-slab__strap\" aria-hidden=\"true\">{{ strapLabel() }}</div>\n <div class=\"dd-card-neo-slab__panel\">\n <div class=\"dd-card-neo-slab__marker\" aria-hidden=\"true\"></div>\n <div class=\"dd-card-neo-slab__content\">\n <ng-content />\n </div>\n </div>\n</article>\n", styles: [".dd-card-neo-slab{position:relative;display:block;background:var(--dd-neo-card-surface);border:4px solid var(--dd-neo-card-border);box-shadow:10px 10px 0 var(--dd-neo-card-shadow);color:var(--dd-neo-card-text);transform-origin:center bottom;will-change:transform}.dd-card-neo-slab.dd-card-neo-slab--swipeable{-webkit-user-select:none;user-select:none}.dd-card-neo-slab.dd-card-neo-slab--dragging{z-index:1}.dd-card-neo-slab__strap{position:absolute;top:-22px;left:18px;display:inline-flex;align-items:center;justify-content:center;padding:7px 12px;border:3px solid var(--dd-neo-card-border);background:var(--dd-neo-card-accent);box-shadow:4px 4px 0 var(--dd-neo-card-border);font-size:11px;font-weight:900;letter-spacing:.16em;line-height:1;text-transform:uppercase;transform:rotate(-3deg)}.dd-card-neo-slab__panel{position:relative;padding:28px 22px 22px;background:linear-gradient(135deg,color-mix(in srgb,var(--dd-neo-card-accent) 28%,transparent) 0 16%,transparent 16% 100%),var(--dd-neo-card-panel)}.dd-card-neo-slab__marker{position:absolute;top:0;right:0;width:26px;height:26px;border-left:4px solid var(--dd-neo-card-border);border-bottom:4px solid var(--dd-neo-card-border);background:var(--dd-neo-card-accent)}.dd-card-neo-slab__content{position:relative;font-size:15px;line-height:1.6;font-weight:700}.dd-card-neo-slab__content :first-child{margin-top:0}.dd-card-neo-slab__content :last-child{margin-bottom:0}@media(max-width:640px){.dd-card-neo-slab{box-shadow:7px 7px 0 var(--dd-neo-card-shadow)}}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
802
1054
  }
803
1055
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: DuckDevCardNeobrutalSlab, decorators: [{
804
1056
  type: Component,
805
- args: [{ selector: 'dd-card-neobrutal-slab', standalone: true, imports: [NgStyle], template: "<article class=\"dd-card-neo-slab\" [ngStyle]=\"cardStyle()\">\n <div class=\"dd-card-neo-slab__strap\" aria-hidden=\"true\">{{ strapLabel() }}</div>\n <div class=\"dd-card-neo-slab__panel\">\n <div class=\"dd-card-neo-slab__marker\" aria-hidden=\"true\"></div>\n <div class=\"dd-card-neo-slab__content\">\n <ng-content />\n </div>\n </div>\n</article>\n", styles: [".dd-card-neo-slab{position:relative;display:block;background:var(--dd-neo-card-surface);border:4px solid var(--dd-neo-card-border);box-shadow:10px 10px 0 var(--dd-neo-card-shadow);color:var(--dd-neo-card-text)}.dd-card-neo-slab__strap{position:absolute;top:-22px;left:18px;display:inline-flex;align-items:center;justify-content:center;padding:7px 12px;border:3px solid var(--dd-neo-card-border);background:var(--dd-neo-card-accent);box-shadow:4px 4px 0 var(--dd-neo-card-border);font-size:11px;font-weight:900;letter-spacing:.16em;line-height:1;text-transform:uppercase;transform:rotate(-3deg)}.dd-card-neo-slab__panel{position:relative;padding:28px 22px 22px;background:linear-gradient(135deg,color-mix(in srgb,var(--dd-neo-card-accent) 28%,transparent) 0 16%,transparent 16% 100%),var(--dd-neo-card-panel)}.dd-card-neo-slab__marker{position:absolute;top:0;right:0;width:26px;height:26px;border-left:4px solid var(--dd-neo-card-border);border-bottom:4px solid var(--dd-neo-card-border);background:var(--dd-neo-card-accent)}.dd-card-neo-slab__content{position:relative;font-size:15px;line-height:1.6;font-weight:700}.dd-card-neo-slab__content :first-child{margin-top:0}.dd-card-neo-slab__content :last-child{margin-bottom:0}@media(max-width:640px){.dd-card-neo-slab{box-shadow:7px 7px 0 var(--dd-neo-card-shadow)}}\n"] }]
806
- }], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], strapLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "strapLabel", required: true }] }] } });
1057
+ args: [{ selector: 'dd-card-neobrutal-slab', standalone: true, imports: [NgStyle], template: "<article\n class=\"dd-card-neo-slab\"\n [class.dd-card-neo-slab--dragging]=\"isDragging()\"\n [class.dd-card-neo-slab--swipeable]=\"swipeable()\"\n [ngStyle]=\"cardStyle()\"\n [style.cursor]=\"cursorStyle()\"\n [style.touch-action]=\"touchActionStyle()\"\n [style.transform]=\"transformStyle()\"\n [style.transition]=\"dragTransition()\"\n (pointercancel)=\"onPointerCancel($event)\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n>\n <div class=\"dd-card-neo-slab__strap\" aria-hidden=\"true\">{{ strapLabel() }}</div>\n <div class=\"dd-card-neo-slab__panel\">\n <div class=\"dd-card-neo-slab__marker\" aria-hidden=\"true\"></div>\n <div class=\"dd-card-neo-slab__content\">\n <ng-content />\n </div>\n </div>\n</article>\n", styles: [".dd-card-neo-slab{position:relative;display:block;background:var(--dd-neo-card-surface);border:4px solid var(--dd-neo-card-border);box-shadow:10px 10px 0 var(--dd-neo-card-shadow);color:var(--dd-neo-card-text);transform-origin:center bottom;will-change:transform}.dd-card-neo-slab.dd-card-neo-slab--swipeable{-webkit-user-select:none;user-select:none}.dd-card-neo-slab.dd-card-neo-slab--dragging{z-index:1}.dd-card-neo-slab__strap{position:absolute;top:-22px;left:18px;display:inline-flex;align-items:center;justify-content:center;padding:7px 12px;border:3px solid var(--dd-neo-card-border);background:var(--dd-neo-card-accent);box-shadow:4px 4px 0 var(--dd-neo-card-border);font-size:11px;font-weight:900;letter-spacing:.16em;line-height:1;text-transform:uppercase;transform:rotate(-3deg)}.dd-card-neo-slab__panel{position:relative;padding:28px 22px 22px;background:linear-gradient(135deg,color-mix(in srgb,var(--dd-neo-card-accent) 28%,transparent) 0 16%,transparent 16% 100%),var(--dd-neo-card-panel)}.dd-card-neo-slab__marker{position:absolute;top:0;right:0;width:26px;height:26px;border-left:4px solid var(--dd-neo-card-border);border-bottom:4px solid var(--dd-neo-card-border);background:var(--dd-neo-card-accent)}.dd-card-neo-slab__content{position:relative;font-size:15px;line-height:1.6;font-weight:700}.dd-card-neo-slab__content :first-child{margin-top:0}.dd-card-neo-slab__content :last-child{margin-bottom:0}@media(max-width:640px){.dd-card-neo-slab{box-shadow:7px 7px 0 var(--dd-neo-card-shadow)}}\n"] }]
1058
+ }], ctorParameters: () => [], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], strapLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "strapLabel", required: true }] }], swipeable: [{ type: i0.Input, args: [{ isSignal: true, alias: "swipeable", required: false }] }], swipeThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "swipeThreshold", required: false }] }], swipedLeft: [{ type: i0.Output, args: ["swipedLeft"] }], swipedRight: [{ type: i0.Output, args: ["swipedRight"] }] } });
807
1059
 
808
1060
  class DuckDevCardNeobrutalStamp {
809
1061
  color = input(AccentEnumColor.Violet, { ...(ngDevMode ? { debugName: "color" } : {}) });
@@ -3450,11 +3702,71 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
3450
3702
 
3451
3703
  class CardBlock {
3452
3704
  t = inject(TranslocoService);
3705
+ neobrutalSwipeDeck = [
3706
+ {
3707
+ strapLabel: 'Swipe deck',
3708
+ title: 'Launch queue',
3709
+ description: 'Swipe right to keep this release in the active sprint stack.',
3710
+ },
3711
+ {
3712
+ strapLabel: 'Triage',
3713
+ title: 'Bug backlog',
3714
+ description: 'Swipe left to skip noisy work and move to the next candidate.',
3715
+ },
3716
+ {
3717
+ strapLabel: 'Hot drop',
3718
+ title: 'Design sync',
3719
+ description: 'The demo loops through cards so the gesture can be tested repeatedly.',
3720
+ },
3721
+ ];
3722
+ neobrutalPosterSwipeDeck = [
3723
+ {
3724
+ railTop: 'Neo',
3725
+ railMiddle: 'Brut',
3726
+ railBottom: 'Keep',
3727
+ eyebrow: 'Ops bulletin',
3728
+ badge: 'Live',
3729
+ title: 'System pulse',
3730
+ description: 'Swipe right to keep this alert in the active deck.',
3731
+ metricLabel: 'Signal',
3732
+ metric: '99%',
3733
+ },
3734
+ {
3735
+ railTop: 'Skip',
3736
+ railMiddle: 'Noise',
3737
+ railBottom: 'Drop',
3738
+ eyebrow: 'Queue filter',
3739
+ badge: 'Muted',
3740
+ title: 'Alert noise',
3741
+ description: 'Swipe left to discard low-priority cards from triage.',
3742
+ metricLabel: 'Load',
3743
+ metric: '23%',
3744
+ },
3745
+ {
3746
+ railTop: 'Deck',
3747
+ railMiddle: 'Loops',
3748
+ railBottom: 'On',
3749
+ eyebrow: 'Demo mode',
3750
+ badge: 'Next',
3751
+ title: 'Preview flow',
3752
+ description: 'The example restores the next poster card after each swipe.',
3753
+ metricLabel: 'Stack',
3754
+ metric: '3',
3755
+ },
3756
+ ];
3453
3757
  colorViolet = AccentEnumColor.Violet;
3454
3758
  colorOrange = AccentEnumColor.Orange;
3455
3759
  colorWhite = AccentEnumColor.White;
3456
3760
  colorGray = AccentEnumColor.Gray;
3457
3761
  colorDark = AccentEnumColor.Dark;
3762
+ neobrutalSwipeIndex = signal(0, { ...(ngDevMode ? { debugName: "neobrutalSwipeIndex" } : {}) });
3763
+ neobrutalSwipeVisible = signal(true, { ...(ngDevMode ? { debugName: "neobrutalSwipeVisible" } : {}) });
3764
+ neobrutalSwipeStatus = signal('Swipe right to keep, swipe left to skip.', { ...(ngDevMode ? { debugName: "neobrutalSwipeStatus" } : {}) });
3765
+ neobrutalSwipeCard = computed(() => this.neobrutalSwipeDeck[this.neobrutalSwipeIndex()], { ...(ngDevMode ? { debugName: "neobrutalSwipeCard" } : {}) });
3766
+ neobrutalPosterSwipeIndex = signal(0, { ...(ngDevMode ? { debugName: "neobrutalPosterSwipeIndex" } : {}) });
3767
+ neobrutalPosterSwipeVisible = signal(true, { ...(ngDevMode ? { debugName: "neobrutalPosterSwipeVisible" } : {}) });
3768
+ neobrutalPosterSwipeStatus = signal('Poster also supports right/left swipe.', { ...(ngDevMode ? { debugName: "neobrutalPosterSwipeStatus" } : {}) });
3769
+ neobrutalPosterSwipeCard = computed(() => this.neobrutalPosterSwipeDeck[this.neobrutalPosterSwipeIndex()], { ...(ngDevMode ? { debugName: "neobrutalPosterSwipeCard" } : {}) });
3458
3770
  styleTabs = [
3459
3771
  { id: 'classic', label: this.t.translate('documentationStyleTabs.classic') },
3460
3772
  { id: 'neobrutalism', label: this.t.translate('documentationStyleTabs.neobrutalism') },
@@ -3511,13 +3823,33 @@ class CardBlock {
3511
3823
  onStyleTabChange(tab) {
3512
3824
  this.activeStyleTab.set(tab);
3513
3825
  }
3826
+ onNeobrutalSlabSwipe(direction) {
3827
+ this.neobrutalSwipeStatus.set(direction === 'right'
3828
+ ? 'Right swipe emitted `swipedRight`.'
3829
+ : 'Left swipe emitted `swipedLeft`.');
3830
+ this.neobrutalSwipeVisible.set(false);
3831
+ window.setTimeout(() => {
3832
+ this.neobrutalSwipeIndex.update((index) => (index + 1) % this.neobrutalSwipeDeck.length);
3833
+ this.neobrutalSwipeVisible.set(true);
3834
+ });
3835
+ }
3836
+ onNeobrutalPosterSwipe(direction) {
3837
+ this.neobrutalPosterSwipeStatus.set(direction === 'right'
3838
+ ? 'Poster emitted `swipedRight`.'
3839
+ : 'Poster emitted `swipedLeft`.');
3840
+ this.neobrutalPosterSwipeVisible.set(false);
3841
+ window.setTimeout(() => {
3842
+ this.neobrutalPosterSwipeIndex.update((index) => (index + 1) % this.neobrutalPosterSwipeDeck.length);
3843
+ this.neobrutalPosterSwipeVisible.set(true);
3844
+ });
3845
+ }
3514
3846
  createEl(html) {
3515
3847
  const el = document.createElement('div');
3516
3848
  el.innerHTML = html;
3517
3849
  return el;
3518
3850
  }
3519
3851
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: CardBlock, deps: [], target: i0.ɵɵFactoryTarget.Component });
3520
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: CardBlock, isStandalone: true, selector: "app-card-block", ngImport: i0, template: "<div class=\"demo-container\">\n <h1>{{ 'cardDoc.title' | transloco }}</h1>\n <duck-dev-tab [tabs]=\"styleTabs\" (tabChange)=\"onStyleTabChange($event)\">\n @if (activeStyleTab().id === 'classic') {\n\n <dd-card-section>\n <h2>{{ 'cardDoc.basic.title' | transloco }}</h2>\n <p class=\"description\">{{ 'cardDoc.basic.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'cardDoc.basic.usage' | transloco }}</h3>\n <pre><code>&lt;dd-card-accent [color]=\"colorWhite\"&gt;\n &lt;div [innerHTML]=\"exampleDefault.innerHTML\"&gt;&lt;/div&gt;\n &lt;/dd-card-accent&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'cardDoc.basic.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'cardDoc.basic.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.defaultWhite' | transloco }}</p>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"exampleDefault.innerHTML\"></div>\n </dd-card-accent>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.violet' | transloco }}</p>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"exampleViolet.innerHTML\"></div>\n </dd-card-accent>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.orange' | transloco }}</p>\n <dd-card-accent [color]=\"colorOrange\">\n <div [innerHTML]=\"exampleOrange.innerHTML\"></div>\n </dd-card-accent>\n </div>\n </div>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.gray' | transloco }}</p>\n <dd-card-accent [color]=\"colorGray\">\n <div [innerHTML]=\"exampleGray.innerHTML\"></div>\n </dd-card-accent>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.dark' | transloco }}</p>\n <dd-card-accent [color]=\"colorDark\">\n <div [innerHTML]=\"exampleDark.innerHTML\"></div>\n </dd-card-accent>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'cardDoc.minimal.title' | transloco }}</h2>\n <p class=\"description\">{{ 'cardDoc.minimal.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'cardDoc.minimal.usage' | transloco }}</h3>\n <pre><code>&lt;dd-card-minimal [color]=\"colorWhite\"&gt;\n &lt;div [innerHTML]=\"minimalExampleDefault.innerHTML\"&gt;&lt;/div&gt;\n &lt;/dd-card-minimal&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'cardDoc.minimal.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-minimal [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-minimal>\n </li>\n <li>\n <dd-card-minimal [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-minimal>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'cardDoc.minimal.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.defaultWhite' | transloco }}</p>\n <dd-card-minimal [color]=\"colorWhite\">\n <div [innerHTML]=\"minimalExampleDefault.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.violet' | transloco }}</p>\n <dd-card-minimal [color]=\"colorViolet\">\n <div [innerHTML]=\"minimalExampleViolet.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.orange' | transloco }}</p>\n <dd-card-minimal [color]=\"colorOrange\">\n <div [innerHTML]=\"minimalExampleOrange.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n </div>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.gray' | transloco }}</p>\n <dd-card-minimal [color]=\"colorGray\">\n <div [innerHTML]=\"minimalExampleGray.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.dark' | transloco }}</p>\n <dd-card-minimal [color]=\"colorDark\">\n <div [innerHTML]=\"minimalExampleDark.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'cardDoc.outline.title' | transloco }}</h2>\n <p class=\"description\">{{ 'cardDoc.outline.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'cardDoc.outline.usage' | transloco }}</h3>\n <pre><code>&lt;dd-card-outline [color]=\"colorWhite\"&gt;\n &lt;div [innerHTML]=\"outlineExampleDefault.innerHTML\"&gt;&lt;/div&gt;\n &lt;/dd-card-outline&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'cardDoc.outline.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-outline [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-outline>\n </li>\n <li>\n <dd-card-outline [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-outline>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'cardDoc.outline.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.defaultWhite' | transloco }}</p>\n <dd-card-outline [color]=\"colorWhite\">\n <div [innerHTML]=\"outlineExampleDefault.innerHTML\"></div>\n </dd-card-outline>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.violet' | transloco }}</p>\n <dd-card-outline [color]=\"colorViolet\">\n <div [innerHTML]=\"outlineExampleViolet.innerHTML\"></div>\n </dd-card-outline>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.orange' | transloco }}</p>\n <dd-card-outline [color]=\"colorOrange\">\n <div [innerHTML]=\"outlineExampleOrange.innerHTML\"></div>\n </dd-card-outline>\n </div>\n </div>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.gray' | transloco }}</p>\n <dd-card-outline [color]=\"colorGray\">\n <div [innerHTML]=\"outlineExampleGray.innerHTML\"></div>\n </dd-card-outline>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.dark' | transloco }}</p>\n <dd-card-outline [color]=\"colorDark\">\n <div [innerHTML]=\"outlineExampleDark.innerHTML\"></div>\n </dd-card-outline>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'cardDoc.signal.title' | transloco }}</h2>\n <p class=\"description\">{{ 'cardDoc.signal.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'cardDoc.signal.usage' | transloco }}</h3>\n <pre><code>&lt;dd-card-signal [color]=\"colorWhite\"&gt;\n &lt;div [innerHTML]=\"signalExampleDefault.innerHTML\"&gt;&lt;/div&gt;\n &lt;/dd-card-signal&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'cardDoc.signal.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-signal [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-signal>\n </li>\n <li>\n <dd-card-signal [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-signal>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'cardDoc.signal.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.defaultWhite' | transloco }}</p>\n <dd-card-signal [color]=\"colorWhite\">\n <div [innerHTML]=\"signalExampleDefault.innerHTML\"></div>\n </dd-card-signal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.violet' | transloco }}</p>\n <dd-card-signal [color]=\"colorViolet\">\n <div [innerHTML]=\"signalExampleViolet.innerHTML\"></div>\n </dd-card-signal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.orange' | transloco }}</p>\n <dd-card-signal [color]=\"colorOrange\">\n <div [innerHTML]=\"signalExampleOrange.innerHTML\"></div>\n </dd-card-signal>\n </div>\n </div>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.gray' | transloco }}</p>\n <dd-card-signal [color]=\"colorGray\">\n <div [innerHTML]=\"signalExampleGray.innerHTML\"></div>\n </dd-card-signal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.dark' | transloco }}</p>\n <dd-card-signal [color]=\"colorDark\">\n <div [innerHTML]=\"signalExampleDark.innerHTML\"></div>\n </dd-card-signal>\n </div>\n </div>\n </div>\n </dd-card-section>\n } @else {\n <dd-card-section>\n <h2>Neobrutalism Cards</h2>\n <p class=\"description\">\n Bold card variants with hard borders, loud shadows and poster-like composition. They keep the\n same simple API: pass `[color]` and project any content through `ng-content`.\n </p>\n\n <div class=\"usage-block\">\n <h3>Neobrutalism usage</h3>\n <pre><code>&lt;dd-card-neobrutal-slab [color]=\"colorOrange\" strapLabel=\"Duck Dev\"&gt;\n &lt;h4&gt;Launch queue&lt;/h4&gt;\n &lt;p&gt;Three releases are waiting for approval.&lt;/p&gt;\n&lt;/dd-card-neobrutal-slab&gt;</code></pre>\n </div>\n\n <div class=\"examples-block\">\n <h3>Neobrutalism examples</h3>\n <div class=\"example-row\">\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">Slab / Orange</p>\n <dd-card-neobrutal-slab [color]=\"colorOrange\" strapLabel=\"Duck Dev\">\n <h4>Launch queue</h4>\n <p>Three releases are waiting for approval and one build is blocked by QA.</p>\n </dd-card-neobrutal-slab>\n </div>\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">Stamp / Violet</p>\n <dd-card-neobrutal-stamp\n [color]=\"colorViolet\"\n chromeStart=\"Fresh UI\"\n chromeEnd=\"Duck Dev\"\n sealLabel=\"Seal\"\n >\n <h4>Design drop</h4>\n <p>Fresh visual assets landed in the library and need review before sync.</p>\n </dd-card-neobrutal-stamp>\n </div>\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">Poster / Dark</p>\n <dd-card-neobrutal-poster\n [color]=\"colorDark\"\n railTop=\"Neo\"\n railMiddle=\"Brut\"\n railBottom=\"Alert\"\n eyebrow=\"Ops bulletin\"\n badge=\"Live\"\n title=\"System pulse\"\n description=\"Telemetry is clean, rate limits are stable and the service window is open.\"\n metricLabel=\"Signal\"\n metric=\"99%\"\n />\n </div>\n <app-neobrutal-ticket-card-block />\n </div>\n </div>\n </dd-card-section>\n }\n </duck-dev-tab>\n</div>\n", styles: [".demo-container{max-width:1200px;margin:0 auto;padding:40px 20px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.demo-container h1{font-size:36px;font-weight:700;color:var(--dd-base-600);margin-bottom:40px;text-align:center;border-bottom:3px solid var(--dd-base-accent-blue);padding-bottom:20px}.demo-container h2{font-size:28px;font-weight:600;color:var(--dd-base-500);margin-bottom:15px;border-left:4px solid var(--dd-base-accent-blue);padding-left:15px}.demo-container .description{font-size:16px;line-height:1.6;color:var(--dd-base-400);margin-bottom:25px;padding:15px;background:var(--dd-base-100);border-radius:8px;border-left:3px solid var(--dd-base-300)}.demo-container h3{font-size:20px;font-weight:600;color:var(--dd-base-500);margin-bottom:15px;margin-top:25px}.demo-container .usage-block{margin-bottom:25px}.demo-container .usage-block pre{background:var(--dd-base-600);color:var(--dd-base-100);padding:20px;border-radius:8px;overflow-x:auto;margin:0}.demo-container .usage-block pre code{font-family:Courier New,Courier,monospace;font-size:14px;line-height:1.5}.demo-container .inputs-block{margin-bottom:25px}.demo-container .inputs-block ul{list-style:none;padding:0;margin:0}.demo-container .inputs-block ul li{padding:0;margin-bottom:8px;background:transparent;border-radius:0;border:none}.demo-container .examples-block .example-row{display:flex;gap:20px;margin-bottom:20px;flex-wrap:wrap}.demo-container .examples-block .example-row .example-item{flex:1;min-width:250px;padding:20px;background:var(--dd-base-100);border-radius:8px;border:2px solid var(--dd-base-300);display:flex;flex-direction:column;align-items:stretch;gap:15px;transition:all .3s ease}.demo-container .examples-block .example-row .example-item:hover{border-color:var(--dd-base-accent-blue);box-shadow:0 4px 12px var(--dd-base-300)}.demo-container .examples-block .example-row .example-item.example-item--neobrutal{background:linear-gradient(135deg,color-mix(in srgb,var(--dd-base-accent-yellow) 24%,transparent) 0 15%,transparent 15% 100%),var(--dd-base-0);border:4px solid var(--dd-base-600);border-radius:0;box-shadow:8px 8px 0 var(--dd-base-accent-blue)}.demo-container .examples-block .example-row .example-item.example-item--neobrutal:hover{border-color:var(--dd-base-600);box-shadow:10px 10px 0 var(--dd-base-accent-orange)}.demo-container .examples-block .example-row .example-item .example-label{font-size:14px;font-weight:600;color:var(--dd-base-400);margin:0;text-align:left}@media(max-width:768px){.demo-container{padding:20px 15px}.demo-container h1{font-size:28px}.demo-container h2{font-size:24px}.demo-container .examples-block .example-row{flex-direction:column}}\n"], dependencies: [{ kind: "component", type: DuckDevCardAccent, selector: "dd-card-accent", inputs: ["color"] }, { kind: "component", type: DuckDevCardMinimal, selector: "dd-card-minimal", inputs: ["color"] }, { kind: "component", type: DuckDevCardNeobrutalPoster, selector: "dd-card-neobrutal-poster", inputs: ["color", "railTop", "railMiddle", "railBottom", "eyebrow", "title", "description", "badge", "metricLabel", "metric"] }, { kind: "component", type: DuckDevCardNeobrutalSlab, selector: "dd-card-neobrutal-slab", inputs: ["color", "strapLabel"] }, { kind: "component", type: DuckDevCardNeobrutalStamp, selector: "dd-card-neobrutal-stamp", inputs: ["color", "chromeStart", "chromeEnd", "sealLabel"] }, { kind: "component", type: DuckDevCardOutline, selector: "dd-card-outline", inputs: ["color"] }, { kind: "component", type: DuckDevCardSignal, selector: "dd-card-signal", inputs: ["color"] }, { kind: "component", type: DuckDevCardSection, selector: "dd-card-section" }, { kind: "component", type: NeobrutalTicketCardBlock, selector: "app-neobrutal-ticket-card-block" }, { kind: "component", type: DuckDevTab, selector: "duck-dev-tab", inputs: ["tabs"], outputs: ["tabChange"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
3852
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: CardBlock, isStandalone: true, selector: "app-card-block", ngImport: i0, template: "<div class=\"demo-container\">\n <h1>{{ 'cardDoc.title' | transloco }}</h1>\n <duck-dev-tab [tabs]=\"styleTabs\" (tabChange)=\"onStyleTabChange($event)\">\n @if (activeStyleTab().id === 'classic') {\n\n <dd-card-section>\n <h2>{{ 'cardDoc.basic.title' | transloco }}</h2>\n <p class=\"description\">{{ 'cardDoc.basic.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'cardDoc.basic.usage' | transloco }}</h3>\n <pre><code>&lt;dd-card-accent [color]=\"colorWhite\"&gt;\n &lt;div [innerHTML]=\"exampleDefault.innerHTML\"&gt;&lt;/div&gt;\n &lt;/dd-card-accent&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'cardDoc.basic.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'cardDoc.basic.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.defaultWhite' | transloco }}</p>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"exampleDefault.innerHTML\"></div>\n </dd-card-accent>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.violet' | transloco }}</p>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"exampleViolet.innerHTML\"></div>\n </dd-card-accent>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.orange' | transloco }}</p>\n <dd-card-accent [color]=\"colorOrange\">\n <div [innerHTML]=\"exampleOrange.innerHTML\"></div>\n </dd-card-accent>\n </div>\n </div>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.gray' | transloco }}</p>\n <dd-card-accent [color]=\"colorGray\">\n <div [innerHTML]=\"exampleGray.innerHTML\"></div>\n </dd-card-accent>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.dark' | transloco }}</p>\n <dd-card-accent [color]=\"colorDark\">\n <div [innerHTML]=\"exampleDark.innerHTML\"></div>\n </dd-card-accent>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'cardDoc.minimal.title' | transloco }}</h2>\n <p class=\"description\">{{ 'cardDoc.minimal.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'cardDoc.minimal.usage' | transloco }}</h3>\n <pre><code>&lt;dd-card-minimal [color]=\"colorWhite\"&gt;\n &lt;div [innerHTML]=\"minimalExampleDefault.innerHTML\"&gt;&lt;/div&gt;\n &lt;/dd-card-minimal&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'cardDoc.minimal.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-minimal [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-minimal>\n </li>\n <li>\n <dd-card-minimal [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-minimal>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'cardDoc.minimal.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.defaultWhite' | transloco }}</p>\n <dd-card-minimal [color]=\"colorWhite\">\n <div [innerHTML]=\"minimalExampleDefault.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.violet' | transloco }}</p>\n <dd-card-minimal [color]=\"colorViolet\">\n <div [innerHTML]=\"minimalExampleViolet.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.orange' | transloco }}</p>\n <dd-card-minimal [color]=\"colorOrange\">\n <div [innerHTML]=\"minimalExampleOrange.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n </div>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.gray' | transloco }}</p>\n <dd-card-minimal [color]=\"colorGray\">\n <div [innerHTML]=\"minimalExampleGray.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.dark' | transloco }}</p>\n <dd-card-minimal [color]=\"colorDark\">\n <div [innerHTML]=\"minimalExampleDark.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'cardDoc.outline.title' | transloco }}</h2>\n <p class=\"description\">{{ 'cardDoc.outline.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'cardDoc.outline.usage' | transloco }}</h3>\n <pre><code>&lt;dd-card-outline [color]=\"colorWhite\"&gt;\n &lt;div [innerHTML]=\"outlineExampleDefault.innerHTML\"&gt;&lt;/div&gt;\n &lt;/dd-card-outline&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'cardDoc.outline.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-outline [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-outline>\n </li>\n <li>\n <dd-card-outline [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-outline>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'cardDoc.outline.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.defaultWhite' | transloco }}</p>\n <dd-card-outline [color]=\"colorWhite\">\n <div [innerHTML]=\"outlineExampleDefault.innerHTML\"></div>\n </dd-card-outline>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.violet' | transloco }}</p>\n <dd-card-outline [color]=\"colorViolet\">\n <div [innerHTML]=\"outlineExampleViolet.innerHTML\"></div>\n </dd-card-outline>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.orange' | transloco }}</p>\n <dd-card-outline [color]=\"colorOrange\">\n <div [innerHTML]=\"outlineExampleOrange.innerHTML\"></div>\n </dd-card-outline>\n </div>\n </div>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.gray' | transloco }}</p>\n <dd-card-outline [color]=\"colorGray\">\n <div [innerHTML]=\"outlineExampleGray.innerHTML\"></div>\n </dd-card-outline>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.dark' | transloco }}</p>\n <dd-card-outline [color]=\"colorDark\">\n <div [innerHTML]=\"outlineExampleDark.innerHTML\"></div>\n </dd-card-outline>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'cardDoc.signal.title' | transloco }}</h2>\n <p class=\"description\">{{ 'cardDoc.signal.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'cardDoc.signal.usage' | transloco }}</h3>\n <pre><code>&lt;dd-card-signal [color]=\"colorWhite\"&gt;\n &lt;div [innerHTML]=\"signalExampleDefault.innerHTML\"&gt;&lt;/div&gt;\n &lt;/dd-card-signal&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'cardDoc.signal.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-signal [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-signal>\n </li>\n <li>\n <dd-card-signal [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-signal>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'cardDoc.signal.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.defaultWhite' | transloco }}</p>\n <dd-card-signal [color]=\"colorWhite\">\n <div [innerHTML]=\"signalExampleDefault.innerHTML\"></div>\n </dd-card-signal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.violet' | transloco }}</p>\n <dd-card-signal [color]=\"colorViolet\">\n <div [innerHTML]=\"signalExampleViolet.innerHTML\"></div>\n </dd-card-signal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.orange' | transloco }}</p>\n <dd-card-signal [color]=\"colorOrange\">\n <div [innerHTML]=\"signalExampleOrange.innerHTML\"></div>\n </dd-card-signal>\n </div>\n </div>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.gray' | transloco }}</p>\n <dd-card-signal [color]=\"colorGray\">\n <div [innerHTML]=\"signalExampleGray.innerHTML\"></div>\n </dd-card-signal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.dark' | transloco }}</p>\n <dd-card-signal [color]=\"colorDark\">\n <div [innerHTML]=\"signalExampleDark.innerHTML\"></div>\n </dd-card-signal>\n </div>\n </div>\n </div>\n </dd-card-section>\n } @else {\n <dd-card-section>\n <h2>Neobrutalism Cards</h2>\n <p class=\"description\">\n Bold card variants with hard borders, loud shadows and poster-like composition. They keep the\n same simple API: pass `[color]` and project any content through `ng-content`.\n </p>\n\n <div class=\"usage-block\">\n <h3>Neobrutalism usage</h3>\n <pre><code>&lt;dd-card-neobrutal-slab\n [color]=\"colorOrange\"\n strapLabel=\"Swipe deck\"\n [swipeable]=\"true\"\n [swipeThreshold]=\"112\"\n (swipedLeft)=\"onNeobrutalSlabSwipe('left')\"\n (swipedRight)=\"onNeobrutalSlabSwipe('right')\"\n&gt;\n &lt;h4&gt;Launch queue&lt;/h4&gt;\n &lt;p&gt;Swipe right to keep the card, swipe left to skip it.&lt;/p&gt;\n&lt;/dd-card-neobrutal-slab&gt;</code></pre>\n <pre><code>&lt;dd-card-neobrutal-poster\n [color]=\"colorDark\"\n railTop=\"Neo\"\n railMiddle=\"Brut\"\n railBottom=\"Alert\"\n eyebrow=\"Ops bulletin\"\n badge=\"Live\"\n title=\"System pulse\"\n description=\"Swipe right to keep this card in the active deck.\"\n metricLabel=\"Signal\"\n metric=\"99%\"\n [swipeable]=\"true\"\n [swipeThreshold]=\"112\"\n (swipedLeft)=\"onNeobrutalPosterSwipe('left')\"\n (swipedRight)=\"onNeobrutalPosterSwipe('right')\"\n/&gt;</code></pre>\n </div>\n\n <div class=\"examples-block\">\n <h3>Neobrutalism examples</h3>\n <div class=\"example-row\">\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">Slab / Swipe</p>\n @if (neobrutalSwipeVisible()) {\n <dd-card-neobrutal-slab\n [color]=\"colorOrange\"\n [swipeable]=\"true\"\n [swipeThreshold]=\"112\"\n [strapLabel]=\"neobrutalSwipeCard().strapLabel\"\n (swipedLeft)=\"onNeobrutalSlabSwipe('left')\"\n (swipedRight)=\"onNeobrutalSlabSwipe('right')\"\n >\n <h4>{{ neobrutalSwipeCard().title }}</h4>\n <p>{{ neobrutalSwipeCard().description }}</p>\n </dd-card-neobrutal-slab>\n }\n <p class=\"example-note\">{{ neobrutalSwipeStatus() }}</p>\n </div>\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">Slab / Orange</p>\n <dd-card-neobrutal-slab [color]=\"colorOrange\" strapLabel=\"Duck Dev\">\n <h4>Launch queue</h4>\n <p>Three releases are waiting for approval and one build is blocked by QA.</p>\n </dd-card-neobrutal-slab>\n </div>\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">Stamp / Violet</p>\n <dd-card-neobrutal-stamp\n [color]=\"colorViolet\"\n chromeStart=\"Fresh UI\"\n chromeEnd=\"Duck Dev\"\n sealLabel=\"Seal\"\n >\n <h4>Design drop</h4>\n <p>Fresh visual assets landed in the library and need review before sync.</p>\n </dd-card-neobrutal-stamp>\n </div>\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">Poster / Swipe</p>\n @if (neobrutalPosterSwipeVisible()) {\n <dd-card-neobrutal-poster\n [color]=\"colorDark\"\n [railTop]=\"neobrutalPosterSwipeCard().railTop\"\n [railMiddle]=\"neobrutalPosterSwipeCard().railMiddle\"\n [railBottom]=\"neobrutalPosterSwipeCard().railBottom\"\n [eyebrow]=\"neobrutalPosterSwipeCard().eyebrow\"\n [badge]=\"neobrutalPosterSwipeCard().badge\"\n [title]=\"neobrutalPosterSwipeCard().title\"\n [description]=\"neobrutalPosterSwipeCard().description\"\n [metricLabel]=\"neobrutalPosterSwipeCard().metricLabel\"\n [metric]=\"neobrutalPosterSwipeCard().metric\"\n [swipeable]=\"true\"\n [swipeThreshold]=\"112\"\n (swipedLeft)=\"onNeobrutalPosterSwipe('left')\"\n (swipedRight)=\"onNeobrutalPosterSwipe('right')\"\n />\n }\n <p class=\"example-note\">{{ neobrutalPosterSwipeStatus() }}</p>\n </div>\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">Poster / Dark</p>\n <dd-card-neobrutal-poster\n [color]=\"colorDark\"\n railTop=\"Neo\"\n railMiddle=\"Brut\"\n railBottom=\"Alert\"\n eyebrow=\"Ops bulletin\"\n badge=\"Live\"\n title=\"System pulse\"\n description=\"Telemetry is clean, rate limits are stable and the service window is open.\"\n metricLabel=\"Signal\"\n metric=\"99%\"\n />\n </div>\n <app-neobrutal-ticket-card-block />\n </div>\n </div>\n </dd-card-section>\n }\n </duck-dev-tab>\n</div>\n", styles: [".demo-container{max-width:1200px;margin:0 auto;padding:40px 20px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.demo-container h1{font-size:36px;font-weight:700;color:var(--dd-base-600);margin-bottom:40px;text-align:center;border-bottom:3px solid var(--dd-base-accent-blue);padding-bottom:20px}.demo-container h2{font-size:28px;font-weight:600;color:var(--dd-base-500);margin-bottom:15px;border-left:4px solid var(--dd-base-accent-blue);padding-left:15px}.demo-container .description{font-size:16px;line-height:1.6;color:var(--dd-base-400);margin-bottom:25px;padding:15px;background:var(--dd-base-100);border-radius:8px;border-left:3px solid var(--dd-base-300)}.demo-container h3{font-size:20px;font-weight:600;color:var(--dd-base-500);margin-bottom:15px;margin-top:25px}.demo-container .usage-block{margin-bottom:25px}.demo-container .usage-block pre{background:var(--dd-base-600);color:var(--dd-base-100);padding:20px;border-radius:8px;overflow-x:auto;margin:0}.demo-container .usage-block pre code{font-family:Courier New,Courier,monospace;font-size:14px;line-height:1.5}.demo-container .inputs-block{margin-bottom:25px}.demo-container .inputs-block ul{list-style:none;padding:0;margin:0}.demo-container .inputs-block ul li{padding:0;margin-bottom:8px;background:transparent;border-radius:0;border:none}.demo-container .examples-block .example-row{display:flex;gap:20px;margin-bottom:20px;flex-wrap:wrap}.demo-container .examples-block .example-row .example-item{flex:1;min-width:250px;padding:20px;background:var(--dd-base-100);border-radius:8px;border:2px solid var(--dd-base-300);display:flex;flex-direction:column;align-items:stretch;gap:15px;transition:all .3s ease}.demo-container .examples-block .example-row .example-item:hover{border-color:var(--dd-base-accent-blue);box-shadow:0 4px 12px var(--dd-base-300)}.demo-container .examples-block .example-row .example-item.example-item--neobrutal{background:linear-gradient(135deg,color-mix(in srgb,var(--dd-base-accent-yellow) 24%,transparent) 0 15%,transparent 15% 100%),var(--dd-base-0);border:4px solid var(--dd-base-600);border-radius:0;box-shadow:8px 8px 0 var(--dd-base-accent-blue)}.demo-container .examples-block .example-row .example-item.example-item--neobrutal:hover{border-color:var(--dd-base-600);box-shadow:10px 10px 0 var(--dd-base-accent-orange)}.demo-container .examples-block .example-row .example-item .example-label{font-size:14px;font-weight:600;color:var(--dd-base-400);margin:0;text-align:left}.demo-container .examples-block .example-row .example-item .example-note{margin:0;padding:10px 12px;border:2px solid var(--dd-base-600);background:color-mix(in srgb,var(--dd-base-accent-yellow) 20%,var(--dd-base-0));font-size:13px;font-weight:700;line-height:1.4;color:var(--dd-base-600)}@media(max-width:768px){.demo-container{padding:20px 15px}.demo-container h1{font-size:28px}.demo-container h2{font-size:24px}.demo-container .examples-block .example-row{flex-direction:column}}\n"], dependencies: [{ kind: "component", type: DuckDevCardAccent, selector: "dd-card-accent", inputs: ["color"] }, { kind: "component", type: DuckDevCardMinimal, selector: "dd-card-minimal", inputs: ["color"] }, { kind: "component", type: DuckDevCardNeobrutalPoster, selector: "dd-card-neobrutal-poster", inputs: ["color", "railTop", "railMiddle", "railBottom", "eyebrow", "title", "description", "badge", "metricLabel", "metric", "swipeable", "swipeThreshold"], outputs: ["swipedLeft", "swipedRight"] }, { kind: "component", type: DuckDevCardNeobrutalSlab, selector: "dd-card-neobrutal-slab", inputs: ["color", "strapLabel", "swipeable", "swipeThreshold"], outputs: ["swipedLeft", "swipedRight"] }, { kind: "component", type: DuckDevCardNeobrutalStamp, selector: "dd-card-neobrutal-stamp", inputs: ["color", "chromeStart", "chromeEnd", "sealLabel"] }, { kind: "component", type: DuckDevCardOutline, selector: "dd-card-outline", inputs: ["color"] }, { kind: "component", type: DuckDevCardSignal, selector: "dd-card-signal", inputs: ["color"] }, { kind: "component", type: DuckDevCardSection, selector: "dd-card-section" }, { kind: "component", type: NeobrutalTicketCardBlock, selector: "app-neobrutal-ticket-card-block" }, { kind: "component", type: DuckDevTab, selector: "duck-dev-tab", inputs: ["tabs"], outputs: ["tabChange"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
3521
3853
  }
3522
3854
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: CardBlock, decorators: [{
3523
3855
  type: Component,
@@ -3533,7 +3865,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
3533
3865
  DuckDevCardSection,
3534
3866
  NeobrutalTicketCardBlock,
3535
3867
  DuckDevTab,
3536
- ], template: "<div class=\"demo-container\">\n <h1>{{ 'cardDoc.title' | transloco }}</h1>\n <duck-dev-tab [tabs]=\"styleTabs\" (tabChange)=\"onStyleTabChange($event)\">\n @if (activeStyleTab().id === 'classic') {\n\n <dd-card-section>\n <h2>{{ 'cardDoc.basic.title' | transloco }}</h2>\n <p class=\"description\">{{ 'cardDoc.basic.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'cardDoc.basic.usage' | transloco }}</h3>\n <pre><code>&lt;dd-card-accent [color]=\"colorWhite\"&gt;\n &lt;div [innerHTML]=\"exampleDefault.innerHTML\"&gt;&lt;/div&gt;\n &lt;/dd-card-accent&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'cardDoc.basic.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'cardDoc.basic.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.defaultWhite' | transloco }}</p>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"exampleDefault.innerHTML\"></div>\n </dd-card-accent>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.violet' | transloco }}</p>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"exampleViolet.innerHTML\"></div>\n </dd-card-accent>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.orange' | transloco }}</p>\n <dd-card-accent [color]=\"colorOrange\">\n <div [innerHTML]=\"exampleOrange.innerHTML\"></div>\n </dd-card-accent>\n </div>\n </div>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.gray' | transloco }}</p>\n <dd-card-accent [color]=\"colorGray\">\n <div [innerHTML]=\"exampleGray.innerHTML\"></div>\n </dd-card-accent>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.dark' | transloco }}</p>\n <dd-card-accent [color]=\"colorDark\">\n <div [innerHTML]=\"exampleDark.innerHTML\"></div>\n </dd-card-accent>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'cardDoc.minimal.title' | transloco }}</h2>\n <p class=\"description\">{{ 'cardDoc.minimal.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'cardDoc.minimal.usage' | transloco }}</h3>\n <pre><code>&lt;dd-card-minimal [color]=\"colorWhite\"&gt;\n &lt;div [innerHTML]=\"minimalExampleDefault.innerHTML\"&gt;&lt;/div&gt;\n &lt;/dd-card-minimal&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'cardDoc.minimal.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-minimal [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-minimal>\n </li>\n <li>\n <dd-card-minimal [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-minimal>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'cardDoc.minimal.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.defaultWhite' | transloco }}</p>\n <dd-card-minimal [color]=\"colorWhite\">\n <div [innerHTML]=\"minimalExampleDefault.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.violet' | transloco }}</p>\n <dd-card-minimal [color]=\"colorViolet\">\n <div [innerHTML]=\"minimalExampleViolet.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.orange' | transloco }}</p>\n <dd-card-minimal [color]=\"colorOrange\">\n <div [innerHTML]=\"minimalExampleOrange.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n </div>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.gray' | transloco }}</p>\n <dd-card-minimal [color]=\"colorGray\">\n <div [innerHTML]=\"minimalExampleGray.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.dark' | transloco }}</p>\n <dd-card-minimal [color]=\"colorDark\">\n <div [innerHTML]=\"minimalExampleDark.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'cardDoc.outline.title' | transloco }}</h2>\n <p class=\"description\">{{ 'cardDoc.outline.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'cardDoc.outline.usage' | transloco }}</h3>\n <pre><code>&lt;dd-card-outline [color]=\"colorWhite\"&gt;\n &lt;div [innerHTML]=\"outlineExampleDefault.innerHTML\"&gt;&lt;/div&gt;\n &lt;/dd-card-outline&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'cardDoc.outline.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-outline [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-outline>\n </li>\n <li>\n <dd-card-outline [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-outline>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'cardDoc.outline.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.defaultWhite' | transloco }}</p>\n <dd-card-outline [color]=\"colorWhite\">\n <div [innerHTML]=\"outlineExampleDefault.innerHTML\"></div>\n </dd-card-outline>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.violet' | transloco }}</p>\n <dd-card-outline [color]=\"colorViolet\">\n <div [innerHTML]=\"outlineExampleViolet.innerHTML\"></div>\n </dd-card-outline>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.orange' | transloco }}</p>\n <dd-card-outline [color]=\"colorOrange\">\n <div [innerHTML]=\"outlineExampleOrange.innerHTML\"></div>\n </dd-card-outline>\n </div>\n </div>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.gray' | transloco }}</p>\n <dd-card-outline [color]=\"colorGray\">\n <div [innerHTML]=\"outlineExampleGray.innerHTML\"></div>\n </dd-card-outline>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.dark' | transloco }}</p>\n <dd-card-outline [color]=\"colorDark\">\n <div [innerHTML]=\"outlineExampleDark.innerHTML\"></div>\n </dd-card-outline>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'cardDoc.signal.title' | transloco }}</h2>\n <p class=\"description\">{{ 'cardDoc.signal.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'cardDoc.signal.usage' | transloco }}</h3>\n <pre><code>&lt;dd-card-signal [color]=\"colorWhite\"&gt;\n &lt;div [innerHTML]=\"signalExampleDefault.innerHTML\"&gt;&lt;/div&gt;\n &lt;/dd-card-signal&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'cardDoc.signal.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-signal [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-signal>\n </li>\n <li>\n <dd-card-signal [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-signal>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'cardDoc.signal.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.defaultWhite' | transloco }}</p>\n <dd-card-signal [color]=\"colorWhite\">\n <div [innerHTML]=\"signalExampleDefault.innerHTML\"></div>\n </dd-card-signal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.violet' | transloco }}</p>\n <dd-card-signal [color]=\"colorViolet\">\n <div [innerHTML]=\"signalExampleViolet.innerHTML\"></div>\n </dd-card-signal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.orange' | transloco }}</p>\n <dd-card-signal [color]=\"colorOrange\">\n <div [innerHTML]=\"signalExampleOrange.innerHTML\"></div>\n </dd-card-signal>\n </div>\n </div>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.gray' | transloco }}</p>\n <dd-card-signal [color]=\"colorGray\">\n <div [innerHTML]=\"signalExampleGray.innerHTML\"></div>\n </dd-card-signal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.dark' | transloco }}</p>\n <dd-card-signal [color]=\"colorDark\">\n <div [innerHTML]=\"signalExampleDark.innerHTML\"></div>\n </dd-card-signal>\n </div>\n </div>\n </div>\n </dd-card-section>\n } @else {\n <dd-card-section>\n <h2>Neobrutalism Cards</h2>\n <p class=\"description\">\n Bold card variants with hard borders, loud shadows and poster-like composition. They keep the\n same simple API: pass `[color]` and project any content through `ng-content`.\n </p>\n\n <div class=\"usage-block\">\n <h3>Neobrutalism usage</h3>\n <pre><code>&lt;dd-card-neobrutal-slab [color]=\"colorOrange\" strapLabel=\"Duck Dev\"&gt;\n &lt;h4&gt;Launch queue&lt;/h4&gt;\n &lt;p&gt;Three releases are waiting for approval.&lt;/p&gt;\n&lt;/dd-card-neobrutal-slab&gt;</code></pre>\n </div>\n\n <div class=\"examples-block\">\n <h3>Neobrutalism examples</h3>\n <div class=\"example-row\">\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">Slab / Orange</p>\n <dd-card-neobrutal-slab [color]=\"colorOrange\" strapLabel=\"Duck Dev\">\n <h4>Launch queue</h4>\n <p>Three releases are waiting for approval and one build is blocked by QA.</p>\n </dd-card-neobrutal-slab>\n </div>\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">Stamp / Violet</p>\n <dd-card-neobrutal-stamp\n [color]=\"colorViolet\"\n chromeStart=\"Fresh UI\"\n chromeEnd=\"Duck Dev\"\n sealLabel=\"Seal\"\n >\n <h4>Design drop</h4>\n <p>Fresh visual assets landed in the library and need review before sync.</p>\n </dd-card-neobrutal-stamp>\n </div>\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">Poster / Dark</p>\n <dd-card-neobrutal-poster\n [color]=\"colorDark\"\n railTop=\"Neo\"\n railMiddle=\"Brut\"\n railBottom=\"Alert\"\n eyebrow=\"Ops bulletin\"\n badge=\"Live\"\n title=\"System pulse\"\n description=\"Telemetry is clean, rate limits are stable and the service window is open.\"\n metricLabel=\"Signal\"\n metric=\"99%\"\n />\n </div>\n <app-neobrutal-ticket-card-block />\n </div>\n </div>\n </dd-card-section>\n }\n </duck-dev-tab>\n</div>\n", styles: [".demo-container{max-width:1200px;margin:0 auto;padding:40px 20px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.demo-container h1{font-size:36px;font-weight:700;color:var(--dd-base-600);margin-bottom:40px;text-align:center;border-bottom:3px solid var(--dd-base-accent-blue);padding-bottom:20px}.demo-container h2{font-size:28px;font-weight:600;color:var(--dd-base-500);margin-bottom:15px;border-left:4px solid var(--dd-base-accent-blue);padding-left:15px}.demo-container .description{font-size:16px;line-height:1.6;color:var(--dd-base-400);margin-bottom:25px;padding:15px;background:var(--dd-base-100);border-radius:8px;border-left:3px solid var(--dd-base-300)}.demo-container h3{font-size:20px;font-weight:600;color:var(--dd-base-500);margin-bottom:15px;margin-top:25px}.demo-container .usage-block{margin-bottom:25px}.demo-container .usage-block pre{background:var(--dd-base-600);color:var(--dd-base-100);padding:20px;border-radius:8px;overflow-x:auto;margin:0}.demo-container .usage-block pre code{font-family:Courier New,Courier,monospace;font-size:14px;line-height:1.5}.demo-container .inputs-block{margin-bottom:25px}.demo-container .inputs-block ul{list-style:none;padding:0;margin:0}.demo-container .inputs-block ul li{padding:0;margin-bottom:8px;background:transparent;border-radius:0;border:none}.demo-container .examples-block .example-row{display:flex;gap:20px;margin-bottom:20px;flex-wrap:wrap}.demo-container .examples-block .example-row .example-item{flex:1;min-width:250px;padding:20px;background:var(--dd-base-100);border-radius:8px;border:2px solid var(--dd-base-300);display:flex;flex-direction:column;align-items:stretch;gap:15px;transition:all .3s ease}.demo-container .examples-block .example-row .example-item:hover{border-color:var(--dd-base-accent-blue);box-shadow:0 4px 12px var(--dd-base-300)}.demo-container .examples-block .example-row .example-item.example-item--neobrutal{background:linear-gradient(135deg,color-mix(in srgb,var(--dd-base-accent-yellow) 24%,transparent) 0 15%,transparent 15% 100%),var(--dd-base-0);border:4px solid var(--dd-base-600);border-radius:0;box-shadow:8px 8px 0 var(--dd-base-accent-blue)}.demo-container .examples-block .example-row .example-item.example-item--neobrutal:hover{border-color:var(--dd-base-600);box-shadow:10px 10px 0 var(--dd-base-accent-orange)}.demo-container .examples-block .example-row .example-item .example-label{font-size:14px;font-weight:600;color:var(--dd-base-400);margin:0;text-align:left}@media(max-width:768px){.demo-container{padding:20px 15px}.demo-container h1{font-size:28px}.demo-container h2{font-size:24px}.demo-container .examples-block .example-row{flex-direction:column}}\n"] }]
3868
+ ], template: "<div class=\"demo-container\">\n <h1>{{ 'cardDoc.title' | transloco }}</h1>\n <duck-dev-tab [tabs]=\"styleTabs\" (tabChange)=\"onStyleTabChange($event)\">\n @if (activeStyleTab().id === 'classic') {\n\n <dd-card-section>\n <h2>{{ 'cardDoc.basic.title' | transloco }}</h2>\n <p class=\"description\">{{ 'cardDoc.basic.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'cardDoc.basic.usage' | transloco }}</h3>\n <pre><code>&lt;dd-card-accent [color]=\"colorWhite\"&gt;\n &lt;div [innerHTML]=\"exampleDefault.innerHTML\"&gt;&lt;/div&gt;\n &lt;/dd-card-accent&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'cardDoc.basic.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'cardDoc.basic.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.defaultWhite' | transloco }}</p>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"exampleDefault.innerHTML\"></div>\n </dd-card-accent>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.violet' | transloco }}</p>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"exampleViolet.innerHTML\"></div>\n </dd-card-accent>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.orange' | transloco }}</p>\n <dd-card-accent [color]=\"colorOrange\">\n <div [innerHTML]=\"exampleOrange.innerHTML\"></div>\n </dd-card-accent>\n </div>\n </div>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.gray' | transloco }}</p>\n <dd-card-accent [color]=\"colorGray\">\n <div [innerHTML]=\"exampleGray.innerHTML\"></div>\n </dd-card-accent>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.dark' | transloco }}</p>\n <dd-card-accent [color]=\"colorDark\">\n <div [innerHTML]=\"exampleDark.innerHTML\"></div>\n </dd-card-accent>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'cardDoc.minimal.title' | transloco }}</h2>\n <p class=\"description\">{{ 'cardDoc.minimal.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'cardDoc.minimal.usage' | transloco }}</h3>\n <pre><code>&lt;dd-card-minimal [color]=\"colorWhite\"&gt;\n &lt;div [innerHTML]=\"minimalExampleDefault.innerHTML\"&gt;&lt;/div&gt;\n &lt;/dd-card-minimal&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'cardDoc.minimal.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-minimal [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-minimal>\n </li>\n <li>\n <dd-card-minimal [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-minimal>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'cardDoc.minimal.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.defaultWhite' | transloco }}</p>\n <dd-card-minimal [color]=\"colorWhite\">\n <div [innerHTML]=\"minimalExampleDefault.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.violet' | transloco }}</p>\n <dd-card-minimal [color]=\"colorViolet\">\n <div [innerHTML]=\"minimalExampleViolet.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.orange' | transloco }}</p>\n <dd-card-minimal [color]=\"colorOrange\">\n <div [innerHTML]=\"minimalExampleOrange.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n </div>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.gray' | transloco }}</p>\n <dd-card-minimal [color]=\"colorGray\">\n <div [innerHTML]=\"minimalExampleGray.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.dark' | transloco }}</p>\n <dd-card-minimal [color]=\"colorDark\">\n <div [innerHTML]=\"minimalExampleDark.innerHTML\"></div>\n </dd-card-minimal>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'cardDoc.outline.title' | transloco }}</h2>\n <p class=\"description\">{{ 'cardDoc.outline.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'cardDoc.outline.usage' | transloco }}</h3>\n <pre><code>&lt;dd-card-outline [color]=\"colorWhite\"&gt;\n &lt;div [innerHTML]=\"outlineExampleDefault.innerHTML\"&gt;&lt;/div&gt;\n &lt;/dd-card-outline&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'cardDoc.outline.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-outline [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-outline>\n </li>\n <li>\n <dd-card-outline [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-outline>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'cardDoc.outline.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.defaultWhite' | transloco }}</p>\n <dd-card-outline [color]=\"colorWhite\">\n <div [innerHTML]=\"outlineExampleDefault.innerHTML\"></div>\n </dd-card-outline>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.violet' | transloco }}</p>\n <dd-card-outline [color]=\"colorViolet\">\n <div [innerHTML]=\"outlineExampleViolet.innerHTML\"></div>\n </dd-card-outline>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.orange' | transloco }}</p>\n <dd-card-outline [color]=\"colorOrange\">\n <div [innerHTML]=\"outlineExampleOrange.innerHTML\"></div>\n </dd-card-outline>\n </div>\n </div>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.gray' | transloco }}</p>\n <dd-card-outline [color]=\"colorGray\">\n <div [innerHTML]=\"outlineExampleGray.innerHTML\"></div>\n </dd-card-outline>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.dark' | transloco }}</p>\n <dd-card-outline [color]=\"colorDark\">\n <div [innerHTML]=\"outlineExampleDark.innerHTML\"></div>\n </dd-card-outline>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'cardDoc.signal.title' | transloco }}</h2>\n <p class=\"description\">{{ 'cardDoc.signal.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'cardDoc.signal.usage' | transloco }}</h3>\n <pre><code>&lt;dd-card-signal [color]=\"colorWhite\"&gt;\n &lt;div [innerHTML]=\"signalExampleDefault.innerHTML\"&gt;&lt;/div&gt;\n &lt;/dd-card-signal&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'cardDoc.signal.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-signal [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-signal>\n </li>\n <li>\n <dd-card-signal [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-signal>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'cardDoc.signal.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.defaultWhite' | transloco }}</p>\n <dd-card-signal [color]=\"colorWhite\">\n <div [innerHTML]=\"signalExampleDefault.innerHTML\"></div>\n </dd-card-signal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.violet' | transloco }}</p>\n <dd-card-signal [color]=\"colorViolet\">\n <div [innerHTML]=\"signalExampleViolet.innerHTML\"></div>\n </dd-card-signal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.orange' | transloco }}</p>\n <dd-card-signal [color]=\"colorOrange\">\n <div [innerHTML]=\"signalExampleOrange.innerHTML\"></div>\n </dd-card-signal>\n </div>\n </div>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.gray' | transloco }}</p>\n <dd-card-signal [color]=\"colorGray\">\n <div [innerHTML]=\"signalExampleGray.innerHTML\"></div>\n </dd-card-signal>\n </div>\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'cardDoc.examples.dark' | transloco }}</p>\n <dd-card-signal [color]=\"colorDark\">\n <div [innerHTML]=\"signalExampleDark.innerHTML\"></div>\n </dd-card-signal>\n </div>\n </div>\n </div>\n </dd-card-section>\n } @else {\n <dd-card-section>\n <h2>Neobrutalism Cards</h2>\n <p class=\"description\">\n Bold card variants with hard borders, loud shadows and poster-like composition. They keep the\n same simple API: pass `[color]` and project any content through `ng-content`.\n </p>\n\n <div class=\"usage-block\">\n <h3>Neobrutalism usage</h3>\n <pre><code>&lt;dd-card-neobrutal-slab\n [color]=\"colorOrange\"\n strapLabel=\"Swipe deck\"\n [swipeable]=\"true\"\n [swipeThreshold]=\"112\"\n (swipedLeft)=\"onNeobrutalSlabSwipe('left')\"\n (swipedRight)=\"onNeobrutalSlabSwipe('right')\"\n&gt;\n &lt;h4&gt;Launch queue&lt;/h4&gt;\n &lt;p&gt;Swipe right to keep the card, swipe left to skip it.&lt;/p&gt;\n&lt;/dd-card-neobrutal-slab&gt;</code></pre>\n <pre><code>&lt;dd-card-neobrutal-poster\n [color]=\"colorDark\"\n railTop=\"Neo\"\n railMiddle=\"Brut\"\n railBottom=\"Alert\"\n eyebrow=\"Ops bulletin\"\n badge=\"Live\"\n title=\"System pulse\"\n description=\"Swipe right to keep this card in the active deck.\"\n metricLabel=\"Signal\"\n metric=\"99%\"\n [swipeable]=\"true\"\n [swipeThreshold]=\"112\"\n (swipedLeft)=\"onNeobrutalPosterSwipe('left')\"\n (swipedRight)=\"onNeobrutalPosterSwipe('right')\"\n/&gt;</code></pre>\n </div>\n\n <div class=\"examples-block\">\n <h3>Neobrutalism examples</h3>\n <div class=\"example-row\">\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">Slab / Swipe</p>\n @if (neobrutalSwipeVisible()) {\n <dd-card-neobrutal-slab\n [color]=\"colorOrange\"\n [swipeable]=\"true\"\n [swipeThreshold]=\"112\"\n [strapLabel]=\"neobrutalSwipeCard().strapLabel\"\n (swipedLeft)=\"onNeobrutalSlabSwipe('left')\"\n (swipedRight)=\"onNeobrutalSlabSwipe('right')\"\n >\n <h4>{{ neobrutalSwipeCard().title }}</h4>\n <p>{{ neobrutalSwipeCard().description }}</p>\n </dd-card-neobrutal-slab>\n }\n <p class=\"example-note\">{{ neobrutalSwipeStatus() }}</p>\n </div>\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">Slab / Orange</p>\n <dd-card-neobrutal-slab [color]=\"colorOrange\" strapLabel=\"Duck Dev\">\n <h4>Launch queue</h4>\n <p>Three releases are waiting for approval and one build is blocked by QA.</p>\n </dd-card-neobrutal-slab>\n </div>\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">Stamp / Violet</p>\n <dd-card-neobrutal-stamp\n [color]=\"colorViolet\"\n chromeStart=\"Fresh UI\"\n chromeEnd=\"Duck Dev\"\n sealLabel=\"Seal\"\n >\n <h4>Design drop</h4>\n <p>Fresh visual assets landed in the library and need review before sync.</p>\n </dd-card-neobrutal-stamp>\n </div>\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">Poster / Swipe</p>\n @if (neobrutalPosterSwipeVisible()) {\n <dd-card-neobrutal-poster\n [color]=\"colorDark\"\n [railTop]=\"neobrutalPosterSwipeCard().railTop\"\n [railMiddle]=\"neobrutalPosterSwipeCard().railMiddle\"\n [railBottom]=\"neobrutalPosterSwipeCard().railBottom\"\n [eyebrow]=\"neobrutalPosterSwipeCard().eyebrow\"\n [badge]=\"neobrutalPosterSwipeCard().badge\"\n [title]=\"neobrutalPosterSwipeCard().title\"\n [description]=\"neobrutalPosterSwipeCard().description\"\n [metricLabel]=\"neobrutalPosterSwipeCard().metricLabel\"\n [metric]=\"neobrutalPosterSwipeCard().metric\"\n [swipeable]=\"true\"\n [swipeThreshold]=\"112\"\n (swipedLeft)=\"onNeobrutalPosterSwipe('left')\"\n (swipedRight)=\"onNeobrutalPosterSwipe('right')\"\n />\n }\n <p class=\"example-note\">{{ neobrutalPosterSwipeStatus() }}</p>\n </div>\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">Poster / Dark</p>\n <dd-card-neobrutal-poster\n [color]=\"colorDark\"\n railTop=\"Neo\"\n railMiddle=\"Brut\"\n railBottom=\"Alert\"\n eyebrow=\"Ops bulletin\"\n badge=\"Live\"\n title=\"System pulse\"\n description=\"Telemetry is clean, rate limits are stable and the service window is open.\"\n metricLabel=\"Signal\"\n metric=\"99%\"\n />\n </div>\n <app-neobrutal-ticket-card-block />\n </div>\n </div>\n </dd-card-section>\n }\n </duck-dev-tab>\n</div>\n", styles: [".demo-container{max-width:1200px;margin:0 auto;padding:40px 20px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.demo-container h1{font-size:36px;font-weight:700;color:var(--dd-base-600);margin-bottom:40px;text-align:center;border-bottom:3px solid var(--dd-base-accent-blue);padding-bottom:20px}.demo-container h2{font-size:28px;font-weight:600;color:var(--dd-base-500);margin-bottom:15px;border-left:4px solid var(--dd-base-accent-blue);padding-left:15px}.demo-container .description{font-size:16px;line-height:1.6;color:var(--dd-base-400);margin-bottom:25px;padding:15px;background:var(--dd-base-100);border-radius:8px;border-left:3px solid var(--dd-base-300)}.demo-container h3{font-size:20px;font-weight:600;color:var(--dd-base-500);margin-bottom:15px;margin-top:25px}.demo-container .usage-block{margin-bottom:25px}.demo-container .usage-block pre{background:var(--dd-base-600);color:var(--dd-base-100);padding:20px;border-radius:8px;overflow-x:auto;margin:0}.demo-container .usage-block pre code{font-family:Courier New,Courier,monospace;font-size:14px;line-height:1.5}.demo-container .inputs-block{margin-bottom:25px}.demo-container .inputs-block ul{list-style:none;padding:0;margin:0}.demo-container .inputs-block ul li{padding:0;margin-bottom:8px;background:transparent;border-radius:0;border:none}.demo-container .examples-block .example-row{display:flex;gap:20px;margin-bottom:20px;flex-wrap:wrap}.demo-container .examples-block .example-row .example-item{flex:1;min-width:250px;padding:20px;background:var(--dd-base-100);border-radius:8px;border:2px solid var(--dd-base-300);display:flex;flex-direction:column;align-items:stretch;gap:15px;transition:all .3s ease}.demo-container .examples-block .example-row .example-item:hover{border-color:var(--dd-base-accent-blue);box-shadow:0 4px 12px var(--dd-base-300)}.demo-container .examples-block .example-row .example-item.example-item--neobrutal{background:linear-gradient(135deg,color-mix(in srgb,var(--dd-base-accent-yellow) 24%,transparent) 0 15%,transparent 15% 100%),var(--dd-base-0);border:4px solid var(--dd-base-600);border-radius:0;box-shadow:8px 8px 0 var(--dd-base-accent-blue)}.demo-container .examples-block .example-row .example-item.example-item--neobrutal:hover{border-color:var(--dd-base-600);box-shadow:10px 10px 0 var(--dd-base-accent-orange)}.demo-container .examples-block .example-row .example-item .example-label{font-size:14px;font-weight:600;color:var(--dd-base-400);margin:0;text-align:left}.demo-container .examples-block .example-row .example-item .example-note{margin:0;padding:10px 12px;border:2px solid var(--dd-base-600);background:color-mix(in srgb,var(--dd-base-accent-yellow) 20%,var(--dd-base-0));font-size:13px;font-weight:700;line-height:1.4;color:var(--dd-base-600)}@media(max-width:768px){.demo-container{padding:20px 15px}.demo-container h1{font-size:28px}.demo-container h2{font-size:24px}.demo-container .examples-block .example-row{flex-direction:column}}\n"] }]
3537
3869
  }], ctorParameters: () => [] });
3538
3870
 
3539
3871
  class DuckDevTooltip {
@@ -4036,6 +4368,1310 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
4036
4368
  ], template: "<div class=\"demo-container\">\n <h1>{{ 'progressDoc.title' | transloco }}</h1>\n\n <duck-dev-tab [tabs]=\"styleTabs\" (tabChange)=\"onStyleTabChange($event)\">\n @if (activeStyleTab().id === 'classic') {\n <section class=\"component-section\">\n <h2>{{ 'progressDoc.classic.line.title' | transloco }}</h2>\n <p class=\"description\">{{ 'progressDoc.classic.line.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'progressDoc.usage' | transloco }}</h3>\n <pre><code>&lt;duck-dev-progress-line\n label=\"Release sync\"\n [value]=\"72\"\n subtext=\"API schema is aligned\"\n [color]=\"colorViolet\"\n/&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'progressDoc.inputs' | transloco }}</h3>\n <ul>\n <li [innerHTML]=\"'progressDoc.inputsDesc.label' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.value' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.subtext' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.color' | transloco\"></li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'progressDoc.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'progressDoc.classic.line.example' | transloco }}</p>\n <duck-dev-progress-line\n label=\"Release sync\"\n [value]=\"lineProgress\"\n subtext=\"API schema is aligned\"\n [color]=\"colorViolet\"\n />\n </div>\n </div>\n </div>\n </section>\n\n <section class=\"component-section\">\n <h2>{{ 'progressDoc.classic.stack.title' | transloco }}</h2>\n <p class=\"description\">{{ 'progressDoc.classic.stack.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'progressDoc.usage' | transloco }}</h3>\n <pre><code>&lt;duck-dev-progress-stack\n label=\"Content migration\"\n [value]=\"56\"\n subtext=\"6 of 10 blocks shipped\"\n [segmentCount]=\"10\"\n [color]=\"colorOrange\"\n/&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'progressDoc.inputs' | transloco }}</h3>\n <ul>\n <li [innerHTML]=\"'progressDoc.inputsDesc.label' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.value' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.subtext' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.segmentCount' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.color' | transloco\"></li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'progressDoc.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'progressDoc.classic.stack.example' | transloco }}</p>\n <duck-dev-progress-stack\n label=\"Content migration\"\n [value]=\"stackProgress\"\n subtext=\"6 of 10 blocks shipped\"\n [segmentCount]=\"10\"\n [color]=\"colorOrange\"\n />\n </div>\n </div>\n </div>\n </section>\n\n <section class=\"component-section\">\n <h2>{{ 'progressDoc.classic.meter.title' | transloco }}</h2>\n <p class=\"description\">{{ 'progressDoc.classic.meter.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'progressDoc.usage' | transloco }}</h3>\n <pre><code>&lt;duck-dev-progress-meter\n label=\"Regression sweep\"\n [value]=\"84\"\n subtext=\"Visual QA is nearly done\"\n [color]=\"colorGray\"\n/&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'progressDoc.inputs' | transloco }}</h3>\n <ul>\n <li [innerHTML]=\"'progressDoc.inputsDesc.label' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.value' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.subtext' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.color' | transloco\"></li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'progressDoc.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'progressDoc.classic.meter.example' | transloco }}</p>\n <duck-dev-progress-meter\n label=\"Regression sweep\"\n [value]=\"meterProgress\"\n subtext=\"Visual QA is nearly done\"\n [color]=\"colorGray\"\n />\n </div>\n </div>\n </div>\n </section>\n } @else {\n <section class=\"component-section component-section--neobrutal\">\n <h2>{{ 'progressDoc.neobrutal.slab.title' | transloco }}</h2>\n <p class=\"description\">{{ 'progressDoc.neobrutal.slab.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'progressDoc.usage' | transloco }}</h3>\n <pre><code>&lt;duck-dev-progress-neobrutal-slab\n label=\"Build queue\"\n [value]=\"68\"\n subtext=\"Artifact pack is cooking\"\n [color]=\"colorOrange\"\n/&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'progressDoc.inputs' | transloco }}</h3>\n <ul>\n <li [innerHTML]=\"'progressDoc.inputsDesc.label' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.value' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.subtext' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.color' | transloco\"></li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'progressDoc.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">{{ 'progressDoc.neobrutal.slab.example' | transloco }}</p>\n <duck-dev-progress-neobrutal-slab\n label=\"Build queue\"\n [value]=\"slabProgress\"\n subtext=\"Artifact pack is cooking\"\n [color]=\"colorOrange\"\n />\n </div>\n </div>\n </div>\n </section>\n\n <section class=\"component-section component-section--neobrutal\">\n <h2>{{ 'progressDoc.neobrutal.stamp.title' | transloco }}</h2>\n <p class=\"description\">{{ 'progressDoc.neobrutal.stamp.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'progressDoc.usage' | transloco }}</h3>\n <pre><code>&lt;duck-dev-progress-neobrutal-stamp\n kicker=\"Duck Dev\"\n label=\"Verification pass\"\n [value]=\"91\"\n [color]=\"colorViolet\"\n/&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'progressDoc.inputs' | transloco }}</h3>\n <ul>\n <li [innerHTML]=\"'progressDoc.inputsDesc.kicker' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.label' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.value' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.color' | transloco\"></li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'progressDoc.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">{{ 'progressDoc.neobrutal.stamp.example' | transloco }}</p>\n <duck-dev-progress-neobrutal-stamp\n kicker=\"Duck Dev\"\n label=\"Verification pass\"\n [value]=\"stampProgress\"\n [color]=\"colorViolet\"\n />\n </div>\n </div>\n </div>\n </section>\n\n <section class=\"component-section component-section--neobrutal\">\n <h2>{{ 'progressDoc.neobrutal.ticket.title' | transloco }}</h2>\n <p class=\"description\">{{ 'progressDoc.neobrutal.ticket.description' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'progressDoc.usage' | transloco }}</h3>\n <pre><code>&lt;duck-dev-progress-neobrutal-ticket\n leftTag=\"phase 02\"\n rightTag=\"ui sync\"\n label=\"Neobrutal rollout\"\n [value]=\"47\"\n [color]=\"colorDark\"\n/&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'progressDoc.inputs' | transloco }}</h3>\n <ul>\n <li [innerHTML]=\"'progressDoc.inputsDesc.leftTag' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.rightTag' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.label' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.value' | transloco\"></li>\n <li [innerHTML]=\"'progressDoc.inputsDesc.color' | transloco\"></li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'progressDoc.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">{{ 'progressDoc.neobrutal.ticket.example' | transloco }}</p>\n <duck-dev-progress-neobrutal-ticket\n leftTag=\"phase 02\"\n rightTag=\"ui sync\"\n label=\"Neobrutal rollout\"\n [value]=\"ticketProgress\"\n [color]=\"colorDark\"\n />\n </div>\n </div>\n </div>\n </section>\n }\n </duck-dev-tab>\n</div>\n", styles: [":root{--dd-appear-time: .5s;--dd-gray-0: #ffffff;--dd-gray-100: #f8f5f6;--dd-gray-200: #f2f4f5;--dd-gray-300: #eaeaea;--dd-gray-400: #999999;--dd-gray-500: #252525;--dd-gray-600: #121312;--dd-success: #a7ffb5ba;--dd-secondary: #6829ff;--dd-accent-orange: #fe7b20;--dd-orange-active: #e5350f;--dd-accent-pink: #fd6ca9;--dd-accent-yellow: #ffd027;--dd-accent-blue: #3254f3;--dd-base-0: var(--dd-gray-0);--dd-base-100: var(--dd-gray-100);--dd-base-200: var(--dd-gray-200);--dd-base-300: var(--dd-gray-300);--dd-base-400: var(--dd-gray-400);--dd-base-500: var(--dd-gray-500);--dd-base-600: var(--dd-gray-600);--dd-background: var(--dd-gray-200);--dd-base-success: var(--dd-success);--dd-base-secondary: var(--dd-secondary);--dd-base-accent-orange: var(--dd-accent-orange);--dd-base-active-orange: var(--dd-orange-active);--dd-base-accent-pink: var(--dd-accent-pink);--dd-base-accent-yellow: var(--dd-accent-yellow);--dd-base-accent-blue: var(--dd-accent-blue)}[ddTheme=dark]{--dd-base-0: var(--dd-gray-600);--dd-base-100: var(--dd-gray-500);--dd-base-200: var(--dd-gray-400);--dd-base-300: var(--dd-gray-300);--dd-base-400: var(--dd-gray-200);--dd-base-500: var(--dd-gray-100);--dd-base-600: var(--dd-gray-0);--dd-background: var(--dd-gray-500)}[ddTheme=violet]{--dd-base-50: var(--dd-magenta-500)}.demo-container{max-width:1200px;margin:0 auto;padding:40px 20px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.demo-container h1{font-size:36px;font-weight:700;color:var(--dd-base-600);margin-bottom:40px;text-align:center;border-bottom:3px solid var(--dd-base-accent-blue);padding-bottom:20px}.demo-container h2{font-size:28px;font-weight:600;color:var(--dd-base-500);margin-bottom:15px;border-left:4px solid var(--dd-base-accent-blue);padding-left:15px}.demo-container .component-section{margin-bottom:40px}.demo-container .description{font-size:16px;line-height:1.6;color:var(--dd-base-400);margin-bottom:25px;padding:15px;background:var(--dd-base-100);border-radius:8px;border-left:3px solid var(--dd-base-300)}.demo-container h3{font-size:20px;font-weight:600;color:var(--dd-base-500);margin-bottom:15px;margin-top:25px}.demo-container .usage-block{margin-bottom:25px}.demo-container .usage-block pre{background:var(--dd-base-600);color:var(--dd-base-100);padding:20px;border-radius:8px;overflow-x:auto;margin:0}.demo-container .usage-block pre code{font-family:Courier New,Courier,monospace;font-size:14px;line-height:1.5}.demo-container .inputs-block{margin-bottom:25px}.demo-container .inputs-block ul{list-style:none;padding:0;margin:0}.demo-container .inputs-block ul li{margin-bottom:8px}.demo-container .examples-block .example-row{display:flex;gap:20px;margin-bottom:20px;flex-wrap:wrap}.demo-container .examples-block .example-item{flex:1;min-width:280px;padding:20px;background:var(--dd-base-100);border-radius:8px;border:2px solid var(--dd-base-300);display:flex;flex-direction:column;gap:16px;transition:all .3s ease}.demo-container .examples-block .example-item:hover{border-color:var(--dd-base-accent-blue);box-shadow:0 4px 12px var(--dd-base-300)}.demo-container .examples-block .example-item--neobrutal{background:linear-gradient(135deg,color-mix(in srgb,var(--dd-base-accent-yellow) 24%,transparent) 0 15%,transparent 15% 100%),var(--dd-base-0);border:4px solid var(--dd-base-600);border-radius:0;box-shadow:8px 8px 0 var(--dd-base-accent-blue)}.demo-container .examples-block .example-item--neobrutal:hover{border-color:var(--dd-base-600);box-shadow:10px 10px 0 var(--dd-base-accent-orange)}.demo-container .examples-block .example-label{font-size:14px;font-weight:600;color:var(--dd-base-400);margin:0}@media(max-width:768px){.demo-container{padding:20px 15px}.demo-container h1{font-size:28px}.demo-container h2{font-size:24px}.demo-container .examples-block .example-row{flex-direction:column}.demo-container .examples-block .example-item{min-width:100%}}\n"] }]
4037
4369
  }] });
4038
4370
 
4371
+ function getClassicSpeakerBubbleStyle(color) {
4372
+ switch (color) {
4373
+ case AccentEnumColor.Violet:
4374
+ return {
4375
+ '--dd-speaker-surface': 'color-mix(in srgb, var(--dd-base-secondary) 12%, var(--dd-base-0))',
4376
+ '--dd-speaker-surface-muted': 'color-mix(in srgb, var(--dd-base-secondary) 18%, var(--dd-base-0))',
4377
+ '--dd-speaker-text': 'var(--dd-base-600)',
4378
+ '--dd-speaker-border': 'color-mix(in srgb, var(--dd-base-secondary) 42%, var(--dd-base-300))',
4379
+ '--dd-speaker-accent': 'var(--dd-base-secondary)',
4380
+ '--dd-speaker-shadow': 'color-mix(in srgb, var(--dd-base-secondary) 32%, var(--dd-base-accent-blue))',
4381
+ };
4382
+ case AccentEnumColor.Orange:
4383
+ return {
4384
+ '--dd-speaker-surface': 'color-mix(in srgb, var(--dd-base-accent-orange) 14%, var(--dd-base-0))',
4385
+ '--dd-speaker-surface-muted': 'color-mix(in srgb, var(--dd-base-accent-yellow) 24%, var(--dd-base-0))',
4386
+ '--dd-speaker-text': 'var(--dd-base-600)',
4387
+ '--dd-speaker-border': 'color-mix(in srgb, var(--dd-base-accent-orange) 45%, var(--dd-base-300))',
4388
+ '--dd-speaker-accent': 'var(--dd-base-accent-orange)',
4389
+ '--dd-speaker-shadow': 'color-mix(in srgb, var(--dd-base-accent-orange) 42%, var(--dd-base-accent-yellow))',
4390
+ };
4391
+ case AccentEnumColor.Gray:
4392
+ return {
4393
+ '--dd-speaker-surface': 'var(--dd-base-0)',
4394
+ '--dd-speaker-surface-muted': 'var(--dd-base-100)',
4395
+ '--dd-speaker-text': 'var(--dd-base-500)',
4396
+ '--dd-speaker-border': 'var(--dd-base-300)',
4397
+ '--dd-speaker-accent': 'var(--dd-base-400)',
4398
+ '--dd-speaker-shadow': 'var(--dd-base-300)',
4399
+ };
4400
+ case AccentEnumColor.Dark:
4401
+ return {
4402
+ '--dd-speaker-surface': 'color-mix(in srgb, var(--dd-base-600) 94%, var(--dd-base-500))',
4403
+ '--dd-speaker-surface-muted': 'color-mix(in srgb, var(--dd-base-600) 88%, var(--dd-base-500))',
4404
+ '--dd-speaker-text': 'var(--dd-base-0)',
4405
+ '--dd-speaker-border': 'var(--dd-base-400)',
4406
+ '--dd-speaker-accent': 'var(--dd-base-accent-yellow)',
4407
+ '--dd-speaker-shadow': 'color-mix(in srgb, var(--dd-base-accent-orange) 44%, var(--dd-base-600))',
4408
+ };
4409
+ case AccentEnumColor.White:
4410
+ default:
4411
+ return {
4412
+ '--dd-speaker-surface': 'var(--dd-base-0)',
4413
+ '--dd-speaker-surface-muted': 'var(--dd-base-100)',
4414
+ '--dd-speaker-text': 'var(--dd-base-600)',
4415
+ '--dd-speaker-border': 'var(--dd-base-300)',
4416
+ '--dd-speaker-accent': 'var(--dd-base-accent-blue)',
4417
+ '--dd-speaker-shadow': 'color-mix(in srgb, var(--dd-base-accent-blue) 26%, var(--dd-base-300))',
4418
+ };
4419
+ }
4420
+ }
4421
+ function getNeobrutalSpeakerBubbleStyle(color) {
4422
+ switch (color) {
4423
+ case AccentEnumColor.Violet:
4424
+ return {
4425
+ '--dd-speaker-surface': 'color-mix(in srgb, var(--dd-base-accent-blue) 16%, var(--dd-base-0))',
4426
+ '--dd-speaker-surface-muted': 'color-mix(in srgb, var(--dd-base-accent-yellow) 20%, var(--dd-base-0))',
4427
+ '--dd-speaker-text': 'var(--dd-base-600)',
4428
+ '--dd-speaker-border': 'var(--dd-base-600)',
4429
+ '--dd-speaker-accent': 'var(--dd-base-accent-yellow)',
4430
+ '--dd-speaker-shadow': 'var(--dd-base-accent-blue)',
4431
+ };
4432
+ case AccentEnumColor.Orange:
4433
+ return {
4434
+ '--dd-speaker-surface': 'color-mix(in srgb, var(--dd-base-accent-orange) 20%, var(--dd-base-0))',
4435
+ '--dd-speaker-surface-muted': 'color-mix(in srgb, var(--dd-base-accent-pink) 18%, var(--dd-base-0))',
4436
+ '--dd-speaker-text': 'var(--dd-base-600)',
4437
+ '--dd-speaker-border': 'var(--dd-base-600)',
4438
+ '--dd-speaker-accent': 'var(--dd-base-accent-pink)',
4439
+ '--dd-speaker-shadow': 'var(--dd-base-accent-orange)',
4440
+ };
4441
+ case AccentEnumColor.Gray:
4442
+ return {
4443
+ '--dd-speaker-surface': 'var(--dd-base-100)',
4444
+ '--dd-speaker-surface-muted': 'var(--dd-base-0)',
4445
+ '--dd-speaker-text': 'var(--dd-base-600)',
4446
+ '--dd-speaker-border': 'var(--dd-base-600)',
4447
+ '--dd-speaker-accent': 'var(--dd-base-accent-blue)',
4448
+ '--dd-speaker-shadow': 'var(--dd-base-400)',
4449
+ };
4450
+ case AccentEnumColor.Dark:
4451
+ return {
4452
+ '--dd-speaker-surface': 'var(--dd-base-600)',
4453
+ '--dd-speaker-surface-muted': 'color-mix(in srgb, var(--dd-base-600) 90%, var(--dd-base-500))',
4454
+ '--dd-speaker-text': 'var(--dd-base-0)',
4455
+ '--dd-speaker-border': 'var(--dd-base-0)',
4456
+ '--dd-speaker-accent': 'var(--dd-base-accent-yellow)',
4457
+ '--dd-speaker-shadow': 'var(--dd-base-accent-orange)',
4458
+ };
4459
+ case AccentEnumColor.White:
4460
+ default:
4461
+ return {
4462
+ '--dd-speaker-surface': 'var(--dd-base-0)',
4463
+ '--dd-speaker-surface-muted': 'color-mix(in srgb, var(--dd-base-accent-yellow) 14%, var(--dd-base-0))',
4464
+ '--dd-speaker-text': 'var(--dd-base-600)',
4465
+ '--dd-speaker-border': 'var(--dd-base-600)',
4466
+ '--dd-speaker-accent': 'var(--dd-base-accent-orange)',
4467
+ '--dd-speaker-shadow': 'var(--dd-base-accent-blue)',
4468
+ };
4469
+ }
4470
+ }
4471
+
4472
+ const DEFAULT_BUBBLE_GEOMETRY$2 = {
4473
+ side: 'left',
4474
+ style: {
4475
+ left: '0px',
4476
+ top: '0px',
4477
+ width: '1px',
4478
+ height: '1px',
4479
+ },
4480
+ viewBox: '0 0 1 1',
4481
+ path: '',
4482
+ };
4483
+ function clamp$3(value, min, max) {
4484
+ return Math.min(Math.max(value, min), max);
4485
+ }
4486
+ function serializePoint$3(point) {
4487
+ return `${point.x.toFixed(2)} ${point.y.toFixed(2)}`;
4488
+ }
4489
+ function closestPointOnRect$3(rect, point) {
4490
+ return {
4491
+ x: clamp$3(point.x, rect.left, rect.right),
4492
+ y: clamp$3(point.y, rect.top, rect.bottom),
4493
+ };
4494
+ }
4495
+ function resolveTargetElement$3(source, hostElement, documentRef) {
4496
+ if (!source) {
4497
+ return null;
4498
+ }
4499
+ if (source instanceof Element) {
4500
+ return source;
4501
+ }
4502
+ try {
4503
+ const localMatch = hostElement.parentElement?.querySelector(source);
4504
+ if (localMatch) {
4505
+ return localMatch;
4506
+ }
4507
+ return documentRef.querySelector(source);
4508
+ }
4509
+ catch {
4510
+ return null;
4511
+ }
4512
+ }
4513
+ function getBubbleElement$3(hostElement) {
4514
+ return hostElement.firstElementChild instanceof HTMLElement ? hostElement.firstElementChild : null;
4515
+ }
4516
+ function createUnifiedBubblePath$2(width, height, radius, baseStartX, baseEndX, tipX, tipY, offsetX, offsetY) {
4517
+ const left = offsetX;
4518
+ const top = offsetY;
4519
+ const right = offsetX + width;
4520
+ const bottom = offsetY + height;
4521
+ const start = { x: left + radius, y: top };
4522
+ const bottomRight = { x: right, y: bottom - radius };
4523
+ const bottomRightArcEnd = { x: right - radius, y: bottom };
4524
+ const baseStart = { x: offsetX + baseStartX, y: bottom };
4525
+ const baseEnd = { x: offsetX + baseEndX, y: bottom };
4526
+ const tip = { x: offsetX + tipX, y: offsetY + tipY };
4527
+ const bottomLeftArcStart = { x: left + radius, y: bottom };
4528
+ const leftBottom = { x: left, y: bottom - radius };
4529
+ const leftTop = { x: left, y: top + radius };
4530
+ return [
4531
+ `M ${serializePoint$3(start)}`,
4532
+ `H ${(right - radius).toFixed(2)}`,
4533
+ `A ${radius} ${radius} 0 0 1 ${right.toFixed(2)} ${(top + radius).toFixed(2)}`,
4534
+ `V ${bottomRight.y.toFixed(2)}`,
4535
+ `A ${radius} ${radius} 0 0 1 ${serializePoint$3(bottomRightArcEnd)}`,
4536
+ `H ${baseEnd.x.toFixed(2)}`,
4537
+ `L ${serializePoint$3(tip)}`,
4538
+ `L ${serializePoint$3(baseStart)}`,
4539
+ `H ${bottomLeftArcStart.x.toFixed(2)}`,
4540
+ `A ${radius} ${radius} 0 0 1 ${serializePoint$3(leftBottom)}`,
4541
+ `V ${leftTop.y.toFixed(2)}`,
4542
+ `A ${radius} ${radius} 0 0 1 ${serializePoint$3(start)}`,
4543
+ 'Z',
4544
+ ].join(' ');
4545
+ }
4546
+ class DuckDevSpeakerBubbleClassic {
4547
+ color = input(AccentEnumColor.White, { ...(ngDevMode ? { debugName: "color" } : {}) });
4548
+ tail = input('left', { ...(ngDevMode ? { debugName: "tail" } : {}) });
4549
+ target = input(null, { ...(ngDevMode ? { debugName: "target" } : {}) });
4550
+ hostRef = inject((ElementRef));
4551
+ documentRef = inject(DOCUMENT);
4552
+ destroyRef = inject(DestroyRef);
4553
+ platformId = inject(PLATFORM_ID);
4554
+ isBrowser = isPlatformBrowser(this.platformId);
4555
+ bubbleGeometry = signal(DEFAULT_BUBBLE_GEOMETRY$2, { ...(ngDevMode ? { debugName: "bubbleGeometry" } : {}) });
4556
+ animationFrameId = -1;
4557
+ resizeObserver = null;
4558
+ observedTarget = null;
4559
+ observersInitialized = false;
4560
+ bubbleStyle = computed(() => getClassicSpeakerBubbleStyle(this.color()), { ...(ngDevMode ? { debugName: "bubbleStyle" } : {}) });
4561
+ resolvedTail = computed(() => this.bubbleGeometry().side, { ...(ngDevMode ? { debugName: "resolvedTail" } : {}) });
4562
+ shapeStyle = computed(() => this.bubbleGeometry().style, { ...(ngDevMode ? { debugName: "shapeStyle" } : {}) });
4563
+ shapeViewBox = computed(() => this.bubbleGeometry().viewBox, { ...(ngDevMode ? { debugName: "shapeViewBox" } : {}) });
4564
+ shapePath = computed(() => this.bubbleGeometry().path, { ...(ngDevMode ? { debugName: "shapePath" } : {}) });
4565
+ constructor() {
4566
+ afterNextRender(() => {
4567
+ this.setupObservers();
4568
+ this.scheduleRefresh();
4569
+ });
4570
+ afterRenderEffect(() => {
4571
+ this.tail();
4572
+ this.target();
4573
+ this.setupObservers();
4574
+ this.scheduleRefresh();
4575
+ });
4576
+ this.destroyRef.onDestroy(() => {
4577
+ this.documentRef.defaultView?.removeEventListener('resize', this.scheduleRefresh);
4578
+ this.documentRef.removeEventListener('scroll', this.scheduleRefresh, true);
4579
+ if (this.animationFrameId !== -1) {
4580
+ cancelAnimationFrame(this.animationFrameId);
4581
+ }
4582
+ this.resizeObserver?.disconnect();
4583
+ this.resizeObserver = null;
4584
+ this.observedTarget = null;
4585
+ });
4586
+ }
4587
+ scheduleRefresh = () => {
4588
+ if (!this.isBrowser || this.animationFrameId !== -1) {
4589
+ return;
4590
+ }
4591
+ this.animationFrameId = requestAnimationFrame(() => {
4592
+ this.animationFrameId = -1;
4593
+ this.refreshShape();
4594
+ });
4595
+ };
4596
+ setupObservers() {
4597
+ if (!this.isBrowser || this.observersInitialized) {
4598
+ return;
4599
+ }
4600
+ const bubbleElement = getBubbleElement$3(this.hostRef.nativeElement);
4601
+ if (!bubbleElement) {
4602
+ return;
4603
+ }
4604
+ if (typeof ResizeObserver !== 'undefined') {
4605
+ this.resizeObserver = new ResizeObserver(() => this.scheduleRefresh());
4606
+ this.resizeObserver.observe(bubbleElement);
4607
+ }
4608
+ const targetElement = resolveTargetElement$3(this.target(), this.hostRef.nativeElement, this.documentRef);
4609
+ if (targetElement) {
4610
+ this.resizeObserver?.observe(targetElement);
4611
+ this.observedTarget = targetElement;
4612
+ }
4613
+ this.documentRef.defaultView?.addEventListener('resize', this.scheduleRefresh);
4614
+ this.documentRef.addEventListener('scroll', this.scheduleRefresh, true);
4615
+ this.observersInitialized = true;
4616
+ }
4617
+ refreshShape() {
4618
+ if (!this.isBrowser) {
4619
+ return;
4620
+ }
4621
+ const bubbleElement = getBubbleElement$3(this.hostRef.nativeElement);
4622
+ if (!bubbleElement) {
4623
+ return;
4624
+ }
4625
+ const targetElement = resolveTargetElement$3(this.target(), this.hostRef.nativeElement, this.documentRef);
4626
+ if (this.resizeObserver && targetElement !== this.observedTarget) {
4627
+ if (this.observedTarget) {
4628
+ this.resizeObserver.unobserve(this.observedTarget);
4629
+ }
4630
+ if (targetElement) {
4631
+ this.resizeObserver.observe(targetElement);
4632
+ }
4633
+ this.observedTarget = targetElement;
4634
+ }
4635
+ const bubbleRect = bubbleElement.getBoundingClientRect();
4636
+ const targetRect = targetElement?.getBoundingClientRect() ?? null;
4637
+ const side = this.resolveTailSide(bubbleRect, targetRect);
4638
+ const seventh = bubbleRect.width / 7;
4639
+ const baseStartX = side === 'left'
4640
+ ? clamp$3(seventh, 20, bubbleRect.width - 56)
4641
+ : clamp$3(bubbleRect.width - seventh * 2, 20, bubbleRect.width - 56);
4642
+ const baseEndX = side === 'left'
4643
+ ? clamp$3(seventh * 2, baseStartX + 22, bubbleRect.width - 20)
4644
+ : clamp$3(bubbleRect.width - seventh, baseStartX + 22, bubbleRect.width - 20);
4645
+ const anchor = {
4646
+ x: bubbleRect.left + (baseStartX + baseEndX) / 2,
4647
+ y: bubbleRect.bottom,
4648
+ };
4649
+ const targetPoint = targetRect
4650
+ ? closestPointOnRect$3(targetRect, anchor)
4651
+ : {
4652
+ x: bubbleRect.left + (side === 'left' ? baseStartX : baseEndX),
4653
+ y: bubbleRect.bottom + Math.max(24, bubbleRect.height / 4),
4654
+ };
4655
+ const tipX = clamp$3(targetPoint.x - bubbleRect.left, -48, bubbleRect.width + 48);
4656
+ const tipY = Math.max(targetPoint.y - bubbleRect.top, bubbleRect.height + 22);
4657
+ const minX = Math.min(0, tipX);
4658
+ const maxX = Math.max(bubbleRect.width, tipX);
4659
+ const maxY = Math.max(bubbleRect.height, tipY);
4660
+ const padding = 10;
4661
+ const offsetX = padding - minX;
4662
+ const offsetY = padding;
4663
+ const width = maxX - minX + padding * 2;
4664
+ const height = maxY + padding * 2;
4665
+ this.bubbleGeometry.set({
4666
+ side,
4667
+ style: {
4668
+ left: `${minX - padding}px`,
4669
+ top: `${-padding}px`,
4670
+ width: `${width}px`,
4671
+ height: `${height}px`,
4672
+ },
4673
+ viewBox: `0 0 ${width.toFixed(2)} ${height.toFixed(2)}`,
4674
+ path: createUnifiedBubblePath$2(bubbleRect.width, bubbleRect.height, 18, baseStartX, baseEndX, tipX, tipY, offsetX, offsetY),
4675
+ });
4676
+ }
4677
+ resolveTailSide(bubbleRect, targetRect) {
4678
+ const tail = this.tail();
4679
+ if (tail === 'left' || tail === 'right') {
4680
+ return tail;
4681
+ }
4682
+ const targetCenterX = targetRect
4683
+ ? targetRect.left + targetRect.width / 2
4684
+ : bubbleRect.left + bubbleRect.width / 2;
4685
+ return targetCenterX < bubbleRect.left + bubbleRect.width / 2 ? 'left' : 'right';
4686
+ }
4687
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: DuckDevSpeakerBubbleClassic, deps: [], target: i0.ɵɵFactoryTarget.Component });
4688
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.1", type: DuckDevSpeakerBubbleClassic, isStandalone: true, selector: "dd-speaker-bubble-classic", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, tail: { classPropertyName: "tail", publicName: "tail", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\n class=\"dd-speaker-bubble-classic\"\n [attr.data-tail]=\"resolvedTail()\"\n [ngStyle]=\"bubbleStyle()\"\n>\n <svg\n class=\"dd-speaker-bubble-classic__shape\"\n aria-hidden=\"true\"\n [ngStyle]=\"shapeStyle()\"\n [attr.viewBox]=\"shapeViewBox()\"\n preserveAspectRatio=\"none\"\n focusable=\"false\"\n >\n <path\n class=\"dd-speaker-bubble-classic__shape-path\"\n [attr.d]=\"shapePath()\"\n />\n </svg>\n <div class=\"dd-speaker-bubble-classic__content\">\n <ng-content />\n </div>\n</div>\n", styles: [":host{display:block;width:fit-content;max-width:min(100%,36rem)}.dd-speaker-bubble-classic{position:relative;isolation:isolate;overflow:visible;padding:18px 20px 17px;color:var(--dd-speaker-text)}.dd-speaker-bubble-classic__shape{position:absolute;z-index:0;pointer-events:none;filter:drop-shadow(6px 6px 0 color-mix(in srgb,var(--dd-speaker-shadow) 36%,transparent))}.dd-speaker-bubble-classic__shape-path{fill:var(--dd-speaker-surface);stroke:color-mix(in srgb,var(--dd-speaker-border) 90%,var(--dd-speaker-text));stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.dd-speaker-bubble-classic__content{display:block;position:relative;z-index:1}.dd-speaker-bubble-classic__content :first-child{margin-top:0}.dd-speaker-bubble-classic__content :last-child{margin-bottom:0}.dd-speaker-bubble-classic__content strong{color:var(--dd-speaker-accent)}.dd-speaker-bubble-classic__content small{display:block;margin-bottom:6px;color:color-mix(in srgb,var(--dd-speaker-text) 72%,transparent);font-size:12px;font-weight:600;letter-spacing:.05em;text-transform:uppercase}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
4689
+ }
4690
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: DuckDevSpeakerBubbleClassic, decorators: [{
4691
+ type: Component,
4692
+ args: [{ selector: 'dd-speaker-bubble-classic', standalone: true, imports: [NgStyle], template: "<div\n class=\"dd-speaker-bubble-classic\"\n [attr.data-tail]=\"resolvedTail()\"\n [ngStyle]=\"bubbleStyle()\"\n>\n <svg\n class=\"dd-speaker-bubble-classic__shape\"\n aria-hidden=\"true\"\n [ngStyle]=\"shapeStyle()\"\n [attr.viewBox]=\"shapeViewBox()\"\n preserveAspectRatio=\"none\"\n focusable=\"false\"\n >\n <path\n class=\"dd-speaker-bubble-classic__shape-path\"\n [attr.d]=\"shapePath()\"\n />\n </svg>\n <div class=\"dd-speaker-bubble-classic__content\">\n <ng-content />\n </div>\n</div>\n", styles: [":host{display:block;width:fit-content;max-width:min(100%,36rem)}.dd-speaker-bubble-classic{position:relative;isolation:isolate;overflow:visible;padding:18px 20px 17px;color:var(--dd-speaker-text)}.dd-speaker-bubble-classic__shape{position:absolute;z-index:0;pointer-events:none;filter:drop-shadow(6px 6px 0 color-mix(in srgb,var(--dd-speaker-shadow) 36%,transparent))}.dd-speaker-bubble-classic__shape-path{fill:var(--dd-speaker-surface);stroke:color-mix(in srgb,var(--dd-speaker-border) 90%,var(--dd-speaker-text));stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.dd-speaker-bubble-classic__content{display:block;position:relative;z-index:1}.dd-speaker-bubble-classic__content :first-child{margin-top:0}.dd-speaker-bubble-classic__content :last-child{margin-bottom:0}.dd-speaker-bubble-classic__content strong{color:var(--dd-speaker-accent)}.dd-speaker-bubble-classic__content small{display:block;margin-bottom:6px;color:color-mix(in srgb,var(--dd-speaker-text) 72%,transparent);font-size:12px;font-weight:600;letter-spacing:.05em;text-transform:uppercase}\n"] }]
4693
+ }], ctorParameters: () => [], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], tail: [{ type: i0.Input, args: [{ isSignal: true, alias: "tail", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }] } });
4694
+
4695
+ const TAIL_VARIANT_METRICS = {
4696
+ classic: {
4697
+ fallbackDy: 24,
4698
+ padding: 18,
4699
+ },
4700
+ soft: {
4701
+ fallbackDy: 28,
4702
+ padding: 20,
4703
+ },
4704
+ outline: {
4705
+ fallbackDy: 22,
4706
+ padding: 16,
4707
+ },
4708
+ 'neobrutal-slab': {
4709
+ fallbackDy: 28,
4710
+ padding: 22,
4711
+ },
4712
+ 'neobrutal-ticket': {
4713
+ fallbackDy: 28,
4714
+ padding: 22,
4715
+ },
4716
+ };
4717
+ function clamp$2(value, min, max) {
4718
+ return Math.min(Math.max(value, min), max);
4719
+ }
4720
+ function lerpPoint(from, to, t) {
4721
+ return {
4722
+ x: from.x + (to.x - from.x) * t,
4723
+ y: from.y + (to.y - from.y) * t,
4724
+ };
4725
+ }
4726
+ function serializePoint$2(point) {
4727
+ return `${point.x.toFixed(2)} ${point.y.toFixed(2)}`;
4728
+ }
4729
+ function toPath(points, close = true) {
4730
+ if (points.length === 0) {
4731
+ return '';
4732
+ }
4733
+ const [first, ...rest] = points;
4734
+ const path = [`M ${serializePoint$2(first)}`];
4735
+ for (const point of rest) {
4736
+ path.push(`L ${serializePoint$2(point)}`);
4737
+ }
4738
+ if (close) {
4739
+ path.push('Z');
4740
+ }
4741
+ return path.join(' ');
4742
+ }
4743
+ function getBubbleElement$2(hostElement) {
4744
+ return hostElement.firstElementChild instanceof HTMLElement ? hostElement.firstElementChild : null;
4745
+ }
4746
+ function closestPointOnRect$2(rect, point) {
4747
+ return {
4748
+ x: clamp$2(point.x, rect.left, rect.right),
4749
+ y: clamp$2(point.y, rect.top, rect.bottom),
4750
+ };
4751
+ }
4752
+ function resolveTargetElement$2(source, hostElement, documentRef) {
4753
+ if (!source) {
4754
+ return null;
4755
+ }
4756
+ if (source instanceof Element) {
4757
+ return source;
4758
+ }
4759
+ try {
4760
+ const scopedMatch = hostElement.parentElement?.querySelector(source);
4761
+ if (scopedMatch) {
4762
+ return scopedMatch;
4763
+ }
4764
+ return documentRef.querySelector(source);
4765
+ }
4766
+ catch {
4767
+ return null;
4768
+ }
4769
+ }
4770
+ function getTailBasePoints(bubbleRect, side) {
4771
+ const seventh = bubbleRect.width / 7;
4772
+ const baseStartX = side === 'left'
4773
+ ? clamp$2(seventh, 20, bubbleRect.width - 56)
4774
+ : clamp$2(bubbleRect.width - seventh * 2, 20, bubbleRect.width - 56);
4775
+ const baseEndX = side === 'left'
4776
+ ? clamp$2(seventh * 2, baseStartX + 22, bubbleRect.width - 20)
4777
+ : clamp$2(bubbleRect.width - seventh, baseStartX + 22, bubbleRect.width - 20);
4778
+ const baseY = bubbleRect.height;
4779
+ return {
4780
+ baseStart: { x: baseStartX, y: baseY },
4781
+ baseEnd: { x: baseEndX, y: baseY },
4782
+ anchor: { x: (baseStartX + baseEndX) / 2, y: baseY },
4783
+ };
4784
+ }
4785
+ function resolveTailSide(bubbleRect, targetRect, preferredTail) {
4786
+ if (preferredTail === 'left' || preferredTail === 'right') {
4787
+ return preferredTail;
4788
+ }
4789
+ const targetCenterX = targetRect
4790
+ ? targetRect.left + targetRect.width / 2
4791
+ : bubbleRect.left + bubbleRect.width / 2;
4792
+ return targetCenterX < bubbleRect.left + bubbleRect.width / 2 ? 'left' : 'right';
4793
+ }
4794
+ function buildClassicTail(baseStart, baseEnd, anchor, tip, side) {
4795
+ const dir = side === 'left' ? -1 : 1;
4796
+ const outer = side === 'left' ? baseStart : baseEnd;
4797
+ const inner = side === 'left' ? baseEnd : baseStart;
4798
+ const c1 = { x: outer.x + dir * 8, y: outer.y + 7 };
4799
+ const c2 = { x: anchor.x + (tip.x - anchor.x) * 0.34 + dir * 7, y: anchor.y + (tip.y - anchor.y) * 0.2 };
4800
+ const c3 = { x: tip.x - (tip.x - anchor.x) * 0.08 + dir * 6, y: tip.y - (tip.y - anchor.y) * 0.08 };
4801
+ const c4 = { x: tip.x - (tip.x - anchor.x) * 0.16 - dir * 4, y: tip.y - (tip.y - anchor.y) * 0.02 };
4802
+ const c5 = { x: anchor.x + (tip.x - anchor.x) * 0.72 - dir * 8, y: anchor.y + (tip.y - anchor.y) * 0.76 };
4803
+ const c6 = { x: inner.x - dir * 2, y: inner.y + 10 };
4804
+ const seam = { x: anchor.x + dir * 2, y: anchor.y + 2 };
4805
+ return {
4806
+ path: [
4807
+ `M ${serializePoint$2(outer)}`,
4808
+ `C ${serializePoint$2(c1)} ${serializePoint$2(c2)} ${serializePoint$2(c3)} ${serializePoint$2(tip)}`,
4809
+ `C ${serializePoint$2(c4)} ${serializePoint$2(c5)} ${serializePoint$2(c6)} ${serializePoint$2(inner)}`,
4810
+ `Q ${serializePoint$2(seam)} ${serializePoint$2(outer)}`,
4811
+ 'Z',
4812
+ ].join(' '),
4813
+ secondaryPath: null,
4814
+ points: [outer, inner, tip, c1, c2, c3, c4, c5, c6, seam, baseStart, baseEnd],
4815
+ };
4816
+ }
4817
+ function buildSoftTail(baseStart, baseEnd, anchor, tip, side) {
4818
+ const dir = side === 'left' ? -1 : 1;
4819
+ const outer = side === 'left' ? baseStart : baseEnd;
4820
+ const inner = side === 'left' ? baseEnd : baseStart;
4821
+ const c1 = { x: outer.x + dir * 10, y: outer.y + 10 };
4822
+ const c2 = { x: anchor.x + (tip.x - anchor.x) * 0.3 + dir * 8, y: anchor.y + (tip.y - anchor.y) * 0.18 };
4823
+ const c3 = { x: tip.x - (tip.x - anchor.x) * 0.05 + dir * 6, y: tip.y - (tip.y - anchor.y) * 0.08 };
4824
+ const c4 = { x: tip.x - (tip.x - anchor.x) * 0.18 - dir * 7, y: tip.y + (anchor.y - tip.y) * 0.06 };
4825
+ const c5 = { x: anchor.x + (tip.x - anchor.x) * 0.68 - dir * 10, y: anchor.y + (tip.y - anchor.y) * 0.74 };
4826
+ const c6 = { x: inner.x - dir * 3, y: inner.y + 12 };
4827
+ const seam = { x: anchor.x + dir * 1.5, y: anchor.y + 3 };
4828
+ const shineStart = lerpPoint(outer, tip, 0.16);
4829
+ const shineControl = {
4830
+ x: anchor.x + (tip.x - anchor.x) * 0.42,
4831
+ y: anchor.y + (tip.y - anchor.y) * 0.34 - 5,
4832
+ };
4833
+ const shineEnd = lerpPoint(inner, tip, 0.58);
4834
+ return {
4835
+ path: [
4836
+ `M ${serializePoint$2(outer)}`,
4837
+ `C ${serializePoint$2(c1)} ${serializePoint$2(c2)} ${serializePoint$2(c3)} ${serializePoint$2(tip)}`,
4838
+ `C ${serializePoint$2(c4)} ${serializePoint$2(c5)} ${serializePoint$2(c6)} ${serializePoint$2(inner)}`,
4839
+ `Q ${serializePoint$2(seam)} ${serializePoint$2(outer)}`,
4840
+ 'Z',
4841
+ ].join(' '),
4842
+ secondaryPath: `M ${serializePoint$2(shineStart)} Q ${serializePoint$2(shineControl)} ${serializePoint$2(shineEnd)}`,
4843
+ points: [
4844
+ outer,
4845
+ inner,
4846
+ tip,
4847
+ c1,
4848
+ c2,
4849
+ c3,
4850
+ c4,
4851
+ c5,
4852
+ c6,
4853
+ seam,
4854
+ shineStart,
4855
+ shineControl,
4856
+ shineEnd,
4857
+ baseStart,
4858
+ baseEnd,
4859
+ ],
4860
+ };
4861
+ }
4862
+ function buildOutlineTail(baseStart, baseEnd, anchor, tip, side) {
4863
+ const dir = side === 'left' ? -1 : 1;
4864
+ const outer = side === 'left' ? baseStart : baseEnd;
4865
+ const inner = side === 'left' ? baseEnd : baseStart;
4866
+ const elbowA = {
4867
+ x: anchor.x + (tip.x - anchor.x) * 0.26 + dir * 8,
4868
+ y: anchor.y + (tip.y - anchor.y) * 0.2,
4869
+ };
4870
+ const elbowB = {
4871
+ x: anchor.x + (tip.x - anchor.x) * 0.58 + dir * 3,
4872
+ y: anchor.y + (tip.y - anchor.y) * 0.7,
4873
+ };
4874
+ return {
4875
+ path: toPath([outer, elbowA, tip, elbowB, inner]),
4876
+ secondaryPath: null,
4877
+ points: [outer, inner, tip, elbowA, elbowB, baseStart, baseEnd],
4878
+ };
4879
+ }
4880
+ function buildNeobrutalSlabTail(baseStart, baseEnd, anchor, tip, side) {
4881
+ const dir = side === 'left' ? -1 : 1;
4882
+ const topOuter = {
4883
+ x: (side === 'left' ? baseStart.x : baseEnd.x) + dir * 4,
4884
+ y: anchor.y - 6,
4885
+ };
4886
+ const topInner = {
4887
+ x: (side === 'left' ? baseEnd.x : baseStart.x) - dir * 4,
4888
+ y: anchor.y - 6,
4889
+ };
4890
+ const hip = { x: anchor.x - dir * 14, y: anchor.y + 9 };
4891
+ const midA = {
4892
+ x: anchor.x + (tip.x - anchor.x) * 0.24 + dir * 10,
4893
+ y: anchor.y + (tip.y - anchor.y) * 0.2,
4894
+ };
4895
+ const midB = {
4896
+ x: anchor.x + (tip.x - anchor.x) * 0.56 + dir * 4,
4897
+ y: anchor.y + (tip.y - anchor.y) * 0.64,
4898
+ };
4899
+ const accentA = lerpPoint(topInner, tip, 0.18);
4900
+ const accentB = lerpPoint(topOuter, tip, 0.36);
4901
+ const accentC = lerpPoint(hip, tip, 0.58);
4902
+ return {
4903
+ path: toPath([topOuter, topInner, midA, tip, midB, hip]),
4904
+ secondaryPath: toPath([accentA, accentB, tip, accentC]),
4905
+ points: [
4906
+ topOuter,
4907
+ topInner,
4908
+ midA,
4909
+ tip,
4910
+ midB,
4911
+ hip,
4912
+ accentA,
4913
+ accentB,
4914
+ accentC,
4915
+ baseStart,
4916
+ baseEnd,
4917
+ ],
4918
+ };
4919
+ }
4920
+ function buildNeobrutalTicketTail(baseStart, baseEnd, anchor, tip, side) {
4921
+ const dir = side === 'left' ? -1 : 1;
4922
+ const topOuter = {
4923
+ x: (side === 'left' ? baseStart.x : baseEnd.x) + dir * 4,
4924
+ y: anchor.y - 6,
4925
+ };
4926
+ const topInner = {
4927
+ x: (side === 'left' ? baseEnd.x : baseStart.x) - dir * 4,
4928
+ y: anchor.y - 6,
4929
+ };
4930
+ const hip = { x: anchor.x - dir * 12, y: anchor.y + 10 };
4931
+ const midA = {
4932
+ x: anchor.x + (tip.x - anchor.x) * 0.26 + dir * 10,
4933
+ y: anchor.y + (tip.y - anchor.y) * 0.18,
4934
+ };
4935
+ const midB = {
4936
+ x: anchor.x + (tip.x - anchor.x) * 0.58 + dir * 3,
4937
+ y: anchor.y + (tip.y - anchor.y) * 0.62,
4938
+ };
4939
+ const notchStart = {
4940
+ x: anchor.x + dir * 7,
4941
+ y: anchor.y - 5,
4942
+ };
4943
+ const notchMiddle = {
4944
+ x: anchor.x + dir * 7,
4945
+ y: anchor.y + 8,
4946
+ };
4947
+ const notchEnd = {
4948
+ x: anchor.x + (tip.x - anchor.x) * 0.22,
4949
+ y: anchor.y + (tip.y - anchor.y) * 0.34,
4950
+ };
4951
+ return {
4952
+ path: toPath([topOuter, topInner, midA, tip, midB, hip]),
4953
+ secondaryPath: `M ${serializePoint$2(notchStart)} L ${serializePoint$2(notchMiddle)} L ${serializePoint$2(notchEnd)}`,
4954
+ points: [
4955
+ topOuter,
4956
+ topInner,
4957
+ midA,
4958
+ tip,
4959
+ midB,
4960
+ hip,
4961
+ notchStart,
4962
+ notchMiddle,
4963
+ notchEnd,
4964
+ baseStart,
4965
+ baseEnd,
4966
+ ],
4967
+ };
4968
+ }
4969
+ function buildTailPathBundle(variant, baseStart, baseEnd, anchor, tip, side) {
4970
+ switch (variant) {
4971
+ case 'soft':
4972
+ return buildSoftTail(baseStart, baseEnd, anchor, tip, side);
4973
+ case 'outline':
4974
+ return buildOutlineTail(baseStart, baseEnd, anchor, tip, side);
4975
+ case 'neobrutal-slab':
4976
+ return buildNeobrutalSlabTail(baseStart, baseEnd, anchor, tip, side);
4977
+ case 'neobrutal-ticket':
4978
+ return buildNeobrutalTicketTail(baseStart, baseEnd, anchor, tip, side);
4979
+ case 'classic':
4980
+ default:
4981
+ return buildClassicTail(baseStart, baseEnd, anchor, tip, side);
4982
+ }
4983
+ }
4984
+ function buildTailRenderModel(variant, bubbleRect, targetRect, preferredTail) {
4985
+ const metrics = TAIL_VARIANT_METRICS[variant];
4986
+ const side = resolveTailSide(bubbleRect, targetRect, preferredTail);
4987
+ const { baseStart, baseEnd, anchor } = getTailBasePoints(bubbleRect, side);
4988
+ const anchorViewport = {
4989
+ x: bubbleRect.left + anchor.x,
4990
+ y: bubbleRect.top + anchor.y,
4991
+ };
4992
+ const targetPoint = targetRect
4993
+ ? closestPointOnRect$2(targetRect, anchorViewport)
4994
+ : {
4995
+ x: bubbleRect.left + (side === 'left' ? baseStart.x : baseEnd.x),
4996
+ y: anchorViewport.y + metrics.fallbackDy,
4997
+ };
4998
+ const tip = {
4999
+ x: clamp$2(targetPoint.x - bubbleRect.left, -48, bubbleRect.width + 48),
5000
+ y: Math.max(targetPoint.y - bubbleRect.top, bubbleRect.height + metrics.fallbackDy),
5001
+ };
5002
+ const bundle = buildTailPathBundle(variant, baseStart, baseEnd, anchor, tip, side);
5003
+ const bounds = bundle.points.reduce((acc, point) => ({
5004
+ minX: Math.min(acc.minX, point.x),
5005
+ minY: Math.min(acc.minY, point.y),
5006
+ maxX: Math.max(acc.maxX, point.x),
5007
+ maxY: Math.max(acc.maxY, point.y),
5008
+ }), {
5009
+ minX: Number.POSITIVE_INFINITY,
5010
+ minY: Number.POSITIVE_INFINITY,
5011
+ maxX: Number.NEGATIVE_INFINITY,
5012
+ maxY: Number.NEGATIVE_INFINITY,
5013
+ });
5014
+ const translateX = metrics.padding - bounds.minX;
5015
+ const translateY = metrics.padding - bounds.minY;
5016
+ const width = Math.max(1, bounds.maxX - bounds.minX + metrics.padding * 2);
5017
+ const height = Math.max(1, bounds.maxY - bounds.minY + metrics.padding * 2);
5018
+ const translatePath = (path) => path
5019
+ ?.replace(/-?\d+(?:\.\d+)? -?\d+(?:\.\d+)?/g, (match) => {
5020
+ const [x, y] = match.split(' ').map(Number);
5021
+ return `${(x + translateX).toFixed(2)} ${(y + translateY).toFixed(2)}`;
5022
+ })
5023
+ .trim() ?? null;
5024
+ return {
5025
+ side,
5026
+ style: {
5027
+ left: `${bounds.minX - metrics.padding}px`,
5028
+ top: `${bounds.minY - metrics.padding}px`,
5029
+ width: `${width}px`,
5030
+ height: `${height}px`,
5031
+ },
5032
+ viewBox: `0 0 ${width.toFixed(2)} ${height.toFixed(2)}`,
5033
+ path: translatePath(bundle.path) ?? '',
5034
+ secondaryPath: translatePath(bundle.secondaryPath),
5035
+ };
5036
+ }
5037
+ function useSpeakerBubbleTail(variant, tail, target) {
5038
+ const hostRef = inject((ElementRef));
5039
+ const documentRef = inject(DOCUMENT);
5040
+ const destroyRef = inject(DestroyRef);
5041
+ const platformId = inject(PLATFORM_ID);
5042
+ const isBrowser = isPlatformBrowser(platformId);
5043
+ const renderModel = signal({
5044
+ side: 'left',
5045
+ style: {
5046
+ left: '0px',
5047
+ top: '0px',
5048
+ width: '1px',
5049
+ height: '1px',
5050
+ },
5051
+ viewBox: '0 0 1 1',
5052
+ path: '',
5053
+ secondaryPath: null,
5054
+ }, { ...(ngDevMode ? { debugName: "renderModel" } : {}) });
5055
+ let animationFrameId = -1;
5056
+ let resizeObserver = null;
5057
+ let observedTarget = null;
5058
+ let isInitialized = false;
5059
+ const cleanupObservers = () => {
5060
+ if (animationFrameId !== -1) {
5061
+ cancelAnimationFrame(animationFrameId);
5062
+ animationFrameId = -1;
5063
+ }
5064
+ resizeObserver?.disconnect();
5065
+ resizeObserver = null;
5066
+ observedTarget = null;
5067
+ };
5068
+ const refreshTail = () => {
5069
+ if (!isBrowser) {
5070
+ return;
5071
+ }
5072
+ const bubbleElement = getBubbleElement$2(hostRef.nativeElement);
5073
+ if (!bubbleElement) {
5074
+ return;
5075
+ }
5076
+ const targetElement = resolveTargetElement$2(target(), hostRef.nativeElement, documentRef);
5077
+ if (resizeObserver && targetElement !== observedTarget) {
5078
+ if (observedTarget) {
5079
+ resizeObserver.unobserve(observedTarget);
5080
+ }
5081
+ if (targetElement) {
5082
+ resizeObserver.observe(targetElement);
5083
+ }
5084
+ observedTarget = targetElement;
5085
+ }
5086
+ renderModel.set(buildTailRenderModel(variant, bubbleElement.getBoundingClientRect(), targetElement?.getBoundingClientRect() ?? null, tail()));
5087
+ };
5088
+ const scheduleRefresh = () => {
5089
+ if (!isBrowser || animationFrameId !== -1) {
5090
+ return;
5091
+ }
5092
+ animationFrameId = requestAnimationFrame(() => {
5093
+ animationFrameId = -1;
5094
+ refreshTail();
5095
+ });
5096
+ };
5097
+ const setupObservers = () => {
5098
+ if (!isBrowser || isInitialized) {
5099
+ return;
5100
+ }
5101
+ const bubbleElement = getBubbleElement$2(hostRef.nativeElement);
5102
+ if (!bubbleElement) {
5103
+ return;
5104
+ }
5105
+ resizeObserver = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(scheduleRefresh);
5106
+ resizeObserver?.observe(bubbleElement);
5107
+ const targetElement = resolveTargetElement$2(target(), hostRef.nativeElement, documentRef);
5108
+ if (targetElement) {
5109
+ resizeObserver?.observe(targetElement);
5110
+ observedTarget = targetElement;
5111
+ }
5112
+ documentRef.defaultView?.addEventListener('resize', scheduleRefresh);
5113
+ documentRef.addEventListener('scroll', scheduleRefresh, true);
5114
+ destroyRef.onDestroy(() => {
5115
+ documentRef.defaultView?.removeEventListener('resize', scheduleRefresh);
5116
+ documentRef.removeEventListener('scroll', scheduleRefresh, true);
5117
+ cleanupObservers();
5118
+ });
5119
+ isInitialized = true;
5120
+ scheduleRefresh();
5121
+ };
5122
+ afterNextRender(() => {
5123
+ setupObservers();
5124
+ scheduleRefresh();
5125
+ });
5126
+ afterRenderEffect(() => {
5127
+ if (!isBrowser) {
5128
+ return;
5129
+ }
5130
+ tail();
5131
+ target();
5132
+ setupObservers();
5133
+ scheduleRefresh();
5134
+ });
5135
+ return {
5136
+ resolvedTail: computed(() => renderModel().side),
5137
+ tailStyle: computed(() => renderModel().style),
5138
+ tailViewBox: computed(() => renderModel().viewBox),
5139
+ tailPath: computed(() => renderModel().path),
5140
+ tailSecondaryPath: computed(() => renderModel().secondaryPath),
5141
+ };
5142
+ }
5143
+
5144
+ class DuckDevSpeakerBubbleSoft {
5145
+ color = input(AccentEnumColor.Violet, { ...(ngDevMode ? { debugName: "color" } : {}) });
5146
+ tail = input('left', { ...(ngDevMode ? { debugName: "tail" } : {}) });
5147
+ target = input(null, { ...(ngDevMode ? { debugName: "target" } : {}) });
5148
+ tailController = useSpeakerBubbleTail('soft', this.tail, this.target);
5149
+ bubbleStyle = computed(() => getClassicSpeakerBubbleStyle(this.color()), { ...(ngDevMode ? { debugName: "bubbleStyle" } : {}) });
5150
+ resolvedTail = this.tailController.resolvedTail;
5151
+ tailStyle = this.tailController.tailStyle;
5152
+ tailViewBox = this.tailController.tailViewBox;
5153
+ tailPath = this.tailController.tailPath;
5154
+ tailSecondaryPath = this.tailController.tailSecondaryPath;
5155
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: DuckDevSpeakerBubbleSoft, deps: [], target: i0.ɵɵFactoryTarget.Component });
5156
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.1", type: DuckDevSpeakerBubbleSoft, isStandalone: true, selector: "dd-speaker-bubble-soft", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, tail: { classPropertyName: "tail", publicName: "tail", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"dd-speaker-bubble-soft\" [attr.data-tail]=\"resolvedTail()\" [ngStyle]=\"bubbleStyle()\">\n <span class=\"dd-speaker-bubble-soft__tail\" aria-hidden=\"true\" [ngStyle]=\"tailStyle()\">\n <svg\n [attr.viewBox]=\"tailViewBox()\"\n preserveAspectRatio=\"none\"\n focusable=\"false\"\n aria-hidden=\"true\"\n >\n <path\n class=\"dd-speaker-bubble-soft__tail-path\"\n [attr.d]=\"tailPath()\"\n />\n <path\n class=\"dd-speaker-bubble-soft__tail-shine\"\n [attr.d]=\"tailSecondaryPath()\"\n />\n </svg>\n </span>\n <div class=\"dd-speaker-bubble-soft__content\">\n <ng-content />\n </div>\n</div>\n", styles: [":host{display:block;width:fit-content;max-width:min(100%,36rem)}.dd-speaker-bubble-soft{position:relative;isolation:isolate;overflow:visible;padding:19px 21px 18px;border:1px solid color-mix(in srgb,var(--dd-speaker-border) 78%,var(--dd-speaker-accent));border-radius:28px 28px 28px 18px;background:radial-gradient(circle at top right,color-mix(in srgb,var(--dd-speaker-accent) 22%,transparent) 0,transparent 38%),radial-gradient(circle at 24% 18%,color-mix(in srgb,white 42%,transparent) 0,transparent 22%),linear-gradient(180deg,color-mix(in srgb,var(--dd-speaker-surface-muted) 82%,var(--dd-speaker-surface)) 0,var(--dd-speaker-surface) 100%);box-shadow:inset 0 1px color-mix(in srgb,var(--dd-speaker-surface) 85%,white),0 16px 30px color-mix(in srgb,var(--dd-speaker-shadow) 16%,transparent),0 4px 14px color-mix(in srgb,var(--dd-speaker-accent) 10%,transparent);color:var(--dd-speaker-text);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.dd-speaker-bubble-soft[data-tail=right]{border-radius:28px 28px 18px}.dd-speaker-bubble-soft__tail{position:absolute;z-index:-1;filter:drop-shadow(0 12px 18px color-mix(in srgb,var(--dd-speaker-shadow) 14%,transparent)) drop-shadow(0 2px 3px color-mix(in srgb,white 24%,transparent));pointer-events:none}.dd-speaker-bubble-soft__tail svg{display:block;width:100%;height:100%;overflow:visible}.dd-speaker-bubble-soft__tail-path{fill:color-mix(in srgb,var(--dd-speaker-surface-muted) 84%,var(--dd-speaker-surface));stroke:color-mix(in srgb,var(--dd-speaker-border) 72%,var(--dd-speaker-accent));stroke-width:1.3;stroke-linecap:round;stroke-linejoin:round}.dd-speaker-bubble-soft__tail-shine{fill:none;stroke:color-mix(in srgb,white 48%,var(--dd-speaker-accent));stroke-width:1.6;stroke-linecap:round;opacity:.72}.dd-speaker-bubble-soft__content :first-child{margin-top:0}.dd-speaker-bubble-soft__content :last-child{margin-bottom:0}.dd-speaker-bubble-soft__content strong{color:var(--dd-speaker-accent)}.dd-speaker-bubble-soft__content small{display:block;margin-bottom:8px;color:color-mix(in srgb,var(--dd-speaker-text) 72%,transparent);font-size:12px;letter-spacing:.05em;text-transform:uppercase}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
5157
+ }
5158
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: DuckDevSpeakerBubbleSoft, decorators: [{
5159
+ type: Component,
5160
+ args: [{ selector: 'dd-speaker-bubble-soft', standalone: true, imports: [NgStyle], template: "<div class=\"dd-speaker-bubble-soft\" [attr.data-tail]=\"resolvedTail()\" [ngStyle]=\"bubbleStyle()\">\n <span class=\"dd-speaker-bubble-soft__tail\" aria-hidden=\"true\" [ngStyle]=\"tailStyle()\">\n <svg\n [attr.viewBox]=\"tailViewBox()\"\n preserveAspectRatio=\"none\"\n focusable=\"false\"\n aria-hidden=\"true\"\n >\n <path\n class=\"dd-speaker-bubble-soft__tail-path\"\n [attr.d]=\"tailPath()\"\n />\n <path\n class=\"dd-speaker-bubble-soft__tail-shine\"\n [attr.d]=\"tailSecondaryPath()\"\n />\n </svg>\n </span>\n <div class=\"dd-speaker-bubble-soft__content\">\n <ng-content />\n </div>\n</div>\n", styles: [":host{display:block;width:fit-content;max-width:min(100%,36rem)}.dd-speaker-bubble-soft{position:relative;isolation:isolate;overflow:visible;padding:19px 21px 18px;border:1px solid color-mix(in srgb,var(--dd-speaker-border) 78%,var(--dd-speaker-accent));border-radius:28px 28px 28px 18px;background:radial-gradient(circle at top right,color-mix(in srgb,var(--dd-speaker-accent) 22%,transparent) 0,transparent 38%),radial-gradient(circle at 24% 18%,color-mix(in srgb,white 42%,transparent) 0,transparent 22%),linear-gradient(180deg,color-mix(in srgb,var(--dd-speaker-surface-muted) 82%,var(--dd-speaker-surface)) 0,var(--dd-speaker-surface) 100%);box-shadow:inset 0 1px color-mix(in srgb,var(--dd-speaker-surface) 85%,white),0 16px 30px color-mix(in srgb,var(--dd-speaker-shadow) 16%,transparent),0 4px 14px color-mix(in srgb,var(--dd-speaker-accent) 10%,transparent);color:var(--dd-speaker-text);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.dd-speaker-bubble-soft[data-tail=right]{border-radius:28px 28px 18px}.dd-speaker-bubble-soft__tail{position:absolute;z-index:-1;filter:drop-shadow(0 12px 18px color-mix(in srgb,var(--dd-speaker-shadow) 14%,transparent)) drop-shadow(0 2px 3px color-mix(in srgb,white 24%,transparent));pointer-events:none}.dd-speaker-bubble-soft__tail svg{display:block;width:100%;height:100%;overflow:visible}.dd-speaker-bubble-soft__tail-path{fill:color-mix(in srgb,var(--dd-speaker-surface-muted) 84%,var(--dd-speaker-surface));stroke:color-mix(in srgb,var(--dd-speaker-border) 72%,var(--dd-speaker-accent));stroke-width:1.3;stroke-linecap:round;stroke-linejoin:round}.dd-speaker-bubble-soft__tail-shine{fill:none;stroke:color-mix(in srgb,white 48%,var(--dd-speaker-accent));stroke-width:1.6;stroke-linecap:round;opacity:.72}.dd-speaker-bubble-soft__content :first-child{margin-top:0}.dd-speaker-bubble-soft__content :last-child{margin-bottom:0}.dd-speaker-bubble-soft__content strong{color:var(--dd-speaker-accent)}.dd-speaker-bubble-soft__content small{display:block;margin-bottom:8px;color:color-mix(in srgb,var(--dd-speaker-text) 72%,transparent);font-size:12px;letter-spacing:.05em;text-transform:uppercase}\n"] }]
5161
+ }], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], tail: [{ type: i0.Input, args: [{ isSignal: true, alias: "tail", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }] } });
5162
+
5163
+ class DuckDevSpeakerBubbleOutline {
5164
+ color = input(AccentEnumColor.Gray, { ...(ngDevMode ? { debugName: "color" } : {}) });
5165
+ tail = input('left', { ...(ngDevMode ? { debugName: "tail" } : {}) });
5166
+ target = input(null, { ...(ngDevMode ? { debugName: "target" } : {}) });
5167
+ tailController = useSpeakerBubbleTail('outline', this.tail, this.target);
5168
+ bubbleStyle = computed(() => getClassicSpeakerBubbleStyle(this.color()), { ...(ngDevMode ? { debugName: "bubbleStyle" } : {}) });
5169
+ resolvedTail = this.tailController.resolvedTail;
5170
+ tailStyle = this.tailController.tailStyle;
5171
+ tailViewBox = this.tailController.tailViewBox;
5172
+ tailPath = this.tailController.tailPath;
5173
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: DuckDevSpeakerBubbleOutline, deps: [], target: i0.ɵɵFactoryTarget.Component });
5174
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.1", type: DuckDevSpeakerBubbleOutline, isStandalone: true, selector: "dd-speaker-bubble-outline", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, tail: { classPropertyName: "tail", publicName: "tail", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\n class=\"dd-speaker-bubble-outline\"\n [attr.data-tail]=\"resolvedTail()\"\n [ngStyle]=\"bubbleStyle()\"\n>\n <span class=\"dd-speaker-bubble-outline__tail\" aria-hidden=\"true\" [ngStyle]=\"tailStyle()\">\n <svg\n [attr.viewBox]=\"tailViewBox()\"\n preserveAspectRatio=\"none\"\n focusable=\"false\"\n aria-hidden=\"true\"\n >\n <path\n class=\"dd-speaker-bubble-outline__tail-path\"\n [attr.d]=\"tailPath()\"\n />\n </svg>\n </span>\n <div class=\"dd-speaker-bubble-outline__content\">\n <ng-content />\n </div>\n</div>\n", styles: [":host{display:block;width:fit-content;max-width:min(100%,36rem)}.dd-speaker-bubble-outline{position:relative;isolation:isolate;overflow:visible;padding:17px 19px 16px;border:2px solid var(--dd-speaker-border);border-radius:22px 22px 22px 10px;outline:1px dashed color-mix(in srgb,var(--dd-speaker-accent) 45%,transparent);outline-offset:-8px;background:linear-gradient(90deg,var(--dd-speaker-accent),var(--dd-speaker-accent)) 14px calc(100% - 12px) /28px 3px no-repeat,linear-gradient(180deg,color-mix(in srgb,var(--dd-speaker-accent) 8%,transparent) 0,transparent 52%),var(--dd-speaker-surface);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--dd-speaker-surface) 50%,white),6px 6px color-mix(in srgb,var(--dd-speaker-accent) 18%,transparent);color:var(--dd-speaker-text)}.dd-speaker-bubble-outline[data-tail=right]{border-radius:22px 22px 10px;background-position:calc(100% - 14px) calc(100% - 12px),0 0,0 0}.dd-speaker-bubble-outline__tail{position:absolute;z-index:-1;filter:drop-shadow(3px 4px 0 color-mix(in srgb,var(--dd-speaker-accent) 14%,transparent));pointer-events:none}.dd-speaker-bubble-outline__tail svg{display:block;width:100%;height:100%;overflow:visible}.dd-speaker-bubble-outline__tail-path{fill:var(--dd-speaker-surface);stroke:var(--dd-speaker-border);stroke-width:2;stroke-linecap:square;stroke-linejoin:miter}.dd-speaker-bubble-outline__content :first-child{margin-top:0}.dd-speaker-bubble-outline__content :last-child{margin-bottom:0}.dd-speaker-bubble-outline__content strong{color:var(--dd-speaker-accent)}.dd-speaker-bubble-outline__content small{display:block;margin-bottom:8px;color:color-mix(in srgb,var(--dd-speaker-text) 72%,transparent);font-size:12px;letter-spacing:.08em;text-transform:uppercase}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
5175
+ }
5176
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: DuckDevSpeakerBubbleOutline, decorators: [{
5177
+ type: Component,
5178
+ args: [{ selector: 'dd-speaker-bubble-outline', standalone: true, imports: [NgStyle], template: "<div\n class=\"dd-speaker-bubble-outline\"\n [attr.data-tail]=\"resolvedTail()\"\n [ngStyle]=\"bubbleStyle()\"\n>\n <span class=\"dd-speaker-bubble-outline__tail\" aria-hidden=\"true\" [ngStyle]=\"tailStyle()\">\n <svg\n [attr.viewBox]=\"tailViewBox()\"\n preserveAspectRatio=\"none\"\n focusable=\"false\"\n aria-hidden=\"true\"\n >\n <path\n class=\"dd-speaker-bubble-outline__tail-path\"\n [attr.d]=\"tailPath()\"\n />\n </svg>\n </span>\n <div class=\"dd-speaker-bubble-outline__content\">\n <ng-content />\n </div>\n</div>\n", styles: [":host{display:block;width:fit-content;max-width:min(100%,36rem)}.dd-speaker-bubble-outline{position:relative;isolation:isolate;overflow:visible;padding:17px 19px 16px;border:2px solid var(--dd-speaker-border);border-radius:22px 22px 22px 10px;outline:1px dashed color-mix(in srgb,var(--dd-speaker-accent) 45%,transparent);outline-offset:-8px;background:linear-gradient(90deg,var(--dd-speaker-accent),var(--dd-speaker-accent)) 14px calc(100% - 12px) /28px 3px no-repeat,linear-gradient(180deg,color-mix(in srgb,var(--dd-speaker-accent) 8%,transparent) 0,transparent 52%),var(--dd-speaker-surface);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--dd-speaker-surface) 50%,white),6px 6px color-mix(in srgb,var(--dd-speaker-accent) 18%,transparent);color:var(--dd-speaker-text)}.dd-speaker-bubble-outline[data-tail=right]{border-radius:22px 22px 10px;background-position:calc(100% - 14px) calc(100% - 12px),0 0,0 0}.dd-speaker-bubble-outline__tail{position:absolute;z-index:-1;filter:drop-shadow(3px 4px 0 color-mix(in srgb,var(--dd-speaker-accent) 14%,transparent));pointer-events:none}.dd-speaker-bubble-outline__tail svg{display:block;width:100%;height:100%;overflow:visible}.dd-speaker-bubble-outline__tail-path{fill:var(--dd-speaker-surface);stroke:var(--dd-speaker-border);stroke-width:2;stroke-linecap:square;stroke-linejoin:miter}.dd-speaker-bubble-outline__content :first-child{margin-top:0}.dd-speaker-bubble-outline__content :last-child{margin-bottom:0}.dd-speaker-bubble-outline__content strong{color:var(--dd-speaker-accent)}.dd-speaker-bubble-outline__content small{display:block;margin-bottom:8px;color:color-mix(in srgb,var(--dd-speaker-text) 72%,transparent);font-size:12px;letter-spacing:.08em;text-transform:uppercase}\n"] }]
5179
+ }], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], tail: [{ type: i0.Input, args: [{ isSignal: true, alias: "tail", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }] } });
5180
+
5181
+ const DEFAULT_BUBBLE_GEOMETRY$1 = {
5182
+ side: 'left',
5183
+ style: {
5184
+ left: '0px',
5185
+ top: '0px',
5186
+ width: '1px',
5187
+ height: '1px',
5188
+ },
5189
+ viewBox: '0 0 1 1',
5190
+ path: '',
5191
+ };
5192
+ function clamp$1(value, min, max) {
5193
+ return Math.min(Math.max(value, min), max);
5194
+ }
5195
+ function serializePoint$1(point) {
5196
+ return `${point.x.toFixed(2)} ${point.y.toFixed(2)}`;
5197
+ }
5198
+ function closestPointOnRect$1(rect, point) {
5199
+ return {
5200
+ x: clamp$1(point.x, rect.left, rect.right),
5201
+ y: clamp$1(point.y, rect.top, rect.bottom),
5202
+ };
5203
+ }
5204
+ function resolveTargetElement$1(source, hostElement, documentRef) {
5205
+ if (!source) {
5206
+ return null;
5207
+ }
5208
+ if (source instanceof Element) {
5209
+ return source;
5210
+ }
5211
+ try {
5212
+ const localMatch = hostElement.parentElement?.querySelector(source);
5213
+ if (localMatch) {
5214
+ return localMatch;
5215
+ }
5216
+ return documentRef.querySelector(source);
5217
+ }
5218
+ catch {
5219
+ return null;
5220
+ }
5221
+ }
5222
+ function getBubbleElement$1(hostElement) {
5223
+ return hostElement.firstElementChild instanceof HTMLElement ? hostElement.firstElementChild : null;
5224
+ }
5225
+ function createUnifiedBubblePath$1(width, height, radius, baseStartX, baseEndX, tipX, tipY, offsetX, offsetY) {
5226
+ const left = offsetX;
5227
+ const top = offsetY;
5228
+ const right = offsetX + width;
5229
+ const bottom = offsetY + height;
5230
+ const start = { x: left + radius, y: top };
5231
+ const bottomRight = { x: right, y: bottom - radius };
5232
+ const bottomRightArcEnd = { x: right - radius, y: bottom };
5233
+ const baseStart = { x: offsetX + baseStartX, y: bottom };
5234
+ const baseEnd = { x: offsetX + baseEndX, y: bottom };
5235
+ const tip = { x: offsetX + tipX, y: offsetY + tipY };
5236
+ const bottomLeftArcStart = { x: left + radius, y: bottom };
5237
+ const leftBottom = { x: left, y: bottom - radius };
5238
+ const leftTop = { x: left, y: top + radius };
5239
+ return [
5240
+ `M ${serializePoint$1(start)}`,
5241
+ `H ${(right - radius).toFixed(2)}`,
5242
+ `A ${radius} ${radius} 0 0 1 ${right.toFixed(2)} ${(top + radius).toFixed(2)}`,
5243
+ `V ${bottomRight.y.toFixed(2)}`,
5244
+ `A ${radius} ${radius} 0 0 1 ${serializePoint$1(bottomRightArcEnd)}`,
5245
+ `H ${baseEnd.x.toFixed(2)}`,
5246
+ `L ${serializePoint$1(tip)}`,
5247
+ `L ${serializePoint$1(baseStart)}`,
5248
+ `H ${bottomLeftArcStart.x.toFixed(2)}`,
5249
+ `A ${radius} ${radius} 0 0 1 ${serializePoint$1(leftBottom)}`,
5250
+ `V ${leftTop.y.toFixed(2)}`,
5251
+ `A ${radius} ${radius} 0 0 1 ${serializePoint$1(start)}`,
5252
+ 'Z',
5253
+ ].join(' ');
5254
+ }
5255
+ class DuckDevSpeakerBubbleNeobrutalSlab {
5256
+ color = input(AccentEnumColor.Orange, { ...(ngDevMode ? { debugName: "color" } : {}) });
5257
+ tail = input('left', { ...(ngDevMode ? { debugName: "tail" } : {}) });
5258
+ target = input(null, { ...(ngDevMode ? { debugName: "target" } : {}) });
5259
+ hostRef = inject((ElementRef));
5260
+ documentRef = inject(DOCUMENT);
5261
+ destroyRef = inject(DestroyRef);
5262
+ platformId = inject(PLATFORM_ID);
5263
+ isBrowser = isPlatformBrowser(this.platformId);
5264
+ bubbleGeometry = signal(DEFAULT_BUBBLE_GEOMETRY$1, { ...(ngDevMode ? { debugName: "bubbleGeometry" } : {}) });
5265
+ animationFrameId = -1;
5266
+ resizeObserver = null;
5267
+ observedTarget = null;
5268
+ observersInitialized = false;
5269
+ bubbleStyle = computed(() => getNeobrutalSpeakerBubbleStyle(this.color()), { ...(ngDevMode ? { debugName: "bubbleStyle" } : {}) });
5270
+ resolvedTail = computed(() => this.bubbleGeometry().side, { ...(ngDevMode ? { debugName: "resolvedTail" } : {}) });
5271
+ shapeStyle = computed(() => this.bubbleGeometry().style, { ...(ngDevMode ? { debugName: "shapeStyle" } : {}) });
5272
+ shapeViewBox = computed(() => this.bubbleGeometry().viewBox, { ...(ngDevMode ? { debugName: "shapeViewBox" } : {}) });
5273
+ shapePath = computed(() => this.bubbleGeometry().path, { ...(ngDevMode ? { debugName: "shapePath" } : {}) });
5274
+ constructor() {
5275
+ afterNextRender(() => {
5276
+ this.setupObservers();
5277
+ this.scheduleRefresh();
5278
+ });
5279
+ afterRenderEffect(() => {
5280
+ this.tail();
5281
+ this.target();
5282
+ this.setupObservers();
5283
+ this.scheduleRefresh();
5284
+ });
5285
+ this.destroyRef.onDestroy(() => {
5286
+ this.documentRef.defaultView?.removeEventListener('resize', this.scheduleRefresh);
5287
+ this.documentRef.removeEventListener('scroll', this.scheduleRefresh, true);
5288
+ if (this.animationFrameId !== -1) {
5289
+ cancelAnimationFrame(this.animationFrameId);
5290
+ }
5291
+ this.resizeObserver?.disconnect();
5292
+ this.resizeObserver = null;
5293
+ this.observedTarget = null;
5294
+ });
5295
+ }
5296
+ scheduleRefresh = () => {
5297
+ if (!this.isBrowser || this.animationFrameId !== -1) {
5298
+ return;
5299
+ }
5300
+ this.animationFrameId = requestAnimationFrame(() => {
5301
+ this.animationFrameId = -1;
5302
+ this.refreshShape();
5303
+ });
5304
+ };
5305
+ setupObservers() {
5306
+ if (!this.isBrowser || this.observersInitialized) {
5307
+ return;
5308
+ }
5309
+ const bubbleElement = getBubbleElement$1(this.hostRef.nativeElement);
5310
+ if (!bubbleElement) {
5311
+ return;
5312
+ }
5313
+ if (typeof ResizeObserver !== 'undefined') {
5314
+ this.resizeObserver = new ResizeObserver(() => this.scheduleRefresh());
5315
+ this.resizeObserver.observe(bubbleElement);
5316
+ }
5317
+ const targetElement = resolveTargetElement$1(this.target(), this.hostRef.nativeElement, this.documentRef);
5318
+ if (targetElement) {
5319
+ this.resizeObserver?.observe(targetElement);
5320
+ this.observedTarget = targetElement;
5321
+ }
5322
+ this.documentRef.defaultView?.addEventListener('resize', this.scheduleRefresh);
5323
+ this.documentRef.addEventListener('scroll', this.scheduleRefresh, true);
5324
+ this.observersInitialized = true;
5325
+ }
5326
+ refreshShape() {
5327
+ if (!this.isBrowser) {
5328
+ return;
5329
+ }
5330
+ const bubbleElement = getBubbleElement$1(this.hostRef.nativeElement);
5331
+ if (!bubbleElement) {
5332
+ return;
5333
+ }
5334
+ const targetElement = resolveTargetElement$1(this.target(), this.hostRef.nativeElement, this.documentRef);
5335
+ if (this.resizeObserver && targetElement !== this.observedTarget) {
5336
+ if (this.observedTarget) {
5337
+ this.resizeObserver.unobserve(this.observedTarget);
5338
+ }
5339
+ if (targetElement) {
5340
+ this.resizeObserver.observe(targetElement);
5341
+ }
5342
+ this.observedTarget = targetElement;
5343
+ }
5344
+ const bubbleRect = bubbleElement.getBoundingClientRect();
5345
+ const targetRect = targetElement?.getBoundingClientRect() ?? null;
5346
+ const side = this.resolveTailSide(bubbleRect, targetRect);
5347
+ const seventh = bubbleRect.width / 7;
5348
+ const baseStartX = side === 'left'
5349
+ ? clamp$1(seventh, 24, bubbleRect.width - 64)
5350
+ : clamp$1(bubbleRect.width - seventh * 2, 24, bubbleRect.width - 64);
5351
+ const baseEndX = side === 'left'
5352
+ ? clamp$1(seventh * 2, baseStartX + 24, bubbleRect.width - 24)
5353
+ : clamp$1(bubbleRect.width - seventh, baseStartX + 24, bubbleRect.width - 24);
5354
+ const anchor = {
5355
+ x: bubbleRect.left + (baseStartX + baseEndX) / 2,
5356
+ y: bubbleRect.bottom,
5357
+ };
5358
+ const targetPoint = targetRect
5359
+ ? closestPointOnRect$1(targetRect, anchor)
5360
+ : {
5361
+ x: bubbleRect.left + (side === 'left' ? baseStartX : baseEndX),
5362
+ y: bubbleRect.bottom + Math.max(28, bubbleRect.height / 4),
5363
+ };
5364
+ const tipX = clamp$1(targetPoint.x - bubbleRect.left, -52, bubbleRect.width + 52);
5365
+ const tipY = Math.max(targetPoint.y - bubbleRect.top, bubbleRect.height + 24);
5366
+ const minX = Math.min(0, tipX);
5367
+ const maxX = Math.max(bubbleRect.width, tipX);
5368
+ const maxY = Math.max(bubbleRect.height, tipY);
5369
+ const padding = 12;
5370
+ const offsetX = padding - minX;
5371
+ const offsetY = padding;
5372
+ const width = maxX - minX + padding * 2;
5373
+ const height = maxY + padding * 2;
5374
+ this.bubbleGeometry.set({
5375
+ side,
5376
+ style: {
5377
+ left: `${minX - padding}px`,
5378
+ top: `${-padding}px`,
5379
+ width: `${width}px`,
5380
+ height: `${height}px`,
5381
+ },
5382
+ viewBox: `0 0 ${width.toFixed(2)} ${height.toFixed(2)}`,
5383
+ path: createUnifiedBubblePath$1(bubbleRect.width, bubbleRect.height, 8, baseStartX, baseEndX, tipX, tipY, offsetX, offsetY),
5384
+ });
5385
+ }
5386
+ resolveTailSide(bubbleRect, targetRect) {
5387
+ const tail = this.tail();
5388
+ if (tail === 'left' || tail === 'right') {
5389
+ return tail;
5390
+ }
5391
+ const targetCenterX = targetRect
5392
+ ? targetRect.left + targetRect.width / 2
5393
+ : bubbleRect.left + bubbleRect.width / 2;
5394
+ return targetCenterX < bubbleRect.left + bubbleRect.width / 2 ? 'left' : 'right';
5395
+ }
5396
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: DuckDevSpeakerBubbleNeobrutalSlab, deps: [], target: i0.ɵɵFactoryTarget.Component });
5397
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.1", type: DuckDevSpeakerBubbleNeobrutalSlab, isStandalone: true, selector: "dd-speaker-bubble-neobrutal-slab", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, tail: { classPropertyName: "tail", publicName: "tail", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\n class=\"dd-speaker-bubble-neo-slab\"\n [attr.data-tail]=\"resolvedTail()\"\n [ngStyle]=\"bubbleStyle()\"\n>\n <svg\n class=\"dd-speaker-bubble-neo-slab__shape\"\n aria-hidden=\"true\"\n [ngStyle]=\"shapeStyle()\"\n [attr.viewBox]=\"shapeViewBox()\"\n preserveAspectRatio=\"none\"\n focusable=\"false\"\n >\n <path\n class=\"dd-speaker-bubble-neo-slab__shape-path\"\n [attr.d]=\"shapePath()\"\n />\n </svg>\n <span class=\"dd-speaker-bubble-neo-slab__pin\" aria-hidden=\"true\"></span>\n <span class=\"dd-speaker-bubble-neo-slab__corner\" aria-hidden=\"true\"></span>\n <div class=\"dd-speaker-bubble-neo-slab__content\">\n <ng-content />\n </div>\n</div>\n", styles: [":host{display:block;width:fit-content;max-width:min(100%,38rem)}.dd-speaker-bubble-neo-slab{position:relative;isolation:isolate;overflow:visible;padding:28px 22px 18px;color:var(--dd-speaker-text)}.dd-speaker-bubble-neo-slab__shape{position:absolute;inset:0;z-index:0;pointer-events:none}.dd-speaker-bubble-neo-slab__shape-path{fill:var(--dd-speaker-surface);stroke:var(--dd-speaker-border);stroke-width:4;stroke-linecap:square;stroke-linejoin:miter;filter:drop-shadow(8px 8px 0 var(--dd-speaker-shadow))}.dd-speaker-bubble-neo-slab__pin{position:absolute;top:-16px;left:18px;width:46px;height:18px;border:4px solid var(--dd-speaker-border);background:var(--dd-speaker-accent);box-shadow:4px 4px 0 var(--dd-speaker-border);transform:rotate(-4deg)}.dd-speaker-bubble-neo-slab__corner{position:absolute;top:0;right:0;width:24px;height:24px;border-left:4px solid var(--dd-speaker-border);border-bottom:4px solid var(--dd-speaker-border);background:color-mix(in srgb,var(--dd-speaker-accent) 74%,white)}.dd-speaker-bubble-neo-slab[data-tail=right] .dd-speaker-bubble-neo-slab__pin{right:18px;left:auto;transform:rotate(4deg)}.dd-speaker-bubble-neo-slab[data-tail=right] .dd-speaker-bubble-neo-slab__corner{right:auto;left:0;border-right:4px solid var(--dd-speaker-border);border-left:0}.dd-speaker-bubble-neo-slab__content{position:relative;z-index:1;font-size:15px;font-weight:800;line-height:1.55;background:linear-gradient(135deg,color-mix(in srgb,var(--dd-speaker-accent) 28%,transparent) 0 18px,transparent 18px 100%),linear-gradient(180deg,color-mix(in srgb,var(--dd-speaker-surface-muted) 84%,var(--dd-speaker-surface)) 0,var(--dd-speaker-surface) 100%)}.dd-speaker-bubble-neo-slab__content :first-child{margin-top:0}.dd-speaker-bubble-neo-slab__content :last-child{margin-bottom:0}.dd-speaker-bubble-neo-slab__content strong{color:var(--dd-speaker-accent)}.dd-speaker-bubble-neo-slab__content small{display:inline-flex;align-items:center;gap:8px;margin-bottom:10px;padding:6px 10px 5px;border:3px solid var(--dd-speaker-border);background:color-mix(in srgb,var(--dd-speaker-accent) 20%,var(--dd-speaker-surface));box-shadow:3px 3px 0 var(--dd-speaker-shadow);color:var(--dd-speaker-text);font-size:11px;font-weight:1000;letter-spacing:.12em;line-height:1;text-transform:uppercase;white-space:nowrap}.dd-speaker-bubble-neo-slab__content small:before{content:\"\";width:10px;height:10px;flex:0 0 auto;border:3px solid var(--dd-speaker-border);background:var(--dd-speaker-accent)}.dd-speaker-bubble-neo-slab[data-tail=right] .dd-speaker-bubble-neo-slab__content{background:linear-gradient(225deg,color-mix(in srgb,var(--dd-speaker-accent) 28%,transparent) 0 18px,transparent 18px 100%),linear-gradient(180deg,color-mix(in srgb,var(--dd-speaker-surface-muted) 84%,var(--dd-speaker-surface)) 0,var(--dd-speaker-surface) 100%)}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
5398
+ }
5399
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: DuckDevSpeakerBubbleNeobrutalSlab, decorators: [{
5400
+ type: Component,
5401
+ args: [{ selector: 'dd-speaker-bubble-neobrutal-slab', standalone: true, imports: [NgStyle], template: "<div\n class=\"dd-speaker-bubble-neo-slab\"\n [attr.data-tail]=\"resolvedTail()\"\n [ngStyle]=\"bubbleStyle()\"\n>\n <svg\n class=\"dd-speaker-bubble-neo-slab__shape\"\n aria-hidden=\"true\"\n [ngStyle]=\"shapeStyle()\"\n [attr.viewBox]=\"shapeViewBox()\"\n preserveAspectRatio=\"none\"\n focusable=\"false\"\n >\n <path\n class=\"dd-speaker-bubble-neo-slab__shape-path\"\n [attr.d]=\"shapePath()\"\n />\n </svg>\n <span class=\"dd-speaker-bubble-neo-slab__pin\" aria-hidden=\"true\"></span>\n <span class=\"dd-speaker-bubble-neo-slab__corner\" aria-hidden=\"true\"></span>\n <div class=\"dd-speaker-bubble-neo-slab__content\">\n <ng-content />\n </div>\n</div>\n", styles: [":host{display:block;width:fit-content;max-width:min(100%,38rem)}.dd-speaker-bubble-neo-slab{position:relative;isolation:isolate;overflow:visible;padding:28px 22px 18px;color:var(--dd-speaker-text)}.dd-speaker-bubble-neo-slab__shape{position:absolute;inset:0;z-index:0;pointer-events:none}.dd-speaker-bubble-neo-slab__shape-path{fill:var(--dd-speaker-surface);stroke:var(--dd-speaker-border);stroke-width:4;stroke-linecap:square;stroke-linejoin:miter;filter:drop-shadow(8px 8px 0 var(--dd-speaker-shadow))}.dd-speaker-bubble-neo-slab__pin{position:absolute;top:-16px;left:18px;width:46px;height:18px;border:4px solid var(--dd-speaker-border);background:var(--dd-speaker-accent);box-shadow:4px 4px 0 var(--dd-speaker-border);transform:rotate(-4deg)}.dd-speaker-bubble-neo-slab__corner{position:absolute;top:0;right:0;width:24px;height:24px;border-left:4px solid var(--dd-speaker-border);border-bottom:4px solid var(--dd-speaker-border);background:color-mix(in srgb,var(--dd-speaker-accent) 74%,white)}.dd-speaker-bubble-neo-slab[data-tail=right] .dd-speaker-bubble-neo-slab__pin{right:18px;left:auto;transform:rotate(4deg)}.dd-speaker-bubble-neo-slab[data-tail=right] .dd-speaker-bubble-neo-slab__corner{right:auto;left:0;border-right:4px solid var(--dd-speaker-border);border-left:0}.dd-speaker-bubble-neo-slab__content{position:relative;z-index:1;font-size:15px;font-weight:800;line-height:1.55;background:linear-gradient(135deg,color-mix(in srgb,var(--dd-speaker-accent) 28%,transparent) 0 18px,transparent 18px 100%),linear-gradient(180deg,color-mix(in srgb,var(--dd-speaker-surface-muted) 84%,var(--dd-speaker-surface)) 0,var(--dd-speaker-surface) 100%)}.dd-speaker-bubble-neo-slab__content :first-child{margin-top:0}.dd-speaker-bubble-neo-slab__content :last-child{margin-bottom:0}.dd-speaker-bubble-neo-slab__content strong{color:var(--dd-speaker-accent)}.dd-speaker-bubble-neo-slab__content small{display:inline-flex;align-items:center;gap:8px;margin-bottom:10px;padding:6px 10px 5px;border:3px solid var(--dd-speaker-border);background:color-mix(in srgb,var(--dd-speaker-accent) 20%,var(--dd-speaker-surface));box-shadow:3px 3px 0 var(--dd-speaker-shadow);color:var(--dd-speaker-text);font-size:11px;font-weight:1000;letter-spacing:.12em;line-height:1;text-transform:uppercase;white-space:nowrap}.dd-speaker-bubble-neo-slab__content small:before{content:\"\";width:10px;height:10px;flex:0 0 auto;border:3px solid var(--dd-speaker-border);background:var(--dd-speaker-accent)}.dd-speaker-bubble-neo-slab[data-tail=right] .dd-speaker-bubble-neo-slab__content{background:linear-gradient(225deg,color-mix(in srgb,var(--dd-speaker-accent) 28%,transparent) 0 18px,transparent 18px 100%),linear-gradient(180deg,color-mix(in srgb,var(--dd-speaker-surface-muted) 84%,var(--dd-speaker-surface)) 0,var(--dd-speaker-surface) 100%)}\n"] }]
5402
+ }], ctorParameters: () => [], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], tail: [{ type: i0.Input, args: [{ isSignal: true, alias: "tail", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }] } });
5403
+
5404
+ const DEFAULT_BUBBLE_GEOMETRY = {
5405
+ side: 'left',
5406
+ style: {
5407
+ left: '0px',
5408
+ top: '0px',
5409
+ width: '1px',
5410
+ height: '1px',
5411
+ },
5412
+ viewBox: '0 0 1 1',
5413
+ path: '',
5414
+ };
5415
+ function clamp(value, min, max) {
5416
+ return Math.min(Math.max(value, min), max);
5417
+ }
5418
+ function serializePoint(point) {
5419
+ return `${point.x.toFixed(2)} ${point.y.toFixed(2)}`;
5420
+ }
5421
+ function closestPointOnRect(rect, point) {
5422
+ return {
5423
+ x: clamp(point.x, rect.left, rect.right),
5424
+ y: clamp(point.y, rect.top, rect.bottom),
5425
+ };
5426
+ }
5427
+ function resolveTargetElement(source, hostElement, documentRef) {
5428
+ if (!source) {
5429
+ return null;
5430
+ }
5431
+ if (source instanceof Element) {
5432
+ return source;
5433
+ }
5434
+ try {
5435
+ const localMatch = hostElement.parentElement?.querySelector(source);
5436
+ if (localMatch) {
5437
+ return localMatch;
5438
+ }
5439
+ return documentRef.querySelector(source);
5440
+ }
5441
+ catch {
5442
+ return null;
5443
+ }
5444
+ }
5445
+ function getBubbleElement(hostElement) {
5446
+ return hostElement.firstElementChild instanceof HTMLElement ? hostElement.firstElementChild : null;
5447
+ }
5448
+ function createUnifiedBubblePath(width, height, radius, baseStartX, baseEndX, tipX, tipY, offsetX, offsetY) {
5449
+ const left = offsetX;
5450
+ const top = offsetY;
5451
+ const right = offsetX + width;
5452
+ const bottom = offsetY + height;
5453
+ const start = { x: left + radius, y: top };
5454
+ const bottomRight = { x: right, y: bottom - radius };
5455
+ const bottomRightArcEnd = { x: right - radius, y: bottom };
5456
+ const baseStart = { x: offsetX + baseStartX, y: bottom };
5457
+ const baseEnd = { x: offsetX + baseEndX, y: bottom };
5458
+ const tip = { x: offsetX + tipX, y: offsetY + tipY };
5459
+ const bottomLeftArcStart = { x: left + radius, y: bottom };
5460
+ const leftBottom = { x: left, y: bottom - radius };
5461
+ const leftTop = { x: left, y: top + radius };
5462
+ return [
5463
+ `M ${serializePoint(start)}`,
5464
+ `H ${(right - radius).toFixed(2)}`,
5465
+ `A ${radius} ${radius} 0 0 1 ${right.toFixed(2)} ${(top + radius).toFixed(2)}`,
5466
+ `V ${bottomRight.y.toFixed(2)}`,
5467
+ `A ${radius} ${radius} 0 0 1 ${serializePoint(bottomRightArcEnd)}`,
5468
+ `H ${baseEnd.x.toFixed(2)}`,
5469
+ `L ${serializePoint(tip)}`,
5470
+ `L ${serializePoint(baseStart)}`,
5471
+ `H ${bottomLeftArcStart.x.toFixed(2)}`,
5472
+ `A ${radius} ${radius} 0 0 1 ${serializePoint(leftBottom)}`,
5473
+ `V ${leftTop.y.toFixed(2)}`,
5474
+ `A ${radius} ${radius} 0 0 1 ${serializePoint(start)}`,
5475
+ 'Z',
5476
+ ].join(' ');
5477
+ }
5478
+ class DuckDevSpeakerBubbleNeobrutalTicket {
5479
+ color = input(AccentEnumColor.Dark, { ...(ngDevMode ? { debugName: "color" } : {}) });
5480
+ tail = input('left', { ...(ngDevMode ? { debugName: "tail" } : {}) });
5481
+ target = input(null, { ...(ngDevMode ? { debugName: "target" } : {}) });
5482
+ hostRef = inject((ElementRef));
5483
+ documentRef = inject(DOCUMENT);
5484
+ destroyRef = inject(DestroyRef);
5485
+ platformId = inject(PLATFORM_ID);
5486
+ isBrowser = isPlatformBrowser(this.platformId);
5487
+ bubbleGeometry = signal(DEFAULT_BUBBLE_GEOMETRY, { ...(ngDevMode ? { debugName: "bubbleGeometry" } : {}) });
5488
+ animationFrameId = -1;
5489
+ resizeObserver = null;
5490
+ observedTarget = null;
5491
+ observersInitialized = false;
5492
+ bubbleStyle = computed(() => getNeobrutalSpeakerBubbleStyle(this.color()), { ...(ngDevMode ? { debugName: "bubbleStyle" } : {}) });
5493
+ resolvedTail = computed(() => this.bubbleGeometry().side, { ...(ngDevMode ? { debugName: "resolvedTail" } : {}) });
5494
+ shapeStyle = computed(() => this.bubbleGeometry().style, { ...(ngDevMode ? { debugName: "shapeStyle" } : {}) });
5495
+ shapeViewBox = computed(() => this.bubbleGeometry().viewBox, { ...(ngDevMode ? { debugName: "shapeViewBox" } : {}) });
5496
+ shapePath = computed(() => this.bubbleGeometry().path, { ...(ngDevMode ? { debugName: "shapePath" } : {}) });
5497
+ constructor() {
5498
+ afterNextRender(() => {
5499
+ this.setupObservers();
5500
+ this.scheduleRefresh();
5501
+ });
5502
+ afterRenderEffect(() => {
5503
+ this.tail();
5504
+ this.target();
5505
+ this.setupObservers();
5506
+ this.scheduleRefresh();
5507
+ });
5508
+ this.destroyRef.onDestroy(() => {
5509
+ this.documentRef.defaultView?.removeEventListener('resize', this.scheduleRefresh);
5510
+ this.documentRef.removeEventListener('scroll', this.scheduleRefresh, true);
5511
+ if (this.animationFrameId !== -1) {
5512
+ cancelAnimationFrame(this.animationFrameId);
5513
+ }
5514
+ this.resizeObserver?.disconnect();
5515
+ this.resizeObserver = null;
5516
+ this.observedTarget = null;
5517
+ });
5518
+ }
5519
+ scheduleRefresh = () => {
5520
+ if (!this.isBrowser || this.animationFrameId !== -1) {
5521
+ return;
5522
+ }
5523
+ this.animationFrameId = requestAnimationFrame(() => {
5524
+ this.animationFrameId = -1;
5525
+ this.refreshShape();
5526
+ });
5527
+ };
5528
+ setupObservers() {
5529
+ if (!this.isBrowser || this.observersInitialized) {
5530
+ return;
5531
+ }
5532
+ const bubbleElement = getBubbleElement(this.hostRef.nativeElement);
5533
+ if (!bubbleElement) {
5534
+ return;
5535
+ }
5536
+ if (typeof ResizeObserver !== 'undefined') {
5537
+ this.resizeObserver = new ResizeObserver(() => this.scheduleRefresh());
5538
+ this.resizeObserver.observe(bubbleElement);
5539
+ }
5540
+ const targetElement = resolveTargetElement(this.target(), this.hostRef.nativeElement, this.documentRef);
5541
+ if (targetElement) {
5542
+ this.resizeObserver?.observe(targetElement);
5543
+ this.observedTarget = targetElement;
5544
+ }
5545
+ this.documentRef.defaultView?.addEventListener('resize', this.scheduleRefresh);
5546
+ this.documentRef.addEventListener('scroll', this.scheduleRefresh, true);
5547
+ this.observersInitialized = true;
5548
+ }
5549
+ refreshShape() {
5550
+ if (!this.isBrowser) {
5551
+ return;
5552
+ }
5553
+ const bubbleElement = getBubbleElement(this.hostRef.nativeElement);
5554
+ if (!bubbleElement) {
5555
+ return;
5556
+ }
5557
+ const targetElement = resolveTargetElement(this.target(), this.hostRef.nativeElement, this.documentRef);
5558
+ if (this.resizeObserver && targetElement !== this.observedTarget) {
5559
+ if (this.observedTarget) {
5560
+ this.resizeObserver.unobserve(this.observedTarget);
5561
+ }
5562
+ if (targetElement) {
5563
+ this.resizeObserver.observe(targetElement);
5564
+ }
5565
+ this.observedTarget = targetElement;
5566
+ }
5567
+ const bubbleRect = bubbleElement.getBoundingClientRect();
5568
+ const targetRect = targetElement?.getBoundingClientRect() ?? null;
5569
+ const side = this.resolveTailSide(bubbleRect, targetRect);
5570
+ const seventh = bubbleRect.width / 7;
5571
+ const baseStartX = side === 'left'
5572
+ ? clamp(seventh, 26, bubbleRect.width - 72)
5573
+ : clamp(bubbleRect.width - seventh * 2, 26, bubbleRect.width - 72);
5574
+ const baseEndX = side === 'left'
5575
+ ? clamp(seventh * 2, baseStartX + 24, bubbleRect.width - 26)
5576
+ : clamp(bubbleRect.width - seventh, baseStartX + 24, bubbleRect.width - 26);
5577
+ const anchor = {
5578
+ x: bubbleRect.left + (baseStartX + baseEndX) / 2,
5579
+ y: bubbleRect.bottom,
5580
+ };
5581
+ const targetPoint = targetRect
5582
+ ? closestPointOnRect(targetRect, anchor)
5583
+ : {
5584
+ x: bubbleRect.left + (side === 'left' ? baseStartX : baseEndX),
5585
+ y: bubbleRect.bottom + Math.max(28, bubbleRect.height / 4),
5586
+ };
5587
+ const tipX = clamp(targetPoint.x - bubbleRect.left, -56, bubbleRect.width + 56);
5588
+ const tipY = Math.max(targetPoint.y - bubbleRect.top, bubbleRect.height + 24);
5589
+ const minX = Math.min(0, tipX);
5590
+ const maxX = Math.max(bubbleRect.width, tipX);
5591
+ const maxY = Math.max(bubbleRect.height, tipY);
5592
+ const padding = 12;
5593
+ const offsetX = padding - minX;
5594
+ const offsetY = padding;
5595
+ const width = maxX - minX + padding * 2;
5596
+ const height = maxY + padding * 2;
5597
+ this.bubbleGeometry.set({
5598
+ side,
5599
+ style: {
5600
+ left: `${minX - padding}px`,
5601
+ top: `${-padding}px`,
5602
+ width: `${width}px`,
5603
+ height: `${height}px`,
5604
+ },
5605
+ viewBox: `0 0 ${width.toFixed(2)} ${height.toFixed(2)}`,
5606
+ path: createUnifiedBubblePath(bubbleRect.width, bubbleRect.height, 6, baseStartX, baseEndX, tipX, tipY, offsetX, offsetY),
5607
+ });
5608
+ }
5609
+ resolveTailSide(bubbleRect, targetRect) {
5610
+ const tail = this.tail();
5611
+ if (tail === 'left' || tail === 'right') {
5612
+ return tail;
5613
+ }
5614
+ const targetCenterX = targetRect
5615
+ ? targetRect.left + targetRect.width / 2
5616
+ : bubbleRect.left + bubbleRect.width / 2;
5617
+ return targetCenterX < bubbleRect.left + bubbleRect.width / 2 ? 'left' : 'right';
5618
+ }
5619
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: DuckDevSpeakerBubbleNeobrutalTicket, deps: [], target: i0.ɵɵFactoryTarget.Component });
5620
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.1", type: DuckDevSpeakerBubbleNeobrutalTicket, isStandalone: true, selector: "dd-speaker-bubble-neobrutal-ticket", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, tail: { classPropertyName: "tail", publicName: "tail", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\n class=\"dd-speaker-bubble-neo-ticket\"\n [attr.data-tail]=\"resolvedTail()\"\n [ngStyle]=\"bubbleStyle()\"\n>\n <svg\n class=\"dd-speaker-bubble-neo-ticket__shape\"\n aria-hidden=\"true\"\n [ngStyle]=\"shapeStyle()\"\n [attr.viewBox]=\"shapeViewBox()\"\n preserveAspectRatio=\"none\"\n focusable=\"false\"\n >\n <path\n class=\"dd-speaker-bubble-neo-ticket__shape-path\"\n [attr.d]=\"shapePath()\"\n />\n </svg>\n\n <div class=\"dd-speaker-bubble-neo-ticket__shell\">\n <div class=\"dd-speaker-bubble-neo-ticket__body\">\n <span class=\"dd-speaker-bubble-neo-ticket__flash\" aria-hidden=\"true\"></span>\n\n <div class=\"dd-speaker-bubble-neo-ticket__content\">\n <ng-content />\n </div>\n </div>\n\n <span class=\"dd-speaker-bubble-neo-ticket__stub\" aria-hidden=\"true\">\n <span></span>\n <span></span>\n <span></span>\n </span>\n </div>\n</div>\n", styles: [":host{display:block;width:fit-content;max-width:min(100%,40rem)}.dd-speaker-bubble-neo-ticket{position:relative;isolation:isolate;overflow:visible;color:var(--dd-speaker-text)}.dd-speaker-bubble-neo-ticket__shape{position:absolute;inset:0;z-index:0;pointer-events:none}.dd-speaker-bubble-neo-ticket__shape-path{fill:var(--dd-speaker-surface);stroke:var(--dd-speaker-border);stroke-width:4;stroke-linecap:square;stroke-linejoin:miter;filter:drop-shadow(10px 10px 0 var(--dd-speaker-shadow))}.dd-speaker-bubble-neo-ticket__shell{position:relative;z-index:1;display:grid;grid-template-columns:minmax(0,1fr) 58px;grid-template-areas:\"body stub\";padding:4px}.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__shell{grid-template-columns:58px minmax(0,1fr);grid-template-areas:\"stub body\"}.dd-speaker-bubble-neo-ticket__body{grid-area:body;position:relative;padding:22px 22px 18px;background:linear-gradient(135deg,color-mix(in srgb,var(--dd-speaker-accent) 20%,transparent) 0 16px,transparent 16px 100%),repeating-linear-gradient(90deg,transparent 0 14px,color-mix(in srgb,var(--dd-speaker-border) 8%,transparent) 14px 16px),color-mix(in srgb,var(--dd-speaker-surface-muted) 78%,var(--dd-speaker-surface))}.dd-speaker-bubble-neo-ticket__body:before,.dd-speaker-bubble-neo-ticket__body:after{content:\"\";position:absolute;top:18px;right:-18px;width:28px;height:28px;border:4px solid var(--dd-speaker-border);border-radius:999px;background:var(--dd-speaker-surface)}.dd-speaker-bubble-neo-ticket__body:after{top:auto;bottom:18px}.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__body:before,.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__body:after{right:auto;left:-18px}.dd-speaker-bubble-neo-ticket__flash{position:absolute;top:14px;left:18px;width:30px;height:12px;border:3px solid var(--dd-speaker-border);background:var(--dd-speaker-accent);box-shadow:4px 4px 0 var(--dd-speaker-shadow);transform:rotate(-7deg)}.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__flash{left:auto;right:18px;transform:rotate(7deg)}.dd-speaker-bubble-neo-ticket__content{position:relative;z-index:1;padding-top:18px;font-size:15px;font-weight:800;line-height:1.55}.dd-speaker-bubble-neo-ticket__content :first-child{margin-top:0}.dd-speaker-bubble-neo-ticket__content :last-child{margin-bottom:0}.dd-speaker-bubble-neo-ticket__content strong{color:var(--dd-speaker-accent)}.dd-speaker-bubble-neo-ticket__content small{display:inline-flex;margin-bottom:10px;padding:5px 8px 4px;border:3px solid var(--dd-speaker-border);background:var(--dd-speaker-accent);color:var(--dd-speaker-border);font-size:11px;font-weight:1000;letter-spacing:.14em;line-height:1;text-transform:uppercase;white-space:nowrap}.dd-speaker-bubble-neo-ticket__stub{grid-area:stub;display:grid;align-content:center;justify-items:center;gap:10px;padding:16px 8px;border-left:4px dashed var(--dd-speaker-border);background:color-mix(in srgb,var(--dd-speaker-accent) 70%,var(--dd-speaker-surface))}.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__stub{border-right:4px dashed var(--dd-speaker-border);border-left:0}.dd-speaker-bubble-neo-ticket__stub span{width:18px;height:18px;border:4px solid var(--dd-speaker-border);border-radius:999px;background:color-mix(in srgb,var(--dd-speaker-surface) 80%,white)}@media(max-width:640px){.dd-speaker-bubble-neo-ticket__shape-path{filter:drop-shadow(8px 8px 0 var(--dd-speaker-shadow))}.dd-speaker-bubble-neo-ticket__shell,.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__shell{grid-template-columns:1fr;grid-template-areas:\"body\" \"stub\"}.dd-speaker-bubble-neo-ticket__body:before,.dd-speaker-bubble-neo-ticket__body:after,.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__body:before,.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__body:after{inset:auto auto -18px 22px;width:24px;height:24px}.dd-speaker-bubble-neo-ticket__body:after,.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__body:after{left:auto;right:22px}.dd-speaker-bubble-neo-ticket__stub,.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__stub{grid-template-columns:repeat(3,minmax(0,1fr));gap:0;padding:12px 14px;border-top:4px dashed var(--dd-speaker-border);border-right:0;border-left:0}}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
5621
+ }
5622
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: DuckDevSpeakerBubbleNeobrutalTicket, decorators: [{
5623
+ type: Component,
5624
+ args: [{ selector: 'dd-speaker-bubble-neobrutal-ticket', standalone: true, imports: [NgStyle], template: "<div\n class=\"dd-speaker-bubble-neo-ticket\"\n [attr.data-tail]=\"resolvedTail()\"\n [ngStyle]=\"bubbleStyle()\"\n>\n <svg\n class=\"dd-speaker-bubble-neo-ticket__shape\"\n aria-hidden=\"true\"\n [ngStyle]=\"shapeStyle()\"\n [attr.viewBox]=\"shapeViewBox()\"\n preserveAspectRatio=\"none\"\n focusable=\"false\"\n >\n <path\n class=\"dd-speaker-bubble-neo-ticket__shape-path\"\n [attr.d]=\"shapePath()\"\n />\n </svg>\n\n <div class=\"dd-speaker-bubble-neo-ticket__shell\">\n <div class=\"dd-speaker-bubble-neo-ticket__body\">\n <span class=\"dd-speaker-bubble-neo-ticket__flash\" aria-hidden=\"true\"></span>\n\n <div class=\"dd-speaker-bubble-neo-ticket__content\">\n <ng-content />\n </div>\n </div>\n\n <span class=\"dd-speaker-bubble-neo-ticket__stub\" aria-hidden=\"true\">\n <span></span>\n <span></span>\n <span></span>\n </span>\n </div>\n</div>\n", styles: [":host{display:block;width:fit-content;max-width:min(100%,40rem)}.dd-speaker-bubble-neo-ticket{position:relative;isolation:isolate;overflow:visible;color:var(--dd-speaker-text)}.dd-speaker-bubble-neo-ticket__shape{position:absolute;inset:0;z-index:0;pointer-events:none}.dd-speaker-bubble-neo-ticket__shape-path{fill:var(--dd-speaker-surface);stroke:var(--dd-speaker-border);stroke-width:4;stroke-linecap:square;stroke-linejoin:miter;filter:drop-shadow(10px 10px 0 var(--dd-speaker-shadow))}.dd-speaker-bubble-neo-ticket__shell{position:relative;z-index:1;display:grid;grid-template-columns:minmax(0,1fr) 58px;grid-template-areas:\"body stub\";padding:4px}.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__shell{grid-template-columns:58px minmax(0,1fr);grid-template-areas:\"stub body\"}.dd-speaker-bubble-neo-ticket__body{grid-area:body;position:relative;padding:22px 22px 18px;background:linear-gradient(135deg,color-mix(in srgb,var(--dd-speaker-accent) 20%,transparent) 0 16px,transparent 16px 100%),repeating-linear-gradient(90deg,transparent 0 14px,color-mix(in srgb,var(--dd-speaker-border) 8%,transparent) 14px 16px),color-mix(in srgb,var(--dd-speaker-surface-muted) 78%,var(--dd-speaker-surface))}.dd-speaker-bubble-neo-ticket__body:before,.dd-speaker-bubble-neo-ticket__body:after{content:\"\";position:absolute;top:18px;right:-18px;width:28px;height:28px;border:4px solid var(--dd-speaker-border);border-radius:999px;background:var(--dd-speaker-surface)}.dd-speaker-bubble-neo-ticket__body:after{top:auto;bottom:18px}.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__body:before,.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__body:after{right:auto;left:-18px}.dd-speaker-bubble-neo-ticket__flash{position:absolute;top:14px;left:18px;width:30px;height:12px;border:3px solid var(--dd-speaker-border);background:var(--dd-speaker-accent);box-shadow:4px 4px 0 var(--dd-speaker-shadow);transform:rotate(-7deg)}.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__flash{left:auto;right:18px;transform:rotate(7deg)}.dd-speaker-bubble-neo-ticket__content{position:relative;z-index:1;padding-top:18px;font-size:15px;font-weight:800;line-height:1.55}.dd-speaker-bubble-neo-ticket__content :first-child{margin-top:0}.dd-speaker-bubble-neo-ticket__content :last-child{margin-bottom:0}.dd-speaker-bubble-neo-ticket__content strong{color:var(--dd-speaker-accent)}.dd-speaker-bubble-neo-ticket__content small{display:inline-flex;margin-bottom:10px;padding:5px 8px 4px;border:3px solid var(--dd-speaker-border);background:var(--dd-speaker-accent);color:var(--dd-speaker-border);font-size:11px;font-weight:1000;letter-spacing:.14em;line-height:1;text-transform:uppercase;white-space:nowrap}.dd-speaker-bubble-neo-ticket__stub{grid-area:stub;display:grid;align-content:center;justify-items:center;gap:10px;padding:16px 8px;border-left:4px dashed var(--dd-speaker-border);background:color-mix(in srgb,var(--dd-speaker-accent) 70%,var(--dd-speaker-surface))}.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__stub{border-right:4px dashed var(--dd-speaker-border);border-left:0}.dd-speaker-bubble-neo-ticket__stub span{width:18px;height:18px;border:4px solid var(--dd-speaker-border);border-radius:999px;background:color-mix(in srgb,var(--dd-speaker-surface) 80%,white)}@media(max-width:640px){.dd-speaker-bubble-neo-ticket__shape-path{filter:drop-shadow(8px 8px 0 var(--dd-speaker-shadow))}.dd-speaker-bubble-neo-ticket__shell,.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__shell{grid-template-columns:1fr;grid-template-areas:\"body\" \"stub\"}.dd-speaker-bubble-neo-ticket__body:before,.dd-speaker-bubble-neo-ticket__body:after,.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__body:before,.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__body:after{inset:auto auto -18px 22px;width:24px;height:24px}.dd-speaker-bubble-neo-ticket__body:after,.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__body:after{left:auto;right:22px}.dd-speaker-bubble-neo-ticket__stub,.dd-speaker-bubble-neo-ticket[data-tail=right] .dd-speaker-bubble-neo-ticket__stub{grid-template-columns:repeat(3,minmax(0,1fr));gap:0;padding:12px 14px;border-top:4px dashed var(--dd-speaker-border);border-right:0;border-left:0}}\n"] }]
5625
+ }], ctorParameters: () => [], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], tail: [{ type: i0.Input, args: [{ isSignal: true, alias: "tail", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }] } });
5626
+
5627
+ class SpeakerBubbleBlock {
5628
+ t = inject(TranslocoService);
5629
+ colorViolet = AccentEnumColor.Violet;
5630
+ colorOrange = AccentEnumColor.Orange;
5631
+ colorWhite = AccentEnumColor.White;
5632
+ colorGray = AccentEnumColor.Gray;
5633
+ colorDark = AccentEnumColor.Dark;
5634
+ styleTabs = [
5635
+ { id: 'classic', label: this.t.translate('documentationStyleTabs.classic') },
5636
+ { id: 'neobrutalism', label: this.t.translate('documentationStyleTabs.neobrutalism') },
5637
+ ];
5638
+ activeStyleTab = signal(this.styleTabs[0], { ...(ngDevMode ? { debugName: "activeStyleTab" } : {}) });
5639
+ introEl;
5640
+ inputContentEl;
5641
+ inputColorEl;
5642
+ inputTailEl;
5643
+ constructor() {
5644
+ this.introEl = this.createEl(this.t.translate('speakerBubbleDoc.intro'));
5645
+ this.inputContentEl = this.createEl(this.t.translate('speakerBubbleDoc.inputsDesc.content'));
5646
+ this.inputColorEl = this.createEl(this.t.translate('speakerBubbleDoc.inputsDesc.color'));
5647
+ this.inputTailEl = this.createEl(this.t.translate('speakerBubbleDoc.inputsDesc.tail'));
5648
+ }
5649
+ onStyleTabChange(tab) {
5650
+ this.activeStyleTab.set(tab);
5651
+ }
5652
+ createEl(html) {
5653
+ const el = document.createElement('div');
5654
+ el.innerHTML = html;
5655
+ return el;
5656
+ }
5657
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: SpeakerBubbleBlock, deps: [], target: i0.ɵɵFactoryTarget.Component });
5658
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: SpeakerBubbleBlock, isStandalone: true, selector: "app-speaker-bubble-block", ngImport: i0, template: "<div class=\"demo-container\">\n <h1>{{ 'speakerBubbleDoc.title' | transloco }}</h1>\n\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"introEl.innerHTML\"></div>\n </dd-card-accent>\n\n <duck-dev-tab [tabs]=\"styleTabs\" (tabChange)=\"onStyleTabChange($event)\">\n @if (activeStyleTab().id === 'classic') {\n <dd-card-section>\n <h2>{{ 'speakerBubbleDoc.classic.bubbleTitle' | transloco }}</h2>\n <p class=\"description\">{{ 'speakerBubbleDoc.classic.bubbleDescription' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'speakerBubbleDoc.common.usage' | transloco }}</h3>\n <pre><code>&lt;dd-speaker-bubble-classic [color]=\"colorWhite\" [tail]=\"'left'\"&gt;\n &lt;small&gt;Product team&lt;/small&gt;\n &lt;p&gt;Can we move the onboarding review to Thursday?&lt;/p&gt;\n&lt;/dd-speaker-bubble-classic&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'speakerBubbleDoc.common.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorOrange\">\n <div [innerHTML]=\"inputTailEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'speakerBubbleDoc.common.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.leftTail' | transloco }}</p>\n <div class=\"bubble-preview\">\n <dd-speaker-bubble-classic\n [color]=\"colorWhite\"\n [tail]=\"'left'\"\n [target]=\"classicLeftTarget\"\n >\n <small>Design sync</small>\n <p>Can we keep the hero copy shorter on mobile?</p>\n </dd-speaker-bubble-classic>\n <span class=\"bubble-target\" #classicLeftTarget aria-hidden=\"true\"></span>\n </div>\n </div>\n\n <div class=\"example-item example-item--right\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.rightTail' | transloco }}</p>\n <div class=\"bubble-preview bubble-preview--end\">\n <dd-speaker-bubble-classic\n [color]=\"colorViolet\"\n [tail]=\"'right'\"\n [target]=\"classicRightTarget\"\n >\n <small>Frontend</small>\n <p><strong>Yes</strong>, the block can keep a CTA and badge inside projected content.</p>\n </dd-speaker-bubble-classic>\n <span\n class=\"bubble-target bubble-target--violet\"\n #classicRightTarget\n aria-hidden=\"true\"\n ></span>\n </div>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'speakerBubbleDoc.classic.softTitle' | transloco }}</h2>\n <p class=\"description\">{{ 'speakerBubbleDoc.classic.softDescription' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'speakerBubbleDoc.common.usage' | transloco }}</h3>\n <pre><code>&lt;dd-speaker-bubble-soft [color]=\"colorOrange\" [tail]=\"'right'\"&gt;\n &lt;small&gt;Assistant&lt;/small&gt;\n &lt;p&gt;Projected markup can include &lt;strong&gt;inline emphasis&lt;/strong&gt; and metadata.&lt;/p&gt;\n&lt;/dd-speaker-bubble-soft&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'speakerBubbleDoc.common.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorOrange\">\n <div [innerHTML]=\"inputTailEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'speakerBubbleDoc.common.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.richContent' | transloco }}</p>\n <div class=\"bubble-preview\">\n <dd-speaker-bubble-soft\n [color]=\"colorOrange\"\n [tail]=\"'left'\"\n [target]=\"softLeftTarget\"\n >\n <small>Release note</small>\n <p>Bubble keeps a softer glassy surface for editorial comments and gentle callouts.</p>\n </dd-speaker-bubble-soft>\n <span\n class=\"bubble-target bubble-target--orange\"\n #softLeftTarget\n aria-hidden=\"true\"\n ></span>\n </div>\n </div>\n\n <div class=\"example-item example-item--right\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.darkMode' | transloco }}</p>\n <div class=\"bubble-preview bubble-preview--end\">\n <dd-speaker-bubble-soft\n [color]=\"colorDark\"\n [tail]=\"'right'\"\n [target]=\"softRightTarget\"\n >\n <small>Night queue</small>\n <p>Rich content can stay readable even on dark palette variants.</p>\n </dd-speaker-bubble-soft>\n <span\n class=\"bubble-target bubble-target--dark\"\n #softRightTarget\n aria-hidden=\"true\"\n ></span>\n </div>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'speakerBubbleDoc.classic.outlineTitle' | transloco }}</h2>\n <p class=\"description\">{{ 'speakerBubbleDoc.classic.outlineDescription' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'speakerBubbleDoc.common.usage' | transloco }}</h3>\n <pre><code>&lt;dd-speaker-bubble-outline [color]=\"colorGray\" [tail]=\"'left'\"&gt;\n &lt;small&gt;System&lt;/small&gt;\n &lt;p&gt;Outline variants work well for neutral hints and documentation notes.&lt;/p&gt;\n&lt;/dd-speaker-bubble-outline&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'speakerBubbleDoc.common.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorOrange\">\n <div [innerHTML]=\"inputTailEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'speakerBubbleDoc.common.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.note' | transloco }}</p>\n <div class=\"bubble-preview\">\n <dd-speaker-bubble-outline\n [color]=\"colorGray\"\n [tail]=\"'left'\"\n [target]=\"outlineLeftTarget\"\n >\n <small>Documentation</small>\n <p>Outlined speaker bubbles are useful for neutral side notes in dense layouts.</p>\n </dd-speaker-bubble-outline>\n <span class=\"bubble-target\" #outlineLeftTarget aria-hidden=\"true\"></span>\n </div>\n </div>\n\n <div class=\"example-item example-item--right\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.replyRight' | transloco }}</p>\n <div class=\"bubble-preview bubble-preview--end\">\n <dd-speaker-bubble-outline\n [color]=\"colorWhite\"\n [tail]=\"'right'\"\n [target]=\"outlineRightTarget\"\n >\n <small>QA</small>\n <p>Tail position still flips while content remains projected markup.</p>\n </dd-speaker-bubble-outline>\n <span class=\"bubble-target\" #outlineRightTarget aria-hidden=\"true\"></span>\n </div>\n </div>\n </div>\n </div>\n </dd-card-section>\n } @else {\n <dd-card-section>\n <h2>{{ 'speakerBubbleDoc.neobrutal.slabTitle' | transloco }}</h2>\n <p class=\"description\">{{ 'speakerBubbleDoc.neobrutal.slabDescription' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'speakerBubbleDoc.common.usage' | transloco }}</h3>\n <pre><code>&lt;dd-speaker-bubble-neobrutal-slab [color]=\"colorOrange\" [tail]=\"'left'\"&gt;\n &lt;small&gt;Live drop&lt;/small&gt;\n &lt;p&gt;Use ng-content for bold labels, paragraphs and inline status chips.&lt;/p&gt;\n&lt;/dd-speaker-bubble-neobrutal-slab&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'speakerBubbleDoc.common.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorOrange\">\n <div [innerHTML]=\"inputTailEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'speakerBubbleDoc.common.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.livePanel' | transloco }}</p>\n <div class=\"bubble-preview\">\n <dd-speaker-bubble-neobrutal-slab\n [color]=\"colorOrange\"\n [tail]=\"'left'\"\n [target]=\"slabLeftTarget\"\n >\n <small>Queue A</small>\n <p><strong>Live</strong> release banner for dashboards, status walls and loud interface narration.</p>\n </dd-speaker-bubble-neobrutal-slab>\n <span\n class=\"bubble-target bubble-target--orange\"\n #slabLeftTarget\n aria-hidden=\"true\"\n ></span>\n </div>\n </div>\n\n <div class=\"example-item example-item--neobrutal example-item--right\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.hotReply' | transloco }}</p>\n <div class=\"bubble-preview bubble-preview--end\">\n <dd-speaker-bubble-neobrutal-slab\n [color]=\"colorViolet\"\n [tail]=\"'right'\"\n [target]=\"slabRightTarget\"\n >\n <small>Ops</small>\n <p>The slab version keeps a heavy tail and rigid geometry for louder chat layouts.</p>\n </dd-speaker-bubble-neobrutal-slab>\n <span\n class=\"bubble-target bubble-target--violet\"\n #slabRightTarget\n aria-hidden=\"true\"\n ></span>\n </div>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'speakerBubbleDoc.neobrutal.ticketTitle' | transloco }}</h2>\n <p class=\"description\">{{ 'speakerBubbleDoc.neobrutal.ticketDescription' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'speakerBubbleDoc.common.usage' | transloco }}</h3>\n <pre><code>&lt;dd-speaker-bubble-neobrutal-ticket [color]=\"colorDark\" [tail]=\"'right'\"&gt;\n &lt;small&gt;Alert feed&lt;/small&gt;\n &lt;p&gt;Projected content stays flexible while the component provides the ticket shell.&lt;/p&gt;\n&lt;/dd-speaker-bubble-neobrutal-ticket&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'speakerBubbleDoc.common.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorOrange\">\n <div [innerHTML]=\"inputTailEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'speakerBubbleDoc.common.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.alertTicket' | transloco }}</p>\n <div class=\"bubble-preview\">\n <dd-speaker-bubble-neobrutal-ticket\n [color]=\"colorDark\"\n [tail]=\"'left'\"\n [target]=\"ticketLeftTarget\"\n >\n <small>Alert feed</small>\n <p>Ticket framing works for warning streams, operations chatter and serialized event logs.</p>\n </dd-speaker-bubble-neobrutal-ticket>\n <span\n class=\"bubble-target bubble-target--dark\"\n #ticketLeftTarget\n aria-hidden=\"true\"\n ></span>\n </div>\n </div>\n\n <div class=\"example-item example-item--neobrutal example-item--right\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.ticketReply' | transloco }}</p>\n <div class=\"bubble-preview bubble-preview--end\">\n <dd-speaker-bubble-neobrutal-ticket\n [color]=\"colorWhite\"\n [tail]=\"'right'\"\n [target]=\"ticketRightTarget\"\n >\n <small>Review</small>\n <p><strong>Approved</strong> for launch preview, keep the counter-note visible in the timeline.</p>\n </dd-speaker-bubble-neobrutal-ticket>\n <span\n class=\"bubble-target bubble-target--orange\"\n #ticketRightTarget\n aria-hidden=\"true\"\n ></span>\n </div>\n </div>\n </div>\n </div>\n </dd-card-section>\n }\n </duck-dev-tab>\n</div>\n", styles: [".demo-container{max-width:1200px;margin:0 auto;padding:40px 20px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.demo-container h1{font-size:36px;font-weight:700;color:var(--dd-base-600);margin-bottom:30px;text-align:center;border-bottom:3px solid var(--dd-base-accent-blue);padding-bottom:20px}.demo-container h2{font-size:28px;font-weight:600;color:var(--dd-base-500);margin-bottom:15px;border-left:4px solid var(--dd-base-accent-blue);padding-left:15px}.demo-container .description{font-size:16px;line-height:1.6;color:var(--dd-base-400);margin-bottom:25px;padding:15px;background:var(--dd-base-100);border-radius:8px;border-left:3px solid var(--dd-base-300)}.demo-container h3{font-size:20px;font-weight:600;color:var(--dd-base-500);margin-bottom:15px;margin-top:25px}.demo-container .usage-block{margin-bottom:25px}.demo-container .usage-block pre{background:var(--dd-base-600);color:var(--dd-base-100);padding:20px;border-radius:8px;overflow-x:auto;margin:0}.demo-container .usage-block pre code{font-family:Courier New,Courier,monospace;font-size:14px;line-height:1.5}.demo-container .inputs-block{margin-bottom:25px}.demo-container .inputs-block ul{list-style:none;padding:0;margin:0}.demo-container .inputs-block ul li{margin-bottom:8px}.demo-container .examples-block .example-row{display:flex;gap:20px;margin-bottom:20px;flex-wrap:wrap}.demo-container .examples-block .example-item{flex:1;min-width:280px;padding:20px;background:var(--dd-base-100);border-radius:8px;border:2px solid var(--dd-base-300);display:flex;flex-direction:column;gap:15px;transition:all .3s ease}.demo-container .examples-block .example-item:hover{border-color:var(--dd-base-accent-blue);box-shadow:0 4px 12px var(--dd-base-300)}.demo-container .examples-block .example-item--right .example-label{text-align:right}.demo-container .examples-block .example-item--neobrutal{background:linear-gradient(135deg,color-mix(in srgb,var(--dd-base-accent-yellow) 24%,transparent) 0 15%,transparent 15% 100%),var(--dd-base-0);border:4px solid var(--dd-base-600);border-radius:0;box-shadow:8px 8px 0 var(--dd-base-accent-blue)}.demo-container .examples-block .example-item--neobrutal:hover{border-color:var(--dd-base-600);box-shadow:10px 10px 0 var(--dd-base-accent-orange)}.demo-container .examples-block .example-label{font-size:14px;font-weight:600;color:var(--dd-base-400);margin:0;text-align:left}.demo-container .bubble-preview{width:100%;display:flex;flex-direction:column;align-items:flex-start;gap:16px}.demo-container .bubble-preview--end{align-items:flex-end}.demo-container .bubble-target{position:relative;width:54px;height:54px;border:2px solid var(--dd-base-300);border-radius:18px;background:radial-gradient(circle at 34% 34%,var(--dd-base-0) 0 18%,transparent 18% 100%),linear-gradient(145deg,color-mix(in srgb,var(--dd-base-accent-blue) 16%,transparent) 0,transparent 52%),var(--dd-base-100);box-shadow:0 10px 18px color-mix(in srgb,var(--dd-base-400) 24%,transparent);flex:0 0 auto}.demo-container .bubble-target:before{content:\"\";position:absolute;inset:11px 13px 17px;border-radius:999px;background:color-mix(in srgb,var(--dd-base-accent-blue) 22%,var(--dd-base-0))}.demo-container .bubble-target:after{content:\"\";position:absolute;left:17px;right:17px;bottom:10px;height:10px;border-radius:999px;background:color-mix(in srgb,var(--dd-base-300) 85%,var(--dd-base-0))}.demo-container .bubble-target--violet{border-color:color-mix(in srgb,var(--dd-base-secondary) 42%,var(--dd-base-300));background:radial-gradient(circle at 34% 34%,var(--dd-base-0) 0 18%,transparent 18% 100%),linear-gradient(145deg,color-mix(in srgb,var(--dd-base-secondary) 18%,transparent) 0,transparent 52%),color-mix(in srgb,var(--dd-base-secondary) 10%,var(--dd-base-0))}.demo-container .bubble-target--orange{border-color:color-mix(in srgb,var(--dd-base-accent-orange) 46%,var(--dd-base-300));background:radial-gradient(circle at 34% 34%,var(--dd-base-0) 0 18%,transparent 18% 100%),linear-gradient(145deg,color-mix(in srgb,var(--dd-base-accent-orange) 22%,transparent) 0,transparent 52%),color-mix(in srgb,var(--dd-base-accent-yellow) 18%,var(--dd-base-0))}.demo-container .bubble-target--dark{border-color:var(--dd-base-500);background:radial-gradient(circle at 34% 34%,color-mix(in srgb,var(--dd-base-0) 88%,transparent) 0 18%,transparent 18% 100%),linear-gradient(145deg,color-mix(in srgb,var(--dd-base-accent-yellow) 16%,transparent) 0,transparent 52%),color-mix(in srgb,var(--dd-base-600) 92%,var(--dd-base-500))}.demo-container .bubble-target--dark:before{background:color-mix(in srgb,var(--dd-base-accent-yellow) 18%,var(--dd-base-0))}.demo-container .bubble-target--dark:after{background:color-mix(in srgb,var(--dd-base-400) 80%,var(--dd-base-600))}.demo-container .example-item--neobrutal .bubble-target{border-width:4px;border-color:var(--dd-base-600);border-radius:0;box-shadow:6px 6px 0 var(--dd-base-600)}@media(max-width:768px){.demo-container{padding:20px 15px}.demo-container h1{font-size:28px}.demo-container h2{font-size:24px}.demo-container .examples-block .example-row{flex-direction:column}}\n"], dependencies: [{ kind: "component", type: DuckDevCardAccent, selector: "dd-card-accent", inputs: ["color"] }, { kind: "component", type: DuckDevCardSection, selector: "dd-card-section" }, { kind: "component", type: DuckDevSpeakerBubbleClassic, selector: "dd-speaker-bubble-classic", inputs: ["color", "tail", "target"] }, { kind: "component", type: DuckDevSpeakerBubbleSoft, selector: "dd-speaker-bubble-soft", inputs: ["color", "tail", "target"] }, { kind: "component", type: DuckDevSpeakerBubbleOutline, selector: "dd-speaker-bubble-outline", inputs: ["color", "tail", "target"] }, { kind: "component", type: DuckDevSpeakerBubbleNeobrutalSlab, selector: "dd-speaker-bubble-neobrutal-slab", inputs: ["color", "tail", "target"] }, { kind: "component", type: DuckDevSpeakerBubbleNeobrutalTicket, selector: "dd-speaker-bubble-neobrutal-ticket", inputs: ["color", "tail", "target"] }, { kind: "component", type: DuckDevTab, selector: "duck-dev-tab", inputs: ["tabs"], outputs: ["tabChange"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
5659
+ }
5660
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: SpeakerBubbleBlock, decorators: [{
5661
+ type: Component,
5662
+ args: [{ selector: 'app-speaker-bubble-block', standalone: true, imports: [
5663
+ TranslocoPipe,
5664
+ DuckDevCardAccent,
5665
+ DuckDevCardSection,
5666
+ DuckDevSpeakerBubbleClassic,
5667
+ DuckDevSpeakerBubbleSoft,
5668
+ DuckDevSpeakerBubbleOutline,
5669
+ DuckDevSpeakerBubbleNeobrutalSlab,
5670
+ DuckDevSpeakerBubbleNeobrutalTicket,
5671
+ DuckDevTab,
5672
+ ], template: "<div class=\"demo-container\">\n <h1>{{ 'speakerBubbleDoc.title' | transloco }}</h1>\n\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"introEl.innerHTML\"></div>\n </dd-card-accent>\n\n <duck-dev-tab [tabs]=\"styleTabs\" (tabChange)=\"onStyleTabChange($event)\">\n @if (activeStyleTab().id === 'classic') {\n <dd-card-section>\n <h2>{{ 'speakerBubbleDoc.classic.bubbleTitle' | transloco }}</h2>\n <p class=\"description\">{{ 'speakerBubbleDoc.classic.bubbleDescription' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'speakerBubbleDoc.common.usage' | transloco }}</h3>\n <pre><code>&lt;dd-speaker-bubble-classic [color]=\"colorWhite\" [tail]=\"'left'\"&gt;\n &lt;small&gt;Product team&lt;/small&gt;\n &lt;p&gt;Can we move the onboarding review to Thursday?&lt;/p&gt;\n&lt;/dd-speaker-bubble-classic&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'speakerBubbleDoc.common.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorOrange\">\n <div [innerHTML]=\"inputTailEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'speakerBubbleDoc.common.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.leftTail' | transloco }}</p>\n <div class=\"bubble-preview\">\n <dd-speaker-bubble-classic\n [color]=\"colorWhite\"\n [tail]=\"'left'\"\n [target]=\"classicLeftTarget\"\n >\n <small>Design sync</small>\n <p>Can we keep the hero copy shorter on mobile?</p>\n </dd-speaker-bubble-classic>\n <span class=\"bubble-target\" #classicLeftTarget aria-hidden=\"true\"></span>\n </div>\n </div>\n\n <div class=\"example-item example-item--right\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.rightTail' | transloco }}</p>\n <div class=\"bubble-preview bubble-preview--end\">\n <dd-speaker-bubble-classic\n [color]=\"colorViolet\"\n [tail]=\"'right'\"\n [target]=\"classicRightTarget\"\n >\n <small>Frontend</small>\n <p><strong>Yes</strong>, the block can keep a CTA and badge inside projected content.</p>\n </dd-speaker-bubble-classic>\n <span\n class=\"bubble-target bubble-target--violet\"\n #classicRightTarget\n aria-hidden=\"true\"\n ></span>\n </div>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'speakerBubbleDoc.classic.softTitle' | transloco }}</h2>\n <p class=\"description\">{{ 'speakerBubbleDoc.classic.softDescription' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'speakerBubbleDoc.common.usage' | transloco }}</h3>\n <pre><code>&lt;dd-speaker-bubble-soft [color]=\"colorOrange\" [tail]=\"'right'\"&gt;\n &lt;small&gt;Assistant&lt;/small&gt;\n &lt;p&gt;Projected markup can include &lt;strong&gt;inline emphasis&lt;/strong&gt; and metadata.&lt;/p&gt;\n&lt;/dd-speaker-bubble-soft&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'speakerBubbleDoc.common.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorOrange\">\n <div [innerHTML]=\"inputTailEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'speakerBubbleDoc.common.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.richContent' | transloco }}</p>\n <div class=\"bubble-preview\">\n <dd-speaker-bubble-soft\n [color]=\"colorOrange\"\n [tail]=\"'left'\"\n [target]=\"softLeftTarget\"\n >\n <small>Release note</small>\n <p>Bubble keeps a softer glassy surface for editorial comments and gentle callouts.</p>\n </dd-speaker-bubble-soft>\n <span\n class=\"bubble-target bubble-target--orange\"\n #softLeftTarget\n aria-hidden=\"true\"\n ></span>\n </div>\n </div>\n\n <div class=\"example-item example-item--right\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.darkMode' | transloco }}</p>\n <div class=\"bubble-preview bubble-preview--end\">\n <dd-speaker-bubble-soft\n [color]=\"colorDark\"\n [tail]=\"'right'\"\n [target]=\"softRightTarget\"\n >\n <small>Night queue</small>\n <p>Rich content can stay readable even on dark palette variants.</p>\n </dd-speaker-bubble-soft>\n <span\n class=\"bubble-target bubble-target--dark\"\n #softRightTarget\n aria-hidden=\"true\"\n ></span>\n </div>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'speakerBubbleDoc.classic.outlineTitle' | transloco }}</h2>\n <p class=\"description\">{{ 'speakerBubbleDoc.classic.outlineDescription' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'speakerBubbleDoc.common.usage' | transloco }}</h3>\n <pre><code>&lt;dd-speaker-bubble-outline [color]=\"colorGray\" [tail]=\"'left'\"&gt;\n &lt;small&gt;System&lt;/small&gt;\n &lt;p&gt;Outline variants work well for neutral hints and documentation notes.&lt;/p&gt;\n&lt;/dd-speaker-bubble-outline&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'speakerBubbleDoc.common.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorOrange\">\n <div [innerHTML]=\"inputTailEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'speakerBubbleDoc.common.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.note' | transloco }}</p>\n <div class=\"bubble-preview\">\n <dd-speaker-bubble-outline\n [color]=\"colorGray\"\n [tail]=\"'left'\"\n [target]=\"outlineLeftTarget\"\n >\n <small>Documentation</small>\n <p>Outlined speaker bubbles are useful for neutral side notes in dense layouts.</p>\n </dd-speaker-bubble-outline>\n <span class=\"bubble-target\" #outlineLeftTarget aria-hidden=\"true\"></span>\n </div>\n </div>\n\n <div class=\"example-item example-item--right\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.replyRight' | transloco }}</p>\n <div class=\"bubble-preview bubble-preview--end\">\n <dd-speaker-bubble-outline\n [color]=\"colorWhite\"\n [tail]=\"'right'\"\n [target]=\"outlineRightTarget\"\n >\n <small>QA</small>\n <p>Tail position still flips while content remains projected markup.</p>\n </dd-speaker-bubble-outline>\n <span class=\"bubble-target\" #outlineRightTarget aria-hidden=\"true\"></span>\n </div>\n </div>\n </div>\n </div>\n </dd-card-section>\n } @else {\n <dd-card-section>\n <h2>{{ 'speakerBubbleDoc.neobrutal.slabTitle' | transloco }}</h2>\n <p class=\"description\">{{ 'speakerBubbleDoc.neobrutal.slabDescription' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'speakerBubbleDoc.common.usage' | transloco }}</h3>\n <pre><code>&lt;dd-speaker-bubble-neobrutal-slab [color]=\"colorOrange\" [tail]=\"'left'\"&gt;\n &lt;small&gt;Live drop&lt;/small&gt;\n &lt;p&gt;Use ng-content for bold labels, paragraphs and inline status chips.&lt;/p&gt;\n&lt;/dd-speaker-bubble-neobrutal-slab&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'speakerBubbleDoc.common.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorOrange\">\n <div [innerHTML]=\"inputTailEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'speakerBubbleDoc.common.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.livePanel' | transloco }}</p>\n <div class=\"bubble-preview\">\n <dd-speaker-bubble-neobrutal-slab\n [color]=\"colorOrange\"\n [tail]=\"'left'\"\n [target]=\"slabLeftTarget\"\n >\n <small>Queue A</small>\n <p><strong>Live</strong> release banner for dashboards, status walls and loud interface narration.</p>\n </dd-speaker-bubble-neobrutal-slab>\n <span\n class=\"bubble-target bubble-target--orange\"\n #slabLeftTarget\n aria-hidden=\"true\"\n ></span>\n </div>\n </div>\n\n <div class=\"example-item example-item--neobrutal example-item--right\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.hotReply' | transloco }}</p>\n <div class=\"bubble-preview bubble-preview--end\">\n <dd-speaker-bubble-neobrutal-slab\n [color]=\"colorViolet\"\n [tail]=\"'right'\"\n [target]=\"slabRightTarget\"\n >\n <small>Ops</small>\n <p>The slab version keeps a heavy tail and rigid geometry for louder chat layouts.</p>\n </dd-speaker-bubble-neobrutal-slab>\n <span\n class=\"bubble-target bubble-target--violet\"\n #slabRightTarget\n aria-hidden=\"true\"\n ></span>\n </div>\n </div>\n </div>\n </div>\n </dd-card-section>\n\n <dd-card-section>\n <h2>{{ 'speakerBubbleDoc.neobrutal.ticketTitle' | transloco }}</h2>\n <p class=\"description\">{{ 'speakerBubbleDoc.neobrutal.ticketDescription' | transloco }}</p>\n\n <div class=\"usage-block\">\n <h3>{{ 'speakerBubbleDoc.common.usage' | transloco }}</h3>\n <pre><code>&lt;dd-speaker-bubble-neobrutal-ticket [color]=\"colorDark\" [tail]=\"'right'\"&gt;\n &lt;small&gt;Alert feed&lt;/small&gt;\n &lt;p&gt;Projected content stays flexible while the component provides the ticket shell.&lt;/p&gt;\n&lt;/dd-speaker-bubble-neobrutal-ticket&gt;</code></pre>\n </div>\n\n <div class=\"inputs-block\">\n <h3>{{ 'speakerBubbleDoc.common.inputs' | transloco }}</h3>\n <ul>\n <li>\n <dd-card-accent [color]=\"colorWhite\">\n <div [innerHTML]=\"inputContentEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorViolet\">\n <div [innerHTML]=\"inputColorEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n <li>\n <dd-card-accent [color]=\"colorOrange\">\n <div [innerHTML]=\"inputTailEl.innerHTML\"></div>\n </dd-card-accent>\n </li>\n </ul>\n </div>\n\n <div class=\"examples-block\">\n <h3>{{ 'speakerBubbleDoc.common.examples' | transloco }}</h3>\n <div class=\"example-row\">\n <div class=\"example-item example-item--neobrutal\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.alertTicket' | transloco }}</p>\n <div class=\"bubble-preview\">\n <dd-speaker-bubble-neobrutal-ticket\n [color]=\"colorDark\"\n [tail]=\"'left'\"\n [target]=\"ticketLeftTarget\"\n >\n <small>Alert feed</small>\n <p>Ticket framing works for warning streams, operations chatter and serialized event logs.</p>\n </dd-speaker-bubble-neobrutal-ticket>\n <span\n class=\"bubble-target bubble-target--dark\"\n #ticketLeftTarget\n aria-hidden=\"true\"\n ></span>\n </div>\n </div>\n\n <div class=\"example-item example-item--neobrutal example-item--right\">\n <p class=\"example-label\">{{ 'speakerBubbleDoc.labels.ticketReply' | transloco }}</p>\n <div class=\"bubble-preview bubble-preview--end\">\n <dd-speaker-bubble-neobrutal-ticket\n [color]=\"colorWhite\"\n [tail]=\"'right'\"\n [target]=\"ticketRightTarget\"\n >\n <small>Review</small>\n <p><strong>Approved</strong> for launch preview, keep the counter-note visible in the timeline.</p>\n </dd-speaker-bubble-neobrutal-ticket>\n <span\n class=\"bubble-target bubble-target--orange\"\n #ticketRightTarget\n aria-hidden=\"true\"\n ></span>\n </div>\n </div>\n </div>\n </div>\n </dd-card-section>\n }\n </duck-dev-tab>\n</div>\n", styles: [".demo-container{max-width:1200px;margin:0 auto;padding:40px 20px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.demo-container h1{font-size:36px;font-weight:700;color:var(--dd-base-600);margin-bottom:30px;text-align:center;border-bottom:3px solid var(--dd-base-accent-blue);padding-bottom:20px}.demo-container h2{font-size:28px;font-weight:600;color:var(--dd-base-500);margin-bottom:15px;border-left:4px solid var(--dd-base-accent-blue);padding-left:15px}.demo-container .description{font-size:16px;line-height:1.6;color:var(--dd-base-400);margin-bottom:25px;padding:15px;background:var(--dd-base-100);border-radius:8px;border-left:3px solid var(--dd-base-300)}.demo-container h3{font-size:20px;font-weight:600;color:var(--dd-base-500);margin-bottom:15px;margin-top:25px}.demo-container .usage-block{margin-bottom:25px}.demo-container .usage-block pre{background:var(--dd-base-600);color:var(--dd-base-100);padding:20px;border-radius:8px;overflow-x:auto;margin:0}.demo-container .usage-block pre code{font-family:Courier New,Courier,monospace;font-size:14px;line-height:1.5}.demo-container .inputs-block{margin-bottom:25px}.demo-container .inputs-block ul{list-style:none;padding:0;margin:0}.demo-container .inputs-block ul li{margin-bottom:8px}.demo-container .examples-block .example-row{display:flex;gap:20px;margin-bottom:20px;flex-wrap:wrap}.demo-container .examples-block .example-item{flex:1;min-width:280px;padding:20px;background:var(--dd-base-100);border-radius:8px;border:2px solid var(--dd-base-300);display:flex;flex-direction:column;gap:15px;transition:all .3s ease}.demo-container .examples-block .example-item:hover{border-color:var(--dd-base-accent-blue);box-shadow:0 4px 12px var(--dd-base-300)}.demo-container .examples-block .example-item--right .example-label{text-align:right}.demo-container .examples-block .example-item--neobrutal{background:linear-gradient(135deg,color-mix(in srgb,var(--dd-base-accent-yellow) 24%,transparent) 0 15%,transparent 15% 100%),var(--dd-base-0);border:4px solid var(--dd-base-600);border-radius:0;box-shadow:8px 8px 0 var(--dd-base-accent-blue)}.demo-container .examples-block .example-item--neobrutal:hover{border-color:var(--dd-base-600);box-shadow:10px 10px 0 var(--dd-base-accent-orange)}.demo-container .examples-block .example-label{font-size:14px;font-weight:600;color:var(--dd-base-400);margin:0;text-align:left}.demo-container .bubble-preview{width:100%;display:flex;flex-direction:column;align-items:flex-start;gap:16px}.demo-container .bubble-preview--end{align-items:flex-end}.demo-container .bubble-target{position:relative;width:54px;height:54px;border:2px solid var(--dd-base-300);border-radius:18px;background:radial-gradient(circle at 34% 34%,var(--dd-base-0) 0 18%,transparent 18% 100%),linear-gradient(145deg,color-mix(in srgb,var(--dd-base-accent-blue) 16%,transparent) 0,transparent 52%),var(--dd-base-100);box-shadow:0 10px 18px color-mix(in srgb,var(--dd-base-400) 24%,transparent);flex:0 0 auto}.demo-container .bubble-target:before{content:\"\";position:absolute;inset:11px 13px 17px;border-radius:999px;background:color-mix(in srgb,var(--dd-base-accent-blue) 22%,var(--dd-base-0))}.demo-container .bubble-target:after{content:\"\";position:absolute;left:17px;right:17px;bottom:10px;height:10px;border-radius:999px;background:color-mix(in srgb,var(--dd-base-300) 85%,var(--dd-base-0))}.demo-container .bubble-target--violet{border-color:color-mix(in srgb,var(--dd-base-secondary) 42%,var(--dd-base-300));background:radial-gradient(circle at 34% 34%,var(--dd-base-0) 0 18%,transparent 18% 100%),linear-gradient(145deg,color-mix(in srgb,var(--dd-base-secondary) 18%,transparent) 0,transparent 52%),color-mix(in srgb,var(--dd-base-secondary) 10%,var(--dd-base-0))}.demo-container .bubble-target--orange{border-color:color-mix(in srgb,var(--dd-base-accent-orange) 46%,var(--dd-base-300));background:radial-gradient(circle at 34% 34%,var(--dd-base-0) 0 18%,transparent 18% 100%),linear-gradient(145deg,color-mix(in srgb,var(--dd-base-accent-orange) 22%,transparent) 0,transparent 52%),color-mix(in srgb,var(--dd-base-accent-yellow) 18%,var(--dd-base-0))}.demo-container .bubble-target--dark{border-color:var(--dd-base-500);background:radial-gradient(circle at 34% 34%,color-mix(in srgb,var(--dd-base-0) 88%,transparent) 0 18%,transparent 18% 100%),linear-gradient(145deg,color-mix(in srgb,var(--dd-base-accent-yellow) 16%,transparent) 0,transparent 52%),color-mix(in srgb,var(--dd-base-600) 92%,var(--dd-base-500))}.demo-container .bubble-target--dark:before{background:color-mix(in srgb,var(--dd-base-accent-yellow) 18%,var(--dd-base-0))}.demo-container .bubble-target--dark:after{background:color-mix(in srgb,var(--dd-base-400) 80%,var(--dd-base-600))}.demo-container .example-item--neobrutal .bubble-target{border-width:4px;border-color:var(--dd-base-600);border-radius:0;box-shadow:6px 6px 0 var(--dd-base-600)}@media(max-width:768px){.demo-container{padding:20px 15px}.demo-container h1{font-size:28px}.demo-container h2{font-size:24px}.demo-container .examples-block .example-row{flex-direction:column}}\n"] }]
5673
+ }], ctorParameters: () => [] });
5674
+
4039
5675
  class MainDocumentationPage {
4040
5676
  translocoService = inject(TranslocoService);
4041
5677
  title = signal('demo', { ...(ngDevMode ? { debugName: "title" } : {}) });
@@ -4050,6 +5686,7 @@ class MainDocumentationPage {
4050
5686
  { id: 'badge', label: this.translocoService.translate('tabs.badge') },
4051
5687
  { id: 'directives', label: this.translocoService.translate('tabs.directives') },
4052
5688
  { id: 'card', label: this.translocoService.translate('tabs.card') },
5689
+ { id: 'speaker-bubble', label: this.translocoService.translate('tabs.speakerBubble') },
4053
5690
  { id: 'input', label: this.translocoService.translate('tabs.input') },
4054
5691
  { id: 'modal', label: this.translocoService.translate('tabs.modal') },
4055
5692
  { id: 'notifications', label: this.translocoService.translate('tabs.notifications') },
@@ -4062,7 +5699,7 @@ class MainDocumentationPage {
4062
5699
  this.activeTab.set(tab);
4063
5700
  }
4064
5701
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MainDocumentationPage, deps: [], target: i0.ɵɵFactoryTarget.Component });
4065
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: MainDocumentationPage, isStandalone: true, selector: "duck-dev-main-documentation-page", ngImport: i0, template: "<duck-dev-tab-vertical [tabs]=\"tabs\" (tabChange)=\"onTabChange($event)\">\n @switch (activeTab().id) {\n @case ('quick-start') {\n <app-quick-start-block />\n }\n @case ('accordion') {\n <app-accordion-block />\n }\n @case ('buttons') {\n <app-button-block />\n }\n @case ('loaders') {\n <app-loader-block />\n }\n @case ('progress') {\n <app-progress-bar-block />\n }\n @case ('tabs') {\n <app-tabs-block />\n }\n @case ('tooltip') {\n <app-tooltip-block />\n }\n @case ('badge') {\n <app-badge-block />\n }\n @case ('directives') {\n <app-directive-block />\n }\n @case ('card') {\n <app-card-block />\n }\n @case ('modal') {\n <app-modal-block />\n }\n @case ('input') {\n <app-input-block />\n }\n @case ('notifications') {\n <app-notification-block />\n }\n @case ('slider') {\n <app-slider-block />\n }\n @case ('segment') {\n <app-segment-block />\n }\n @case ('svg') {\n <app-duck-dev-svg-block />\n }\n }\n</duck-dev-tab-vertical>\n<duck-dev-notification-container />\n", styles: [":host{display:block;height:100%}\n"], dependencies: [{ kind: "component", type: ButtonBlock, selector: "app-button-block" }, { kind: "component", type: LoaderBlock, selector: "app-loader-block" }, { kind: "component", type: TabsBlock, selector: "app-tabs-block" }, { kind: "component", type: DuckDevSvgBlock, selector: "app-duck-dev-svg-block" }, { kind: "component", type: DuckDevTabVertical, selector: "duck-dev-tab-vertical", inputs: ["tabs"], outputs: ["tabChange"] }, { kind: "component", type: InputBlock, selector: "app-input-block" }, { kind: "component", type: NotificationBlock, selector: "app-notification-block" }, { kind: "component", type: DuckDevNotificationContainer, selector: "duck-dev-notification-container" }, { kind: "component", type: BadgeBlock, selector: "app-badge-block" }, { kind: "component", type: DirectiveBlock, selector: "app-directive-block" }, { kind: "component", type: AccordionBlock, selector: "app-accordion-block" }, { kind: "component", type: SliderBlock, selector: "app-slider-block" }, { kind: "component", type: CardBlock, selector: "app-card-block" }, { kind: "component", type: TooltipBlock, selector: "app-tooltip-block" }, { kind: "component", type: QuickStartBlock, selector: "app-quick-start-block" }, { kind: "component", type: ModalBlock, selector: "app-modal-block" }, { kind: "component", type: SegmentBlock, selector: "app-segment-block" }, { kind: "component", type: ProgressBarBlock, selector: "app-progress-bar-block" }] });
5702
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: MainDocumentationPage, isStandalone: true, selector: "duck-dev-main-documentation-page", ngImport: i0, template: "<duck-dev-tab-vertical [tabs]=\"tabs\" (tabChange)=\"onTabChange($event)\">\n @switch (activeTab().id) {\n @case ('quick-start') {\n <app-quick-start-block />\n }\n @case ('accordion') {\n <app-accordion-block />\n }\n @case ('buttons') {\n <app-button-block />\n }\n @case ('loaders') {\n <app-loader-block />\n }\n @case ('progress') {\n <app-progress-bar-block />\n }\n @case ('tabs') {\n <app-tabs-block />\n }\n @case ('tooltip') {\n <app-tooltip-block />\n }\n @case ('badge') {\n <app-badge-block />\n }\n @case ('directives') {\n <app-directive-block />\n }\n @case ('card') {\n <app-card-block />\n }\n @case ('speaker-bubble') {\n <app-speaker-bubble-block />\n }\n @case ('modal') {\n <app-modal-block />\n }\n @case ('input') {\n <app-input-block />\n }\n @case ('notifications') {\n <app-notification-block />\n }\n @case ('slider') {\n <app-slider-block />\n }\n @case ('segment') {\n <app-segment-block />\n }\n @case ('svg') {\n <app-duck-dev-svg-block />\n }\n }\n</duck-dev-tab-vertical>\n<duck-dev-notification-container />\n", styles: [":host{display:block;height:100%}\n"], dependencies: [{ kind: "component", type: ButtonBlock, selector: "app-button-block" }, { kind: "component", type: LoaderBlock, selector: "app-loader-block" }, { kind: "component", type: TabsBlock, selector: "app-tabs-block" }, { kind: "component", type: DuckDevSvgBlock, selector: "app-duck-dev-svg-block" }, { kind: "component", type: DuckDevTabVertical, selector: "duck-dev-tab-vertical", inputs: ["tabs"], outputs: ["tabChange"] }, { kind: "component", type: InputBlock, selector: "app-input-block" }, { kind: "component", type: NotificationBlock, selector: "app-notification-block" }, { kind: "component", type: DuckDevNotificationContainer, selector: "duck-dev-notification-container" }, { kind: "component", type: BadgeBlock, selector: "app-badge-block" }, { kind: "component", type: DirectiveBlock, selector: "app-directive-block" }, { kind: "component", type: AccordionBlock, selector: "app-accordion-block" }, { kind: "component", type: SliderBlock, selector: "app-slider-block" }, { kind: "component", type: CardBlock, selector: "app-card-block" }, { kind: "component", type: TooltipBlock, selector: "app-tooltip-block" }, { kind: "component", type: QuickStartBlock, selector: "app-quick-start-block" }, { kind: "component", type: ModalBlock, selector: "app-modal-block" }, { kind: "component", type: SegmentBlock, selector: "app-segment-block" }, { kind: "component", type: ProgressBarBlock, selector: "app-progress-bar-block" }, { kind: "component", type: SpeakerBubbleBlock, selector: "app-speaker-bubble-block" }] });
4066
5703
  }
4067
5704
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MainDocumentationPage, decorators: [{
4068
5705
  type: Component,
@@ -4085,12 +5722,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImpor
4085
5722
  ModalBlock,
4086
5723
  SegmentBlock,
4087
5724
  ProgressBarBlock,
4088
- ], template: "<duck-dev-tab-vertical [tabs]=\"tabs\" (tabChange)=\"onTabChange($event)\">\n @switch (activeTab().id) {\n @case ('quick-start') {\n <app-quick-start-block />\n }\n @case ('accordion') {\n <app-accordion-block />\n }\n @case ('buttons') {\n <app-button-block />\n }\n @case ('loaders') {\n <app-loader-block />\n }\n @case ('progress') {\n <app-progress-bar-block />\n }\n @case ('tabs') {\n <app-tabs-block />\n }\n @case ('tooltip') {\n <app-tooltip-block />\n }\n @case ('badge') {\n <app-badge-block />\n }\n @case ('directives') {\n <app-directive-block />\n }\n @case ('card') {\n <app-card-block />\n }\n @case ('modal') {\n <app-modal-block />\n }\n @case ('input') {\n <app-input-block />\n }\n @case ('notifications') {\n <app-notification-block />\n }\n @case ('slider') {\n <app-slider-block />\n }\n @case ('segment') {\n <app-segment-block />\n }\n @case ('svg') {\n <app-duck-dev-svg-block />\n }\n }\n</duck-dev-tab-vertical>\n<duck-dev-notification-container />\n", styles: [":host{display:block;height:100%}\n"] }]
5725
+ SpeakerBubbleBlock,
5726
+ ], template: "<duck-dev-tab-vertical [tabs]=\"tabs\" (tabChange)=\"onTabChange($event)\">\n @switch (activeTab().id) {\n @case ('quick-start') {\n <app-quick-start-block />\n }\n @case ('accordion') {\n <app-accordion-block />\n }\n @case ('buttons') {\n <app-button-block />\n }\n @case ('loaders') {\n <app-loader-block />\n }\n @case ('progress') {\n <app-progress-bar-block />\n }\n @case ('tabs') {\n <app-tabs-block />\n }\n @case ('tooltip') {\n <app-tooltip-block />\n }\n @case ('badge') {\n <app-badge-block />\n }\n @case ('directives') {\n <app-directive-block />\n }\n @case ('card') {\n <app-card-block />\n }\n @case ('speaker-bubble') {\n <app-speaker-bubble-block />\n }\n @case ('modal') {\n <app-modal-block />\n }\n @case ('input') {\n <app-input-block />\n }\n @case ('notifications') {\n <app-notification-block />\n }\n @case ('slider') {\n <app-slider-block />\n }\n @case ('segment') {\n <app-segment-block />\n }\n @case ('svg') {\n <app-duck-dev-svg-block />\n }\n }\n</duck-dev-tab-vertical>\n<duck-dev-notification-container />\n", styles: [":host{display:block;height:100%}\n"] }]
4089
5727
  }] });
4090
5728
 
4091
5729
  const DuckDevLibTranslations = {
4092
- en: import('./duck-dev-lib-en-CDxyWfrd.mjs'),
4093
- ru: import('./duck-dev-lib-ru-1jQ8uE1i.mjs'),
5730
+ en: import('./duck-dev-lib-en-VOJz-IcV.mjs'),
5731
+ ru: import('./duck-dev-lib-ru-COyomsqL.mjs'),
4094
5732
  };
4095
5733
 
4096
5734
  /*
@@ -4101,5 +5739,5 @@ const DuckDevLibTranslations = {
4101
5739
  * Generated bundle index. Do not edit.
4102
5740
  */
4103
5741
 
4104
- export { AccentEnumColor, Badge, BadgeNeobrutalSlab, BadgeNeobrutalStamp, BadgeNeobrutalTicket, ButtonBlurLift, ButtonCasper, ButtonFlip, ButtonGlideOver, ButtonNeobrutalBurst, ButtonNeobrutalSlab, ButtonNeobrutalTag, DdFlexDirectionDirective, DuckDevAccordionComponent as DuckDevAccordion, DuckDevAccordionNeobrutalComponent as DuckDevAccordionNeobrutal, DuckDevCardAccent, DuckDevCardMinimal, DuckDevCardNeobrutalPoster, DuckDevCardNeobrutalSlab, DuckDevCardNeobrutalStamp, DuckDevCardNeobrutalTicket, DuckDevCardOutline, DuckDevCardSection, DuckDevCardSignal, DuckDevIcon, DuckDevInput, DuckDevInputNeobrutalPoster, DuckDevInputNeobrutalRadio, DuckDevInputNeobrutalSlab, DuckDevInputNeobrutalStrip, DuckDevInputNeobrutalToggle, DuckDevLibTranslations, DuckDevModalClassic, DuckDevNotification, DuckDevNotificationContainer, DuckDevNotificationService, DuckDevProgressLine, DuckDevProgressMeter, DuckDevProgressNeobrutalSlab, DuckDevProgressNeobrutalStamp, DuckDevProgressNeobrutalTicket, DuckDevProgressStack, DuckDevSegmentButton, DuckDevSegmentClassic, DuckDevSegmentNeobrutal, DuckDevTab, DuckDevTabVertical, DuckDevTooltip, DuckDevTooltipNeobrutalComponent, LoaderClassic, LoaderLoadingBubble, LoaderNeobrutalBars, LoaderNeobrutalMarquee, LoaderNeobrutalStamp, LoaderThreeDots, MainDocumentationPage, SliderClassic };
5742
+ export { AccentEnumColor, Badge, BadgeNeobrutalSlab, BadgeNeobrutalStamp, BadgeNeobrutalTicket, ButtonBlurLift, ButtonCasper, ButtonFlip, ButtonGlideOver, ButtonNeobrutalBurst, ButtonNeobrutalSlab, ButtonNeobrutalTag, DdFlexDirectionDirective, DuckDevAccordionComponent as DuckDevAccordion, DuckDevAccordionNeobrutalComponent as DuckDevAccordionNeobrutal, DuckDevCardAccent, DuckDevCardMinimal, DuckDevCardNeobrutalPoster, DuckDevCardNeobrutalSlab, DuckDevCardNeobrutalStamp, DuckDevCardNeobrutalTicket, DuckDevCardOutline, DuckDevCardSection, DuckDevCardSignal, DuckDevIcon, DuckDevInput, DuckDevInputNeobrutalPoster, DuckDevInputNeobrutalRadio, DuckDevInputNeobrutalSlab, DuckDevInputNeobrutalStrip, DuckDevInputNeobrutalToggle, DuckDevLibTranslations, DuckDevModalClassic, DuckDevNotification, DuckDevNotificationContainer, DuckDevNotificationService, DuckDevProgressLine, DuckDevProgressMeter, DuckDevProgressNeobrutalSlab, DuckDevProgressNeobrutalStamp, DuckDevProgressNeobrutalTicket, DuckDevProgressStack, DuckDevSegmentButton, DuckDevSegmentClassic, DuckDevSegmentNeobrutal, DuckDevSpeakerBubbleClassic, DuckDevSpeakerBubbleNeobrutalSlab, DuckDevSpeakerBubbleNeobrutalTicket, DuckDevSpeakerBubbleOutline, DuckDevSpeakerBubbleSoft, DuckDevTab, DuckDevTabVertical, DuckDevTooltip, DuckDevTooltipNeobrutalComponent, LoaderClassic, LoaderLoadingBubble, LoaderNeobrutalBars, LoaderNeobrutalMarquee, LoaderNeobrutalStamp, LoaderThreeDots, MainDocumentationPage, SliderClassic, getClassicSpeakerBubbleStyle, getNeobrutalSpeakerBubbleStyle, useSpeakerBubbleTail };
4105
5743
  //# sourceMappingURL=duck-dev-lib.mjs.map