@brickclay-org/ui 0.0.65 → 0.0.67

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.
@@ -6742,65 +6742,113 @@ class BkColumnSelect {
6742
6742
  columnFilterService;
6743
6743
  searchable = false;
6744
6744
  cacheKey;
6745
- columns;
6745
+ columns = [];
6746
6746
  isOpened = false;
6747
- formBoxRef;
6748
- change = new EventEmitter();
6749
6747
  isOpenedChange = new EventEmitter();
6748
+ formBoxRef;
6749
+ /** Value bound via ngModel – only updated when user ticks/unticks a checkbox, never on search. */
6750
6750
  columnsFilterList = [];
6751
6751
  search = '';
6752
+ onChangeCallback = () => { };
6753
+ onTouchedCallback = () => { };
6752
6754
  constructor(columnFilterService) {
6753
6755
  this.columnFilterService = columnFilterService;
6754
6756
  }
6755
- ngOnInit() {
6756
- this.getColumnsFilterList();
6757
+ writeValue(value) {
6758
+ const isEmpty = !value || !Array.isArray(value) || value.length === 0;
6759
+ if (isEmpty && this.shouldLoadFromService()) {
6760
+ this.loadColumnsFilterListFromService();
6761
+ }
6762
+ else {
6763
+ this.columnsFilterList = Array.isArray(value) ? value : [];
6764
+ }
6757
6765
  }
6758
6766
  ngOnChanges(changes) {
6759
- if (changes['columns'] && !changes['columns'].firstChange) {
6760
- this.getColumnsFilterList();
6767
+ const columnsChanged = changes['columns'] && !changes['columns'].firstChange;
6768
+ const cacheKeyChanged = changes['cacheKey'] && !changes['cacheKey'].firstChange;
6769
+ if ((columnsChanged || cacheKeyChanged) && this.columnsFilterList.length === 0 && this.shouldLoadFromService()) {
6770
+ this.loadColumnsFilterListFromService();
6761
6771
  }
6762
6772
  }
6763
- getColumnsFilterList() {
6773
+ shouldLoadFromService() {
6774
+ return !!this.cacheKey && !!this.columns?.length;
6775
+ }
6776
+ loadColumnsFilterListFromService() {
6764
6777
  this.columnsFilterList = this.columnFilterService.getColumnsFilterList(this.cacheKey, this.columns);
6765
- this.change.emit(this.columnsFilterList);
6778
+ this.onChangeCallback(this.columnsFilterList);
6779
+ }
6780
+ registerOnChange(fn) {
6781
+ this.onChangeCallback = fn;
6782
+ }
6783
+ registerOnTouched(fn) {
6784
+ this.onTouchedCallback = fn;
6785
+ }
6786
+ setDisabledState(isDisabled) {
6787
+ // Optional: disable button/dropdown when control is disabled
6766
6788
  }
6767
6789
  filterButtonClicked(event) {
6768
6790
  event.stopPropagation();
6769
- this.isOpenedChange.emit(!this.isOpened);
6791
+ const willOpen = !this.isOpened;
6792
+ if (!willOpen) {
6793
+ this.clearSearch();
6794
+ this.onTouchedCallback();
6795
+ }
6796
+ this.isOpenedChange.emit(willOpen);
6770
6797
  }
6771
- onChangeColumnFilter(evt) {
6798
+ /** Called only on checkbox tick/untick – not on search. Emits via CVA so ngModel updates. */
6799
+ onChangeColumnFilter() {
6772
6800
  this.columnFilterService.updateColumnFilterList(this.cacheKey, this.columnsFilterList);
6773
- this.change.emit(this.columnsFilterList);
6801
+ this.onChangeCallback(this.columnsFilterList);
6802
+ this.onTouchedCallback();
6803
+ }
6804
+ clearSearch() {
6805
+ this.search = '';
6806
+ }
6807
+ closeDropdown() {
6808
+ this.clearSearch();
6809
+ this.onTouchedCallback();
6810
+ this.isOpened = false;
6811
+ this.isOpenedChange.emit(this.isOpened);
6774
6812
  }
6775
6813
  onClick(event) {
6776
- // Check if the click target is inside the form_box
6777
- if ((this.isOpened) &&
6778
- this.formBoxRef.nativeElement.contains(event.target)) {
6779
- return; // Do nothing if click occurred inside the form_box
6814
+ if (!this.isOpened) {
6815
+ return;
6816
+ }
6817
+ const formBox = this.formBoxRef?.nativeElement;
6818
+ if (formBox && formBox.contains(event.target)) {
6819
+ return;
6780
6820
  }
6781
- // Check if the click target is .ng-value-icon
6782
6821
  if (event.target instanceof HTMLElement &&
6783
6822
  event.target.classList.contains('ng-value-icon')) {
6784
- // Do nothing if click is on .ng-value-icon
6785
6823
  return;
6786
6824
  }
6787
- // Check if the click target is the button
6788
- if (!(event.target instanceof HTMLElement) ||
6789
- !event.target.closest('.btn-light-primary-custom')) {
6790
- // Close the popup if the click is not on the button
6791
- this.isOpened = false;
6792
- this.isOpenedChange.emit(this.isOpened);
6825
+ if (event.target instanceof HTMLElement &&
6826
+ event.target.closest('.btn-light-primary-custom')) {
6827
+ return;
6793
6828
  }
6829
+ this.closeDropdown();
6794
6830
  }
6795
6831
  get list() {
6796
6832
  return this.columnsFilterList.filter((x) => x.columnName.toLowerCase().includes(this.search.toLowerCase()));
6797
6833
  }
6798
6834
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkColumnSelect, deps: [{ token: BkColumnFilterService }], target: i0.ɵɵFactoryTarget.Component });
6799
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkColumnSelect, isStandalone: true, selector: "bk-column-select", inputs: { searchable: "searchable", cacheKey: "cacheKey", columns: "columns", isOpened: "isOpened" }, outputs: { change: "change", isOpenedChange: "isOpenedChange" }, host: { listeners: { "document:click": "onClick($event)" } }, viewQueries: [{ propertyName: "formBoxRef", first: true, predicate: ["formBox"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"relative\">\r\n\r\n <bk-button [size]=\"'xsm'\" [variant]=\"'secondary'\" [leftIcon]=\"'../../../../assets/icons/columns-black.svg'\"\r\n (click)=\"filterButtonClicked($event)\" [label]=\"'Columns'\" [buttonClass]=\"'!text-black'\"></bk-button>\r\n\r\n <!-- Dropdown Box -->\r\n @if(isOpened){\r\n\r\n <div #formBox\r\n class=\"absolute right-0 mt-2 w-[178px] bg-white border border-[#EFEFF1] rounded-xl shadow-xl p-3 pe-1 z-[9999]\">\r\n @if(searchable){\r\n <bk-input class=\"w-full\" [id]=\"'search-input-1'\" [name]=\"'search-input-1'\"\r\n [iconSrc]=\"'../../../../assets/icons/search-input.svg'\" type=\"text\" [(ngModel)]=\"search\"\r\n placeholder=\"Search\"></bk-input>\r\n }\r\n <div class=\"flex flex-col gap-0.5 max-h-[360px] overflow-y-auto\">\r\n @for (column of list; track $index;let i=$index) {\r\n <div class=\"flex items-center gap-2 px-3 py-2\">\r\n <bk-checkbox id=\"columnsFilterList-{{i}}\" checkboxClass=\"sm\" [(ngModel)]=\"column.selected\"\r\n (change)=\"onChangeColumnFilter($event)\">\r\n\r\n </bk-checkbox>\r\n\r\n\r\n\r\n <label class=\"text-xs cursor-pointer text-[#141414] select-none truncate font-medium\"\r\n for=\"columnsFilterList-{{i}}\">\r\n {{column.columnName}}\r\n </label>\r\n </div>\r\n }\r\n @if(!list.length){\r\n <p class=\"text-sm font-medium text-gray-500 mt-3 text-center\">No Records Found</p>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkButton, selector: "bk-button", inputs: ["variant", "size", "label", "leftIcon", "rightIcon", "iconAlt", "type", "loading", "disabled", "buttonClass", "textClass", "spinnerClass"], outputs: ["clicked"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "component", type: BkInput, selector: "bk-input", inputs: ["id", "name", "mask", "autoComplete", "label", "placeholder", "hint", "required", "type", "value", "hasError", "showErrorIcon", "errorMessage", "disabled", "tabIndex", "readOnly", "autoCapitalize", "inputMode", "iconSrc", "iconAlt", "showIcon", "phone", "countryCode", "countryOptions", "iconOrientation", "password", "showPassword", "pattern", "max", "min", "step", "maxlength", "minlength"], outputs: ["input", "change", "focus", "blur", "clicked"] }] });
6835
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkColumnSelect, isStandalone: true, selector: "bk-column-select", inputs: { searchable: "searchable", cacheKey: "cacheKey", columns: "columns", isOpened: "isOpened" }, outputs: { isOpenedChange: "isOpenedChange" }, host: { listeners: { "document:click": "onClick($event)" } }, providers: [
6836
+ {
6837
+ provide: NG_VALUE_ACCESSOR,
6838
+ useExisting: forwardRef(() => BkColumnSelect),
6839
+ multi: true,
6840
+ },
6841
+ ], viewQueries: [{ propertyName: "formBoxRef", first: true, predicate: ["formBox"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"relative\">\r\n\r\n <bk-button [size]=\"'xsm'\" [variant]=\"'secondary'\" [leftIcon]=\"'../../../../assets/icons/columns-black.svg'\"\r\n (click)=\"filterButtonClicked($event)\" [label]=\"'Columns'\" [buttonClass]=\"'!text-black'\"></bk-button>\r\n\r\n <!-- Dropdown Box -->\r\n @if(isOpened){\r\n\r\n <div #formBox\r\n class=\"absolute right-0 mt-2 w-[178px] bg-white border border-[#EFEFF1] rounded-xl shadow-xl p-3 pe-1 z-[9999]\">\r\n @if(searchable){\r\n <bk-input [id]=\"'search-input-1'\" [name]=\"'search-input-1'\"\r\n [iconSrc]=\"'../../../../assets/icons/search-input.svg'\" type=\"text\" [(ngModel)]=\"search\"\r\n placeholder=\"Search\"></bk-input>\r\n }\r\n <div class=\"flex flex-col gap-0.5 max-h-[360px] overflow-y-auto\">\r\n @for (column of list; track column.columnName; let i = $index) {\r\n <div class=\"flex items-center gap-2 px-3 py-2\">\r\n <bk-checkbox id=\"columnsFilterList-{{column.columnName}}\" checkboxClass=\"sm\" [(ngModel)]=\"column.selected\"\r\n (change)=\"onChangeColumnFilter()\">\r\n\r\n </bk-checkbox>\r\n\r\n\r\n\r\n <label class=\"text-xs cursor-pointer text-[#141414] select-none truncate font-medium\"\r\n for=\"columnsFilterList-{{column.columnName}}\">\r\n {{column.columnName}}\r\n </label>\r\n </div>\r\n }\r\n @if(!list.length){\r\n <p class=\"column-select-option-empty\">No items found</p>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n\r\n\r\n", styles: [".column-select-option-empty{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BkButton, selector: "bk-button", inputs: ["variant", "size", "label", "leftIcon", "rightIcon", "iconAlt", "type", "loading", "disabled", "buttonClass", "textClass", "spinnerClass"], outputs: ["clicked"] }, { kind: "component", type: BkCheckbox, selector: "bk-checkbox", inputs: ["checkboxClass", "label", "labelClass", "disabled"], outputs: ["change"] }, { kind: "component", type: BkInput, selector: "bk-input", inputs: ["id", "name", "mask", "autoComplete", "label", "placeholder", "hint", "required", "type", "value", "hasError", "showErrorIcon", "errorMessage", "disabled", "tabIndex", "readOnly", "autoCapitalize", "inputMode", "iconSrc", "iconAlt", "showIcon", "phone", "countryCode", "countryOptions", "iconOrientation", "password", "showPassword", "pattern", "max", "min", "step", "maxlength", "minlength"], outputs: ["input", "change", "focus", "blur", "clicked"] }] });
6800
6842
  }
6801
6843
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkColumnSelect, decorators: [{
6802
6844
  type: Component,
6803
- args: [{ selector: 'bk-column-select', imports: [FormsModule, BkButton, BkCheckbox, BkInput], standalone: true, template: "<div class=\"relative\">\r\n\r\n <bk-button [size]=\"'xsm'\" [variant]=\"'secondary'\" [leftIcon]=\"'../../../../assets/icons/columns-black.svg'\"\r\n (click)=\"filterButtonClicked($event)\" [label]=\"'Columns'\" [buttonClass]=\"'!text-black'\"></bk-button>\r\n\r\n <!-- Dropdown Box -->\r\n @if(isOpened){\r\n\r\n <div #formBox\r\n class=\"absolute right-0 mt-2 w-[178px] bg-white border border-[#EFEFF1] rounded-xl shadow-xl p-3 pe-1 z-[9999]\">\r\n @if(searchable){\r\n <bk-input class=\"w-full\" [id]=\"'search-input-1'\" [name]=\"'search-input-1'\"\r\n [iconSrc]=\"'../../../../assets/icons/search-input.svg'\" type=\"text\" [(ngModel)]=\"search\"\r\n placeholder=\"Search\"></bk-input>\r\n }\r\n <div class=\"flex flex-col gap-0.5 max-h-[360px] overflow-y-auto\">\r\n @for (column of list; track $index;let i=$index) {\r\n <div class=\"flex items-center gap-2 px-3 py-2\">\r\n <bk-checkbox id=\"columnsFilterList-{{i}}\" checkboxClass=\"sm\" [(ngModel)]=\"column.selected\"\r\n (change)=\"onChangeColumnFilter($event)\">\r\n\r\n </bk-checkbox>\r\n\r\n\r\n\r\n <label class=\"text-xs cursor-pointer text-[#141414] select-none truncate font-medium\"\r\n for=\"columnsFilterList-{{i}}\">\r\n {{column.columnName}}\r\n </label>\r\n </div>\r\n }\r\n @if(!list.length){\r\n <p class=\"text-sm font-medium text-gray-500 mt-3 text-center\">No Records Found</p>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n" }]
6845
+ args: [{ selector: 'bk-column-select', imports: [FormsModule, BkButton, BkCheckbox, BkInput], standalone: true, providers: [
6846
+ {
6847
+ provide: NG_VALUE_ACCESSOR,
6848
+ useExisting: forwardRef(() => BkColumnSelect),
6849
+ multi: true,
6850
+ },
6851
+ ], template: "<div class=\"relative\">\r\n\r\n <bk-button [size]=\"'xsm'\" [variant]=\"'secondary'\" [leftIcon]=\"'../../../../assets/icons/columns-black.svg'\"\r\n (click)=\"filterButtonClicked($event)\" [label]=\"'Columns'\" [buttonClass]=\"'!text-black'\"></bk-button>\r\n\r\n <!-- Dropdown Box -->\r\n @if(isOpened){\r\n\r\n <div #formBox\r\n class=\"absolute right-0 mt-2 w-[178px] bg-white border border-[#EFEFF1] rounded-xl shadow-xl p-3 pe-1 z-[9999]\">\r\n @if(searchable){\r\n <bk-input [id]=\"'search-input-1'\" [name]=\"'search-input-1'\"\r\n [iconSrc]=\"'../../../../assets/icons/search-input.svg'\" type=\"text\" [(ngModel)]=\"search\"\r\n placeholder=\"Search\"></bk-input>\r\n }\r\n <div class=\"flex flex-col gap-0.5 max-h-[360px] overflow-y-auto\">\r\n @for (column of list; track column.columnName; let i = $index) {\r\n <div class=\"flex items-center gap-2 px-3 py-2\">\r\n <bk-checkbox id=\"columnsFilterList-{{column.columnName}}\" checkboxClass=\"sm\" [(ngModel)]=\"column.selected\"\r\n (change)=\"onChangeColumnFilter()\">\r\n\r\n </bk-checkbox>\r\n\r\n\r\n\r\n <label class=\"text-xs cursor-pointer text-[#141414] select-none truncate font-medium\"\r\n for=\"columnsFilterList-{{column.columnName}}\">\r\n {{column.columnName}}\r\n </label>\r\n </div>\r\n }\r\n @if(!list.length){\r\n <p class=\"column-select-option-empty\">No items found</p>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n\r\n\r\n", styles: [".column-select-option-empty{@apply px-3 py-2 text-gray-400 cursor-default text-sm;}\n"] }]
6804
6852
  }], ctorParameters: () => [{ type: BkColumnFilterService }], propDecorators: { searchable: [{
6805
6853
  type: Input
6806
6854
  }], cacheKey: [{
@@ -6809,18 +6857,262 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6809
6857
  type: Input
6810
6858
  }], isOpened: [{
6811
6859
  type: Input
6860
+ }], isOpenedChange: [{
6861
+ type: Output
6812
6862
  }], formBoxRef: [{
6813
6863
  type: ViewChild,
6814
6864
  args: ['formBox']
6815
- }], change: [{
6816
- type: Output
6817
- }], isOpenedChange: [{
6818
- type: Output
6819
6865
  }], onClick: [{
6820
6866
  type: HostListener,
6821
6867
  args: ['document:click', ['$event']]
6822
6868
  }] } });
6823
6869
 
6870
+ class BkFilePicker {
6871
+ id = '';
6872
+ name = '';
6873
+ accept = '';
6874
+ multi = false;
6875
+ // @Input() maxFileSizeKB: number | null = null;
6876
+ disable = false;
6877
+ errorMessage = '';
6878
+ hasError = false;
6879
+ draggable = true;
6880
+ set required(val) {
6881
+ this._required = val;
6882
+ this._onValidatorChange?.();
6883
+ }
6884
+ get required() {
6885
+ return this._required;
6886
+ }
6887
+ _required = false;
6888
+ change = new EventEmitter();
6889
+ error = new EventEmitter();
6890
+ cancel = new EventEmitter();
6891
+ fileInputRef;
6892
+ _value = null;
6893
+ _onValidatorChange;
6894
+ onChange = () => { };
6895
+ onTouched = () => { };
6896
+ writeValue(value) {
6897
+ this._value = value;
6898
+ if (!value && this.fileInputRef?.nativeElement) {
6899
+ this.fileInputRef.nativeElement.value = '';
6900
+ }
6901
+ }
6902
+ registerOnChange(fn) {
6903
+ this.onChange = fn;
6904
+ }
6905
+ registerOnTouched(fn) {
6906
+ this.onTouched = fn;
6907
+ }
6908
+ setDisabledState(isDisabled) {
6909
+ this.disable = isDisabled;
6910
+ }
6911
+ validate(control) {
6912
+ if (this.required && !this._value) {
6913
+ return { required: true };
6914
+ }
6915
+ return null;
6916
+ }
6917
+ registerOnValidatorChange(fn) {
6918
+ this._onValidatorChange = fn;
6919
+ }
6920
+ get pickerState() {
6921
+ if (this.disable)
6922
+ return 'disabled';
6923
+ return 'default';
6924
+ }
6925
+ onContainerClick() {
6926
+ if (this.disable)
6927
+ return;
6928
+ this.onTouched(); // ⭐ Touch on interaction start
6929
+ this.fileInputRef?.nativeElement?.click();
6930
+ }
6931
+ onFileChange(event) {
6932
+ // 1. Stop the native HTML change event from bubbling up to the <bk-file-picker> tag
6933
+ event.stopPropagation();
6934
+ const input = event.target;
6935
+ const files = input.files;
6936
+ // 2. Case: User clicked 'Cancel' or no files selected
6937
+ // We update the form state (ngModel) but DO NOT emit the @Output() change
6938
+ if (!files?.length) {
6939
+ this._value = null;
6940
+ this.onChange(null);
6941
+ this.onTouched();
6942
+ return; // Exit without emitting change
6943
+ }
6944
+ const fileList = Array.from(files);
6945
+ // // 3. Case: File exceeds size limit
6946
+ // if (this.maxFileSizeKB != null) {
6947
+ // const maxBytes = this.maxFileSizeKB * 1024;
6948
+ // const oversized = fileList.filter((f) => f.size > maxBytes);
6949
+ // if (oversized.length > 0) {
6950
+ // this.error.emit(`File size exceeds ${this.maxFileSizeKB} KB limit.`);
6951
+ // // Reset internal state and form control
6952
+ // this._value = null;
6953
+ // this.onChange(null);
6954
+ // this.onTouched();
6955
+ // // Reset the physical input so the same file can be picked again later
6956
+ // input.value = '';
6957
+ // return; // Exit without emitting change
6958
+ // }
6959
+ // }
6960
+ // 4. Case: Valid selection
6961
+ const value = this.multi ? fileList : (fileList[0] ?? null);
6962
+ this._value = value;
6963
+ this.onChange(value); // Updates ngModel
6964
+ this.onTouched();
6965
+ // Only emit the custom @Output() now
6966
+ this.change.emit(event);
6967
+ }
6968
+ onCancel() {
6969
+ // Check if there is currently no file selected
6970
+ if (!this._value) {
6971
+ // Reset internal state and notify Angular Forms that the value is null
6972
+ this._value = null;
6973
+ this.onChange(null);
6974
+ // Mark the control as touched to trigger 'required' error visibility
6975
+ this.onTouched();
6976
+ // Force Angular to re-run the 'validate()' function immediately
6977
+ this._onValidatorChange?.();
6978
+ // Clear the native file input value to ensure the browser reset is in sync
6979
+ if (this.fileInputRef?.nativeElement) {
6980
+ this.fileInputRef.nativeElement.value = '';
6981
+ }
6982
+ // Clear any previous error messages (e.g., size limit errors)
6983
+ this.cancel.emit();
6984
+ }
6985
+ }
6986
+ onDragOver(event) {
6987
+ if (this.disable)
6988
+ return;
6989
+ event.preventDefault();
6990
+ event.stopPropagation();
6991
+ }
6992
+ onDrop(event) {
6993
+ if (this.disable)
6994
+ return;
6995
+ event.preventDefault();
6996
+ event.stopPropagation();
6997
+ const input = this.fileInputRef?.nativeElement;
6998
+ if (!input)
6999
+ return;
7000
+ const items = event.dataTransfer?.items;
7001
+ if (!items?.length)
7002
+ return;
7003
+ const files = [];
7004
+ for (let i = 0; i < items.length; i++) {
7005
+ const file = items[i].getAsFile();
7006
+ if (file)
7007
+ files.push(file);
7008
+ }
7009
+ if (files.length === 0)
7010
+ return;
7011
+ const dt = new DataTransfer();
7012
+ (this.multi ? files : [files[0]]).forEach((f) => dt.items.add(f));
7013
+ input.files = dt.files;
7014
+ input.dispatchEvent(new Event('change', { bubbles: true }));
7015
+ }
7016
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkFilePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
7017
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkFilePicker, isStandalone: true, selector: "bk-file-picker", inputs: { id: "id", name: "name", accept: "accept", multi: "multi", disable: "disable", errorMessage: "errorMessage", hasError: "hasError", draggable: "draggable", required: "required" }, outputs: { change: "change", error: "error", cancel: "cancel" }, providers: [
7018
+ {
7019
+ provide: NG_VALUE_ACCESSOR,
7020
+ useExisting: forwardRef(() => BkFilePicker),
7021
+ multi: true,
7022
+ },
7023
+ {
7024
+ provide: NG_VALIDATORS,
7025
+ useExisting: forwardRef(() => BkFilePicker),
7026
+ multi: true,
7027
+ },
7028
+ ], viewQueries: [{ propertyName: "fileInputRef", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: "<div class=\"file-picker-wrapper\">\n <input\n #fileInput\n type=\"file\"\n [id]=\"id\"\n [name]=\"name\"\n [accept]=\"accept\"\n [multiple]=\"multi\"\n [disabled]=\"disable\"\n [required]=\"required\"\n class=\"file-picker__input\"\n (cancel)=\"onCancel()\"\n (change)=\"onFileChange($event)\"\n />\n\n <div\n class=\"file-picker\"\n [ngClass]=\"{\n 'file-picker--default': pickerState === 'default',\n 'file-picker--active': pickerState === 'active',\n 'file-picker--disabled': pickerState === 'disabled',\n 'file-picker-has-error': hasError\n }\"\n (click)=\"onContainerClick()\"\n (dragover)=\"onDragOver($event)\"\n (drop)=\"onDrop($event)\"\n role=\"button\"\n [attr.aria-disabled]=\"disable\"\n tabindex=\"0\"\n>\n <svg\n width=\"48\"\n height=\"48\"\n viewBox=\"0 0 48 48\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"file-picker__icon\">\n <rect\n x=\"3.57007\"\n y=\"3.56995\"\n width=\"40\"\n height=\"40\"\n rx=\"20\"\n [attr.fill]=\"pickerState === 'active' ? '#C7E2FF' : pickerState === 'disabled' ? '#F4F4F6' : '#F4F4F6'\"/>\n <rect\n x=\"3.57007\"\n y=\"3.56995\"\n width=\"40\"\n height=\"40\"\n rx=\"20\"\n [attr.stroke]=\"pickerState === 'active' ? '#E5F3FF' : pickerState === 'disabled' ? '#F9FAFA' : '#F9FAFA'\"\n stroke-width=\"7.14\"/>\n <g clip-path=\"url(#clip0_1_149094)\">\n <path\n d=\"M23.5702 20.2366V23.5699M23.5702 26.9032H23.5785M31.9035 23.5699C31.9035 28.1723 28.1725 31.9032 23.5702 31.9032C18.9678 31.9032 15.2368 28.1723 15.2368 23.5699C15.2368 18.9675 18.9678 15.2366 23.5702 15.2366C28.1725 15.2366 31.9035 18.9675 31.9035 23.5699Z\"\n [attr.stroke]=\"pickerState === 'active' ? '#1434CB' : pickerState === 'disabled' ? '#868997' : '#868997'\"\n stroke-width=\"1.66667\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"/>\n </g>\n <defs>\n <clipPath id=\"clip0_1_149094\">\n <rect width=\"20\" height=\"20\" fill=\"white\" transform=\"translate(13.5701 13.5699)\"/>\n </clipPath>\n </defs>\n </svg>\n <p\n class=\"file-picker__text-primary\"\n [ngClass]=\"{\n 'file-picker__text-primary--default': pickerState === 'default',\n 'file-picker__text-primary--active': pickerState === 'active',\n 'file-picker__text-primary--disabled': pickerState === 'disabled'\n }\">\n <span\n [ngClass]=\"{\n 'file-picker__text-primary-bold--default': pickerState === 'default',\n 'file-picker__text-primary-bold--active': pickerState === 'active',\n 'file-picker__text-primary-bold--disabled': pickerState === 'disabled'\n }\">Click to upload</span> or drag and drop\n </p>\n <p\n class=\"file-picker__text-secondary\"\n [ngClass]=\"{\n 'file-picker__text-secondary--default': pickerState === 'default',\n 'file-picker__text-secondary--active': pickerState === 'active',\n 'file-picker__text-secondary--disabled': pickerState === 'disabled'\n }\">SVG, PNG, JPG or GIF (max. 800x400px)</p>\n </div>\n\n @if (hasError) {\n @if (errorMessage) {\n <p class=\"file-picker-error\">{{ errorMessage }}</p>\n }\n }\n</div>\n", styles: [".file-picker-wrapper{@apply relative w-full;}.file-picker__input{@apply absolute opacity-0 w-0 h-0 overflow-hidden pointer-events-none;}.file-picker{@apply py-4 px-6 inline-flex flex-col justify-center items-center rounded-lg cursor-pointer transition-all duration-200 w-full relative;}.file-picker-has-error{@apply border-[#d11e14];}.file-picker-error{@apply text-xs text-[#E7000B] font-normal;}.file-picker--default{@apply border border-[#E5F3FF] bg-white;}.file-picker--active{@apply border border-[#E5F3FF] bg-[#F4FAFF];}.file-picker--disabled{@apply border border-[#D6D7DC] bg-[#F4F4F6] opacity-60 cursor-not-allowed;}.file-picker__icon{@apply mb-3;}.file-picker__text-primary{@apply font-normal text-sm tracking-normal mb-1;}.file-picker__text-primary--default,.file-picker__text-primary--active{@apply text-[#1B223A];}.file-picker__text-primary--disabled{@apply text-[#A1A3AE];}.file-picker__text-primary-bold--default,.file-picker__text-primary-bold--active{@apply font-medium text-[#102BA5];}.file-picker__text-primary-bold--disabled{@apply font-medium text-[#A1A3AE];}.file-picker__text-secondary{@apply font-normal text-xs leading-[18px];}.file-picker__text-secondary--default,.file-picker__text-secondary--active{@apply text-[#6B7080];}.file-picker__text-secondary--disabled{@apply text-[#A1A3AE];}.file-picker__file-item{@apply p-4 border border-[#EFEFF1] rounded-lg bg-white flex items-start justify-between mb-1;}.file-picker__file-content{@apply flex gap-4;}.file-picker__file-info-title{@apply font-medium text-sm text-[#1B223A];}.file-picker__file-info-size{@apply text-[#1B223A] font-normal text-sm;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
7029
+ }
7030
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkFilePicker, decorators: [{
7031
+ type: Component,
7032
+ args: [{ selector: 'bk-file-picker', imports: [CommonModule], standalone: true, providers: [
7033
+ {
7034
+ provide: NG_VALUE_ACCESSOR,
7035
+ useExisting: forwardRef(() => BkFilePicker),
7036
+ multi: true,
7037
+ },
7038
+ {
7039
+ provide: NG_VALIDATORS,
7040
+ useExisting: forwardRef(() => BkFilePicker),
7041
+ multi: true,
7042
+ },
7043
+ ], template: "<div class=\"file-picker-wrapper\">\n <input\n #fileInput\n type=\"file\"\n [id]=\"id\"\n [name]=\"name\"\n [accept]=\"accept\"\n [multiple]=\"multi\"\n [disabled]=\"disable\"\n [required]=\"required\"\n class=\"file-picker__input\"\n (cancel)=\"onCancel()\"\n (change)=\"onFileChange($event)\"\n />\n\n <div\n class=\"file-picker\"\n [ngClass]=\"{\n 'file-picker--default': pickerState === 'default',\n 'file-picker--active': pickerState === 'active',\n 'file-picker--disabled': pickerState === 'disabled',\n 'file-picker-has-error': hasError\n }\"\n (click)=\"onContainerClick()\"\n (dragover)=\"onDragOver($event)\"\n (drop)=\"onDrop($event)\"\n role=\"button\"\n [attr.aria-disabled]=\"disable\"\n tabindex=\"0\"\n>\n <svg\n width=\"48\"\n height=\"48\"\n viewBox=\"0 0 48 48\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"file-picker__icon\">\n <rect\n x=\"3.57007\"\n y=\"3.56995\"\n width=\"40\"\n height=\"40\"\n rx=\"20\"\n [attr.fill]=\"pickerState === 'active' ? '#C7E2FF' : pickerState === 'disabled' ? '#F4F4F6' : '#F4F4F6'\"/>\n <rect\n x=\"3.57007\"\n y=\"3.56995\"\n width=\"40\"\n height=\"40\"\n rx=\"20\"\n [attr.stroke]=\"pickerState === 'active' ? '#E5F3FF' : pickerState === 'disabled' ? '#F9FAFA' : '#F9FAFA'\"\n stroke-width=\"7.14\"/>\n <g clip-path=\"url(#clip0_1_149094)\">\n <path\n d=\"M23.5702 20.2366V23.5699M23.5702 26.9032H23.5785M31.9035 23.5699C31.9035 28.1723 28.1725 31.9032 23.5702 31.9032C18.9678 31.9032 15.2368 28.1723 15.2368 23.5699C15.2368 18.9675 18.9678 15.2366 23.5702 15.2366C28.1725 15.2366 31.9035 18.9675 31.9035 23.5699Z\"\n [attr.stroke]=\"pickerState === 'active' ? '#1434CB' : pickerState === 'disabled' ? '#868997' : '#868997'\"\n stroke-width=\"1.66667\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"/>\n </g>\n <defs>\n <clipPath id=\"clip0_1_149094\">\n <rect width=\"20\" height=\"20\" fill=\"white\" transform=\"translate(13.5701 13.5699)\"/>\n </clipPath>\n </defs>\n </svg>\n <p\n class=\"file-picker__text-primary\"\n [ngClass]=\"{\n 'file-picker__text-primary--default': pickerState === 'default',\n 'file-picker__text-primary--active': pickerState === 'active',\n 'file-picker__text-primary--disabled': pickerState === 'disabled'\n }\">\n <span\n [ngClass]=\"{\n 'file-picker__text-primary-bold--default': pickerState === 'default',\n 'file-picker__text-primary-bold--active': pickerState === 'active',\n 'file-picker__text-primary-bold--disabled': pickerState === 'disabled'\n }\">Click to upload</span> or drag and drop\n </p>\n <p\n class=\"file-picker__text-secondary\"\n [ngClass]=\"{\n 'file-picker__text-secondary--default': pickerState === 'default',\n 'file-picker__text-secondary--active': pickerState === 'active',\n 'file-picker__text-secondary--disabled': pickerState === 'disabled'\n }\">SVG, PNG, JPG or GIF (max. 800x400px)</p>\n </div>\n\n @if (hasError) {\n @if (errorMessage) {\n <p class=\"file-picker-error\">{{ errorMessage }}</p>\n }\n }\n</div>\n", styles: [".file-picker-wrapper{@apply relative w-full;}.file-picker__input{@apply absolute opacity-0 w-0 h-0 overflow-hidden pointer-events-none;}.file-picker{@apply py-4 px-6 inline-flex flex-col justify-center items-center rounded-lg cursor-pointer transition-all duration-200 w-full relative;}.file-picker-has-error{@apply border-[#d11e14];}.file-picker-error{@apply text-xs text-[#E7000B] font-normal;}.file-picker--default{@apply border border-[#E5F3FF] bg-white;}.file-picker--active{@apply border border-[#E5F3FF] bg-[#F4FAFF];}.file-picker--disabled{@apply border border-[#D6D7DC] bg-[#F4F4F6] opacity-60 cursor-not-allowed;}.file-picker__icon{@apply mb-3;}.file-picker__text-primary{@apply font-normal text-sm tracking-normal mb-1;}.file-picker__text-primary--default,.file-picker__text-primary--active{@apply text-[#1B223A];}.file-picker__text-primary--disabled{@apply text-[#A1A3AE];}.file-picker__text-primary-bold--default,.file-picker__text-primary-bold--active{@apply font-medium text-[#102BA5];}.file-picker__text-primary-bold--disabled{@apply font-medium text-[#A1A3AE];}.file-picker__text-secondary{@apply font-normal text-xs leading-[18px];}.file-picker__text-secondary--default,.file-picker__text-secondary--active{@apply text-[#6B7080];}.file-picker__text-secondary--disabled{@apply text-[#A1A3AE];}.file-picker__file-item{@apply p-4 border border-[#EFEFF1] rounded-lg bg-white flex items-start justify-between mb-1;}.file-picker__file-content{@apply flex gap-4;}.file-picker__file-info-title{@apply font-medium text-sm text-[#1B223A];}.file-picker__file-info-size{@apply text-[#1B223A] font-normal text-sm;}\n"] }]
7044
+ }], propDecorators: { id: [{
7045
+ type: Input
7046
+ }], name: [{
7047
+ type: Input
7048
+ }], accept: [{
7049
+ type: Input
7050
+ }], multi: [{
7051
+ type: Input
7052
+ }], disable: [{
7053
+ type: Input
7054
+ }], errorMessage: [{
7055
+ type: Input
7056
+ }], hasError: [{
7057
+ type: Input
7058
+ }], draggable: [{
7059
+ type: Input
7060
+ }], required: [{
7061
+ type: Input
7062
+ }], change: [{
7063
+ type: Output
7064
+ }], error: [{
7065
+ type: Output
7066
+ }], cancel: [{
7067
+ type: Output
7068
+ }], fileInputRef: [{
7069
+ type: ViewChild,
7070
+ args: ['fileInput']
7071
+ }] } });
7072
+
7073
+ class BkFileCard {
7074
+ id = '';
7075
+ state = 'uploading';
7076
+ fileName = 'Tech design requirements.pdf';
7077
+ fileSize = '200 KB';
7078
+ progress = 65; // Progress percentage (0-100)
7079
+ errorMessage = 'Upload failed, please try again';
7080
+ remove = new EventEmitter();
7081
+ /**
7082
+ *
7083
+ */
7084
+ constructor() {
7085
+ }
7086
+ ngOnInit() {
7087
+ if (!this.id) {
7088
+ this.id = crypto.randomUUID();
7089
+ }
7090
+ }
7091
+ onRemove() {
7092
+ this.remove.emit(this.id);
7093
+ }
7094
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkFileCard, deps: [], target: i0.ɵɵFactoryTarget.Component });
7095
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkFileCard, isStandalone: true, selector: "bk-file-card", inputs: { id: "id", state: "state", fileName: "fileName", fileSize: "fileSize", progress: "progress", errorMessage: "errorMessage" }, outputs: { remove: "remove" }, ngImport: i0, template: "\r\n <div\r\n class=\"file-uploader\"\r\n [ngClass]=\"{\r\n 'file-uploader--uploading': state === 'uploading',\r\n 'file-uploader--uploaded': state === 'uploaded',\r\n 'file-uploader--failed': state === 'failed'\r\n }\">\r\n <!-- Icon Section -->\r\n <div class=\"file-uploader__icon-container\">\r\n <svg\r\n width=\"48\"\r\n height=\"48\"\r\n viewBox=\"0 0 48 48\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n class=\"file-uploader__icon\">\r\n <rect\r\n x=\"3.57007\"\r\n y=\"3.56995\"\r\n width=\"40\"\r\n height=\"40\"\r\n rx=\"20\"\r\n [attr.fill]=\"state === 'uploading' ? '#C7E2FF' : state === 'uploaded' ? '#C7E2FF' : '#FECACA'\"/>\r\n <rect\r\n x=\"3.57007\"\r\n y=\"3.56995\"\r\n width=\"40\"\r\n height=\"40\"\r\n rx=\"20\"\r\n [attr.stroke]=\"state === 'uploading' ? '#E5F3FF' : state === 'uploaded' ? '#E5F3FF' : '#FEE2E2'\"\r\n stroke-width=\"7.14\"/>\r\n <g clip-path=\"url(#clip0_1_149094)\">\r\n <path\r\n d=\"M23.5702 20.2366V23.5699M23.5702 26.9032H23.5785M31.9035 23.5699C31.9035 28.1723 28.1725 31.9032 23.5702 31.9032C18.9678 31.9032 15.2368 28.1723 15.2368 23.5699C15.2368 18.9675 18.9678 15.2366 23.5702 15.2366C28.1725 15.2366 31.9035 18.9675 31.9035 23.5699Z\"\r\n [attr.stroke]=\"state === 'uploading' ? '#1434CB' : state === 'uploaded' ? '#1434CB' : '#EF4444'\"\r\n stroke-width=\"1.66667\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"/>\r\n </g>\r\n <defs>\r\n <clipPath id=\"clip0_1_149094\">\r\n <rect width=\"20\" height=\"20\" fill=\"white\" transform=\"translate(13.5701 13.5699)\"/>\r\n </clipPath>\r\n </defs>\r\n </svg>\r\n </div>\r\n\r\n <!-- Content Section -->\r\n <div class=\"file-uploader__content\">\r\n <!-- Row 1: File Info + Delete -->\r\n <div class=\"file-uploader__row-1\">\r\n <div class=\"file-uploader__file-info\">\r\n <!-- Uploading State -->\r\n\r\n @if (state === 'uploading' || state === 'uploaded') {\r\n <ng-container>\r\n <span class=\"file-uploader__file-name\">{{ fileName }}</span>\r\n <span class=\"file-uploader__file-size\">{{ fileSize }}</span>\r\n </ng-container>\r\n }\r\n\r\n @if(state === 'failed'){\r\n <!-- Failed State -->\r\n <ng-container>\r\n <p class=\"file-uploader__error-message\">{{ errorMessage }}</p>\r\n <span class=\"file-uploader__file-name file-uploader__file-name--failed\">{{ fileName }}</span>\r\n <p class=\"file-uploader__error-message\">Try again</p>\r\n </ng-container>\r\n }\r\n </div>\r\n ../../../../assets/images/icons/global/bin-gray.svg\r\n <img\r\n src=\"../../assets/icons/bin-gray.svg\"\r\n alt=\"Delete\"\r\n bkTooltip=\"Delete\"\r\n bkTooltipPosition=\"left\"\r\n class=\"file-uploader__delete-icon\"\r\n (click)=\"onRemove()\"\r\n >\r\n </div>\r\n\r\n <!-- Row 2: Progress Bar + Percentage -->\r\n <div class=\"file-uploader__row-2\">\r\n @if (state === 'uploading') {\r\n <!-- Uploading State -->\r\n <ng-container>\r\n <div class=\"file-uploader__progress-bar\">\r\n <div\r\n class=\"file-uploader__progress-fill\"\r\n [style.width.%]=\"progress\"></div>\r\n </div>\r\n <span class=\"file-uploader__progress-text\">{{ progress }}%</span>\r\n </ng-container>\r\n }\r\n @if(state === 'uploaded'){\r\n <!-- Uploaded State -->\r\n <ng-container>\r\n <div class=\"file-uploader__progress-bar\">\r\n <div class=\"file-uploader__progress-fill file-uploader__progress-fill--complete\"></div>\r\n </div>\r\n <img src=\"../../assets/icons/check-green.svg\" alt=\"\" class=\"file-uploader__checkmark\">\r\n </ng-container>\r\n }\r\n\r\n </div>\r\n </div>\r\n </div>\r\n\r\n\r\n", styles: [".file-uploader{@apply p-4 flex gap-4 border rounded-lg border-transparent bg-[white];}.file-uploader--uploading{@apply border-[#EFEFF1];}.file-uploader--uploaded{@apply border-[#1434CB];}.file-uploader--failed{@apply border-[#FDA4A8] bg-[#FFF1F1];}.file-uploader__icon-container,.file-uploader__icon{@apply flex-shrink-0;}.file-uploader__content{@apply flex flex-col flex-1 gap-0;}.file-uploader__row-1{@apply flex items-start justify-between;}.file-uploader__file-info{@apply flex flex-col;}.file-uploader__file-name{@apply font-medium text-sm text-[#1B223A];}.file-uploader__file-name--failed{@apply text-[#B41E32] font-normal mb-1;}.file-uploader__file-size{@apply text-[#1B223A] font-normal text-sm;}.file-uploader__row-2{@apply flex justify-between items-center gap-3 mt-1;}.file-uploader--failed .file-uploader__row-2{@apply mt-0;}.file-uploader__progress-bar{@apply flex-1 h-2 bg-[#EFEFF1] rounded-full overflow-hidden;}.file-uploader__progress-fill{@apply h-full bg-[#1336EF] transition-all duration-300 rounded-full;}.file-uploader__progress-fill--complete{@apply bg-[#22973F];}.file-uploader__progress-text{@apply text-sm text-[#6B7080] font-medium;}.file-uploader__checkmark{@apply flex-shrink-0 size-[14px];}.file-uploader__error-message{@apply text-[#B41E32] font-medium text-sm;}.file-uploader__delete-icon{@apply flex-shrink-0 cursor-pointer size-5;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: BKTooltipDirective, selector: "[bkTooltip]", inputs: ["bkTooltip", "bkTooltipPosition"] }] });
7096
+ }
7097
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkFileCard, decorators: [{
7098
+ type: Component,
7099
+ args: [{ imports: [CommonModule, BKTooltipDirective], selector: 'bk-file-card', standalone: true, template: "\r\n <div\r\n class=\"file-uploader\"\r\n [ngClass]=\"{\r\n 'file-uploader--uploading': state === 'uploading',\r\n 'file-uploader--uploaded': state === 'uploaded',\r\n 'file-uploader--failed': state === 'failed'\r\n }\">\r\n <!-- Icon Section -->\r\n <div class=\"file-uploader__icon-container\">\r\n <svg\r\n width=\"48\"\r\n height=\"48\"\r\n viewBox=\"0 0 48 48\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n class=\"file-uploader__icon\">\r\n <rect\r\n x=\"3.57007\"\r\n y=\"3.56995\"\r\n width=\"40\"\r\n height=\"40\"\r\n rx=\"20\"\r\n [attr.fill]=\"state === 'uploading' ? '#C7E2FF' : state === 'uploaded' ? '#C7E2FF' : '#FECACA'\"/>\r\n <rect\r\n x=\"3.57007\"\r\n y=\"3.56995\"\r\n width=\"40\"\r\n height=\"40\"\r\n rx=\"20\"\r\n [attr.stroke]=\"state === 'uploading' ? '#E5F3FF' : state === 'uploaded' ? '#E5F3FF' : '#FEE2E2'\"\r\n stroke-width=\"7.14\"/>\r\n <g clip-path=\"url(#clip0_1_149094)\">\r\n <path\r\n d=\"M23.5702 20.2366V23.5699M23.5702 26.9032H23.5785M31.9035 23.5699C31.9035 28.1723 28.1725 31.9032 23.5702 31.9032C18.9678 31.9032 15.2368 28.1723 15.2368 23.5699C15.2368 18.9675 18.9678 15.2366 23.5702 15.2366C28.1725 15.2366 31.9035 18.9675 31.9035 23.5699Z\"\r\n [attr.stroke]=\"state === 'uploading' ? '#1434CB' : state === 'uploaded' ? '#1434CB' : '#EF4444'\"\r\n stroke-width=\"1.66667\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"/>\r\n </g>\r\n <defs>\r\n <clipPath id=\"clip0_1_149094\">\r\n <rect width=\"20\" height=\"20\" fill=\"white\" transform=\"translate(13.5701 13.5699)\"/>\r\n </clipPath>\r\n </defs>\r\n </svg>\r\n </div>\r\n\r\n <!-- Content Section -->\r\n <div class=\"file-uploader__content\">\r\n <!-- Row 1: File Info + Delete -->\r\n <div class=\"file-uploader__row-1\">\r\n <div class=\"file-uploader__file-info\">\r\n <!-- Uploading State -->\r\n\r\n @if (state === 'uploading' || state === 'uploaded') {\r\n <ng-container>\r\n <span class=\"file-uploader__file-name\">{{ fileName }}</span>\r\n <span class=\"file-uploader__file-size\">{{ fileSize }}</span>\r\n </ng-container>\r\n }\r\n\r\n @if(state === 'failed'){\r\n <!-- Failed State -->\r\n <ng-container>\r\n <p class=\"file-uploader__error-message\">{{ errorMessage }}</p>\r\n <span class=\"file-uploader__file-name file-uploader__file-name--failed\">{{ fileName }}</span>\r\n <p class=\"file-uploader__error-message\">Try again</p>\r\n </ng-container>\r\n }\r\n </div>\r\n ../../../../assets/images/icons/global/bin-gray.svg\r\n <img\r\n src=\"../../assets/icons/bin-gray.svg\"\r\n alt=\"Delete\"\r\n bkTooltip=\"Delete\"\r\n bkTooltipPosition=\"left\"\r\n class=\"file-uploader__delete-icon\"\r\n (click)=\"onRemove()\"\r\n >\r\n </div>\r\n\r\n <!-- Row 2: Progress Bar + Percentage -->\r\n <div class=\"file-uploader__row-2\">\r\n @if (state === 'uploading') {\r\n <!-- Uploading State -->\r\n <ng-container>\r\n <div class=\"file-uploader__progress-bar\">\r\n <div\r\n class=\"file-uploader__progress-fill\"\r\n [style.width.%]=\"progress\"></div>\r\n </div>\r\n <span class=\"file-uploader__progress-text\">{{ progress }}%</span>\r\n </ng-container>\r\n }\r\n @if(state === 'uploaded'){\r\n <!-- Uploaded State -->\r\n <ng-container>\r\n <div class=\"file-uploader__progress-bar\">\r\n <div class=\"file-uploader__progress-fill file-uploader__progress-fill--complete\"></div>\r\n </div>\r\n <img src=\"../../assets/icons/check-green.svg\" alt=\"\" class=\"file-uploader__checkmark\">\r\n </ng-container>\r\n }\r\n\r\n </div>\r\n </div>\r\n </div>\r\n\r\n\r\n", styles: [".file-uploader{@apply p-4 flex gap-4 border rounded-lg border-transparent bg-[white];}.file-uploader--uploading{@apply border-[#EFEFF1];}.file-uploader--uploaded{@apply border-[#1434CB];}.file-uploader--failed{@apply border-[#FDA4A8] bg-[#FFF1F1];}.file-uploader__icon-container,.file-uploader__icon{@apply flex-shrink-0;}.file-uploader__content{@apply flex flex-col flex-1 gap-0;}.file-uploader__row-1{@apply flex items-start justify-between;}.file-uploader__file-info{@apply flex flex-col;}.file-uploader__file-name{@apply font-medium text-sm text-[#1B223A];}.file-uploader__file-name--failed{@apply text-[#B41E32] font-normal mb-1;}.file-uploader__file-size{@apply text-[#1B223A] font-normal text-sm;}.file-uploader__row-2{@apply flex justify-between items-center gap-3 mt-1;}.file-uploader--failed .file-uploader__row-2{@apply mt-0;}.file-uploader__progress-bar{@apply flex-1 h-2 bg-[#EFEFF1] rounded-full overflow-hidden;}.file-uploader__progress-fill{@apply h-full bg-[#1336EF] transition-all duration-300 rounded-full;}.file-uploader__progress-fill--complete{@apply bg-[#22973F];}.file-uploader__progress-text{@apply text-sm text-[#6B7080] font-medium;}.file-uploader__checkmark{@apply flex-shrink-0 size-[14px];}.file-uploader__error-message{@apply text-[#B41E32] font-medium text-sm;}.file-uploader__delete-icon{@apply flex-shrink-0 cursor-pointer size-5;}\n"] }]
7100
+ }], ctorParameters: () => [], propDecorators: { id: [{
7101
+ type: Input
7102
+ }], state: [{
7103
+ type: Input
7104
+ }], fileName: [{
7105
+ type: Input
7106
+ }], fileSize: [{
7107
+ type: Input
7108
+ }], progress: [{
7109
+ type: Input
7110
+ }], errorMessage: [{
7111
+ type: Input
7112
+ }], remove: [{
7113
+ type: Output
7114
+ }] } });
7115
+
6824
7116
  /*
6825
7117
  * Public API Surface of brickclay-lib
6826
7118
  */
@@ -6830,5 +7122,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6830
7122
  * Generated bundle index. Do not edit.
6831
7123
  */
6832
7124
 
6833
- export { BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BkAvatar, BkAvatarUploader, BkBadge, BkButton, BkButtonGroup, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkPill, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTabs, BkTextarea, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkValidator, BrickclayIcons, BrickclayLib, CalendarManagerService, CalendarModule, CalendarSelection, ColumnFilterOption, getDialogBackdropAnimation, getDialogPanelAnimation };
7125
+ export { BKTooltipDirective, BK_DEFAULT_DIALOG_CONFIG, BK_DIALOG_DATA, BK_DIALOG_GLOBAL_CONFIG, BkAvatar, BkAvatarUploader, BkBadge, BkButton, BkButtonGroup, BkCheckbox, BkColumnFilterService, BkColumnSelect, BkCustomCalendar, BkDialogActions, BkDialogClose, BkDialogContent, BkDialogModule, BkDialogRef, BkDialogService, BkDialogTitle, BkFileCard, BkFilePicker, BkGrid, BkHierarchicalSelect, BkIconButton, BkInput, BkInputChips, BkPill, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTabs, BkTextarea, BkTimePicker, BkToastr, BkToastrService, BkToggle, BkValidator, BrickclayIcons, BrickclayLib, CalendarManagerService, CalendarModule, CalendarSelection, ColumnFilterOption, getDialogBackdropAnimation, getDialogPanelAnimation };
6834
7126
  //# sourceMappingURL=brickclay-org-ui.mjs.map