@besaitech/ng-design-system 0.0.40 → 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$
|
|
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$
|
|
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$
|
|
271
|
-
const SIZES$
|
|
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$
|
|
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$
|
|
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
|
*
|
|
@@ -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
|