@basis-ng/primitives 0.0.1-alpha.83 → 0.0.1-alpha.84

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.
@@ -1537,6 +1537,263 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.3", ngImpor
1537
1537
  }]
1538
1538
  }], ctorParameters: () => [] });
1539
1539
 
1540
+ /**
1541
+ * Component representing a One-Time Password (OTP) input group.
1542
+ *
1543
+ * This component manages a set of digit inputs for entering OTP codes, handling keyboard navigation,
1544
+ * paste events, and integration with Angular Forms via ControlValueAccessor.
1545
+ *
1546
+ * @example
1547
+ * <b-otp>
1548
+ * <input otp-digit />
1549
+ * <input otp-digit />
1550
+ * <input otp-digit />
1551
+ * <input otp-digit />
1552
+ * </b-otp>
1553
+ */
1554
+ /**
1555
+ * OtpComponent manages a group of digit inputs for OTP entry.
1556
+ * Implements keyboard navigation, paste handling, and ControlValueAccessor for Angular Forms.
1557
+ */
1558
+ class OtpComponent {
1559
+ /**
1560
+ * The visual size of the OTP inputs. Accepts '1', '2', or '3'. Default is '2'.
1561
+ */
1562
+ size = model('2', ...(ngDevMode ? [{ debugName: "size" }] : []));
1563
+ /**
1564
+ * Computed signal for the number of digit inputs.
1565
+ */
1566
+ length = computed(() => this.digitInputs().length, ...(ngDevMode ? [{ debugName: "length" }] : []));
1567
+ /**
1568
+ * Emits the full OTP value when changed.
1569
+ */
1570
+ otpChange = output();
1571
+ /**
1572
+ * Query for all child digit inputs (OtpDigitDirective).
1573
+ */
1574
+ digitInputs = contentChildren(OtpDigitDirective, ...(ngDevMode ? [{ debugName: "digitInputs" }] : []));
1575
+ /**
1576
+ * Internal array holding the current values of each digit input.
1577
+ */
1578
+ values = [];
1579
+ /**
1580
+ * Model indicating whether the OTP input group is disabled.
1581
+ */
1582
+ disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
1583
+ /**
1584
+ * Callback for propagating value changes to Angular Forms.
1585
+ */
1586
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
1587
+ onChange = () => { };
1588
+ /**
1589
+ * Callback for marking the component as touched in Angular Forms.
1590
+ */
1591
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
1592
+ onTouched = () => { };
1593
+ ngAfterContentInit() {
1594
+ // Inicializar listeners en los inputs hijos
1595
+ this.digitInputs().forEach((input, idx) => {
1596
+ const el = input.el.nativeElement;
1597
+ // maxLength y type se aplican por la directiva
1598
+ el.disabled = this.disabled();
1599
+ el.classList.remove('size-1', 'size-2', 'size-3');
1600
+ el.classList.add(`size-${this.size()}`);
1601
+ el.addEventListener('input', (event) => {
1602
+ this.onInput(event, idx);
1603
+ });
1604
+ el.addEventListener('keydown', (event) => {
1605
+ this.onKeyDown(event, idx);
1606
+ });
1607
+ el.addEventListener('paste', (event) => {
1608
+ this.onPaste(event);
1609
+ });
1610
+ });
1611
+ this.resetValues();
1612
+ }
1613
+ /**
1614
+ * Handles input event for each digit input.
1615
+ * Moves focus to next input if value entered.
1616
+ *
1617
+ * @param event - Input event
1618
+ *
1619
+ * @param idx - Index of the digit input
1620
+ */
1621
+ onInput(event, idx) {
1622
+ const input = event.target;
1623
+ const val = input.value;
1624
+ this.values[idx] = val;
1625
+ if (val && idx < this.length() - 1) {
1626
+ this.focusDigit(idx + 1);
1627
+ }
1628
+ this.emitValue();
1629
+ }
1630
+ /**
1631
+ * Handles keyboard navigation for digit inputs.
1632
+ * Supports Backspace, ArrowLeft, ArrowRight.
1633
+ *
1634
+ * @param event - Keyboard event
1635
+ *
1636
+ * @param idx - Index of the digit input
1637
+ */
1638
+ onKeyDown(event, idx) {
1639
+ const input = event.target;
1640
+ if (event.key === 'Backspace') {
1641
+ if (!input.value && idx > 0) {
1642
+ this.focusDigit(idx - 1);
1643
+ }
1644
+ this.values[idx] = '';
1645
+ this.emitValue();
1646
+ }
1647
+ else if (event.key === 'ArrowLeft' && idx > 0) {
1648
+ this.focusDigit(idx - 1);
1649
+ }
1650
+ else if (event.key === 'ArrowRight' && idx < this.length() - 1) {
1651
+ this.focusDigit(idx + 1);
1652
+ }
1653
+ }
1654
+ /**
1655
+ * Handles paste event for the OTP input group.
1656
+ * Distributes pasted characters across digit inputs.
1657
+ *
1658
+ * @param event - Clipboard event
1659
+ */
1660
+ onPaste(event) {
1661
+ event.preventDefault();
1662
+ const paste = event.clipboardData?.getData('text') ?? '';
1663
+ const chars = paste.slice(0, this.length()).split('');
1664
+ chars.forEach((c, i) => {
1665
+ this.values[i] = c;
1666
+ const input = this.digitInputs()[i];
1667
+ if (input) {
1668
+ input.el.nativeElement.value = c;
1669
+ }
1670
+ });
1671
+ this.emitValue();
1672
+ this.focusDigit(chars.length - 1);
1673
+ }
1674
+ /**
1675
+ * Focuses the digit input at the given index.
1676
+ *
1677
+ * @param idx - Index of the digit input to focus
1678
+ */
1679
+ focusDigit(idx) {
1680
+ const input = this.digitInputs()[idx];
1681
+ if (input) {
1682
+ input.el.nativeElement.focus();
1683
+ }
1684
+ }
1685
+ /**
1686
+ * Emits the full OTP value via output and ControlValueAccessor.
1687
+ */
1688
+ emitValue() {
1689
+ const otp = this.values.join('');
1690
+ this.otpChange.emit(otp);
1691
+ this.onChange(otp);
1692
+ this.onTouched();
1693
+ }
1694
+ /**
1695
+ * Resets all digit input values to empty.
1696
+ */
1697
+ resetValues() {
1698
+ this.values = Array(this.length()).fill('');
1699
+ this.digitInputs().forEach(input => {
1700
+ input.el.nativeElement.value = '';
1701
+ });
1702
+ }
1703
+ // ControlValueAccessor implementation
1704
+ /**
1705
+ * Writes a new value to the OTP input group.
1706
+ * Called by Angular Forms to update the value.
1707
+ *
1708
+ * @param value - New OTP value
1709
+ */
1710
+ writeValue(value) {
1711
+ this.values = Array(this.length()).fill('');
1712
+ if (value) {
1713
+ value
1714
+ .slice(0, this.length())
1715
+ .split('')
1716
+ .forEach((c, i) => {
1717
+ this.values[i] = c;
1718
+ const input = this.digitInputs()[i];
1719
+ if (input) {
1720
+ input.el.nativeElement.value = c;
1721
+ }
1722
+ });
1723
+ }
1724
+ else {
1725
+ this.resetValues();
1726
+ }
1727
+ }
1728
+ /**
1729
+ * Registers a callback to be called when the value changes.
1730
+ *
1731
+ * @param fn - Callback function
1732
+ */
1733
+ registerOnChange(fn) {
1734
+ this.onChange = fn;
1735
+ }
1736
+ /**
1737
+ * Registers a callback to be called when the component is touched.
1738
+ *
1739
+ * @param fn - Callback function
1740
+ */
1741
+ registerOnTouched(fn) {
1742
+ this.onTouched = fn;
1743
+ }
1744
+ /**
1745
+ * Sets the disabled state of the OTP input group.
1746
+ * Called by Angular Forms to enable/disable the component.
1747
+ *
1748
+ * @param isDisabled - Boolean indicating disabled state
1749
+ */
1750
+ setDisabledState(isDisabled) {
1751
+ this.disabled.set(isDisabled);
1752
+ this.digitInputs().forEach(input => {
1753
+ input.el.nativeElement.disabled = isDisabled;
1754
+ input.el.nativeElement.classList.remove('size-1', 'size-2', 'size-3');
1755
+ input.el.nativeElement.classList.add(`size-${this.size()}`);
1756
+ });
1757
+ }
1758
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: OtpComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1759
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.2.3", type: OtpComponent, isStandalone: true, selector: "b-otp", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { size: "sizeChange", otpChange: "otpChange", disabled: "disabledChange" }, providers: [
1760
+ {
1761
+ provide: NG_VALUE_ACCESSOR,
1762
+ useExisting: forwardRef(() => OtpComponent),
1763
+ multi: true,
1764
+ },
1765
+ ], queries: [{ propertyName: "digitInputs", predicate: OtpDigitDirective, isSignal: true }], ngImport: i0, template: `<ng-content />`, isInline: true });
1766
+ }
1767
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: OtpComponent, decorators: [{
1768
+ type: Component,
1769
+ args: [{
1770
+ selector: 'b-otp',
1771
+ template: `<ng-content />`,
1772
+ providers: [
1773
+ {
1774
+ provide: NG_VALUE_ACCESSOR,
1775
+ useExisting: forwardRef(() => OtpComponent),
1776
+ multi: true,
1777
+ },
1778
+ ],
1779
+ }]
1780
+ }] });
1781
+ class OtpDigitDirective {
1782
+ /** Reference to the native input element. */
1783
+ el = inject((ElementRef));
1784
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: OtpDigitDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1785
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.3", type: OtpDigitDirective, isStandalone: true, selector: "input[otp-digit]", host: { attributes: { "maxlength": "1" } }, ngImport: i0 });
1786
+ }
1787
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: OtpDigitDirective, decorators: [{
1788
+ type: Directive,
1789
+ args: [{
1790
+ selector: 'input[otp-digit]',
1791
+ host: {
1792
+ maxlength: '1',
1793
+ },
1794
+ }]
1795
+ }] });
1796
+
1540
1797
  class BadgeComponent {
1541
1798
  /** The variant of the badge. */
1542
1799
  variant = input('primary', ...(ngDevMode ? [{ debugName: "variant" }] : []));
@@ -3515,5 +3772,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.3", ngImpor
3515
3772
  * Generated bundle index. Do not edit.
3516
3773
  */
3517
3774
 
3518
- export { AlertComponent, BadgeComponent, ButtonComponent, ButtonGroupComponent, CardComponent, CardContentComponent, CardDescriptionComponent, CardFooterComponent, CardHeaderComponent, CardSubtitleComponent, CardTitleComponent, Checkbox, ColorPickerComponent, ComboboxComponent, CommandComponent, CommandOptionsComponent, DialogDirective, DialogService, DrawerComponent, IconComponent, InViewportDirective, InViewportService, InputComponent, InputGroupComponent, LazyContentDirective, MenuComponent, MenuGroupComponent, MenuItemCheckboxComponent, MenuItemComponent, MenuItemRadioComponent, MenuLabelComponent, MenuTriggerDirective, OptionComponent, OverlayDirective, OverlayTriggerDirective, RangeComponent, ResponsiveService, RowComponent, RowItemComponent, SelectComponent, SelectOptionsComponent, SheetComponent, SpinnerComponent, SwitchComponent, TabComponent, TableComponent, TabsComponent, TextareaComponent, ThemeService, TooltipDirective, TreeComponent, TreeNodeComponent };
3775
+ export { AlertComponent, BadgeComponent, ButtonComponent, ButtonGroupComponent, CardComponent, CardContentComponent, CardDescriptionComponent, CardFooterComponent, CardHeaderComponent, CardSubtitleComponent, CardTitleComponent, Checkbox, ColorPickerComponent, ComboboxComponent, CommandComponent, CommandOptionsComponent, DialogDirective, DialogService, DrawerComponent, IconComponent, InViewportDirective, InViewportService, InputComponent, InputGroupComponent, LazyContentDirective, MenuComponent, MenuGroupComponent, MenuItemCheckboxComponent, MenuItemComponent, MenuItemRadioComponent, MenuLabelComponent, MenuTriggerDirective, OptionComponent, OtpComponent, OtpDigitDirective, OverlayDirective, OverlayTriggerDirective, RangeComponent, ResponsiveService, RowComponent, RowItemComponent, SelectComponent, SelectOptionsComponent, SheetComponent, SpinnerComponent, SwitchComponent, TabComponent, TableComponent, TabsComponent, TextareaComponent, ThemeService, TooltipDirective, TreeComponent, TreeNodeComponent };
3519
3776
  //# sourceMappingURL=basis-ng-primitives.mjs.map