@besaitech/ng-design-system 0.0.39 → 0.0.41

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.
@@ -155,7 +155,7 @@ const VARIANTS$2 = {
155
155
  ghost: 'bg-transparent text-ink-soft hover:bg-black/5 active:bg-black/10',
156
156
  danger: 'bg-danger text-white shadow-sm hover:brightness-95 active:brightness-90',
157
157
  };
158
- const SIZES$a = {
158
+ const SIZES$b = {
159
159
  sm: 'h-8 px-3 text-sm',
160
160
  md: 'h-10 px-4 text-sm',
161
161
  lg: 'h-12 px-5 text-base',
@@ -215,7 +215,7 @@ class SdsButton {
215
215
  BASE,
216
216
  this.shape() === 'pill' ? 'rounded-full' : 'rounded-control',
217
217
  VARIANTS$2[this.variant()],
218
- SIZES$a[size],
218
+ SIZES$b[size],
219
219
  this.iconOnly() ? ICON_ONLY[size] : '',
220
220
  this.block() ? 'w-full' : '',
221
221
  ]
@@ -267,8 +267,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
267
267
  `, styles: [".sds-spinner{width:1em;height:1em;border:2px solid currentColor;border-right-color:transparent;border-radius:9999px;animation:sds-spin .6s linear infinite}@keyframes sds-spin{to{transform:rotate(360deg)}}\n"] }]
268
268
  }], ctorParameters: () => [], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], block: [{ type: i0.Input, args: [{ isSignal: true, alias: "block", required: false }] }], iconOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOnly", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
269
269
 
270
- let nextId$b = 0;
271
- const SIZES$9 = {
270
+ let nextId$c = 0;
271
+ const SIZES$a = {
272
272
  sm: 'h-9 text-sm',
273
273
  md: 'h-10 text-sm',
274
274
  lg: 'h-12 text-base',
@@ -280,7 +280,7 @@ const SIZES$9 = {
280
280
  * sidebar search field).
281
281
  */
282
282
  class SdsInput {
283
- inputId = `sds-input-${nextId$b++}`;
283
+ inputId = `sds-input-${nextId$c++}`;
284
284
  label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
285
285
  /** Accessible name used when no visible [label] is provided. */
286
286
  ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
@@ -357,7 +357,7 @@ class SdsInput {
357
357
  return `${left} ${right}`;
358
358
  }, ...(ngDevMode ? [{ debugName: "fieldPadding" }] : []));
359
359
  wrapperClasses = computed(() => {
360
- const parts = [SIZES$9[this.size()], this.pill() ? 'rounded-full' : 'rounded-control'];
360
+ const parts = [SIZES$a[this.size()], this.pill() ? 'rounded-full' : 'rounded-control'];
361
361
  if (this.isDisabled())
362
362
  parts.push('opacity-60 cursor-not-allowed');
363
363
  if (this.filled()) {
@@ -601,6 +601,282 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
601
601
  `, styles: ["input:-webkit-autofill,input:-webkit-autofill:hover,input:-webkit-autofill:focus,input:-webkit-autofill:active{transition:background-color 100000s ease-in-out 0s;-webkit-text-fill-color:currentColor;caret-color:currentColor}\n"] }]
602
602
  }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], clearLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearLabel", required: false }] }], leadingIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "leadingIcon", required: false }] }], trailingIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "trailingIcon", required: false }] }], trailingAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "trailingAction", required: false }] }], trailingActionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "trailingActionLabel", required: false }] }], trailingActionPressed: [{ type: i0.Input, args: [{ isSignal: true, alias: "trailingActionPressed", required: false }] }], trailingActionClick: [{ type: i0.Output, args: ["trailingActionClick"] }] } });
603
603
 
604
+ let nextId$b = 0;
605
+ const SIZES$9 = {
606
+ sm: 'min-h-9 text-sm',
607
+ md: 'min-h-10 text-sm',
608
+ lg: 'min-h-12 text-base',
609
+ };
610
+ /**
611
+ * One language-aware text field for editing a translated value (a {@link SdsLocalizedValue} — a title,
612
+ * label or description in several languages). Only one language is edited at a time; a compact switcher
613
+ * sitting **inside the field** flips which translation you are editing, and a dot marks the languages that
614
+ * already have content, so a partially-translated value is obvious at a glance.
615
+ *
616
+ * The active language defaults to {@link currentLanguage} when it is one of {@link languages}, otherwise the
617
+ * first accepted language — so the field "opens on the language you are working in". Empty translations are
618
+ * pruned from the emitted value, keeping the stored map clean.
619
+ *
620
+ * Implements ControlValueAccessor over the map — use with reactive forms or `[(ngModel)]`:
621
+ * `<sds-localized-input [languages]="['fr','nl','en']" [(ngModel)]="title" />`.
622
+ */
623
+ class SdsLocalizedInput {
624
+ inputId = `sds-localized-input-${nextId$b++}`;
625
+ label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
626
+ hint = input('', ...(ngDevMode ? [{ debugName: "hint" }] : []));
627
+ placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
628
+ /** The accepted language codes, in display order (e.g. `['fr','nl','en']`). */
629
+ languages = input([], ...(ngDevMode ? [{ debugName: "languages" }] : []));
630
+ /** Language to pre-select; used when it is one of {@link languages}, else the first accepted language. */
631
+ currentLanguage = input(null, ...(ngDevMode ? [{ debugName: "currentLanguage" }] : []));
632
+ multiline = input(false, ...(ngDevMode ? [{ debugName: "multiline", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
633
+ rows = input(3, ...(ngDevMode ? [{ debugName: "rows", transform: numberAttribute }] : [{ transform: numberAttribute }]));
634
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
635
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
636
+ /**
637
+ * Accessible name for the in-field language switcher, and the "no translation yet" title suffix on each
638
+ * language button. French defaults so existing consumers are unchanged; translate them in a multi-language
639
+ * app (the buttons are letter-only, so the title carries their meaning).
640
+ */
641
+ languageSwitcherLabel = input('Langue', ...(ngDevMode ? [{ debugName: "languageSwitcherLabel" }] : []));
642
+ untranslatedLabel = input('à traduire', ...(ngDevMode ? [{ debugName: "untranslatedLabel" }] : []));
643
+ valueMap = signal({}, ...(ngDevMode ? [{ debugName: "valueMap" }] : []));
644
+ /** Language chosen via the switcher; null means "follow currentLanguage / the first language". */
645
+ manual = signal(null, ...(ngDevMode ? [{ debugName: "manual" }] : []));
646
+ cvaDisabled = signal(false, ...(ngDevMode ? [{ debugName: "cvaDisabled" }] : []));
647
+ isDisabled = computed(() => this.disabled() || this.cvaDisabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
648
+ wrapperClasses = computed(() => {
649
+ const parts = [SIZES$9[this.size()]];
650
+ parts.push(this.isDisabled()
651
+ ? 'border-border opacity-60 cursor-not-allowed'
652
+ : 'border-border focus-within:border-brand-500 focus-within:ring-2 focus-within:ring-brand-500/25');
653
+ return parts.join(' ');
654
+ }, ...(ngDevMode ? [{ debugName: "wrapperClasses" }] : []));
655
+ /** The language currently being edited. */
656
+ activeLang = computed(() => {
657
+ const langs = this.languages();
658
+ if (!langs.length) {
659
+ return '';
660
+ }
661
+ const manual = this.manual();
662
+ if (manual && langs.includes(manual)) {
663
+ return manual;
664
+ }
665
+ const preferred = this.currentLanguage();
666
+ return preferred && langs.includes(preferred) ? preferred : langs[0];
667
+ }, ...(ngDevMode ? [{ debugName: "activeLang" }] : []));
668
+ current = computed(() => this.valueMap()[this.activeLang()] ?? '', ...(ngDevMode ? [{ debugName: "current" }] : []));
669
+ filled(lang) {
670
+ const text = this.valueMap()[lang];
671
+ return !!text && text.trim().length > 0;
672
+ }
673
+ fieldPlaceholder() {
674
+ const base = this.placeholder();
675
+ const lang = this.activeLang().toUpperCase();
676
+ if (base) {
677
+ return lang ? `${base} (${lang})` : base;
678
+ }
679
+ return lang ? `(${lang})` : '';
680
+ }
681
+ select(lang) {
682
+ this.manual.set(lang);
683
+ this.onTouched();
684
+ }
685
+ write(event) {
686
+ const lang = this.activeLang();
687
+ if (!lang) {
688
+ return;
689
+ }
690
+ const text = event.target.value;
691
+ const next = { ...this.valueMap() };
692
+ if (text) {
693
+ next[lang] = text;
694
+ }
695
+ else {
696
+ delete next[lang];
697
+ }
698
+ this.valueMap.set(next);
699
+ this.onChange(next);
700
+ }
701
+ // --- ControlValueAccessor -------------------------------------------------
702
+ onChange = () => { };
703
+ onTouched = () => { };
704
+ writeValue(value) {
705
+ this.valueMap.set(value ? { ...value } : {});
706
+ }
707
+ registerOnChange(fn) {
708
+ this.onChange = fn;
709
+ }
710
+ registerOnTouched(fn) {
711
+ this.onTouched = fn;
712
+ }
713
+ setDisabledState(isDisabled) {
714
+ this.cvaDisabled.set(isDisabled);
715
+ }
716
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdsLocalizedInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
717
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: SdsLocalizedInput, isStandalone: true, selector: "sds-localized-input", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, languages: { classPropertyName: "languages", publicName: "languages", isSignal: true, isRequired: false, transformFunction: null }, currentLanguage: { classPropertyName: "currentLanguage", publicName: "currentLanguage", isSignal: true, isRequired: false, transformFunction: null }, multiline: { classPropertyName: "multiline", publicName: "multiline", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, languageSwitcherLabel: { classPropertyName: "languageSwitcherLabel", publicName: "languageSwitcherLabel", isSignal: true, isRequired: false, transformFunction: null }, untranslatedLabel: { classPropertyName: "untranslatedLabel", publicName: "untranslatedLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "block" }, providers: [
718
+ {
719
+ provide: NG_VALUE_ACCESSOR,
720
+ useExisting: forwardRef(() => SdsLocalizedInput),
721
+ multi: true,
722
+ },
723
+ ], ngImport: i0, template: `
724
+ @if (label()) {
725
+ <label [for]="inputId" class="mb-1.5 block text-sm font-medium text-ink">{{ label() }}</label>
726
+ }
727
+
728
+ <div
729
+ class="relative flex items-stretch rounded-control border bg-white text-ink transition-colors"
730
+ [class]="wrapperClasses()"
731
+ >
732
+ @if (multiline()) {
733
+ <textarea
734
+ [id]="inputId"
735
+ [rows]="rows()"
736
+ [placeholder]="fieldPlaceholder()"
737
+ [disabled]="isDisabled()"
738
+ [value]="current()"
739
+ (input)="write($event)"
740
+ (blur)="onTouched()"
741
+ class="min-w-0 flex-1 resize-y bg-transparent px-3.5 py-2 outline-none placeholder:text-current/50 disabled:cursor-not-allowed"
742
+ ></textarea>
743
+ } @else {
744
+ <input
745
+ [id]="inputId"
746
+ [placeholder]="fieldPlaceholder()"
747
+ [disabled]="isDisabled()"
748
+ [value]="current()"
749
+ (input)="write($event)"
750
+ (blur)="onTouched()"
751
+ class="min-w-0 flex-1 bg-transparent px-3.5 outline-none placeholder:text-current/50 disabled:cursor-not-allowed"
752
+ />
753
+ }
754
+
755
+ @if (languages().length > 1) {
756
+ <div
757
+ class="flex shrink-0 items-center gap-0.5 self-start p-1"
758
+ [class]="multiline() ? '' : 'self-center'"
759
+ role="tablist"
760
+ [attr.aria-label]="languageSwitcherLabel()"
761
+ >
762
+ @for (lang of languages(); track lang) {
763
+ <button
764
+ type="button"
765
+ role="tab"
766
+ tabindex="-1"
767
+ [disabled]="isDisabled()"
768
+ (click)="select(lang)"
769
+ [attr.aria-selected]="activeLang() === lang"
770
+ [attr.title]="lang.toUpperCase() + (filled(lang) ? '' : ' — ' + untranslatedLabel())"
771
+ class="flex items-center gap-1 rounded px-1.5 py-0.5 text-[11px] font-semibold uppercase leading-none transition-colors disabled:cursor-not-allowed disabled:opacity-50"
772
+ [class]="
773
+ activeLang() === lang
774
+ ? 'bg-brand-50 text-brand-700'
775
+ : 'text-ink-faint hover:bg-muted hover:text-ink-soft'
776
+ "
777
+ >
778
+ {{ lang }}
779
+ <span
780
+ class="inline-block h-1 w-1 rounded-full"
781
+ [class]="filled(lang) ? 'bg-success' : 'bg-current/30'"
782
+ ></span>
783
+ </button>
784
+ }
785
+ </div>
786
+ }
787
+ </div>
788
+
789
+ @if (hint()) {
790
+ <p class="mt-1.5 text-xs text-ink-faint">{{ hint() }}</p>
791
+ }
792
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
793
+ }
794
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdsLocalizedInput, decorators: [{
795
+ type: Component,
796
+ args: [{
797
+ selector: 'sds-localized-input',
798
+ changeDetection: ChangeDetectionStrategy.OnPush,
799
+ providers: [
800
+ {
801
+ provide: NG_VALUE_ACCESSOR,
802
+ useExisting: forwardRef(() => SdsLocalizedInput),
803
+ multi: true,
804
+ },
805
+ ],
806
+ host: { class: 'block' },
807
+ template: `
808
+ @if (label()) {
809
+ <label [for]="inputId" class="mb-1.5 block text-sm font-medium text-ink">{{ label() }}</label>
810
+ }
811
+
812
+ <div
813
+ class="relative flex items-stretch rounded-control border bg-white text-ink transition-colors"
814
+ [class]="wrapperClasses()"
815
+ >
816
+ @if (multiline()) {
817
+ <textarea
818
+ [id]="inputId"
819
+ [rows]="rows()"
820
+ [placeholder]="fieldPlaceholder()"
821
+ [disabled]="isDisabled()"
822
+ [value]="current()"
823
+ (input)="write($event)"
824
+ (blur)="onTouched()"
825
+ class="min-w-0 flex-1 resize-y bg-transparent px-3.5 py-2 outline-none placeholder:text-current/50 disabled:cursor-not-allowed"
826
+ ></textarea>
827
+ } @else {
828
+ <input
829
+ [id]="inputId"
830
+ [placeholder]="fieldPlaceholder()"
831
+ [disabled]="isDisabled()"
832
+ [value]="current()"
833
+ (input)="write($event)"
834
+ (blur)="onTouched()"
835
+ class="min-w-0 flex-1 bg-transparent px-3.5 outline-none placeholder:text-current/50 disabled:cursor-not-allowed"
836
+ />
837
+ }
838
+
839
+ @if (languages().length > 1) {
840
+ <div
841
+ class="flex shrink-0 items-center gap-0.5 self-start p-1"
842
+ [class]="multiline() ? '' : 'self-center'"
843
+ role="tablist"
844
+ [attr.aria-label]="languageSwitcherLabel()"
845
+ >
846
+ @for (lang of languages(); track lang) {
847
+ <button
848
+ type="button"
849
+ role="tab"
850
+ tabindex="-1"
851
+ [disabled]="isDisabled()"
852
+ (click)="select(lang)"
853
+ [attr.aria-selected]="activeLang() === lang"
854
+ [attr.title]="lang.toUpperCase() + (filled(lang) ? '' : ' — ' + untranslatedLabel())"
855
+ class="flex items-center gap-1 rounded px-1.5 py-0.5 text-[11px] font-semibold uppercase leading-none transition-colors disabled:cursor-not-allowed disabled:opacity-50"
856
+ [class]="
857
+ activeLang() === lang
858
+ ? 'bg-brand-50 text-brand-700'
859
+ : 'text-ink-faint hover:bg-muted hover:text-ink-soft'
860
+ "
861
+ >
862
+ {{ lang }}
863
+ <span
864
+ class="inline-block h-1 w-1 rounded-full"
865
+ [class]="filled(lang) ? 'bg-success' : 'bg-current/30'"
866
+ ></span>
867
+ </button>
868
+ }
869
+ </div>
870
+ }
871
+ </div>
872
+
873
+ @if (hint()) {
874
+ <p class="mt-1.5 text-xs text-ink-faint">{{ hint() }}</p>
875
+ }
876
+ `,
877
+ }]
878
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], languages: [{ type: i0.Input, args: [{ isSignal: true, alias: "languages", required: false }] }], currentLanguage: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentLanguage", required: false }] }], multiline: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiline", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], languageSwitcherLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "languageSwitcherLabel", required: false }] }], untranslatedLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "untranslatedLabel", required: false }] }] } });
879
+
604
880
  let nextId$a = 0;
605
881
  const SIZES$8 = {
606
882
  md: 'h-12 w-11 text-lg',
@@ -7398,6 +7674,157 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
7398
7674
  }]
7399
7675
  }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], dataKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataKey", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], striped: [{ type: i0.Input, args: [{ isSignal: true, alias: "striped", required: false }] }], gridlines: [{ type: i0.Input, args: [{ isSignal: true, alias: "gridlines", required: false }] }], hoverable: [{ type: i0.Input, args: [{ isSignal: true, alias: "hoverable", required: false }] }], sortable: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortable", required: false }] }], paginator: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginator", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], rowsPerPageOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowsPerPageOptions", required: false }] }], showCurrentPageReport: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCurrentPageReport", required: false }] }], currentPageReportTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentPageReportTemplate", required: false }] }], rowsPerPageLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowsPerPageLabel", required: false }] }], paginationLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginationLabel", required: false }] }], firstPageLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstPageLabel", required: false }] }], previousPageLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "previousPageLabel", required: false }] }], nextPageLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextPageLabel", required: false }] }], lastPageLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "lastPageLabel", required: false }] }], pageLinkLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageLinkLabel", required: false }] }], globalFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "globalFilter", required: false }] }], globalFilterPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "globalFilterPlaceholder", required: false }] }], globalFilterAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "globalFilterAriaLabel", required: false }] }], globalFilterFields: [{ type: i0.Input, args: [{ isSignal: true, alias: "globalFilterFields", required: false }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], selection: [{ type: i0.Input, args: [{ isSignal: true, alias: "selection", required: false }] }, { type: i0.Output, args: ["selectionChange"] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], caption: [{ type: i0.Input, args: [{ isSignal: true, alias: "caption", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], scrollHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollHeight", required: false }] }], lazy: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazy", required: false }] }], totalRecords: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalRecords", required: false }] }], expandable: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandable", required: false }] }], resizableColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizableColumns", required: false }] }], reorderableColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "reorderableColumns", required: false }] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], rowSelect: [{ type: i0.Output, args: ["rowSelect"] }], rowUnselect: [{ type: i0.Output, args: ["rowUnselect"] }], lazyLoad: [{ type: i0.Output, args: ["lazyLoad"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], rowExpand: [{ type: i0.Output, args: ["rowExpand"] }], rowCollapse: [{ type: i0.Output, args: ["rowCollapse"] }], colReorder: [{ type: i0.Output, args: ["colReorder"] }], cellTemplates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SdsTableCell), { isSignal: true }] }], rowExpansion: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SdsTableRowExpansion), { isSignal: true }] }] } });
7400
7676
 
7677
+ /**
7678
+ * A tiny transient-notification bus. Application code calls {@link success} / {@link error} / {@link info}
7679
+ * after an action; a single {@link SdsToastHost} mounted in the app shell renders the queue and each toast
7680
+ * auto-dismisses. Deliberately minimal — no positions, no actions-in-toast — because it exists to confirm
7681
+ * an action, not to be a notification centre.
7682
+ *
7683
+ * `providedIn: 'root'`, so injecting it anywhere shares one queue:
7684
+ *
7685
+ * ```ts
7686
+ * private readonly toasts = inject(SdsToastService);
7687
+ * this.toasts.success('Enregistré.');
7688
+ * ```
7689
+ *
7690
+ * Mount the host once (e.g. in the shell): `<sds-toast-host />`.
7691
+ */
7692
+ class SdsToastService {
7693
+ seq = 0;
7694
+ toasts = signal([], ...(ngDevMode ? [{ debugName: "toasts" }] : []));
7695
+ /** How long a toast stays, in ms, by kind. Errors linger; success/info are brief. */
7696
+ static TTL = {
7697
+ success: 3500,
7698
+ info: 3500,
7699
+ error: 6000,
7700
+ };
7701
+ success(text) {
7702
+ this.push('success', text);
7703
+ }
7704
+ error(text) {
7705
+ this.push('error', text);
7706
+ }
7707
+ info(text) {
7708
+ this.push('info', text);
7709
+ }
7710
+ dismiss(id) {
7711
+ this.toasts.update((list) => list.filter((t) => t.id !== id));
7712
+ }
7713
+ push(kind, text) {
7714
+ const id = ++this.seq;
7715
+ this.toasts.update((list) => [...list, { id, kind, text }]);
7716
+ setTimeout(() => this.dismiss(id), SdsToastService.TTL[kind]);
7717
+ }
7718
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdsToastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
7719
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdsToastService, providedIn: 'root' });
7720
+ }
7721
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdsToastService, decorators: [{
7722
+ type: Injectable,
7723
+ args: [{ providedIn: 'root' }]
7724
+ }] });
7725
+
7726
+ /**
7727
+ * Renders the {@link SdsToastService} queue, fixed bottom-centre. Mount it once, in the app shell:
7728
+ * `<sds-toast-host />`. Application code pushes toasts through the injected service.
7729
+ *
7730
+ * Accessibility: the two live regions are ALWAYS in the DOM (even when empty), because a live region must
7731
+ * pre-exist for its later content changes to be announced. Errors go to an assertive `role="alert"` region
7732
+ * so a failure interrupts; success/info go to a polite region so they queue.
7733
+ */
7734
+ class SdsToastHost {
7735
+ toasts = inject(SdsToastService);
7736
+ /**
7737
+ * Accessible name for each toast's close button. French default so existing consumers are unchanged; the
7738
+ * button is icon-only, so an app serving more than one language MUST translate it.
7739
+ */
7740
+ closeLabel = input('Fermer', ...(ngDevMode ? [{ debugName: "closeLabel" }] : []));
7741
+ errors = computed(() => this.toasts.toasts().filter((t) => t.kind === 'error'), ...(ngDevMode ? [{ debugName: "errors" }] : []));
7742
+ notices = computed(() => this.toasts.toasts().filter((t) => t.kind !== 'error'), ...(ngDevMode ? [{ debugName: "notices" }] : []));
7743
+ icon(kind) {
7744
+ return kind === 'success' ? 'check-circle' : kind === 'error' ? 'alert-circle' : 'info';
7745
+ }
7746
+ tone(kind) {
7747
+ return kind === 'success' ? 'text-success' : kind === 'error' ? 'text-danger' : 'text-accent-blue';
7748
+ }
7749
+ border(kind) {
7750
+ const accent = kind === 'success' ? 'border-l-success' : kind === 'error' ? 'border-l-danger' : 'border-l-accent-blue';
7751
+ return `border-l-4 ${accent} border-y-border border-r-border`;
7752
+ }
7753
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdsToastHost, deps: [], target: i0.ɵɵFactoryTarget.Component });
7754
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: SdsToastHost, isStandalone: true, selector: "sds-toast-host", inputs: { closeLabel: { classPropertyName: "closeLabel", publicName: "closeLabel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
7755
+ <div class="pointer-events-none fixed inset-x-0 bottom-6 z-[100] flex flex-col items-center gap-2 px-4">
7756
+ <div role="alert" aria-live="assertive" class="flex w-full flex-col items-center gap-2">
7757
+ @for (t of errors(); track t.id) {
7758
+ <ng-container [ngTemplateOutlet]="toast" [ngTemplateOutletContext]="{ t }" />
7759
+ }
7760
+ </div>
7761
+ <div aria-live="polite" class="flex w-full flex-col items-center gap-2">
7762
+ @for (t of notices(); track t.id) {
7763
+ <ng-container [ngTemplateOutlet]="toast" [ngTemplateOutletContext]="{ t }" />
7764
+ }
7765
+ </div>
7766
+ </div>
7767
+
7768
+ <ng-template #toast let-t="t">
7769
+ <div
7770
+ class="pointer-events-auto flex max-w-md items-start gap-2.5 rounded-card border bg-surface px-4 py-3 text-sm shadow-lg"
7771
+ [class]="border(t.kind)"
7772
+ >
7773
+ <sds-icon [name]="icon(t.kind)" [size]="18" class="mt-0.5 shrink-0" [class]="tone(t.kind)" />
7774
+ <span class="text-ink">{{ t.text }}</span>
7775
+ <button
7776
+ type="button"
7777
+ (click)="toasts.dismiss(t.id)"
7778
+ [attr.aria-label]="closeLabel()"
7779
+ class="ml-1 shrink-0 rounded p-0.5 text-ink-faint hover:bg-muted hover:text-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500"
7780
+ >
7781
+ <sds-icon name="x" [size]="15" />
7782
+ </button>
7783
+ </div>
7784
+ </ng-template>
7785
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SdsIcon, selector: "sds-icon", inputs: ["name", "size", "strokeWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7786
+ }
7787
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdsToastHost, decorators: [{
7788
+ type: Component,
7789
+ args: [{
7790
+ selector: 'sds-toast-host',
7791
+ changeDetection: ChangeDetectionStrategy.OnPush,
7792
+ imports: [NgTemplateOutlet, SdsIcon],
7793
+ template: `
7794
+ <div class="pointer-events-none fixed inset-x-0 bottom-6 z-[100] flex flex-col items-center gap-2 px-4">
7795
+ <div role="alert" aria-live="assertive" class="flex w-full flex-col items-center gap-2">
7796
+ @for (t of errors(); track t.id) {
7797
+ <ng-container [ngTemplateOutlet]="toast" [ngTemplateOutletContext]="{ t }" />
7798
+ }
7799
+ </div>
7800
+ <div aria-live="polite" class="flex w-full flex-col items-center gap-2">
7801
+ @for (t of notices(); track t.id) {
7802
+ <ng-container [ngTemplateOutlet]="toast" [ngTemplateOutletContext]="{ t }" />
7803
+ }
7804
+ </div>
7805
+ </div>
7806
+
7807
+ <ng-template #toast let-t="t">
7808
+ <div
7809
+ class="pointer-events-auto flex max-w-md items-start gap-2.5 rounded-card border bg-surface px-4 py-3 text-sm shadow-lg"
7810
+ [class]="border(t.kind)"
7811
+ >
7812
+ <sds-icon [name]="icon(t.kind)" [size]="18" class="mt-0.5 shrink-0" [class]="tone(t.kind)" />
7813
+ <span class="text-ink">{{ t.text }}</span>
7814
+ <button
7815
+ type="button"
7816
+ (click)="toasts.dismiss(t.id)"
7817
+ [attr.aria-label]="closeLabel()"
7818
+ class="ml-1 shrink-0 rounded p-0.5 text-ink-faint hover:bg-muted hover:text-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500"
7819
+ >
7820
+ <sds-icon name="x" [size]="15" />
7821
+ </button>
7822
+ </div>
7823
+ </ng-template>
7824
+ `,
7825
+ }]
7826
+ }], propDecorators: { closeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeLabel", required: false }] }] } });
7827
+
7401
7828
  /**
7402
7829
  * Shared collapse state for the sidebar and its nav items.
7403
7830
  *
@@ -7505,7 +7932,7 @@ class SdsTopbar {
7505
7932
  @if (appearance() === 'brand') {
7506
7933
  <span class="pointer-events-none absolute inset-0 overflow-hidden" aria-hidden="true">
7507
7934
  <svg
7508
- class="pointer-events-none absolute inset-y-0 right-0 h-full w-2/3 min-w-[420px]"
7935
+ class="pointer-events-none absolute inset-y-0 right-0 h-full w-2/3 min-w-105"
7509
7936
  viewBox="0 0 600 64"
7510
7937
  preserveAspectRatio="none"
7511
7938
  fill="none"
@@ -7604,7 +8031,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
7604
8031
  @if (appearance() === 'brand') {
7605
8032
  <span class="pointer-events-none absolute inset-0 overflow-hidden" aria-hidden="true">
7606
8033
  <svg
7607
- class="pointer-events-none absolute inset-y-0 right-0 h-full w-2/3 min-w-[420px]"
8034
+ class="pointer-events-none absolute inset-y-0 right-0 h-full w-2/3 min-w-105"
7608
8035
  viewBox="0 0 600 64"
7609
8036
  preserveAspectRatio="none"
7610
8037
  fill="none"
@@ -8213,5 +8640,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
8213
8640
  * Generated bundle index. Do not edit.
8214
8641
  */
8215
8642
 
8216
- export { SDS_ICONS, SDS_PHONE_COUNTRIES, SdsAccordion, SdsAccordionContent, SdsAccordionHeader, SdsAccordionPanel, SdsAccordionStore, SdsAvatar, SdsBadge, SdsButton, SdsCalendar, SdsCard, SdsCheckbox, SdsDatePicker, SdsIcon, SdsInput, SdsMultiSelect, SdsNavGroup, SdsNavItem, SdsOtpInput, SdsPaginator, SdsPhoneInput, SdsSelect, SdsShell, SdsSidebar, SdsTab, SdsTabList, SdsTabPanel, SdsTabPanels, SdsTable, SdsTableCell, SdsTableRowExpansion, SdsTabs, SdsTabsStore, SdsTextarea, SdsToggleSwitch, SdsTopbar, SidebarStore, addDays, addMonths, addMonthsKeepDay, formatDdMmYyyy, formatHhMm, isOutOfRange, isSameDay, isoDay, pad2, sdsFormatNational, sdsMatchDialCode, sdsNormalizeSignificant, startOfDay, startOfMonth };
8643
+ export { SDS_ICONS, SDS_PHONE_COUNTRIES, SdsAccordion, SdsAccordionContent, SdsAccordionHeader, SdsAccordionPanel, SdsAccordionStore, SdsAvatar, SdsBadge, SdsButton, SdsCalendar, SdsCard, SdsCheckbox, SdsDatePicker, SdsIcon, SdsInput, SdsLocalizedInput, SdsMultiSelect, SdsNavGroup, SdsNavItem, SdsOtpInput, SdsPaginator, SdsPhoneInput, SdsSelect, SdsShell, SdsSidebar, SdsTab, SdsTabList, SdsTabPanel, SdsTabPanels, SdsTable, SdsTableCell, SdsTableRowExpansion, SdsTabs, SdsTabsStore, SdsTextarea, SdsToastHost, SdsToastService, SdsToggleSwitch, SdsTopbar, SidebarStore, addDays, addMonths, addMonthsKeepDay, formatDdMmYyyy, formatHhMm, isOutOfRange, isSameDay, isoDay, pad2, sdsFormatNational, sdsMatchDialCode, sdsNormalizeSignificant, startOfDay, startOfMonth };
8217
8644
  //# sourceMappingURL=besaitech-ng-design-system.mjs.map