@besaitech/ng-design-system 0.0.33 → 0.0.35
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,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, input, computed, ChangeDetectionStrategy, Component, booleanAttribute, isDevMode, effect, output, signal, forwardRef,
|
|
2
|
+
import { inject, input, computed, ChangeDetectionStrategy, Component, booleanAttribute, isDevMode, effect, output, signal, forwardRef, numberAttribute, viewChildren, afterRenderEffect, viewChild, ElementRef, model, Injector, afterNextRender, Injectable, TemplateRef, Directive, contentChildren, contentChild } from '@angular/core';
|
|
3
3
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
4
4
|
import * as i1 from '@angular/forms';
|
|
5
5
|
import { NG_VALUE_ACCESSOR, NG_VALIDATORS, FormsModule } from '@angular/forms';
|
|
@@ -27,6 +27,7 @@ const SDS_ICONS = {
|
|
|
27
27
|
'user-round': '<circle cx="12" cy="8" r="5"/><path d="M20 21a8 8 0 0 0-16 0"/>',
|
|
28
28
|
home: '<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/>',
|
|
29
29
|
'user-plus': '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" x2="19" y1="8" y2="14"/><line x1="22" x2="16" y1="11" y2="11"/>',
|
|
30
|
+
'user-check': '<path d="m16 11 2 2 4-4"/><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/>',
|
|
30
31
|
hand: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-hand-icon lucide-hand"><path d="M18 11V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2"/><path d="M14 10V4a2 2 0 0 0-2-2a2 2 0 0 0-2 2v2"/><path d="M10 10.5V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2v8"/><path d="M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15"/></svg>',
|
|
31
32
|
users: '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',
|
|
32
33
|
// Couriers. The back-office and the courier-facing screens both name a rider, and every Belvigo
|
|
@@ -152,7 +153,7 @@ const VARIANTS$2 = {
|
|
|
152
153
|
ghost: 'bg-transparent text-ink-soft hover:bg-black/5 active:bg-black/10',
|
|
153
154
|
danger: 'bg-danger text-white shadow-sm hover:brightness-95 active:brightness-90',
|
|
154
155
|
};
|
|
155
|
-
const SIZES$
|
|
156
|
+
const SIZES$a = {
|
|
156
157
|
sm: 'h-8 px-3 text-sm',
|
|
157
158
|
md: 'h-10 px-4 text-sm',
|
|
158
159
|
lg: 'h-12 px-5 text-base',
|
|
@@ -212,7 +213,7 @@ class SdsButton {
|
|
|
212
213
|
BASE,
|
|
213
214
|
this.shape() === 'pill' ? 'rounded-full' : 'rounded-control',
|
|
214
215
|
VARIANTS$2[this.variant()],
|
|
215
|
-
SIZES$
|
|
216
|
+
SIZES$a[size],
|
|
216
217
|
this.iconOnly() ? ICON_ONLY[size] : '',
|
|
217
218
|
this.block() ? 'w-full' : '',
|
|
218
219
|
]
|
|
@@ -264,8 +265,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
264
265
|
`, 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"] }]
|
|
265
266
|
}], 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 }] }] } });
|
|
266
267
|
|
|
267
|
-
let nextId$
|
|
268
|
-
const SIZES$
|
|
268
|
+
let nextId$b = 0;
|
|
269
|
+
const SIZES$9 = {
|
|
269
270
|
sm: 'h-9 text-sm',
|
|
270
271
|
md: 'h-10 text-sm',
|
|
271
272
|
lg: 'h-12 text-base',
|
|
@@ -277,7 +278,7 @@ const SIZES$8 = {
|
|
|
277
278
|
* sidebar search field).
|
|
278
279
|
*/
|
|
279
280
|
class SdsInput {
|
|
280
|
-
inputId = `sds-input-${nextId$
|
|
281
|
+
inputId = `sds-input-${nextId$b++}`;
|
|
281
282
|
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
282
283
|
/** Accessible name used when no visible [label] is provided. */
|
|
283
284
|
ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
@@ -354,7 +355,7 @@ class SdsInput {
|
|
|
354
355
|
return `${left} ${right}`;
|
|
355
356
|
}, ...(ngDevMode ? [{ debugName: "fieldPadding" }] : []));
|
|
356
357
|
wrapperClasses = computed(() => {
|
|
357
|
-
const parts = [SIZES$
|
|
358
|
+
const parts = [SIZES$9[this.size()], this.pill() ? 'rounded-full' : 'rounded-control'];
|
|
358
359
|
if (this.isDisabled())
|
|
359
360
|
parts.push('opacity-60 cursor-not-allowed');
|
|
360
361
|
if (this.filled()) {
|
|
@@ -598,6 +599,323 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
598
599
|
`, 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"] }]
|
|
599
600
|
}], 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"] }] } });
|
|
600
601
|
|
|
602
|
+
let nextId$a = 0;
|
|
603
|
+
const SIZES$8 = {
|
|
604
|
+
md: 'h-12 w-11 text-lg',
|
|
605
|
+
lg: 'h-14 w-12 text-xl',
|
|
606
|
+
};
|
|
607
|
+
/**
|
|
608
|
+
* A segmented one-time-code field: one box per character, for the short numeric codes emailed or
|
|
609
|
+
* texted for sign-in and verification. Implements ControlValueAccessor — bind
|
|
610
|
+
* `formControlName`/`[(ngModel)]`; the value is the concatenated string (e.g. `"483920"`), and
|
|
611
|
+
* {@link completed} fires the moment every box is filled.
|
|
612
|
+
*
|
|
613
|
+
* <p>Only digits are accepted (`inputMode` is `numeric` by default). Typing auto-advances,
|
|
614
|
+
* Backspace steps back and clears, the arrow keys move between boxes, and pasting a whole code
|
|
615
|
+
* distributes it across the boxes from the focused one — so a user can paste `483920` into the
|
|
616
|
+
* first box and have it land correctly.
|
|
617
|
+
*/
|
|
618
|
+
class SdsOtpInput {
|
|
619
|
+
groupId = `sds-otp-${nextId$a++}`;
|
|
620
|
+
/** How many boxes / characters the code has. */
|
|
621
|
+
length = input(6, ...(ngDevMode ? [{ debugName: "length", transform: numberAttribute }] : [{ transform: numberAttribute }]));
|
|
622
|
+
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
623
|
+
/** Accessible name for the whole group when no visible [label] is provided. */
|
|
624
|
+
ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
625
|
+
hint = input('', ...(ngDevMode ? [{ debugName: "hint" }] : []));
|
|
626
|
+
error = input('', ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
627
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
628
|
+
/** `numeric` for digit codes (the default); `text` for alphanumeric codes. */
|
|
629
|
+
inputMode = input('numeric', ...(ngDevMode ? [{ debugName: "inputMode" }] : []));
|
|
630
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
|
|
631
|
+
/** Focus the first box on first render. */
|
|
632
|
+
autoFocus = input(false, ...(ngDevMode ? [{ debugName: "autoFocus", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
|
|
633
|
+
/**
|
|
634
|
+
* Accessible name for an individual box, suffixed with its 1-based position ("Digit 1", "Digit
|
|
635
|
+
* 2", …). French default so existing consumers are unchanged; translate it in an app serving more
|
|
636
|
+
* than one language, since each box is an icon-less control whose only name this is.
|
|
637
|
+
*/
|
|
638
|
+
cellLabel = input('Chiffre', ...(ngDevMode ? [{ debugName: "cellLabel" }] : []));
|
|
639
|
+
/** Emitted with the full value the moment the last box is filled. */
|
|
640
|
+
completed = output();
|
|
641
|
+
cells = viewChildren('cell', ...(ngDevMode ? [{ debugName: "cells" }] : []));
|
|
642
|
+
/** One entry per box; the source of truth, kept exactly {@link length} long. */
|
|
643
|
+
chars = signal([], ...(ngDevMode ? [{ debugName: "chars" }] : []));
|
|
644
|
+
cvaDisabled = signal(false, ...(ngDevMode ? [{ debugName: "cvaDisabled" }] : []));
|
|
645
|
+
indexes = computed(() => Array.from({ length: this.length() }, (_, i) => i), ...(ngDevMode ? [{ debugName: "indexes" }] : []));
|
|
646
|
+
isDisabled = computed(() => this.disabled() || this.cvaDisabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
|
|
647
|
+
describedBy = computed(() => {
|
|
648
|
+
if (this.error())
|
|
649
|
+
return `${this.groupId}-err`;
|
|
650
|
+
if (this.hint())
|
|
651
|
+
return `${this.groupId}-hint`;
|
|
652
|
+
return null;
|
|
653
|
+
}, ...(ngDevMode ? [{ debugName: "describedBy" }] : []));
|
|
654
|
+
cellClasses = computed(() => {
|
|
655
|
+
const parts = ['rounded-control border', SIZES$8[this.size()]];
|
|
656
|
+
parts.push(this.error()
|
|
657
|
+
? 'border-danger focus:border-danger focus:ring-2 focus:ring-danger/25'
|
|
658
|
+
: 'border-border text-ink focus:border-brand-500 focus:ring-2 focus:ring-brand-500/25');
|
|
659
|
+
if (this.isDisabled())
|
|
660
|
+
parts.push('opacity-60');
|
|
661
|
+
return parts.join(' ');
|
|
662
|
+
}, ...(ngDevMode ? [{ debugName: "cellClasses" }] : []));
|
|
663
|
+
constructor() {
|
|
664
|
+
// Autofocus once the boxes are in the DOM. afterRenderEffect re-runs on signal reads, but the
|
|
665
|
+
// guard keeps it to the first paint — refocusing on every value change would fight the user.
|
|
666
|
+
let focused = false;
|
|
667
|
+
afterRenderEffect(() => {
|
|
668
|
+
if (this.autoFocus() && !focused && !this.isDisabled()) {
|
|
669
|
+
this.cells()[0]?.nativeElement.focus();
|
|
670
|
+
focused = true;
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
// --- ControlValueAccessor -------------------------------------------------
|
|
675
|
+
onChange = () => { };
|
|
676
|
+
onTouched = () => { };
|
|
677
|
+
writeValue(value) {
|
|
678
|
+
// Programmatic set never emits — CVA writeValue must not call onChange.
|
|
679
|
+
this.chars.set(this.spread(value ?? ''));
|
|
680
|
+
}
|
|
681
|
+
registerOnChange(fn) {
|
|
682
|
+
this.onChange = fn;
|
|
683
|
+
}
|
|
684
|
+
registerOnTouched(fn) {
|
|
685
|
+
this.onTouched = fn;
|
|
686
|
+
}
|
|
687
|
+
setDisabledState(isDisabled) {
|
|
688
|
+
this.cvaDisabled.set(isDisabled);
|
|
689
|
+
}
|
|
690
|
+
// --- events ---------------------------------------------------------------
|
|
691
|
+
charAt(index) {
|
|
692
|
+
return this.chars()[index] ?? '';
|
|
693
|
+
}
|
|
694
|
+
onInput(event, index) {
|
|
695
|
+
const el = event.target;
|
|
696
|
+
const raw = el.value;
|
|
697
|
+
const digits = this.sanitize(raw);
|
|
698
|
+
if (digits.length === 0) {
|
|
699
|
+
if (raw.length === 0) {
|
|
700
|
+
// Genuinely emptied (cut, or a deletion the keydown handler did not catch) — clear the box.
|
|
701
|
+
this.setChar(index, '');
|
|
702
|
+
}
|
|
703
|
+
else {
|
|
704
|
+
// A rejected character (letter, symbol) — reassert the box's real content, since the
|
|
705
|
+
// [value] binding will not repaint an unchanged signal.
|
|
706
|
+
el.value = this.charAt(index);
|
|
707
|
+
}
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
if (digits.length > 1) {
|
|
711
|
+
// Fast typing or an autofill dropped several characters into one box — spread them.
|
|
712
|
+
this.fill(digits, index);
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
this.setChar(index, digits);
|
|
716
|
+
this.focusIndex(index + 1);
|
|
717
|
+
}
|
|
718
|
+
onKeydown(event, index) {
|
|
719
|
+
switch (event.key) {
|
|
720
|
+
case 'Backspace':
|
|
721
|
+
event.preventDefault();
|
|
722
|
+
if (this.charAt(index)) {
|
|
723
|
+
this.setChar(index, '');
|
|
724
|
+
}
|
|
725
|
+
else if (index > 0) {
|
|
726
|
+
this.setChar(index - 1, '');
|
|
727
|
+
this.focusIndex(index - 1);
|
|
728
|
+
}
|
|
729
|
+
break;
|
|
730
|
+
case 'ArrowLeft':
|
|
731
|
+
event.preventDefault();
|
|
732
|
+
this.focusIndex(index - 1);
|
|
733
|
+
break;
|
|
734
|
+
case 'ArrowRight':
|
|
735
|
+
event.preventDefault();
|
|
736
|
+
this.focusIndex(index + 1);
|
|
737
|
+
break;
|
|
738
|
+
case 'Delete':
|
|
739
|
+
event.preventDefault();
|
|
740
|
+
this.setChar(index, '');
|
|
741
|
+
break;
|
|
742
|
+
default:
|
|
743
|
+
break;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
onPaste(event, index) {
|
|
747
|
+
const digits = this.sanitize(event.clipboardData?.getData('text') ?? '');
|
|
748
|
+
if (!digits)
|
|
749
|
+
return;
|
|
750
|
+
event.preventDefault();
|
|
751
|
+
this.fill(digits, index);
|
|
752
|
+
}
|
|
753
|
+
onFocus(event) {
|
|
754
|
+
// Select the box's content so a keystroke overwrites rather than being rejected by maxlength.
|
|
755
|
+
event.target.select();
|
|
756
|
+
}
|
|
757
|
+
// --- internals ------------------------------------------------------------
|
|
758
|
+
sanitize(raw) {
|
|
759
|
+
return this.inputMode() === 'numeric'
|
|
760
|
+
? raw.replace(/\D/g, '')
|
|
761
|
+
: raw.replace(/[^A-Za-z0-9]/g, '');
|
|
762
|
+
}
|
|
763
|
+
/** Normalize any input string into an array exactly {@link length} long. */
|
|
764
|
+
spread(raw) {
|
|
765
|
+
const cleaned = this.sanitize(raw).slice(0, this.length());
|
|
766
|
+
return Array.from({ length: this.length() }, (_, i) => cleaned[i] ?? '');
|
|
767
|
+
}
|
|
768
|
+
setChar(index, value) {
|
|
769
|
+
const next = this.normalized();
|
|
770
|
+
next[index] = value;
|
|
771
|
+
this.commit(next);
|
|
772
|
+
}
|
|
773
|
+
/** Write `digits` across the boxes starting at `start`, then focus the next empty box. */
|
|
774
|
+
fill(digits, start) {
|
|
775
|
+
const next = this.normalized();
|
|
776
|
+
let cursor = start;
|
|
777
|
+
for (const ch of digits) {
|
|
778
|
+
if (cursor >= this.length())
|
|
779
|
+
break;
|
|
780
|
+
next[cursor] = ch;
|
|
781
|
+
cursor += 1;
|
|
782
|
+
}
|
|
783
|
+
this.commit(next);
|
|
784
|
+
this.focusIndex(Math.min(cursor, this.length() - 1));
|
|
785
|
+
}
|
|
786
|
+
commit(next) {
|
|
787
|
+
this.chars.set(next);
|
|
788
|
+
const value = next.join('');
|
|
789
|
+
this.onChange(value);
|
|
790
|
+
if (next.every((c) => c !== '')) {
|
|
791
|
+
this.completed.emit(value);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
/** The current boxes as a fresh, correctly-sized array to mutate. */
|
|
795
|
+
normalized() {
|
|
796
|
+
const current = this.chars();
|
|
797
|
+
return Array.from({ length: this.length() }, (_, i) => current[i] ?? '');
|
|
798
|
+
}
|
|
799
|
+
focusIndex(index) {
|
|
800
|
+
const clamped = Math.max(0, Math.min(index, this.length() - 1));
|
|
801
|
+
const cell = this.cells()[clamped]?.nativeElement;
|
|
802
|
+
if (cell) {
|
|
803
|
+
cell.focus();
|
|
804
|
+
cell.select();
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdsOtpInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
808
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: SdsOtpInput, isStandalone: true, selector: "sds-otp-input", inputs: { length: { classPropertyName: "length", publicName: "length", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, inputMode: { classPropertyName: "inputMode", publicName: "inputMode", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null }, cellLabel: { classPropertyName: "cellLabel", publicName: "cellLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { completed: "completed" }, host: { classAttribute: "block" }, providers: [
|
|
809
|
+
{
|
|
810
|
+
provide: NG_VALUE_ACCESSOR,
|
|
811
|
+
useExisting: forwardRef(() => SdsOtpInput),
|
|
812
|
+
multi: true,
|
|
813
|
+
},
|
|
814
|
+
], viewQueries: [{ propertyName: "cells", predicate: ["cell"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
815
|
+
@if (label()) {
|
|
816
|
+
<label [id]="groupId + '-label'" class="mb-1.5 block text-sm font-medium text-ink">
|
|
817
|
+
{{ label() }}
|
|
818
|
+
</label>
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
<div
|
|
822
|
+
class="flex items-center gap-2"
|
|
823
|
+
role="group"
|
|
824
|
+
[attr.aria-labelledby]="label() ? groupId + '-label' : null"
|
|
825
|
+
[attr.aria-label]="!label() && ariaLabel() ? ariaLabel() : null"
|
|
826
|
+
[attr.aria-describedby]="describedBy()"
|
|
827
|
+
>
|
|
828
|
+
@for (i of indexes(); track i) {
|
|
829
|
+
<input
|
|
830
|
+
#cell
|
|
831
|
+
type="text"
|
|
832
|
+
[attr.data-index]="i"
|
|
833
|
+
[inputMode]="inputMode()"
|
|
834
|
+
autocomplete="one-time-code"
|
|
835
|
+
maxlength="1"
|
|
836
|
+
[value]="charAt(i)"
|
|
837
|
+
[disabled]="isDisabled()"
|
|
838
|
+
[attr.aria-label]="cellLabel() + ' ' + (i + 1)"
|
|
839
|
+
[attr.aria-invalid]="error() ? 'true' : null"
|
|
840
|
+
class="bg-white text-center font-semibold tabular-nums outline-none transition-colors
|
|
841
|
+
disabled:cursor-not-allowed"
|
|
842
|
+
[class]="cellClasses()"
|
|
843
|
+
(input)="onInput($event, i)"
|
|
844
|
+
(keydown)="onKeydown($event, i)"
|
|
845
|
+
(paste)="onPaste($event, i)"
|
|
846
|
+
(focus)="onFocus($event)"
|
|
847
|
+
(blur)="onTouched()"
|
|
848
|
+
/>
|
|
849
|
+
}
|
|
850
|
+
</div>
|
|
851
|
+
|
|
852
|
+
@if (error()) {
|
|
853
|
+
<p [id]="groupId + '-err'" class="mt-1.5 text-xs font-medium text-danger">{{ error() }}</p>
|
|
854
|
+
} @else if (hint()) {
|
|
855
|
+
<p [id]="groupId + '-hint'" class="mt-1.5 text-xs text-ink-faint">{{ hint() }}</p>
|
|
856
|
+
}
|
|
857
|
+
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
858
|
+
}
|
|
859
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdsOtpInput, decorators: [{
|
|
860
|
+
type: Component,
|
|
861
|
+
args: [{
|
|
862
|
+
selector: 'sds-otp-input',
|
|
863
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
864
|
+
providers: [
|
|
865
|
+
{
|
|
866
|
+
provide: NG_VALUE_ACCESSOR,
|
|
867
|
+
useExisting: forwardRef(() => SdsOtpInput),
|
|
868
|
+
multi: true,
|
|
869
|
+
},
|
|
870
|
+
],
|
|
871
|
+
host: { class: 'block' },
|
|
872
|
+
template: `
|
|
873
|
+
@if (label()) {
|
|
874
|
+
<label [id]="groupId + '-label'" class="mb-1.5 block text-sm font-medium text-ink">
|
|
875
|
+
{{ label() }}
|
|
876
|
+
</label>
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
<div
|
|
880
|
+
class="flex items-center gap-2"
|
|
881
|
+
role="group"
|
|
882
|
+
[attr.aria-labelledby]="label() ? groupId + '-label' : null"
|
|
883
|
+
[attr.aria-label]="!label() && ariaLabel() ? ariaLabel() : null"
|
|
884
|
+
[attr.aria-describedby]="describedBy()"
|
|
885
|
+
>
|
|
886
|
+
@for (i of indexes(); track i) {
|
|
887
|
+
<input
|
|
888
|
+
#cell
|
|
889
|
+
type="text"
|
|
890
|
+
[attr.data-index]="i"
|
|
891
|
+
[inputMode]="inputMode()"
|
|
892
|
+
autocomplete="one-time-code"
|
|
893
|
+
maxlength="1"
|
|
894
|
+
[value]="charAt(i)"
|
|
895
|
+
[disabled]="isDisabled()"
|
|
896
|
+
[attr.aria-label]="cellLabel() + ' ' + (i + 1)"
|
|
897
|
+
[attr.aria-invalid]="error() ? 'true' : null"
|
|
898
|
+
class="bg-white text-center font-semibold tabular-nums outline-none transition-colors
|
|
899
|
+
disabled:cursor-not-allowed"
|
|
900
|
+
[class]="cellClasses()"
|
|
901
|
+
(input)="onInput($event, i)"
|
|
902
|
+
(keydown)="onKeydown($event, i)"
|
|
903
|
+
(paste)="onPaste($event, i)"
|
|
904
|
+
(focus)="onFocus($event)"
|
|
905
|
+
(blur)="onTouched()"
|
|
906
|
+
/>
|
|
907
|
+
}
|
|
908
|
+
</div>
|
|
909
|
+
|
|
910
|
+
@if (error()) {
|
|
911
|
+
<p [id]="groupId + '-err'" class="mt-1.5 text-xs font-medium text-danger">{{ error() }}</p>
|
|
912
|
+
} @else if (hint()) {
|
|
913
|
+
<p [id]="groupId + '-hint'" class="mt-1.5 text-xs text-ink-faint">{{ hint() }}</p>
|
|
914
|
+
}
|
|
915
|
+
`,
|
|
916
|
+
}]
|
|
917
|
+
}], ctorParameters: () => [], propDecorators: { length: [{ type: i0.Input, args: [{ isSignal: true, alias: "length", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], inputMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputMode", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], cellLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellLabel", required: false }] }], completed: [{ type: i0.Output, args: ["completed"] }], cells: [{ type: i0.ViewChildren, args: ['cell', { isSignal: true }] }] } });
|
|
918
|
+
|
|
601
919
|
let nextId$9 = 0;
|
|
602
920
|
const SIZES$7 = {
|
|
603
921
|
sm: 'text-sm px-3 py-2',
|
|
@@ -7467,5 +7785,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
7467
7785
|
* Generated bundle index. Do not edit.
|
|
7468
7786
|
*/
|
|
7469
7787
|
|
|
7470
|
-
export { SDS_ICONS, SDS_PHONE_COUNTRIES, SdsAccordion, SdsAccordionContent, SdsAccordionHeader, SdsAccordionPanel, SdsAccordionStore, SdsAvatar, SdsBadge, SdsButton, SdsCalendar, SdsCard, SdsCheckbox, SdsDatePicker, SdsIcon, SdsInput, SdsMultiSelect, SdsNavGroup, SdsNavItem, SdsPaginator, SdsPhoneInput, SdsSelect, SdsShell, SdsSidebar, SdsTab, SdsTabList, SdsTabPanel, SdsTabPanels, SdsTable, SdsTableCell, SdsTableRowExpansion, SdsTabs, SdsTabsStore, SdsTextarea, SdsToggleSwitch, SdsTopbar, SidebarStore, addDays, addMonths, addMonthsKeepDay, formatDdMmYyyy, isOutOfRange, isSameDay, isoDay, sdsFormatNational, sdsMatchDialCode, sdsNormalizeSignificant, startOfDay, startOfMonth };
|
|
7788
|
+
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, isOutOfRange, isSameDay, isoDay, sdsFormatNational, sdsMatchDialCode, sdsNormalizeSignificant, startOfDay, startOfMonth };
|
|
7471
7789
|
//# sourceMappingURL=besaitech-ng-design-system.mjs.map
|