@bravobit/bb-foundation 0.53.0 → 0.53.2

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 +1,3 @@
1
1
  export declare function injectAcceptString(): string;
2
+ export declare function injectMaxFileSize(): number;
3
+ export declare function injectMaxTotalFileSize(): number;
@@ -35,5 +35,7 @@ export interface ElementsConfig {
35
35
  errors?: ElementsError;
36
36
  defaultDisplayUnit?: ElementsDisplayUnit;
37
37
  allowedFileTypes?: string[];
38
+ maxFileSize?: number;
39
+ maxTotalFileSize?: number;
38
40
  }
39
41
  export type ElementsDisplayUnit = 'rem' | 'px';
@@ -30,9 +30,10 @@ import * as i26 from "./date-picker/date-picker.component";
30
30
  import * as i27 from "./color-slider/color-slider.component";
31
31
  import * as i28 from "./color-picker/color-picker.component";
32
32
  import * as i29 from "./image-control/image-control.component";
33
+ import * as i30 from "./pincode-control/pincode-control.component";
33
34
  export declare class ElementsModule {
34
35
  static forRoot(config?: ElementsConfig): ModuleWithProviders<ElementsModule>;
35
36
  static ɵfac: i0.ɵɵFactoryDeclaration<ElementsModule, never>;
36
- static ɵmod: i0.ɵɵNgModuleDeclaration<ElementsModule, never, [typeof i1.BbFormError, typeof i2.BbFormSubmit, typeof i3.BbFormSubmitter, typeof i4.BbInput, typeof i5.BbImageUpload, typeof i6.BbExtraErrorControls, typeof i7.BbFileDrop, typeof i8.ColorPickerDirective, typeof i9.BbFileSize, typeof i10.BbFileImage, typeof i11.BbRelativeTime, typeof i12.BbDate, typeof i13.BbButton, typeof i13.BbAnchor, typeof i14.BbSpinner, typeof i15.BbIcon, typeof i16.BbFormControl, typeof i17.BbFormGroup, typeof i18.BbCheckbox, typeof i19.BbCheckboxGroup, typeof i20.BbRadioGroup, typeof i21.BbRadioButton, typeof i22.BbAvatar, typeof i23.BbMultiFileControl, typeof i24.BbFilePicker, typeof i25.BbImagePicker, typeof i26.BbDatePicker, typeof i27.BbColorSlider, typeof i28.BbColorPicker, typeof i29.BbImageControl], [typeof i1.BbFormError, typeof i2.BbFormSubmit, typeof i3.BbFormSubmitter, typeof i4.BbInput, typeof i5.BbImageUpload, typeof i6.BbExtraErrorControls, typeof i7.BbFileDrop, typeof i8.ColorPickerDirective, typeof i9.BbFileSize, typeof i10.BbFileImage, typeof i11.BbRelativeTime, typeof i12.BbDate, typeof i13.BbButton, typeof i13.BbAnchor, typeof i14.BbSpinner, typeof i15.BbIcon, typeof i16.BbFormControl, typeof i17.BbFormGroup, typeof i18.BbCheckbox, typeof i19.BbCheckboxGroup, typeof i20.BbRadioGroup, typeof i21.BbRadioButton, typeof i22.BbAvatar, typeof i23.BbMultiFileControl, typeof i24.BbFilePicker, typeof i25.BbImagePicker, typeof i26.BbDatePicker, typeof i27.BbColorSlider, typeof i28.BbColorPicker, typeof i29.BbImageControl]>;
37
+ static ɵmod: i0.ɵɵNgModuleDeclaration<ElementsModule, never, [typeof i1.BbFormError, typeof i2.BbFormSubmit, typeof i3.BbFormSubmitter, typeof i4.BbInput, typeof i5.BbImageUpload, typeof i6.BbExtraErrorControls, typeof i7.BbFileDrop, typeof i8.ColorPickerDirective, typeof i9.BbFileSize, typeof i10.BbFileImage, typeof i11.BbRelativeTime, typeof i12.BbDate, typeof i13.BbButton, typeof i13.BbAnchor, typeof i14.BbSpinner, typeof i15.BbIcon, typeof i16.BbFormControl, typeof i17.BbFormGroup, typeof i18.BbCheckbox, typeof i19.BbCheckboxGroup, typeof i20.BbRadioGroup, typeof i21.BbRadioButton, typeof i22.BbAvatar, typeof i23.BbMultiFileControl, typeof i24.BbFilePicker, typeof i25.BbImagePicker, typeof i26.BbDatePicker, typeof i27.BbColorSlider, typeof i28.BbColorPicker, typeof i29.BbImageControl, typeof i30.BbPincodeControl], [typeof i1.BbFormError, typeof i2.BbFormSubmit, typeof i3.BbFormSubmitter, typeof i4.BbInput, typeof i5.BbImageUpload, typeof i6.BbExtraErrorControls, typeof i7.BbFileDrop, typeof i8.ColorPickerDirective, typeof i9.BbFileSize, typeof i10.BbFileImage, typeof i11.BbRelativeTime, typeof i12.BbDate, typeof i13.BbButton, typeof i13.BbAnchor, typeof i14.BbSpinner, typeof i15.BbIcon, typeof i16.BbFormControl, typeof i17.BbFormGroup, typeof i18.BbCheckbox, typeof i19.BbCheckboxGroup, typeof i20.BbRadioGroup, typeof i21.BbRadioButton, typeof i22.BbAvatar, typeof i23.BbMultiFileControl, typeof i24.BbFilePicker, typeof i25.BbImagePicker, typeof i26.BbDatePicker, typeof i27.BbColorSlider, typeof i28.BbColorPicker, typeof i29.BbImageControl, typeof i30.BbPincodeControl]>;
37
38
  static ɵinj: i0.ɵɵInjectorDeclaration<ElementsModule>;
38
39
  }
@@ -9,6 +9,7 @@ export declare class BbFilePicker implements ControlValueAccessor {
9
9
  label: string | TemplateRef<any> | null;
10
10
  hint: string | TemplateRef<any> | null;
11
11
  accept: string;
12
+ maxFileSize: number;
12
13
  showImages: boolean;
13
14
  grouped: boolean;
14
15
  required: boolean;
@@ -36,11 +37,19 @@ export declare class BbFilePicker implements ControlValueAccessor {
36
37
  } | null): void;
37
38
  validate({ value }: FormControl<File>): {
38
39
  invalidFileType: boolean;
40
+ maxFileSize?: undefined;
41
+ } | {
42
+ maxFileSize: {
43
+ maxSize: string;
44
+ };
45
+ invalidFileType?: undefined;
39
46
  };
40
47
  saveFile(files: File[]): void;
41
48
  private getFilesFromEvent;
42
49
  static ɵfac: i0.ɵɵFactoryDeclaration<BbFilePicker, never>;
43
- static ɵcmp: i0.ɵɵComponentDeclaration<BbFilePicker, "bb-file-picker", never, { "label": { "alias": "label"; "required": false; }; "hint": { "alias": "hint"; "required": false; }; "accept": { "alias": "accept"; "required": false; }; "showImages": { "alias": "showImages"; "required": false; }; "grouped": { "alias": "grouped"; "required": false; }; "required": { "alias": "required"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "hideErrors": { "alias": "hideErrors"; "required": false; }; "value": { "alias": "value"; "required": false; }; }, { "valueChange": "valueChange"; }, ["extraTemplate"], never, true, never>;
50
+ static ɵcmp: i0.ɵɵComponentDeclaration<BbFilePicker, "bb-file-picker", never, { "label": { "alias": "label"; "required": false; }; "hint": { "alias": "hint"; "required": false; }; "accept": { "alias": "accept"; "required": false; }; "maxFileSize": { "alias": "maxFileSize"; "required": false; }; "showImages": { "alias": "showImages"; "required": false; }; "grouped": { "alias": "grouped"; "required": false; }; "required": { "alias": "required"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "hideErrors": { "alias": "hideErrors"; "required": false; }; "value": { "alias": "value"; "required": false; }; }, { "valueChange": "valueChange"; }, ["extraTemplate"], never, true, never>;
51
+ static ngAcceptInputType_maxFileSize: unknown;
52
+ static ngAcceptInputType_showImages: unknown;
44
53
  static ngAcceptInputType_grouped: unknown;
45
54
  static ngAcceptInputType_required: unknown;
46
55
  static ngAcceptInputType_disabled: unknown;
@@ -9,6 +9,8 @@ export declare class BbMultiFileControl implements ControlValueAccessor {
9
9
  label: string | TemplateRef<any> | null;
10
10
  hint: string | TemplateRef<any> | null;
11
11
  accept: string;
12
+ maxFileSize: number;
13
+ maxTotalFileSize: number;
12
14
  grouped: boolean;
13
15
  required: boolean;
14
16
  disabled: boolean;
@@ -40,13 +42,29 @@ export declare class BbMultiFileControl implements ControlValueAccessor {
40
42
  token: string;
41
43
  data?: any;
42
44
  } | null): void;
43
- validate({ value }: FormControl<File[]>): {
45
+ validate(control: FormControl<File[]>): {
44
46
  invalidFiles: Record<number, boolean>;
47
+ maxFileSize?: undefined;
48
+ maxTotalFileSize?: undefined;
49
+ } | {
50
+ maxFileSize: {
51
+ maxSize: string;
52
+ };
53
+ invalidFiles?: undefined;
54
+ maxTotalFileSize?: undefined;
55
+ } | {
56
+ maxTotalFileSize: {
57
+ max: string;
58
+ current: string;
59
+ };
60
+ invalidFiles?: undefined;
61
+ maxFileSize?: undefined;
45
62
  };
46
63
  addFiles(files: File[]): void;
47
- private isFileLike;
48
64
  static ɵfac: i0.ɵɵFactoryDeclaration<BbMultiFileControl, never>;
49
- static ɵcmp: i0.ɵɵComponentDeclaration<BbMultiFileControl, "bb-multi-file-control", never, { "label": { "alias": "label"; "required": false; }; "hint": { "alias": "hint"; "required": false; }; "accept": { "alias": "accept"; "required": false; }; "grouped": { "alias": "grouped"; "required": false; }; "required": { "alias": "required"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "hideErrors": { "alias": "hideErrors"; "required": false; }; "items": { "alias": "items"; "required": false; }; }, { "delete": "delete"; }, never, never, true, never>;
65
+ static ɵcmp: i0.ɵɵComponentDeclaration<BbMultiFileControl, "bb-multi-file-control", never, { "label": { "alias": "label"; "required": false; }; "hint": { "alias": "hint"; "required": false; }; "accept": { "alias": "accept"; "required": false; }; "maxFileSize": { "alias": "maxFileSize"; "required": false; }; "maxTotalFileSize": { "alias": "maxTotalFileSize"; "required": false; }; "grouped": { "alias": "grouped"; "required": false; }; "required": { "alias": "required"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "hideErrors": { "alias": "hideErrors"; "required": false; }; "items": { "alias": "items"; "required": false; }; }, { "delete": "delete"; }, never, never, true, never>;
66
+ static ngAcceptInputType_maxFileSize: unknown;
67
+ static ngAcceptInputType_maxTotalFileSize: unknown;
50
68
  static ngAcceptInputType_grouped: unknown;
51
69
  static ngAcceptInputType_required: unknown;
52
70
  static ngAcceptInputType_disabled: unknown;
@@ -0,0 +1,65 @@
1
+ import { ElementRef, EventEmitter, OnDestroy, OnInit, TemplateRef } from '@angular/core';
2
+ import { ControlValueAccessor, FormControl, Validator } from '@angular/forms';
3
+ import { Observable } from 'rxjs';
4
+ import * as i0 from "@angular/core";
5
+ export declare class BbPincodeControl implements OnInit, OnDestroy, ControlValueAccessor, Validator {
6
+ private readonly _platform;
7
+ private readonly _changeDetectorRef;
8
+ htmlInputElementRef: ElementRef<HTMLInputElement>;
9
+ label: string | TemplateRef<any> | null;
10
+ hint: string | TemplateRef<any> | null;
11
+ placeholder: string | null;
12
+ autoFocus: boolean;
13
+ required: boolean;
14
+ readonly: boolean;
15
+ grouped: boolean;
16
+ digits: number;
17
+ get value(): string | null;
18
+ valueChange: EventEmitter<string>;
19
+ set value(value: string | null);
20
+ data$: Observable<{
21
+ items?: {
22
+ index: number;
23
+ value: string;
24
+ active: boolean;
25
+ }[];
26
+ }>;
27
+ control: FormControl<string>;
28
+ error: boolean;
29
+ onTouchedCallback: () => void;
30
+ onChangeCallback: (_: string | null) => void;
31
+ private _subscription;
32
+ ngOnInit(): void;
33
+ ngOnDestroy(): void;
34
+ writeValue(value: string | null): void;
35
+ registerOnChange(method: (_: string | null) => void): void;
36
+ registerOnTouched(method: () => void): void;
37
+ setDisabledState(isDisabled: boolean): void;
38
+ onErrorChange(error: {
39
+ token: string;
40
+ data?: any;
41
+ } | null): void;
42
+ validate(control: FormControl): {
43
+ maxlength: {
44
+ actualLength: any;
45
+ requiredLength: number;
46
+ };
47
+ minlength?: undefined;
48
+ } | {
49
+ minlength: {
50
+ actualLength: any;
51
+ requiredLength: number;
52
+ };
53
+ maxlength?: undefined;
54
+ };
55
+ private setData;
56
+ private handleValueChanges;
57
+ private handleAutoFocus;
58
+ static ɵfac: i0.ɵɵFactoryDeclaration<BbPincodeControl, never>;
59
+ static ɵcmp: i0.ɵɵComponentDeclaration<BbPincodeControl, "bb-pincode-control", never, { "label": { "alias": "label"; "required": false; }; "hint": { "alias": "hint"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "autoFocus": { "alias": "autoFocus"; "required": false; }; "required": { "alias": "required"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "grouped": { "alias": "grouped"; "required": false; }; "digits": { "alias": "digits"; "required": false; }; "value": { "alias": "value"; "required": false; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
60
+ static ngAcceptInputType_autoFocus: unknown;
61
+ static ngAcceptInputType_required: unknown;
62
+ static ngAcceptInputType_readonly: unknown;
63
+ static ngAcceptInputType_grouped: unknown;
64
+ static ngAcceptInputType_digits: unknown;
65
+ }
@@ -2,7 +2,6 @@ import { PipeTransform } from '@angular/core';
2
2
  import * as i0 from "@angular/core";
3
3
  export declare class BbFileSize implements PipeTransform {
4
4
  transform(value: number): string;
5
- private format;
6
5
  static ɵfac: i0.ɵɵFactoryDeclaration<BbFileSize, never>;
7
6
  static ɵpipe: i0.ɵɵPipeDeclaration<BbFileSize, "bbFileSize", true>;
8
7
  }
@@ -28,6 +28,7 @@ export * from './lib/date-picker/date-picker.component';
28
28
  export * from './lib/color-slider/color-slider.component';
29
29
  export * from './lib/color-picker/color-picker.component';
30
30
  export * from './lib/image-control/image-control.component';
31
+ export * from './lib/pincode-control/pincode-control.component';
31
32
  export * from './lib/elements.inject';
32
33
  export * from './lib/elements.interfaces';
33
34
  export * from './lib/elements.config';
@@ -12,12 +12,13 @@ import { BbTemplate } from '@bravobit/bb-foundation/utils';
12
12
  import * as i1$1 from '@angular/cdk/platform';
13
13
  import { Platform } from '@angular/cdk/platform';
14
14
  import * as i2 from '@bravobit/bb-foundation';
15
- import { Files, clamp, hsvToHex, hexToHsv, Exif, FileLoader, parseDate } from '@bravobit/bb-foundation';
15
+ import { Files, clamp, hsvToHex, hexToHsv, formatFileSize, Exif, FileLoader, parseDate, isValidFileType, isValidFileSize, isFileLike } from '@bravobit/bb-foundation';
16
16
  import { Overlay } from '@angular/cdk/overlay';
17
17
  import { ComponentPortal } from '@angular/cdk/portal';
18
18
  import * as i3 from '@angular/platform-browser';
19
19
  import { trigger, transition, style, animate } from '@angular/animations';
20
20
  import { TooltipDirective } from '@bravobit/bb-foundation/tooltip';
21
+ import { getControlValue } from '@bravobit/bb-foundation/rxjs';
21
22
 
22
23
  class BbFormSubmit {
23
24
  _host;
@@ -775,18 +776,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
775
776
 
776
777
  class BbFileSize {
777
778
  transform(value) {
778
- return this.format(value);
779
+ return formatFileSize(value);
779
780
  }
780
- format = (value, decimals = 2) => {
781
- if (value === 0) {
782
- return '0 Bytes';
783
- }
784
- const k = 1024;
785
- const dm = decimals < 0 ? 0 : decimals;
786
- const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
787
- const index = Math.floor(Math.log(value) / Math.log(k));
788
- return parseFloat((value / Math.pow(k, index)).toFixed(dm)) + ' ' + sizes[index];
789
- };
790
781
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: BbFileSize, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
791
782
  static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.1.6", ngImport: i0, type: BbFileSize, isStandalone: true, name: "bbFileSize" });
792
783
  }
@@ -1702,6 +1693,14 @@ function injectAcceptString() {
1702
1693
  ? null
1703
1694
  : allowedFileTypes.join(',');
1704
1695
  }
1696
+ function injectMaxFileSize() {
1697
+ const config = inject(ELEMENTS_CONFIG, { optional: true });
1698
+ return config?.maxFileSize ?? Number.MAX_SAFE_INTEGER;
1699
+ }
1700
+ function injectMaxTotalFileSize() {
1701
+ const config = inject(ELEMENTS_CONFIG, { optional: true });
1702
+ return config?.maxTotalFileSize ?? Number.MAX_SAFE_INTEGER;
1703
+ }
1705
1704
 
1706
1705
  let nextUniqueId$2 = 0;
1707
1706
  class BbMultiFileControl {
@@ -1716,6 +1715,8 @@ class BbMultiFileControl {
1716
1715
  label = null;
1717
1716
  hint = null;
1718
1717
  accept = injectAcceptString();
1718
+ maxFileSize = injectMaxFileSize();
1719
+ maxTotalFileSize = injectMaxTotalFileSize();
1719
1720
  grouped = false;
1720
1721
  required = false;
1721
1722
  disabled = false;
@@ -1764,19 +1765,32 @@ class BbMultiFileControl {
1764
1765
  onErrorChange(error) {
1765
1766
  this.error = !!error;
1766
1767
  }
1767
- validate({ value }) {
1768
- const regexString = (this.accept ?? '*')
1769
- .replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
1770
- .replace(/,/g, '|');
1771
- const mimeTypeRegex = new RegExp(regexString);
1772
- const errors = (value ?? []).reduce((previous, current, index) => {
1773
- const isValid = this.isFileLike(current) && mimeTypeRegex.test(current?.type);
1774
- if (isValid) {
1768
+ validate(control) {
1769
+ const value = control?.value ?? [];
1770
+ const errors = value.reduce((previous, current, index) => {
1771
+ if (isValidFileType(current, this.accept)) {
1775
1772
  return previous;
1776
1773
  }
1777
1774
  return { ...previous, [index]: true };
1778
1775
  }, {});
1779
- return Object.keys(errors)?.length > 0 ? { invalidFiles: errors } : null;
1776
+ if (Object.keys(errors)?.length > 0) {
1777
+ return { invalidFiles: errors };
1778
+ }
1779
+ for (const file of value) {
1780
+ if (!isValidFileSize(file, this.maxFileSize)) {
1781
+ return { maxFileSize: { maxSize: formatFileSize(this.maxFileSize) } };
1782
+ }
1783
+ }
1784
+ const totalSize = value.reduce((previous, current) => previous + (current?.size ?? 0), 0);
1785
+ if (totalSize > this.maxTotalFileSize) {
1786
+ return {
1787
+ maxTotalFileSize: {
1788
+ max: formatFileSize(this.maxTotalFileSize),
1789
+ current: formatFileSize(totalSize)
1790
+ }
1791
+ };
1792
+ }
1793
+ return null;
1780
1794
  }
1781
1795
  addFiles(files) {
1782
1796
  if (this.disabled) {
@@ -1784,19 +1798,15 @@ class BbMultiFileControl {
1784
1798
  }
1785
1799
  for (let index = 0; index < files?.length; index++) {
1786
1800
  const file = files?.[index] ?? null;
1787
- if (!this.isFileLike(file)) {
1801
+ if (!isFileLike(file)) {
1788
1802
  continue;
1789
1803
  }
1790
1804
  this.value.push(file);
1791
1805
  }
1792
1806
  this.onChangeCallback?.(this.value);
1793
1807
  }
1794
- isFileLike(input) {
1795
- return 'File' in window && input instanceof File
1796
- || 'Blob' in window && input instanceof Blob;
1797
- }
1798
1808
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: BbMultiFileControl, deps: [], target: i0.ɵɵFactoryTarget.Component });
1799
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.6", type: BbMultiFileControl, isStandalone: true, selector: "bb-multi-file-control", inputs: { label: "label", hint: "hint", accept: "accept", grouped: ["grouped", "grouped", booleanAttribute], required: ["required", "required", booleanAttribute], disabled: ["disabled", "disabled", booleanAttribute], hideErrors: ["hideErrors", "hideErrors", booleanAttribute], items: "items" }, outputs: { delete: "delete" }, host: { properties: { "class.required": "required", "class.disabled": "disabled", "class.grouped": "grouped", "class.error": "error" }, classAttribute: "bb-multi-file-control" }, providers: [
1809
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.6", type: BbMultiFileControl, isStandalone: true, selector: "bb-multi-file-control", inputs: { label: "label", hint: "hint", accept: "accept", maxFileSize: ["maxFileSize", "maxFileSize", numberAttribute], maxTotalFileSize: ["maxTotalFileSize", "maxTotalFileSize", numberAttribute], grouped: ["grouped", "grouped", booleanAttribute], required: ["required", "required", booleanAttribute], disabled: ["disabled", "disabled", booleanAttribute], hideErrors: ["hideErrors", "hideErrors", booleanAttribute], items: "items" }, outputs: { delete: "delete" }, host: { properties: { "class.required": "required", "class.disabled": "disabled", "class.grouped": "grouped", "class.error": "error" }, classAttribute: "bb-multi-file-control" }, providers: [
1800
1810
  { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => BbMultiFileControl), multi: true },
1801
1811
  { provide: NG_VALIDATORS, useExisting: BbMultiFileControl, multi: true }
1802
1812
  ], viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, static: true }], ngImport: i0, template: "<!-- The label of the input. -->\n@if (label; as labelContent) {\n <label [for]=\"labelId\"\n class=\"bb-multi-file-control-label\">\n <ng-template [bbTemplate]=\"labelContent\">{{ labelContent }}</ng-template>\n </label>\n}\n\n<input #fileInput\n [id]=\"labelId\"\n [accept]=\"accept\"\n [disabled]=\"disabled\"\n (change)=\"onFileChange($event)\"\n class=\"bb-multi-file-control-input\"\n type=\"file\"\n tabindex=\"-1\"\n multiple>\n\n<div [bbFileDropDisabled]=\"disabled\"\n (bbFileDrop)=\"addFiles($event)\"\n class=\"bb-multi-file-control-container\">\n @if (showList) {\n <ul class=\"bb-multi-file-control-list\">\n @for (item of items; track item?.id) {\n <li class=\"bb-multi-file-control-item\">\n <i class=\"bb-multi-file-control-icon attach-horizontal\"></i>\n <a [href]=\"item?.url\"\n target=\"_blank\"\n rel=\"noopener\"\n class=\"bb-multi-file-control-item-content\">{{ item?.label }}</a>\n @if (!disabled && delete?.observed) {\n <button (click)=\"delete?.emit(item)\"\n type=\"button\"\n class=\"bb-multi-file-control-item-button\">\n <i class=\"bb-multi-file-control-icon clear\"></i>\n </button>\n }\n </li>\n }\n @for (file of value; track $index) {\n <li class=\"bb-multi-file-control-item\">\n <i class=\"bb-multi-file-control-icon attach-horizontal\"></i>\n <button (click)=\"downloadFile(file)\"\n class=\"bb-multi-file-control-item-content\"\n type=\"button\">\n {{ file?.name }}\n </button>\n @if (!disabled) {\n <button (click)=\"deleteFile($index)\"\n type=\"button\"\n class=\"bb-multi-file-control-item-button\">\n <i class=\"bb-multi-file-control-icon clear\"></i>\n </button>\n }\n </li>\n }\n </ul>\n } @else if (!disabled) {\n <i class=\"bb-multi-file-control-icon attach-vertical\"></i>\n <p [bb-localize-string]=\"'multi-file-control.choose_file_text' | bbLocalize\"\n class=\"bb-multi-file-control-empty\">\n <label *bbLocalizeTemplate=\"'label'\"\n [for]=\"labelId\">{{ 'multi-file-control.choose_file' | bbLocalize }}</label>\n </p>\n }\n @if (!disabled) {\n <button (click)=\"openFileDialog()\"\n type=\"button\"\n class=\"primary small bb-multi-file-control-button\"\n bb-button>\n <i class=\"bb-multi-file-control-icon add\" suffix></i>\n {{ 'multi-file-control.choose_file' | bbLocalize }}\n </button>\n }\n</div>\n\n@if (!hideErrors) {\n <bb-form-error (errorChange)=\"onErrorChange($event)\"></bb-form-error>\n}\n\n<!-- The file picker hint. -->\n@if (hint; as hintContent) {\n <p class=\"bb-multi-file-control-hint\">\n <ng-template [bbTemplate]=\"hintContent\">{{ hintContent }}</ng-template>\n </p>\n}\n", styles: [".bb-multi-file-control{display:block;line-height:normal}.bb-multi-file-control.grouped{margin-bottom:1.5rem}.bb-multi-file-control.required>.bb-multi-file-control-label:after{content:\"*\";font-size:.75rem;vertical-align:top;color:var(--bb-form-label-required-color)}.bb-multi-file-control-container.is-hovered{border-color:var(--bb-multi-file-control-focus-border-color);box-shadow:0 .375rem .375rem -.375rem #0000001a,var(--bb-multi-file-control-box-shadow)}.bb-multi-file-control.disabled>.bb-multi-file-control-container{cursor:default;box-shadow:none;color:var(--bb-control-disabled-color);background-color:var(--bb-control-disabled-background-color)}.bb-multi-file-control.error>.bb-multi-file-control-label{color:var(--bb-control-error-color)}.bb-multi-file-control.error>.bb-multi-file-control-hint{display:none}.bb-multi-file-control.error>.bb-multi-file-control-container{border:1px solid var(--bb-control-error-border-color);background-color:var(--bb-control-error-background-color)}.bb-multi-file-control-label{display:block;margin-bottom:.25rem;color:var(--bb-form-label-color);font-size:var(--bb-form-label-font-size);font-weight:var(--bb-form-label-font-weight)}.bb-multi-file-control-input{opacity:0;z-index:-1;width:.1px;height:.1px;overflow:hidden;position:absolute}.bb-multi-file-control-container{width:100%;display:flex;color:#111;padding:.5rem;overflow:hidden;min-height:7.5rem;align-items:center;border-radius:.5rem;flex-direction:column;justify-content:center;background-color:#fff;transition-duration:.25s;transition-property:background-color,box-shadow;transition-timing-function:cubic-bezier(0,0,.2,1);border:1px solid var(--bb-multi-file-control-border-color);box-shadow:0 .375rem .375rem -.375rem #0000001a}.bb-multi-file-control-button{margin-top:.5rem}.bb-multi-file-control-list{flex:1;width:100%;overflow:hidden}.bb-multi-file-control-empty{flex:1;width:100%;color:#758795;display:block;font-weight:400;line-height:1.5;text-align:center;font-size:.875rem}.bb-multi-file-control-empty>label{cursor:pointer;display:inline;font-size:inherit;font-weight:inherit;text-decoration:underline;color:var(--bb-multi-file-control-color)}.bb-multi-file-control-item{height:2rem;display:flex;max-width:100%;overflow:hidden;align-items:center;white-space:nowrap;border-radius:.5rem;text-overflow:ellipsis;padding:0 .25rem 0 .5rem;background-color:#edf4fd;border:1px solid var(--bb-multi-file-control-border-color)}.bb-multi-file-control-item:not(:last-child){margin-bottom:.25rem}.bb-multi-file-control-item-content{flex:1;padding:0;border:none;max-width:100%;margin:0 .5rem;overflow:hidden;appearance:none;text-align:left;font-weight:400;font-size:.875rem;white-space:nowrap;text-decoration:none;text-overflow:ellipsis;background-color:transparent}.bb-multi-file-control-item-content,.bb-multi-file-control-item-content:visited{color:#0a305c}.bb-multi-file-control-item-content:hover,.bb-multi-file-control-item-content:focus{text-decoration:underline}.bb-multi-file-control-item-button{padding:0;width:1.5rem;display:flex;height:1.5rem;align-items:center;border-radius:.25rem;justify-content:center;border:1px solid hsl(0,73%,25%);background-color:#b51c1c}.bb-multi-file-control-item-button:hover,.bb-multi-file-control-item-button:focus{background-color:#a81a1a}.bb-multi-file-control-item-button:active{background-color:#9a1818}.bb-multi-file-control-hint{display:block;line-height:1.5;margin-top:.25rem;font-size:.8125rem;color:#758795}.bb-multi-file-control-icon{width:1.25rem;height:1.25rem;display:inline-flex;background-size:contain;background-repeat:no-repeat;background-position:center center}.bb-multi-file-control-icon.add{background-image:url('data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" fill=\"%23fff\" viewBox=\"0 0 24 24\"%3E%3Cpath d=\"M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z\"/%3E%3C/svg%3E')}.bb-multi-file-control-icon.attach-vertical{width:1.5rem;height:1.5rem;margin-bottom:.5rem;background-image:url('data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" fill=\"%23758795\" viewBox=\"0 0 24 24\"%3E%3Cpath d=\"M16.5 6v11.5c0 2.21-1.79 4-4 4s-4-1.79-4-4V5c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5v10.5c0 .55-.45 1-1 1s-1-.45-1-1V6H10v9.5c0 1.38 1.12 2.5 2.5 2.5s2.5-1.12 2.5-2.5V5c0-2.21-1.79-4-4-4S7 2.79 7 5v12.5c0 3.04 2.46 5.5 5.5 5.5s5.5-2.46 5.5-5.5V6h-1.5z\"/%3E%3C/svg%3E')}.bb-multi-file-control-icon.attach-horizontal{background-image:url('data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"%3E%3Cpath d=\"M2 12.5C2 9.46 4.46 7 7.5 7H18c2.21 0 4 1.79 4 4s-1.79 4-4 4H9.5C8.12 15 7 13.88 7 12.5S8.12 10 9.5 10H17v2H9.41c-.55 0-.55 1 0 1H18c1.1 0 2-.9 2-2s-.9-2-2-2H7.5C5.57 9 4 10.57 4 12.5S5.57 16 7.5 16H17v2H7.5C4.46 18 2 15.54 2 12.5z\"/%3E%3C/svg%3E')}.bb-multi-file-control-icon.clear{background-image:url('data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" fill=\"%23fff\" viewBox=\"0 0 24 24\"%3E%3Cpath d=\"M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/%3E%3C/svg%3E')}\n"], dependencies: [{ kind: "component", type: BbFormError, selector: "bb-form-error", inputs: ["control"], outputs: ["errorChange"] }, { kind: "directive", type: BbTemplate, selector: "[bbTemplate]", inputs: ["bbTemplate"] }, { kind: "component", type: BbButton, selector: "button[bb-button]", inputs: ["disabled", "loading"], exportAs: ["bbButton"] }, { kind: "pipe", type: BbLocalize, name: "bbLocalize" }, { kind: "directive", type: BbLocalizeTemplate, selector: "ng-template[bbLocalizeTemplate]", inputs: ["bbLocalizeTemplate"] }, { kind: "component", type: BbLocalizeString, selector: "[bb-localize-string]", inputs: ["substitutions", "bb-localize-string"] }, { kind: "directive", type: BbFileDrop, selector: "[bbFileDrop]", inputs: ["bbFileDropDisabled"], outputs: ["bbFileDrop"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
@@ -1822,6 +1832,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
1822
1832
  type: Input
1823
1833
  }], accept: [{
1824
1834
  type: Input
1835
+ }], maxFileSize: [{
1836
+ type: Input,
1837
+ args: [{ transform: numberAttribute }]
1838
+ }], maxTotalFileSize: [{
1839
+ type: Input,
1840
+ args: [{ transform: numberAttribute }]
1825
1841
  }], grouped: [{
1826
1842
  type: Input,
1827
1843
  args: [{ transform: booleanAttribute }]
@@ -1851,6 +1867,7 @@ class BbFilePicker {
1851
1867
  label = null;
1852
1868
  hint = null;
1853
1869
  accept = injectAcceptString();
1870
+ maxFileSize = injectMaxFileSize();
1854
1871
  showImages = true;
1855
1872
  grouped = false;
1856
1873
  required = false;
@@ -1916,12 +1933,13 @@ class BbFilePicker {
1916
1933
  if (value === null || value === undefined) {
1917
1934
  return null;
1918
1935
  }
1919
- const regexString = (this.accept ?? '*')
1920
- .replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
1921
- .replace(/,/g, '|');
1922
- const mimeTypeRegex = new RegExp(regexString);
1923
- const isNotValid = (typeof File === 'undefined') || !(value instanceof File) || !mimeTypeRegex.test(value?.type);
1924
- return isNotValid && { invalidFileType: true };
1936
+ if (!isValidFileType(value, this.accept)) {
1937
+ return { invalidFileType: true };
1938
+ }
1939
+ if (!isValidFileSize(value, this.maxFileSize)) {
1940
+ return { maxFileSize: { maxSize: formatFileSize(this.maxFileSize) } };
1941
+ }
1942
+ return null;
1925
1943
  }
1926
1944
  saveFile(files) {
1927
1945
  const file = files?.[0] ?? null;
@@ -1939,7 +1957,7 @@ class BbFilePicker {
1939
1957
  return Array.from(element.files);
1940
1958
  }
1941
1959
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: BbFilePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
1942
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.6", type: BbFilePicker, isStandalone: true, selector: "bb-file-picker", inputs: { label: "label", hint: "hint", accept: "accept", showImages: "showImages", grouped: ["grouped", "grouped", booleanAttribute], required: ["required", "required", booleanAttribute], disabled: ["disabled", "disabled", booleanAttribute], hideErrors: ["hideErrors", "hideErrors", booleanAttribute], value: "value" }, outputs: { valueChange: "valueChange" }, host: { properties: { "class.required": "required", "class.disabled": "disabled", "class.grouped": "grouped", "class.error": "error" }, classAttribute: "bb-file-picker" }, providers: [
1960
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.6", type: BbFilePicker, isStandalone: true, selector: "bb-file-picker", inputs: { label: "label", hint: "hint", accept: "accept", maxFileSize: ["maxFileSize", "maxFileSize", numberAttribute], showImages: ["showImages", "showImages", booleanAttribute], grouped: ["grouped", "grouped", booleanAttribute], required: ["required", "required", booleanAttribute], disabled: ["disabled", "disabled", booleanAttribute], hideErrors: ["hideErrors", "hideErrors", booleanAttribute], value: "value" }, outputs: { valueChange: "valueChange" }, host: { properties: { "class.required": "required", "class.disabled": "disabled", "class.grouped": "grouped", "class.error": "error" }, classAttribute: "bb-file-picker" }, providers: [
1943
1961
  {
1944
1962
  provide: NG_VALUE_ACCESSOR,
1945
1963
  useExisting: forwardRef(() => BbFilePicker),
@@ -2004,8 +2022,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
2004
2022
  type: Input
2005
2023
  }], accept: [{
2006
2024
  type: Input
2025
+ }], maxFileSize: [{
2026
+ type: Input,
2027
+ args: [{ transform: numberAttribute }]
2007
2028
  }], showImages: [{
2008
- type: Input
2029
+ type: Input,
2030
+ args: [{ transform: booleanAttribute }]
2009
2031
  }], grouped: [{
2010
2032
  type: Input,
2011
2033
  args: [{ transform: booleanAttribute }]
@@ -2569,6 +2591,161 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
2569
2591
  type: Output
2570
2592
  }] } });
2571
2593
 
2594
+ class BbPincodeControl {
2595
+ // Dependencies.
2596
+ _platform = inject(Platform);
2597
+ _changeDetectorRef = inject(ChangeDetectorRef);
2598
+ // Views.
2599
+ htmlInputElementRef;
2600
+ // Inputs.
2601
+ label = null;
2602
+ hint = null;
2603
+ placeholder = null;
2604
+ autoFocus = false;
2605
+ required = false;
2606
+ readonly = false;
2607
+ grouped = false;
2608
+ digits = 6;
2609
+ get value() {
2610
+ return this.control?.value;
2611
+ }
2612
+ valueChange = new EventEmitter();
2613
+ set value(value) {
2614
+ this.control?.setValue(value);
2615
+ this.valueChange.emit(value);
2616
+ }
2617
+ // Data.
2618
+ data$;
2619
+ // State.
2620
+ control = new FormControl(null);
2621
+ error = false;
2622
+ // Callbacks.
2623
+ onTouchedCallback = () => ({});
2624
+ onChangeCallback = () => ({});
2625
+ // Subscriptions.
2626
+ _subscription = new Subscription();
2627
+ ngOnInit() {
2628
+ this.setData();
2629
+ this.handleValueChanges();
2630
+ this.handleAutoFocus();
2631
+ }
2632
+ ngOnDestroy() {
2633
+ this._subscription?.unsubscribe();
2634
+ }
2635
+ writeValue(value) {
2636
+ this.value = value;
2637
+ }
2638
+ registerOnChange(method) {
2639
+ this.onChangeCallback = method;
2640
+ }
2641
+ registerOnTouched(method) {
2642
+ this.onTouchedCallback = method;
2643
+ }
2644
+ setDisabledState(isDisabled) {
2645
+ isDisabled
2646
+ ? this.control?.disable()
2647
+ : this.control?.enable();
2648
+ this._changeDetectorRef.markForCheck();
2649
+ }
2650
+ onErrorChange(error) {
2651
+ this.error = !!error;
2652
+ }
2653
+ validate(control) {
2654
+ const value = control?.value;
2655
+ if (value === null || value === undefined) {
2656
+ return null;
2657
+ }
2658
+ if (value?.length > this.digits) {
2659
+ return {
2660
+ maxlength: {
2661
+ actualLength: value?.length ?? 0,
2662
+ requiredLength: this.digits ?? 0
2663
+ }
2664
+ };
2665
+ }
2666
+ if (value?.length < this.digits) {
2667
+ return {
2668
+ minlength: {
2669
+ actualLength: value?.length ?? 0,
2670
+ requiredLength: this.digits ?? 0
2671
+ }
2672
+ };
2673
+ }
2674
+ return null;
2675
+ }
2676
+ setData() {
2677
+ this.data$ = getControlValue(this.control).pipe(map(value => value ?? ''), map(value => {
2678
+ const items = Array(this.digits)
2679
+ .fill(0)
2680
+ .map((_, index, array) => ({
2681
+ index: index,
2682
+ value: value?.[index] ?? '',
2683
+ active: Math.min(array?.length - 1, value?.length) === index
2684
+ }));
2685
+ return { items };
2686
+ }));
2687
+ }
2688
+ handleValueChanges() {
2689
+ const subscription = this.control.valueChanges.pipe(distinctUntilChanged()).subscribe(() => {
2690
+ this.valueChange.emit(this.value);
2691
+ this.onChangeCallback(this.value);
2692
+ });
2693
+ this._subscription.add(subscription);
2694
+ }
2695
+ handleAutoFocus() {
2696
+ if (!this.autoFocus || !this._platform.isBrowser) {
2697
+ return;
2698
+ }
2699
+ setTimeout(() => this.htmlInputElementRef?.nativeElement?.focus?.(), 0);
2700
+ }
2701
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: BbPincodeControl, deps: [], target: i0.ɵɵFactoryTarget.Component });
2702
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.6", type: BbPincodeControl, isStandalone: true, selector: "bb-pincode-control", inputs: { label: "label", hint: "hint", placeholder: "placeholder", autoFocus: ["autoFocus", "autoFocus", booleanAttribute], required: ["required", "required", booleanAttribute], readonly: ["readonly", "readonly", booleanAttribute], grouped: ["grouped", "grouped", booleanAttribute], digits: ["digits", "digits", numberAttribute], value: "value" }, outputs: { valueChange: "valueChange" }, host: { properties: { "class.required": "required", "class.readonly": "readonly", "class.grouped": "grouped", "class.error": "error" }, classAttribute: "bb-pincode-control" }, providers: [
2703
+ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => BbPincodeControl), multi: true },
2704
+ { provide: NG_VALIDATORS, useExisting: BbPincodeControl, multi: true }
2705
+ ], viewQueries: [{ propertyName: "htmlInputElementRef", first: true, predicate: ["htmlInputElement"], descendants: true, static: true }], ngImport: i0, template: "<!-- The label of the input. -->\n@if (label; as labelContent) {\n <label class=\"bb-pincode-control-label\">\n <ng-template [bbTemplate]=\"labelContent\">{{ labelContent }}</ng-template>\n </label>\n}\n\n<input #htmlInputElement\n [formControl]=\"control\"\n [minlength]=\"digits\"\n [maxlength]=\"digits\"\n [readonly]=\"readonly\"\n inputmode=\"numeric\"\n tabindex=\"-1\"\n autocomplete=\"off\"\n class=\"bb-pincode-control-element\"\n type=\"text\">\n\n@if (data$ | async; as data) {\n <div class=\"bb-pincode-control-container\">\n @for (item of data?.items; track item?.index) {\n <div [class.active]=\"item?.active\"\n [class.has-value]=\"!!item?.value\"\n [attr.data-placeholder]=\"placeholder\"\n (click)=\"htmlInputElement?.focus()\"\n class=\"bb-pincode-control-cell\">\n {{ item?.value }}\n </div>\n }\n </div>\n}\n\n<bb-form-error (errorChange)=\"onErrorChange($event)\"></bb-form-error>\n\n<!-- The file picker hint. -->\n@if (hint; as hintContent) {\n <p class=\"bb-pincode-control-hint\">\n <ng-template [bbTemplate]=\"hintContent\">{{ hintContent }}</ng-template>\n </p>\n}\n", styles: [".bb-pincode-control{display:block;line-height:normal}.bb-pincode-control.grouped{margin-bottom:1.5rem}.bb-pincode-control.required>.bb-pincode-control-label:after{content:\"*\";color:#c23934;font-size:.75rem;vertical-align:top}.bb-pincode-control.error>.bb-pincode-control-label{color:var(--bb-control-error-color)}.bb-pincode-control.error>.bb-pincode-control-hint{display:none}.bb-pincode-control.error>.bb-pincode-control-container>.bb-pincode-control-cell{border:1px solid var(--bb-control-error-border-color);background-color:var(--bb-control-error-background-color)}.bb-pincode-control.error>.bb-pincode-control-container>.bb-pincode-control-cell:not(.has-value):before{color:var(--bb-control-error-placeholder-color)}.bb-pincode-control.error>.bb-pincode-control-element:not(:disabled):not(:read-only):focus+.bb-pincode-control-container>.bb-pincode-control-cell.active{box-shadow:var(--bb-control-error-box-shadow)}.bb-pincode-control-element:not(:disabled):read-only+.bb-pincode-control-container>.bb-pincode-control-cell{cursor:default;box-shadow:none;border-style:dotted;border-color:#bdc4c9;background-color:transparent}.bb-pincode-control-element:disabled+.bb-pincode-control-container>.bb-pincode-control-cell{cursor:default;box-shadow:none;pointer-events:none;color:var(--bb-control-disabled-color);background-color:var(--bb-control-disabled-background-color)}.bb-pincode-control-element{opacity:0;z-index:-1;width:.1px;height:.1px;overflow:hidden;position:absolute}.bb-pincode-control-element:not(:disabled):not(:read-only):focus+.bb-pincode-control-container>.bb-pincode-control-cell.active{box-shadow:var(--bb-form-control-focus-box-shadow);border-color:var(--bb-form-control-focus-border-color)}.bb-pincode-control-element:not(:disabled):not(:read-only):focus+.bb-pincode-control-container>.bb-pincode-control-cell.active:not(.has-value):after{top:50%;content:\"|\";position:absolute;text-align:center;transform:translate(-25%) translateY(-50%);animation:bbCursorBlink .8s step-end infinite}.bb-pincode-control-container{display:flex;gap:.75rem;align-items:center}.bb-pincode-control-cell{flex:1;cursor:text;height:3rem;display:flex;font-size:1rem;-webkit-user-select:none;user-select:none;text-align:center;position:relative;align-items:center;justify-content:center;color:var(--text-color);box-shadow:var(--bb-form-control-box-shadow);border:1px solid var(--bb-form-control-border-color);background-color:var(--bb-form-control-background-color);border-radius:var(--bb-form-control-border-radius, .5rem);transition:background-color .25s cubic-bezier(0,0,.2,1),box-shadow .25s cubic-bezier(0,0,.2,1)}.bb-pincode-control-cell:not(.has-value):before{top:0;bottom:0;left:.25rem;right:.25rem;display:block;max-width:100%;overflow:hidden;line-height:3rem;position:absolute;text-align:center;white-space:nowrap;vertical-align:middle;text-overflow:ellipsis;color:#d1d1d1;content:attr(data-placeholder)}.bb-pincode-control-label{color:#525252;display:block;font-weight:400;font-size:.875rem;margin-bottom:.25rem}.bb-pincode-control-hint{display:block;line-height:1.5;margin-top:.25rem;font-size:.8125rem;color:#758795}@keyframes bbCursorBlink{0%{opacity:1}50%{opacity:0}to{opacity:1}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: BbTemplate, selector: "[bbTemplate]", inputs: ["bbTemplate"] }, { kind: "component", type: BbFormError, selector: "bb-form-error", inputs: ["control"], outputs: ["errorChange"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2706
+ }
2707
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: BbPincodeControl, decorators: [{
2708
+ type: Component,
2709
+ args: [{ selector: 'bb-pincode-control', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [
2710
+ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => BbPincodeControl), multi: true },
2711
+ { provide: NG_VALIDATORS, useExisting: BbPincodeControl, multi: true }
2712
+ ], host: {
2713
+ 'class': 'bb-pincode-control',
2714
+ '[class.required]': 'required',
2715
+ '[class.readonly]': 'readonly',
2716
+ '[class.grouped]': 'grouped',
2717
+ '[class.error]': 'error'
2718
+ }, imports: [ReactiveFormsModule, BbTemplate, BbFormError, AsyncPipe], template: "<!-- The label of the input. -->\n@if (label; as labelContent) {\n <label class=\"bb-pincode-control-label\">\n <ng-template [bbTemplate]=\"labelContent\">{{ labelContent }}</ng-template>\n </label>\n}\n\n<input #htmlInputElement\n [formControl]=\"control\"\n [minlength]=\"digits\"\n [maxlength]=\"digits\"\n [readonly]=\"readonly\"\n inputmode=\"numeric\"\n tabindex=\"-1\"\n autocomplete=\"off\"\n class=\"bb-pincode-control-element\"\n type=\"text\">\n\n@if (data$ | async; as data) {\n <div class=\"bb-pincode-control-container\">\n @for (item of data?.items; track item?.index) {\n <div [class.active]=\"item?.active\"\n [class.has-value]=\"!!item?.value\"\n [attr.data-placeholder]=\"placeholder\"\n (click)=\"htmlInputElement?.focus()\"\n class=\"bb-pincode-control-cell\">\n {{ item?.value }}\n </div>\n }\n </div>\n}\n\n<bb-form-error (errorChange)=\"onErrorChange($event)\"></bb-form-error>\n\n<!-- The file picker hint. -->\n@if (hint; as hintContent) {\n <p class=\"bb-pincode-control-hint\">\n <ng-template [bbTemplate]=\"hintContent\">{{ hintContent }}</ng-template>\n </p>\n}\n", styles: [".bb-pincode-control{display:block;line-height:normal}.bb-pincode-control.grouped{margin-bottom:1.5rem}.bb-pincode-control.required>.bb-pincode-control-label:after{content:\"*\";color:#c23934;font-size:.75rem;vertical-align:top}.bb-pincode-control.error>.bb-pincode-control-label{color:var(--bb-control-error-color)}.bb-pincode-control.error>.bb-pincode-control-hint{display:none}.bb-pincode-control.error>.bb-pincode-control-container>.bb-pincode-control-cell{border:1px solid var(--bb-control-error-border-color);background-color:var(--bb-control-error-background-color)}.bb-pincode-control.error>.bb-pincode-control-container>.bb-pincode-control-cell:not(.has-value):before{color:var(--bb-control-error-placeholder-color)}.bb-pincode-control.error>.bb-pincode-control-element:not(:disabled):not(:read-only):focus+.bb-pincode-control-container>.bb-pincode-control-cell.active{box-shadow:var(--bb-control-error-box-shadow)}.bb-pincode-control-element:not(:disabled):read-only+.bb-pincode-control-container>.bb-pincode-control-cell{cursor:default;box-shadow:none;border-style:dotted;border-color:#bdc4c9;background-color:transparent}.bb-pincode-control-element:disabled+.bb-pincode-control-container>.bb-pincode-control-cell{cursor:default;box-shadow:none;pointer-events:none;color:var(--bb-control-disabled-color);background-color:var(--bb-control-disabled-background-color)}.bb-pincode-control-element{opacity:0;z-index:-1;width:.1px;height:.1px;overflow:hidden;position:absolute}.bb-pincode-control-element:not(:disabled):not(:read-only):focus+.bb-pincode-control-container>.bb-pincode-control-cell.active{box-shadow:var(--bb-form-control-focus-box-shadow);border-color:var(--bb-form-control-focus-border-color)}.bb-pincode-control-element:not(:disabled):not(:read-only):focus+.bb-pincode-control-container>.bb-pincode-control-cell.active:not(.has-value):after{top:50%;content:\"|\";position:absolute;text-align:center;transform:translate(-25%) translateY(-50%);animation:bbCursorBlink .8s step-end infinite}.bb-pincode-control-container{display:flex;gap:.75rem;align-items:center}.bb-pincode-control-cell{flex:1;cursor:text;height:3rem;display:flex;font-size:1rem;-webkit-user-select:none;user-select:none;text-align:center;position:relative;align-items:center;justify-content:center;color:var(--text-color);box-shadow:var(--bb-form-control-box-shadow);border:1px solid var(--bb-form-control-border-color);background-color:var(--bb-form-control-background-color);border-radius:var(--bb-form-control-border-radius, .5rem);transition:background-color .25s cubic-bezier(0,0,.2,1),box-shadow .25s cubic-bezier(0,0,.2,1)}.bb-pincode-control-cell:not(.has-value):before{top:0;bottom:0;left:.25rem;right:.25rem;display:block;max-width:100%;overflow:hidden;line-height:3rem;position:absolute;text-align:center;white-space:nowrap;vertical-align:middle;text-overflow:ellipsis;color:#d1d1d1;content:attr(data-placeholder)}.bb-pincode-control-label{color:#525252;display:block;font-weight:400;font-size:.875rem;margin-bottom:.25rem}.bb-pincode-control-hint{display:block;line-height:1.5;margin-top:.25rem;font-size:.8125rem;color:#758795}@keyframes bbCursorBlink{0%{opacity:1}50%{opacity:0}to{opacity:1}}\n"] }]
2719
+ }], propDecorators: { htmlInputElementRef: [{
2720
+ type: ViewChild,
2721
+ args: ['htmlInputElement', { static: true }]
2722
+ }], label: [{
2723
+ type: Input
2724
+ }], hint: [{
2725
+ type: Input
2726
+ }], placeholder: [{
2727
+ type: Input
2728
+ }], autoFocus: [{
2729
+ type: Input,
2730
+ args: [{ transform: booleanAttribute }]
2731
+ }], required: [{
2732
+ type: Input,
2733
+ args: [{ transform: booleanAttribute }]
2734
+ }], readonly: [{
2735
+ type: Input,
2736
+ args: [{ transform: booleanAttribute }]
2737
+ }], grouped: [{
2738
+ type: Input,
2739
+ args: [{ transform: booleanAttribute }]
2740
+ }], digits: [{
2741
+ type: Input,
2742
+ args: [{ transform: numberAttribute }]
2743
+ }], value: [{
2744
+ type: Input
2745
+ }], valueChange: [{
2746
+ type: Output
2747
+ }] } });
2748
+
2572
2749
  function provideElementsConfig(config) {
2573
2750
  const providers = [
2574
2751
  { provide: ELEMENTS_CONFIG, useValue: config },
@@ -2587,6 +2764,7 @@ function provideElementsConfig(config) {
2587
2764
  min: ({ min }) => ({ token: 'form-control-errors.min', data: { min } }),
2588
2765
  max: ({ max }) => ({ token: 'form-control-errors.max', data: { max } }),
2589
2766
  maxFileSize: ({ maxSize }) => ({ token: 'form-control-errors.maxFileSize', data: { maxSize } }),
2767
+ maxTotalFileSize: ({ max, current }) => ({ token: 'form-control-errors.maxTotalFileSize', data: { max, current } }),
2590
2768
  minDate: ({ date }) => ({ token: 'form-control-errors.minDate', data: { date } }),
2591
2769
  maxDate: ({ date }) => ({ token: 'form-control-errors.maxDate', data: { date } }),
2592
2770
  invalidDate: () => 'form-control-errors.invalidDate',
@@ -2654,7 +2832,8 @@ const IMPORTS_EXPORTS = [
2654
2832
  BbDatePicker,
2655
2833
  BbColorSlider,
2656
2834
  BbColorPicker,
2657
- BbImageControl
2835
+ BbImageControl,
2836
+ BbPincodeControl
2658
2837
  ];
2659
2838
  class ElementsModule {
2660
2839
  static forRoot(config) {
@@ -2699,7 +2878,8 @@ class ElementsModule {
2699
2878
  BbDatePicker,
2700
2879
  BbColorSlider,
2701
2880
  BbColorPicker,
2702
- BbImageControl], exports: [
2881
+ BbImageControl,
2882
+ BbPincodeControl], exports: [
2703
2883
  // Directives.
2704
2884
  BbFormError,
2705
2885
  BbFormSubmit,
@@ -2732,9 +2912,11 @@ class ElementsModule {
2732
2912
  BbDatePicker,
2733
2913
  BbColorSlider,
2734
2914
  BbColorPicker,
2735
- BbImageControl] });
2915
+ BbImageControl,
2916
+ BbPincodeControl] });
2736
2917
  static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: ElementsModule, imports: [BbMultiFileControl,
2737
- BbDatePicker] });
2918
+ BbDatePicker,
2919
+ BbPincodeControl] });
2738
2920
  }
2739
2921
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: ElementsModule, decorators: [{
2740
2922
  type: NgModule,
@@ -2748,5 +2930,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
2748
2930
  * Generated bundle index. Do not edit.
2749
2931
  */
2750
2932
 
2751
- export { BbAnchor, BbAvatar, BbButton, BbCheckbox, BbCheckboxGroup, BbColorPicker, BbColorSlider, BbDate, BbDatePicker, BbExtraErrorControls, BbFileDataUrl, BbFileDrop, BbFileImage, BbFilePicker, BbFileSize, BbFormControl, BbFormError, BbFormGroup, BbFormSubmit, BbFormSubmitter, BbIcon, BbImageControl, BbImagePicker, BbImageUpload, BbInput, BbMultiFileControl, BbRadioButton, BbRadioGroup, BbRelativeTime, BbSpinner, ColorPickerDirective, ELEMENTS_CONFIG, ELEMENTS_ERRORS, ELEMENTS_ICONS, ElementsModule, injectAcceptString, provideElementsConfig };
2933
+ export { BbAnchor, BbAvatar, BbButton, BbCheckbox, BbCheckboxGroup, BbColorPicker, BbColorSlider, BbDate, BbDatePicker, BbExtraErrorControls, BbFileDataUrl, BbFileDrop, BbFileImage, BbFilePicker, BbFileSize, BbFormControl, BbFormError, BbFormGroup, BbFormSubmit, BbFormSubmitter, BbIcon, BbImageControl, BbImagePicker, BbImageUpload, BbInput, BbMultiFileControl, BbPincodeControl, BbRadioButton, BbRadioGroup, BbRelativeTime, BbSpinner, ColorPickerDirective, ELEMENTS_CONFIG, ELEMENTS_ERRORS, ELEMENTS_ICONS, ElementsModule, injectAcceptString, injectMaxFileSize, injectMaxTotalFileSize, provideElementsConfig };
2752
2934
  //# sourceMappingURL=bravobit-bb-foundation-elements.mjs.map