@brickclay-org/ui 0.0.30 → 0.0.32
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.
- package/fesm2022/brickclay-org-ui.mjs +287 -74
- package/fesm2022/brickclay-org-ui.mjs.map +1 -1
- package/index.d.ts +76 -17
- package/package.json +1 -1
- package/src/lib/chips/chips.css +147 -0
- package/src/styles.css +1 -1
|
@@ -2776,6 +2776,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
2776
2776
|
|
|
2777
2777
|
class BkTextarea {
|
|
2778
2778
|
ngControl;
|
|
2779
|
+
autoComplete = 'off';
|
|
2779
2780
|
name;
|
|
2780
2781
|
id;
|
|
2781
2782
|
label = '';
|
|
@@ -2783,17 +2784,20 @@ class BkTextarea {
|
|
|
2783
2784
|
rows = 4;
|
|
2784
2785
|
hint = '';
|
|
2785
2786
|
required = false;
|
|
2786
|
-
|
|
2787
|
+
maxlength = null;
|
|
2788
|
+
minlength = null;
|
|
2787
2789
|
hasError = false;
|
|
2790
|
+
disabled = false;
|
|
2788
2791
|
errorMessage = '';
|
|
2789
|
-
|
|
2790
|
-
|
|
2792
|
+
tabIndex = null;
|
|
2793
|
+
readOnly = false;
|
|
2794
|
+
autoCapitalize = null;
|
|
2795
|
+
inputMode = null;
|
|
2791
2796
|
input = new EventEmitter();
|
|
2792
2797
|
change = new EventEmitter();
|
|
2793
2798
|
blur = new EventEmitter();
|
|
2794
2799
|
focus = new EventEmitter();
|
|
2795
2800
|
value = '';
|
|
2796
|
-
isDisabled = false;
|
|
2797
2801
|
// --- ControlValueAccessor ---
|
|
2798
2802
|
onChange = (_) => { };
|
|
2799
2803
|
onTouched = () => { };
|
|
@@ -2803,11 +2807,6 @@ class BkTextarea {
|
|
|
2803
2807
|
this.ngControl.valueAccessor = this;
|
|
2804
2808
|
}
|
|
2805
2809
|
}
|
|
2806
|
-
// --- Computed ID ---
|
|
2807
|
-
get effectiveId() {
|
|
2808
|
-
const base = 'brickclay_textarea_';
|
|
2809
|
-
return this.id ? `${base}${this.id}` : `${base}${this.label?.replace(/\s+/g, '_').toLowerCase()}`;
|
|
2810
|
-
}
|
|
2811
2810
|
// --- Expose FormControl state ---
|
|
2812
2811
|
get control() {
|
|
2813
2812
|
return this.ngControl?.control;
|
|
@@ -2821,52 +2820,21 @@ class BkTextarea {
|
|
|
2821
2820
|
get errors() {
|
|
2822
2821
|
return this.control?.errors;
|
|
2823
2822
|
}
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
return true;
|
|
2827
|
-
if (!this.control)
|
|
2828
|
-
return false;
|
|
2829
|
-
return (this.required && (this.control.dirty || this.control.touched) &&
|
|
2830
|
-
this.control.invalid &&
|
|
2831
|
-
this.control.errors?.['required']);
|
|
2823
|
+
handleFocus(event) {
|
|
2824
|
+
this.focus.emit(event);
|
|
2832
2825
|
}
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
}, 300); // small delay for input event
|
|
2846
|
-
}
|
|
2847
|
-
else if (this.trimWhiteSpaces) {
|
|
2848
|
-
this.value = this.value.trim();
|
|
2849
|
-
input.value = this.value;
|
|
2850
|
-
}
|
|
2851
|
-
// Update ngModel depending on event type
|
|
2852
|
-
if (this.eventType === 'input' && event.type === 'input')
|
|
2853
|
-
this.onChange(this.value);
|
|
2854
|
-
if (this.eventType === 'change' && event.type === 'change')
|
|
2855
|
-
this.onChange(this.value);
|
|
2856
|
-
if (this.eventType === 'blur' && event.type === 'blur')
|
|
2857
|
-
this.onChange(this.value);
|
|
2858
|
-
// Always mark as touched on blur/focus
|
|
2859
|
-
if (event.type === 'blur' || event.type === 'focus')
|
|
2860
|
-
this.onTouched();
|
|
2861
|
-
// ---- Emit component outputs ----
|
|
2862
|
-
if (event.type === 'input')
|
|
2863
|
-
this.input.emit(event);
|
|
2864
|
-
if (event.type === 'change')
|
|
2865
|
-
this.change.emit(event);
|
|
2866
|
-
if (event.type === 'blur')
|
|
2867
|
-
this.blur.emit(event);
|
|
2868
|
-
if (event.type === 'focus')
|
|
2869
|
-
this.focus.emit(event);
|
|
2826
|
+
handleBlur(event) {
|
|
2827
|
+
this.onTouched();
|
|
2828
|
+
this.blur.emit(event);
|
|
2829
|
+
}
|
|
2830
|
+
handleInput(event) {
|
|
2831
|
+
const val = event.target.value;
|
|
2832
|
+
this.value = val; // update CVA value
|
|
2833
|
+
this.onChange(val); // propagate to parent form
|
|
2834
|
+
this.input.emit(event); // emit raw event
|
|
2835
|
+
}
|
|
2836
|
+
handleChange(event) {
|
|
2837
|
+
this.change.emit(event); // emit raw change event
|
|
2870
2838
|
}
|
|
2871
2839
|
writeValue(value) {
|
|
2872
2840
|
this.value = value ?? '';
|
|
@@ -2877,20 +2845,19 @@ class BkTextarea {
|
|
|
2877
2845
|
registerOnTouched(fn) {
|
|
2878
2846
|
this.onTouched = fn;
|
|
2879
2847
|
}
|
|
2880
|
-
setDisabledState(isDisabled) {
|
|
2881
|
-
this.isDisabled = isDisabled;
|
|
2882
|
-
}
|
|
2883
2848
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTextarea, deps: [{ token: i1$1.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
2884
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTextarea, isStandalone: true, selector: "bk-textarea", inputs: { name: "name", id: "id", label: "label", placeholder: "placeholder", rows: "rows", hint: "hint", required: "required",
|
|
2849
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkTextarea, isStandalone: true, selector: "bk-textarea", inputs: { autoComplete: "autoComplete", name: "name", id: "id", label: "label", placeholder: "placeholder", rows: "rows", hint: "hint", required: "required", maxlength: "maxlength", minlength: "minlength", hasError: "hasError", disabled: "disabled", errorMessage: "errorMessage", tabIndex: "tabIndex", readOnly: "readOnly", autoCapitalize: "autoCapitalize", inputMode: "inputMode" }, outputs: { input: "input", change: "change", blur: "blur", focus: "focus" }, ngImport: i0, template: "<div class=\"flex flex-col gap-1.5 w-full\">\r\n\r\n @if (label) {\r\n <label\r\n class=\"text-sm font-medium text-[#141414] block\" [for]=\"id\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"text-[#E7000B] ml-0.5\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"relative\">\r\n <textarea\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [disabled]=\"disabled\"\r\n [tabindex]=\"tabIndex\"\r\n [readOnly]=\"readOnly\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [autocomplete]=\"autoComplete\"\r\n [autocapitalize]=\"autoCapitalize\"\r\n [inputMode]=\"inputMode\"\r\n [value]=\"value\"\r\n (input)=\"handleInput($event)\"\r\n (change)=\"handleChange($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n [placeholder]=\"placeholder\"\r\n\r\n [autocomplete]=\"autoComplete\"\r\n\r\n rows=\"{{rows}}\"\r\n class=\"\r\n w-full\r\n px-3 py-2.5\r\n text-sm\r\n border border-[#E3E3E7] rounded-[4px]\r\n outline-none\r\n transition-colors duration-200\r\n bg-white resize-y\r\n placeholder:text-[#6B7080]\r\n \"\r\n [ngClass]=\"{\r\n 'border-[#FA727A] text-[#141414]': hasError && !disabled,\r\n\r\n 'focus:border-[#6B7080] text-[#141414]': !hasError && !disabled,\r\n\r\n 'bg-[#F4F4F6] text-[#A1A3AE] border-[#E3E3E7] cursor-not-allowed': disabled\r\n }\"\r\n ></textarea>\r\n </div>\r\n\r\n <div class=\"flex justify-between items-start font-normal text-sm\">\r\n\r\n <div class=\"flex-1\">\r\n @if (hasError) {\r\n <span class=\"text-[#F34050]\">\r\n {{ errorMessage }}\r\n </span>\r\n } @else if (hint) {\r\n <span class=\"text-[#868997]\">\r\n {{ hint }}\r\n </span>\r\n }\r\n </div>\r\n\r\n @if (maxlength) {\r\n <div\r\n class=\"text-[#868997] tabular-nums flex-shrink-0\"\r\n >\r\n {{ value.length }}/{{ maxlength }}\r\n </div>\r\n }\r\n\r\n\r\n </div>\r\n\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }] });
|
|
2885
2850
|
}
|
|
2886
2851
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkTextarea, decorators: [{
|
|
2887
2852
|
type: Component,
|
|
2888
|
-
args: [{ selector: 'bk-textarea', standalone: true, imports: [CommonModule, FormsModule], template: "<div class=\"flex flex-col gap-1.5 w-full\">\r\n\r\n @if (label) {\r\n <label\r\n class=\"text-sm font-medium text-[#141414] block\" [
|
|
2853
|
+
args: [{ selector: 'bk-textarea', standalone: true, imports: [CommonModule, FormsModule], template: "<div class=\"flex flex-col gap-1.5 w-full\">\r\n\r\n @if (label) {\r\n <label\r\n class=\"text-sm font-medium text-[#141414] block\" [for]=\"id\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"text-[#E7000B] ml-0.5\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"relative\">\r\n <textarea\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [disabled]=\"disabled\"\r\n [tabindex]=\"tabIndex\"\r\n [readOnly]=\"readOnly\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [autocomplete]=\"autoComplete\"\r\n [autocapitalize]=\"autoCapitalize\"\r\n [inputMode]=\"inputMode\"\r\n [value]=\"value\"\r\n (input)=\"handleInput($event)\"\r\n (change)=\"handleChange($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n [placeholder]=\"placeholder\"\r\n\r\n [autocomplete]=\"autoComplete\"\r\n\r\n rows=\"{{rows}}\"\r\n class=\"\r\n w-full\r\n px-3 py-2.5\r\n text-sm\r\n border border-[#E3E3E7] rounded-[4px]\r\n outline-none\r\n transition-colors duration-200\r\n bg-white resize-y\r\n placeholder:text-[#6B7080]\r\n \"\r\n [ngClass]=\"{\r\n 'border-[#FA727A] text-[#141414]': hasError && !disabled,\r\n\r\n 'focus:border-[#6B7080] text-[#141414]': !hasError && !disabled,\r\n\r\n 'bg-[#F4F4F6] text-[#A1A3AE] border-[#E3E3E7] cursor-not-allowed': disabled\r\n }\"\r\n ></textarea>\r\n </div>\r\n\r\n <div class=\"flex justify-between items-start font-normal text-sm\">\r\n\r\n <div class=\"flex-1\">\r\n @if (hasError) {\r\n <span class=\"text-[#F34050]\">\r\n {{ errorMessage }}\r\n </span>\r\n } @else if (hint) {\r\n <span class=\"text-[#868997]\">\r\n {{ hint }}\r\n </span>\r\n }\r\n </div>\r\n\r\n @if (maxlength) {\r\n <div\r\n class=\"text-[#868997] tabular-nums flex-shrink-0\"\r\n >\r\n {{ value.length }}/{{ maxlength }}\r\n </div>\r\n }\r\n\r\n\r\n </div>\r\n\r\n</div>\r\n" }]
|
|
2889
2854
|
}], ctorParameters: () => [{ type: i1$1.NgControl, decorators: [{
|
|
2890
2855
|
type: Optional
|
|
2891
2856
|
}, {
|
|
2892
2857
|
type: Self
|
|
2893
|
-
}] }], propDecorators: {
|
|
2858
|
+
}] }], propDecorators: { autoComplete: [{
|
|
2859
|
+
type: Input
|
|
2860
|
+
}], name: [{
|
|
2894
2861
|
type: Input
|
|
2895
2862
|
}], id: [{
|
|
2896
2863
|
type: Input
|
|
@@ -2904,15 +2871,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
2904
2871
|
type: Input
|
|
2905
2872
|
}], required: [{
|
|
2906
2873
|
type: Input
|
|
2907
|
-
}],
|
|
2874
|
+
}], maxlength: [{
|
|
2875
|
+
type: Input
|
|
2876
|
+
}], minlength: [{
|
|
2908
2877
|
type: Input
|
|
2909
2878
|
}], hasError: [{
|
|
2910
2879
|
type: Input
|
|
2880
|
+
}], disabled: [{
|
|
2881
|
+
type: Input
|
|
2911
2882
|
}], errorMessage: [{
|
|
2912
2883
|
type: Input
|
|
2913
|
-
}],
|
|
2884
|
+
}], tabIndex: [{
|
|
2914
2885
|
type: Input
|
|
2915
|
-
}],
|
|
2886
|
+
}], readOnly: [{
|
|
2887
|
+
type: Input
|
|
2888
|
+
}], autoCapitalize: [{
|
|
2889
|
+
type: Input
|
|
2890
|
+
}], inputMode: [{
|
|
2916
2891
|
type: Input
|
|
2917
2892
|
}], input: [{
|
|
2918
2893
|
type: Output
|
|
@@ -3443,6 +3418,10 @@ class BkInput {
|
|
|
3443
3418
|
hasError = false;
|
|
3444
3419
|
errorMessage = '';
|
|
3445
3420
|
disabled = false;
|
|
3421
|
+
tabIndex = null;
|
|
3422
|
+
readOnly = false;
|
|
3423
|
+
autoCapitalize = null;
|
|
3424
|
+
inputMode = null;
|
|
3446
3425
|
icon = false;
|
|
3447
3426
|
iconSrc;
|
|
3448
3427
|
iconAlt = 'icon';
|
|
@@ -3572,13 +3551,6 @@ class BkInput {
|
|
|
3572
3551
|
this.onChange(val); // propagate to parent form
|
|
3573
3552
|
this.input.emit(event); // emit raw event
|
|
3574
3553
|
}
|
|
3575
|
-
// handleInput(event: Event): void {
|
|
3576
|
-
// const val = (event.target as HTMLInputElement).value;
|
|
3577
|
-
// this.inputValue = val;
|
|
3578
|
-
// this.value = val;
|
|
3579
|
-
// this.onChange(val); // propagate to parent form
|
|
3580
|
-
// this.input.emit(event);
|
|
3581
|
-
// }
|
|
3582
3554
|
handleChange(event) {
|
|
3583
3555
|
this.change.emit(event); // emit raw change event
|
|
3584
3556
|
}
|
|
@@ -3656,14 +3628,14 @@ class BkInput {
|
|
|
3656
3628
|
return this.type;
|
|
3657
3629
|
}
|
|
3658
3630
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3659
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkInput, isStandalone: true, selector: "bk-input", inputs: { id: "id", name: "name", mask: "mask", autoComplete: "autoComplete", label: "label", placeholder: "placeholder", hint: "hint", required: "required", type: "type", value: "value", hasError: "hasError", errorMessage: "errorMessage", disabled: "disabled", icon: "icon", iconSrc: "iconSrc", iconAlt: "iconAlt", phone: "phone", countryCode: "countryCode", countryOptions: "countryOptions", searchLeft: "searchLeft", searchRight: "searchRight", password: "password", pattern: "pattern", max: "max", min: "min", step: "step", maxlength: "maxlength", minlength: "minlength" }, outputs: { input: "input", change: "change", focus: "focus", blur: "blur" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
|
|
3631
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkInput, isStandalone: true, selector: "bk-input", inputs: { id: "id", name: "name", mask: "mask", autoComplete: "autoComplete", label: "label", placeholder: "placeholder", hint: "hint", required: "required", type: "type", value: "value", hasError: "hasError", errorMessage: "errorMessage", disabled: "disabled", tabIndex: "tabIndex", readOnly: "readOnly", autoCapitalize: "autoCapitalize", inputMode: "inputMode", icon: "icon", iconSrc: "iconSrc", iconAlt: "iconAlt", phone: "phone", countryCode: "countryCode", countryOptions: "countryOptions", searchLeft: "searchLeft", searchRight: "searchRight", password: "password", pattern: "pattern", max: "max", min: "min", step: "step", maxlength: "maxlength", minlength: "minlength" }, outputs: { input: "input", change: "change", focus: "focus", blur: "blur" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
|
|
3660
3632
|
provideNgxMask(),
|
|
3661
3633
|
{
|
|
3662
3634
|
provide: NG_VALUE_ACCESSOR,
|
|
3663
3635
|
useExisting: forwardRef(() => BkInput),
|
|
3664
3636
|
multi: true
|
|
3665
3637
|
}
|
|
3666
|
-
], viewQueries: [{ propertyName: "dropdownRef", first: true, predicate: ["dropdownRef"], descendants: true }, { propertyName: "selectRef", first: true, predicate: ["selectRef"], descendants: true }, { propertyName: "inputField", first: true, predicate: ["inputField"], descendants: true }], ngImport: i0, template: "<div class=\"input-container\">\r\n <label [for]=\"id\" class=\"input-label\">\r\n {{ label }}\r\n @if(required){\r\n <span class=\"input-label-required\">*</span>\r\n }\r\n </label>\r\n\r\n <div class=\"input-wrapper\" [ngClass]=\"{\r\n 'input-wrapper--url': type === 'url',\r\n 'input-wrapper--icon': icon && iconSrc,\r\n 'input-wrapper--phone': phone,\r\n 'input-wrapper--search-left': searchLeft,\r\n 'input-wrapper--search-right': searchRight,\r\n 'input-wrapper--password': password\r\n }\">\r\n\r\n <input\r\n #inputField\r\n [type]=\"currentInputType\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [
|
|
3638
|
+
], viewQueries: [{ propertyName: "dropdownRef", first: true, predicate: ["dropdownRef"], descendants: true }, { propertyName: "selectRef", first: true, predicate: ["selectRef"], descendants: true }, { propertyName: "inputField", first: true, predicate: ["inputField"], descendants: true }], ngImport: i0, template: "<div class=\"input-container\">\r\n <label [for]=\"id\" class=\"input-label\">\r\n {{ label }}\r\n @if(required){\r\n <span class=\"input-label-required\">*</span>\r\n }\r\n </label>\r\n\r\n <div class=\"input-wrapper\" [ngClass]=\"{\r\n 'input-wrapper--url': type === 'url',\r\n 'input-wrapper--icon': icon && iconSrc,\r\n 'input-wrapper--phone': phone,\r\n 'input-wrapper--search-left': searchLeft,\r\n 'input-wrapper--search-right': searchRight,\r\n 'input-wrapper--password': password\r\n }\">\r\n\r\n <input\r\n #inputField\r\n [type]=\"currentInputType\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [disabled]=\"disabled\"\r\n [tabindex]=\"tabIndex\"\r\n [readOnly]=\"readOnly\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [autocomplete]=\"autoComplete\"\r\n [autocapitalize]=\"autoCapitalize\"\r\n\r\n [attr.max]=\"max\"\r\n [attr.min]=\"min\"\r\n [attr.step]=\"step\"\r\n\r\n [placeholder]=\"placeHolderText\"\r\n [pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n\r\n\r\n [mask]=\"maskValue\"\r\n [prefix]=\"maskPrefixValue\"\r\n [showMaskTyped]=\"false\"\r\n [dropSpecialCharacters]=\"false\"\r\n (change)=\"handleChange($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"input-field\"\r\n [ngClass]=\"{\r\n 'input-field--url': type === 'url',\r\n 'input-field--icon': icon && iconSrc,\r\n 'input-field--phone': phone,\r\n 'input-field--search-left': searchLeft,\r\n 'input-field--search-right': searchRight,\r\n 'input-field--password': password,\r\n 'input-field--default': inputState === 'default',\r\n 'input-field--focused': inputState === 'focused',\r\n 'input-field--filled': inputState === 'filled',\r\n 'input-field--error': inputState === 'error',\r\n 'input-field--disabled': inputState === 'disabled'\r\n }\">\r\n\r\n @if(searchLeft){\r\n <img src=\"../../assets/images/icons/global/search-input.svg\" alt=\"Search\" class=\"input-search-icon input-search-icon--left\">\r\n }\r\n\r\n @if(searchRight){\r\n <img src=\"../../assets/images/icons/global/search-input.svg\" alt=\"Search\" class=\"input-search-icon input-search-icon--right\">\r\n }\r\n\r\n @if(password){\r\n <button type=\"button\" (click)=\"togglePasswordVisibility($event)\" class=\"input-password-toggle\" [disabled]=\"disabled\" tabindex=\"-1\">\r\n <img [src]=\"showPassword ? '../../assets/images/icons/global/eye-slash-icon.svg' : '../../assets/images/icons/global/eye-icon.svg'\" [alt]=\"showPassword ? 'Hide password' : 'Show password'\" class=\"input-password-icon\">\r\n </button>\r\n }\r\n\r\n @if(phone){\r\n <div #selectRef class=\"input-phone-selector\" [ngClass]=\"{\r\n 'input-phone-selector--default': inputState === 'default',\r\n 'input-phone-selector--focused': inputState === 'focused',\r\n 'input-phone-selector--filled': inputState === 'filled',\r\n 'input-phone-selector--error': inputState === 'error',\r\n 'input-phone-selector--disabled': inputState === 'disabled'\r\n }\" (click)=\"toggleDropdown($event)\">\r\n <span class=\"input-phone-selector-text\">{{ selectedCountry.name }}</span>\r\n <img src=\"../../assets/images/icons/global/input-arrow-down.svg\" alt=\"Dropdown\" class=\"input-phone-selector-arrow\" [ngClass]=\"{'input-phone-selector-arrow--open': isDropdownOpen}\">\r\n </div>\r\n }\r\n\r\n @if(phone && isDropdownOpen){\r\n <div #dropdownRef class=\"input-phone-dropdown\" (click)=\"$event.stopPropagation()\">\r\n <button *ngFor=\"let country of countryOptions\" type=\"button\" class=\"input-phone-dropdown-item\" [ngClass]=\"{'input-phone-dropdown-item--active': selectedCountry.code === country.code}\" (click)=\"selectCountry(country); $event.stopPropagation()\">\r\n {{ country.name }}\r\n </button>\r\n </div>\r\n }\r\n\r\n @if(icon && iconSrc && !searchLeft){\r\n <img [src]=\"iconSrc\" [alt]=\"iconAlt\" class=\"input-icon\">\r\n }\r\n\r\n @if(type === 'url'){\r\n <span class=\"input-url-prefix\" [ngClass]=\"{\r\n 'input-url-prefix--default': inputState === 'default',\r\n 'input-url-prefix--focused': inputState === 'focused',\r\n 'input-url-prefix--filled': inputState === 'filled',\r\n 'input-url-prefix--error': inputState === 'error',\r\n 'input-url-prefix--disabled': inputState === 'disabled'\r\n }\">https</span>\r\n }\r\n </div>\r\n\r\n @if(hasError){\r\n @if (errorMessage) {\r\n <p class=\"input-error\">{{ errorMessage }}</p>\r\n }\r\n }\r\n @if(!hasError){\r\n <p class=\"input-hint\">{{ hint }}</p>\r\n }\r\n</div>\r\n", styles: [".input-container{@apply flex flex-col gap-1.5;}.input-label{@apply text-sm font-medium text-[#141414];}.input-label-required{@apply text-[#E7000B] ml-0.5;}.input-wrapper{@apply relative;}.input-field{@apply w-full py-2.5 px-3 text-sm border rounded-[4px] outline-none transition-all duration-200 bg-white;height:40px;box-sizing:border-box}.input-field--default{@apply border-[#E3E3E7] text-[#141414] placeholder:text-[#6B7080];}.input-field--focused{@apply border-[#6B7080] text-[#141414];}.input-field--filled{@apply border-[#E3E3E7] text-[#141414] bg-white;}.input-field--error{@apply border-[#E7000B] text-[#141414];}.input-field--disabled{@apply border-[#E3E3E7] bg-[#F4F4F6] text-[#A1A3AE] cursor-not-allowed;}.input-field--icon{@apply pl-[48px];}.input-field--phone{@apply pl-[80px];}.input-field--url{@apply pl-[72px];}.input-field--search-left{@apply pl-[48px];}.input-field--search-right,.input-field--password{@apply pr-[48px];}.input-field--icon.input-field--url{@apply pl-[120px];}.input-field--phone.input-field--icon{@apply pl-[128px];}.input-phone-selector{@apply absolute left-0 top-0 bottom-0 px-3 flex items-center gap-2 cursor-pointer border transition-colors duration-200;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-phone-selector-text{@apply text-xs leading-[18px] text-[#A1A3AE] font-normal;}.input-phone-selector-arrow{@apply w-4 h-4 transition-transform duration-200;}.input-phone-selector-arrow--open{@apply rotate-180;}.input-phone-selector--default{@apply bg-white border-[#E3E3E7];}.input-phone-selector--focused{@apply bg-white border-[#6B7080];}.input-phone-selector--filled{@apply bg-white border-[#E3E3E7];}.input-phone-selector--error{@apply bg-white border-[#E7000B];}.input-phone-selector--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7] cursor-not-allowed;}.input-phone-selector--disabled .input-phone-selector-text{@apply text-[#A1A3AE];}.input-phone-dropdown{@apply absolute left-0 top-full mt-1 w-[80px] bg-white border border-[#E3E3E7] rounded-[4px] shadow-lg z-50 max-h-48 overflow-y-auto;}.input-phone-dropdown-item{@apply w-full px-5 py-2.5 text-center text-xs leading-[18px] text-[#6B7080] hover:bg-[#F9FAFA] transition-colors duration-200 border-none bg-transparent;}.input-phone-dropdown-item--active{@apply bg-[#F9FAFA] text-[#141414];}.input-icon{@apply absolute left-3 top-1/2 -translate-y-1/2 w-6 h-6 pointer-events-none size-6;}.input-wrapper--phone .input-icon{@apply left-[80px];}.input-search-icon{@apply absolute top-1/2 -translate-y-1/2 w-5 h-5 pointer-events-none;}.input-search-icon--left{@apply left-3;}.input-search-icon--right{@apply right-3;}.input-password-toggle{@apply absolute right-3 top-1/2 -translate-y-1/2 w-5 h-5 p-0 border-0 bg-transparent cursor-pointer outline-none flex items-center justify-center;}.input-password-toggle:disabled{@apply cursor-not-allowed opacity-50;}.input-password-toggle:hover:not(:disabled){@apply opacity-70;}.input-password-icon{@apply w-5 h-5 pointer-events-none;}.input-url-prefix{@apply absolute left-0 top-0 bottom-0 py-2.5 px-3 text-sm text-[#6B7080] bg-white border flex items-center transition-colors duration-200 pointer-events-none;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-wrapper--icon .input-url-prefix{@apply left-[48px];}.input-url-prefix--default{@apply border-[#E3E3E7];}.input-url-prefix--focused{@apply border-[#6B7080];}.input-url-prefix--filled{@apply border-[#E3E3E7];}.input-url-prefix--error{@apply border-[#E7000B];}.input-url-prefix--disabled{@apply bg-[#F4F4F6] text-[#A1A3AE] border-r-[#E3E3E7];}.input-hint{@apply text-xs text-[#868997] font-normal;}.input-error{@apply text-xs text-[#E7000B] font-normal;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgxMaskDirective, selector: "input[mask], textarea[mask]", inputs: ["mask", "specialCharacters", "patterns", "prefix", "suffix", "thousandSeparator", "decimalMarker", "dropSpecialCharacters", "hiddenInput", "showMaskTyped", "placeHolderCharacter", "shownMaskExpression", "clearIfNotMatch", "validation", "separatorLimit", "allowNegativeNumbers", "leadZeroDateTime", "leadZero", "triggerOnMaskChange", "apm", "inputTransformFn", "outputTransformFn", "keepCharacterPositions", "instantPrefix"], outputs: ["maskFilled"], exportAs: ["mask", "ngxMask"] }, { kind: "ngmodule", type: FormsModule }] });
|
|
3667
3639
|
}
|
|
3668
3640
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkInput, decorators: [{
|
|
3669
3641
|
type: Component,
|
|
@@ -3674,7 +3646,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
3674
3646
|
useExisting: forwardRef(() => BkInput),
|
|
3675
3647
|
multi: true
|
|
3676
3648
|
}
|
|
3677
|
-
], template: "<div class=\"input-container\">\r\n <label [for]=\"id\" class=\"input-label\">\r\n {{ label }}\r\n @if(required){\r\n <span class=\"input-label-required\">*</span>\r\n }\r\n </label>\r\n\r\n <div class=\"input-wrapper\" [ngClass]=\"{\r\n 'input-wrapper--url': type === 'url',\r\n 'input-wrapper--icon': icon && iconSrc,\r\n 'input-wrapper--phone': phone,\r\n 'input-wrapper--search-left': searchLeft,\r\n 'input-wrapper--search-right': searchRight,\r\n 'input-wrapper--password': password\r\n }\">\r\n\r\n <input\r\n #inputField\r\n [type]=\"currentInputType\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [
|
|
3649
|
+
], template: "<div class=\"input-container\">\r\n <label [for]=\"id\" class=\"input-label\">\r\n {{ label }}\r\n @if(required){\r\n <span class=\"input-label-required\">*</span>\r\n }\r\n </label>\r\n\r\n <div class=\"input-wrapper\" [ngClass]=\"{\r\n 'input-wrapper--url': type === 'url',\r\n 'input-wrapper--icon': icon && iconSrc,\r\n 'input-wrapper--phone': phone,\r\n 'input-wrapper--search-left': searchLeft,\r\n 'input-wrapper--search-right': searchRight,\r\n 'input-wrapper--password': password\r\n }\">\r\n\r\n <input\r\n #inputField\r\n [type]=\"currentInputType\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [disabled]=\"disabled\"\r\n [tabindex]=\"tabIndex\"\r\n [readOnly]=\"readOnly\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [autocomplete]=\"autoComplete\"\r\n [autocapitalize]=\"autoCapitalize\"\r\n\r\n [attr.max]=\"max\"\r\n [attr.min]=\"min\"\r\n [attr.step]=\"step\"\r\n\r\n [placeholder]=\"placeHolderText\"\r\n [pattern]=\"pattern\"\r\n [autocomplete]=\"autoComplete\"\r\n [value]=\"inputValue\"\r\n\r\n\r\n\r\n [mask]=\"maskValue\"\r\n [prefix]=\"maskPrefixValue\"\r\n [showMaskTyped]=\"false\"\r\n [dropSpecialCharacters]=\"false\"\r\n (change)=\"handleChange($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"input-field\"\r\n [ngClass]=\"{\r\n 'input-field--url': type === 'url',\r\n 'input-field--icon': icon && iconSrc,\r\n 'input-field--phone': phone,\r\n 'input-field--search-left': searchLeft,\r\n 'input-field--search-right': searchRight,\r\n 'input-field--password': password,\r\n 'input-field--default': inputState === 'default',\r\n 'input-field--focused': inputState === 'focused',\r\n 'input-field--filled': inputState === 'filled',\r\n 'input-field--error': inputState === 'error',\r\n 'input-field--disabled': inputState === 'disabled'\r\n }\">\r\n\r\n @if(searchLeft){\r\n <img src=\"../../assets/images/icons/global/search-input.svg\" alt=\"Search\" class=\"input-search-icon input-search-icon--left\">\r\n }\r\n\r\n @if(searchRight){\r\n <img src=\"../../assets/images/icons/global/search-input.svg\" alt=\"Search\" class=\"input-search-icon input-search-icon--right\">\r\n }\r\n\r\n @if(password){\r\n <button type=\"button\" (click)=\"togglePasswordVisibility($event)\" class=\"input-password-toggle\" [disabled]=\"disabled\" tabindex=\"-1\">\r\n <img [src]=\"showPassword ? '../../assets/images/icons/global/eye-slash-icon.svg' : '../../assets/images/icons/global/eye-icon.svg'\" [alt]=\"showPassword ? 'Hide password' : 'Show password'\" class=\"input-password-icon\">\r\n </button>\r\n }\r\n\r\n @if(phone){\r\n <div #selectRef class=\"input-phone-selector\" [ngClass]=\"{\r\n 'input-phone-selector--default': inputState === 'default',\r\n 'input-phone-selector--focused': inputState === 'focused',\r\n 'input-phone-selector--filled': inputState === 'filled',\r\n 'input-phone-selector--error': inputState === 'error',\r\n 'input-phone-selector--disabled': inputState === 'disabled'\r\n }\" (click)=\"toggleDropdown($event)\">\r\n <span class=\"input-phone-selector-text\">{{ selectedCountry.name }}</span>\r\n <img src=\"../../assets/images/icons/global/input-arrow-down.svg\" alt=\"Dropdown\" class=\"input-phone-selector-arrow\" [ngClass]=\"{'input-phone-selector-arrow--open': isDropdownOpen}\">\r\n </div>\r\n }\r\n\r\n @if(phone && isDropdownOpen){\r\n <div #dropdownRef class=\"input-phone-dropdown\" (click)=\"$event.stopPropagation()\">\r\n <button *ngFor=\"let country of countryOptions\" type=\"button\" class=\"input-phone-dropdown-item\" [ngClass]=\"{'input-phone-dropdown-item--active': selectedCountry.code === country.code}\" (click)=\"selectCountry(country); $event.stopPropagation()\">\r\n {{ country.name }}\r\n </button>\r\n </div>\r\n }\r\n\r\n @if(icon && iconSrc && !searchLeft){\r\n <img [src]=\"iconSrc\" [alt]=\"iconAlt\" class=\"input-icon\">\r\n }\r\n\r\n @if(type === 'url'){\r\n <span class=\"input-url-prefix\" [ngClass]=\"{\r\n 'input-url-prefix--default': inputState === 'default',\r\n 'input-url-prefix--focused': inputState === 'focused',\r\n 'input-url-prefix--filled': inputState === 'filled',\r\n 'input-url-prefix--error': inputState === 'error',\r\n 'input-url-prefix--disabled': inputState === 'disabled'\r\n }\">https</span>\r\n }\r\n </div>\r\n\r\n @if(hasError){\r\n @if (errorMessage) {\r\n <p class=\"input-error\">{{ errorMessage }}</p>\r\n }\r\n }\r\n @if(!hasError){\r\n <p class=\"input-hint\">{{ hint }}</p>\r\n }\r\n</div>\r\n", styles: [".input-container{@apply flex flex-col gap-1.5;}.input-label{@apply text-sm font-medium text-[#141414];}.input-label-required{@apply text-[#E7000B] ml-0.5;}.input-wrapper{@apply relative;}.input-field{@apply w-full py-2.5 px-3 text-sm border rounded-[4px] outline-none transition-all duration-200 bg-white;height:40px;box-sizing:border-box}.input-field--default{@apply border-[#E3E3E7] text-[#141414] placeholder:text-[#6B7080];}.input-field--focused{@apply border-[#6B7080] text-[#141414];}.input-field--filled{@apply border-[#E3E3E7] text-[#141414] bg-white;}.input-field--error{@apply border-[#E7000B] text-[#141414];}.input-field--disabled{@apply border-[#E3E3E7] bg-[#F4F4F6] text-[#A1A3AE] cursor-not-allowed;}.input-field--icon{@apply pl-[48px];}.input-field--phone{@apply pl-[80px];}.input-field--url{@apply pl-[72px];}.input-field--search-left{@apply pl-[48px];}.input-field--search-right,.input-field--password{@apply pr-[48px];}.input-field--icon.input-field--url{@apply pl-[120px];}.input-field--phone.input-field--icon{@apply pl-[128px];}.input-phone-selector{@apply absolute left-0 top-0 bottom-0 px-3 flex items-center gap-2 cursor-pointer border transition-colors duration-200;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-phone-selector-text{@apply text-xs leading-[18px] text-[#A1A3AE] font-normal;}.input-phone-selector-arrow{@apply w-4 h-4 transition-transform duration-200;}.input-phone-selector-arrow--open{@apply rotate-180;}.input-phone-selector--default{@apply bg-white border-[#E3E3E7];}.input-phone-selector--focused{@apply bg-white border-[#6B7080];}.input-phone-selector--filled{@apply bg-white border-[#E3E3E7];}.input-phone-selector--error{@apply bg-white border-[#E7000B];}.input-phone-selector--disabled{@apply bg-[#F4F4F6] border-[#E3E3E7] cursor-not-allowed;}.input-phone-selector--disabled .input-phone-selector-text{@apply text-[#A1A3AE];}.input-phone-dropdown{@apply absolute left-0 top-full mt-1 w-[80px] bg-white border border-[#E3E3E7] rounded-[4px] shadow-lg z-50 max-h-48 overflow-y-auto;}.input-phone-dropdown-item{@apply w-full px-5 py-2.5 text-center text-xs leading-[18px] text-[#6B7080] hover:bg-[#F9FAFA] transition-colors duration-200 border-none bg-transparent;}.input-phone-dropdown-item--active{@apply bg-[#F9FAFA] text-[#141414];}.input-icon{@apply absolute left-3 top-1/2 -translate-y-1/2 w-6 h-6 pointer-events-none size-6;}.input-wrapper--phone .input-icon{@apply left-[80px];}.input-search-icon{@apply absolute top-1/2 -translate-y-1/2 w-5 h-5 pointer-events-none;}.input-search-icon--left{@apply left-3;}.input-search-icon--right{@apply right-3;}.input-password-toggle{@apply absolute right-3 top-1/2 -translate-y-1/2 w-5 h-5 p-0 border-0 bg-transparent cursor-pointer outline-none flex items-center justify-center;}.input-password-toggle:disabled{@apply cursor-not-allowed opacity-50;}.input-password-toggle:hover:not(:disabled){@apply opacity-70;}.input-password-icon{@apply w-5 h-5 pointer-events-none;}.input-url-prefix{@apply absolute left-0 top-0 bottom-0 py-2.5 px-3 text-sm text-[#6B7080] bg-white border flex items-center transition-colors duration-200 pointer-events-none;border-top-left-radius:4px;border-bottom-left-radius:4px}.input-wrapper--icon .input-url-prefix{@apply left-[48px];}.input-url-prefix--default{@apply border-[#E3E3E7];}.input-url-prefix--focused{@apply border-[#6B7080];}.input-url-prefix--filled{@apply border-[#E3E3E7];}.input-url-prefix--error{@apply border-[#E7000B];}.input-url-prefix--disabled{@apply bg-[#F4F4F6] text-[#A1A3AE] border-r-[#E3E3E7];}.input-hint{@apply text-xs text-[#868997] font-normal;}.input-error{@apply text-xs text-[#E7000B] font-normal;}\n"] }]
|
|
3678
3650
|
}], propDecorators: { id: [{
|
|
3679
3651
|
type: Input
|
|
3680
3652
|
}], name: [{
|
|
@@ -3701,6 +3673,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
3701
3673
|
type: Input
|
|
3702
3674
|
}], disabled: [{
|
|
3703
3675
|
type: Input
|
|
3676
|
+
}], tabIndex: [{
|
|
3677
|
+
type: Input
|
|
3678
|
+
}], readOnly: [{
|
|
3679
|
+
type: Input
|
|
3680
|
+
}], autoCapitalize: [{
|
|
3681
|
+
type: Input
|
|
3682
|
+
}], inputMode: [{
|
|
3683
|
+
type: Input
|
|
3704
3684
|
}], icon: [{
|
|
3705
3685
|
type: Input
|
|
3706
3686
|
}], iconSrc: [{
|
|
@@ -3753,6 +3733,239 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
3753
3733
|
args: ['document:click', ['$event']]
|
|
3754
3734
|
}] } });
|
|
3755
3735
|
|
|
3736
|
+
class BkChips {
|
|
3737
|
+
badgeInput;
|
|
3738
|
+
fieldWrapper;
|
|
3739
|
+
// --- Configuration Inputs ---
|
|
3740
|
+
id;
|
|
3741
|
+
name;
|
|
3742
|
+
label = '';
|
|
3743
|
+
placeholder = '';
|
|
3744
|
+
hint = '';
|
|
3745
|
+
required = false;
|
|
3746
|
+
disabled = false;
|
|
3747
|
+
readOnly = false;
|
|
3748
|
+
/**
|
|
3749
|
+
* If true, displays the component in an error state (red border).
|
|
3750
|
+
* It also replaces the hint text with the error message.
|
|
3751
|
+
*/
|
|
3752
|
+
hasError = false;
|
|
3753
|
+
errorMessage = 'This is a error message';
|
|
3754
|
+
// =================== Output Emitter ===================
|
|
3755
|
+
input = new EventEmitter();
|
|
3756
|
+
change = new EventEmitter();
|
|
3757
|
+
focus = new EventEmitter();
|
|
3758
|
+
blur = new EventEmitter();
|
|
3759
|
+
// --- State Properties ---
|
|
3760
|
+
badges = [];
|
|
3761
|
+
inputValue = '';
|
|
3762
|
+
isFocused = false;
|
|
3763
|
+
needsScroll = false;
|
|
3764
|
+
// --- ControlValueAccessor Methods ---
|
|
3765
|
+
onChange = () => { };
|
|
3766
|
+
onTouched = () => { };
|
|
3767
|
+
// Get input state for styling variants
|
|
3768
|
+
get inputState() {
|
|
3769
|
+
if (this.disabled)
|
|
3770
|
+
return 'disabled';
|
|
3771
|
+
if (this.hasError)
|
|
3772
|
+
return 'error';
|
|
3773
|
+
if (this.isFocused)
|
|
3774
|
+
return 'focused';
|
|
3775
|
+
if (this.badges.length > 0 || this.inputValue.length > 0)
|
|
3776
|
+
return 'filled';
|
|
3777
|
+
return 'default';
|
|
3778
|
+
}
|
|
3779
|
+
// Handle keydown events (Enter to add badge, Backspace to remove)
|
|
3780
|
+
onKeyDown(event) {
|
|
3781
|
+
if (this.disabled)
|
|
3782
|
+
return;
|
|
3783
|
+
// Add badge on Enter or comma
|
|
3784
|
+
if (event.key === 'Enter' || event.key === ',') {
|
|
3785
|
+
event.preventDefault();
|
|
3786
|
+
this.addBadge();
|
|
3787
|
+
}
|
|
3788
|
+
// Remove last badge on Backspace when input is empty
|
|
3789
|
+
else if (event.key === 'Backspace' && this.inputValue === '' && this.badges.length > 0) {
|
|
3790
|
+
this.removeBadge(this.badges.length - 1);
|
|
3791
|
+
}
|
|
3792
|
+
}
|
|
3793
|
+
// Add a badge from the current input value
|
|
3794
|
+
addBadge() {
|
|
3795
|
+
const trimmedValue = this.inputValue.trim();
|
|
3796
|
+
if (trimmedValue && !this.badges.includes(trimmedValue)) {
|
|
3797
|
+
this.badges.push(trimmedValue);
|
|
3798
|
+
this.inputValue = '';
|
|
3799
|
+
this.updateValue();
|
|
3800
|
+
// Check if scroll is needed after adding badge (with delay for DOM update)
|
|
3801
|
+
setTimeout(() => this.checkScrollNeeded(), 10);
|
|
3802
|
+
}
|
|
3803
|
+
else if (trimmedValue && this.badges.includes(trimmedValue)) {
|
|
3804
|
+
// Optionally show a message that badge already exists
|
|
3805
|
+
this.inputValue = '';
|
|
3806
|
+
}
|
|
3807
|
+
}
|
|
3808
|
+
// Remove a badge at the given index
|
|
3809
|
+
removeBadge(index) {
|
|
3810
|
+
if (this.disabled)
|
|
3811
|
+
return;
|
|
3812
|
+
this.badges.splice(index, 1);
|
|
3813
|
+
this.updateValue();
|
|
3814
|
+
// Check if scroll is needed after removing badge (with delay for DOM update)
|
|
3815
|
+
setTimeout(() => {
|
|
3816
|
+
this.checkScrollNeeded();
|
|
3817
|
+
if (this.badgeInput) {
|
|
3818
|
+
this.badgeInput.nativeElement.focus();
|
|
3819
|
+
}
|
|
3820
|
+
}, 10);
|
|
3821
|
+
}
|
|
3822
|
+
// Check if scrolling is needed (when content wraps)
|
|
3823
|
+
checkScrollNeeded() {
|
|
3824
|
+
if (this.fieldWrapper && this.fieldWrapper.nativeElement) {
|
|
3825
|
+
const wrapper = this.fieldWrapper.nativeElement;
|
|
3826
|
+
// Get all badge items
|
|
3827
|
+
const badgeItems = wrapper.querySelectorAll('.input-badge-item');
|
|
3828
|
+
if (badgeItems.length === 0) {
|
|
3829
|
+
// No badges, no scroll needed
|
|
3830
|
+
this.needsScroll = false;
|
|
3831
|
+
return;
|
|
3832
|
+
}
|
|
3833
|
+
// Get the first badge's top position
|
|
3834
|
+
const firstBadge = badgeItems[0];
|
|
3835
|
+
const firstBadgeTop = firstBadge.offsetTop;
|
|
3836
|
+
// Check if any badge is on a different line (different top position)
|
|
3837
|
+
let hasWrapped = false;
|
|
3838
|
+
for (let i = 1; i < badgeItems.length; i++) {
|
|
3839
|
+
const badge = badgeItems[i];
|
|
3840
|
+
// If a badge's top position is different, it means it wrapped to a new line
|
|
3841
|
+
if (Math.abs(badge.offsetTop - firstBadgeTop) > 5) {
|
|
3842
|
+
hasWrapped = true;
|
|
3843
|
+
break;
|
|
3844
|
+
}
|
|
3845
|
+
}
|
|
3846
|
+
// Also check if the input field is on a different line
|
|
3847
|
+
if (!hasWrapped && this.badgeInput && this.badgeInput.nativeElement) {
|
|
3848
|
+
const inputTop = this.badgeInput.nativeElement.offsetTop;
|
|
3849
|
+
if (Math.abs(inputTop - firstBadgeTop) > 5) {
|
|
3850
|
+
hasWrapped = true;
|
|
3851
|
+
}
|
|
3852
|
+
}
|
|
3853
|
+
// Only enable scroll if content actually wrapped
|
|
3854
|
+
this.needsScroll = hasWrapped;
|
|
3855
|
+
}
|
|
3856
|
+
}
|
|
3857
|
+
// Update the value and notify Angular Forms
|
|
3858
|
+
updateValue() {
|
|
3859
|
+
this.onChange([...this.badges]);
|
|
3860
|
+
this.change.emit([...this.badges]);
|
|
3861
|
+
}
|
|
3862
|
+
// Focus the input field
|
|
3863
|
+
focusInput() {
|
|
3864
|
+
if (!this.disabled && this.badgeInput) {
|
|
3865
|
+
this.badgeInput.nativeElement.focus();
|
|
3866
|
+
}
|
|
3867
|
+
}
|
|
3868
|
+
ngAfterViewInit() {
|
|
3869
|
+
// Check scroll after view initializes
|
|
3870
|
+
setTimeout(() => this.checkScrollNeeded(), 10);
|
|
3871
|
+
}
|
|
3872
|
+
// Called when Angular writes a value TO the component (e.g. initial value)
|
|
3873
|
+
writeValue(value) {
|
|
3874
|
+
if (Array.isArray(value)) {
|
|
3875
|
+
this.badges = [...value];
|
|
3876
|
+
}
|
|
3877
|
+
else {
|
|
3878
|
+
this.badges = [];
|
|
3879
|
+
}
|
|
3880
|
+
this.inputValue = '';
|
|
3881
|
+
// Check scroll after value is written (with delay for DOM update)
|
|
3882
|
+
setTimeout(() => this.checkScrollNeeded(), 10);
|
|
3883
|
+
}
|
|
3884
|
+
// Register function to call when value changes
|
|
3885
|
+
registerOnChange(fn) {
|
|
3886
|
+
this.onChange = fn;
|
|
3887
|
+
}
|
|
3888
|
+
// Register function to call when component is touched/blurred
|
|
3889
|
+
registerOnTouched(fn) {
|
|
3890
|
+
this.onTouched = fn;
|
|
3891
|
+
}
|
|
3892
|
+
// Called when the component is disabled via the form control
|
|
3893
|
+
setDisabledState(disabled) {
|
|
3894
|
+
this.disabled = disabled;
|
|
3895
|
+
}
|
|
3896
|
+
// =================== Event Handlers ===================
|
|
3897
|
+
// Called when the value in the UI changes (user types)
|
|
3898
|
+
handleInput(event) {
|
|
3899
|
+
const input = event.target;
|
|
3900
|
+
this.inputValue = input.value;
|
|
3901
|
+
}
|
|
3902
|
+
handleFocus(event) {
|
|
3903
|
+
if (!this.disabled) {
|
|
3904
|
+
this.isFocused = true;
|
|
3905
|
+
}
|
|
3906
|
+
this.onChange([...this.badges]);
|
|
3907
|
+
this.focus.emit(event);
|
|
3908
|
+
}
|
|
3909
|
+
handleBlur(event) {
|
|
3910
|
+
this.isFocused = false;
|
|
3911
|
+
this.onTouched();
|
|
3912
|
+
this.onChange([...this.badges]);
|
|
3913
|
+
this.blur.emit(event);
|
|
3914
|
+
}
|
|
3915
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkChips, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3916
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BkChips, isStandalone: true, selector: "bk-chips", inputs: { id: "id", name: "name", label: "label", placeholder: "placeholder", hint: "hint", required: "required", disabled: "disabled", readOnly: "readOnly", hasError: "hasError", errorMessage: "errorMessage" }, outputs: { input: "input", change: "change", focus: "focus", blur: "blur" }, providers: [
|
|
3917
|
+
{
|
|
3918
|
+
provide: NG_VALUE_ACCESSOR,
|
|
3919
|
+
useExisting: forwardRef(() => BkChips),
|
|
3920
|
+
multi: true
|
|
3921
|
+
}
|
|
3922
|
+
], viewQueries: [{ propertyName: "badgeInput", first: true, predicate: ["badgeInput"], descendants: true }, { propertyName: "fieldWrapper", first: true, predicate: ["fieldWrapper"], descendants: true }], ngImport: i0, template: "<div class=\"input-badge-container\">\r\n @if (label) {\r\n <label\r\n [for]=\"id\"\r\n class=\"input-badge-label\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"input-badge-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"input-badge-wrapper\">\r\n <div\r\n #fieldWrapper\r\n class=\"input-badge-field-wrapper\"\r\n [ngClass]=\"{\r\n 'input-badge-field-wrapper--default': inputState === 'default',\r\n 'input-badge-field-wrapper--focused': inputState === 'focused',\r\n 'input-badge-field-wrapper--filled': inputState === 'filled',\r\n 'input-badge-field-wrapper--error': inputState === 'error',\r\n 'input-badge-field-wrapper--disabled': inputState === 'disabled',\r\n 'input-badge-field-wrapper--scrollable': needsScroll\r\n }\"\r\n (click)=\"focusInput()\"\r\n >\r\n <!-- Badges -->\r\n @for (badge of badges; track badge; let i = $index) {\r\n <div class=\"input-badge-item\">\r\n <span class=\"input-badge-item-text\">{{ badge }}</span>\r\n @if (!disabled) {\r\n <button type=\"button\" (click)=\"removeBadge(i); $event.stopPropagation()\"class=\"input-badge-item-close\" >\r\n <img src=\"../../../../assets/images/icons/global/badge-close.svg\" alt=\"Remove\" class=\"input-badge-item-close-icon\"/>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Input Field -->\r\n <input\r\n #badgeInput\r\n type=\"text\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [value]=\"inputValue\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n [placeholder]=\"badges.length === 0 ? placeholder : ''\"\r\n [disabled]=\"disabled\"\r\n [readOnly]=\"readOnly\"\r\n class=\"input-badge-input\"\r\n [ngClass]=\"{\r\n 'input-badge-input--default': inputState === 'default',\r\n 'input-badge-input--focused': inputState === 'focused',\r\n 'input-badge-input--filled': inputState === 'filled',\r\n 'input-badge-input--error': inputState === 'error',\r\n 'input-badge-input--disabled': inputState === 'disabled'\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div class=\"input-badge-footer\">\r\n <div class=\"input-badge-footer-content\">\r\n @if (hasError) {\r\n <span class=\"input-badge-error\"> {{ errorMessage }}</span>\r\n } @else if (hint) {\r\n <span class=\"input-badge-hint\"> {{ hint }}</span>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".input-badge-container{@apply flex flex-col gap-1.5 w-full;}.input-badge-label{@apply text-sm font-medium text-[#141414] block;}.input-badge-label-required{@apply text-[#E7000B] ml-0.5;}.input-badge-wrapper{@apply relative;}.input-badge-field-wrapper{@apply w-full px-3 py-2 text-sm border rounded-[4px] outline-none transition-colors duration-200 bg-white flex flex-wrap gap-2 items-start;height:40px;box-sizing:border-box;overflow-y:hidden;overflow-x:hidden}.input-badge-field-wrapper--scrollable{overflow-y:auto}.input-badge-field-wrapper--default{@apply border-[#E3E3E7] text-[#141414];}.input-badge-field-wrapper--default:focus-within{@apply border-[#6B7080];}.input-badge-field-wrapper--focused{@apply border-[#6B7080] text-[#141414];}.input-badge-field-wrapper--filled{@apply border-[#E3E3E7] text-[#141414] bg-white;}.input-badge-field-wrapper--filled:focus-within{@apply border-[#6B7080];}.input-badge-field-wrapper--error{@apply border-[#FA727A] text-[#141414];}.input-badge-field-wrapper--disabled{@apply bg-[#F4F4F6] text-[#A1A3AE] border-[#E3E3E7] cursor-not-allowed;}.input-badge-item{@apply inline-flex items-center gap-1 px-2 py-[2.5px] bg-white border border-[#E3E3E7] rounded-[4px];}.input-badge-item-text{@apply text-sm leading-[18px] font-normal text-[#6B7080];}.input-badge-item-close{@apply cursor-pointer outline-none w-3 h-3;}.input-badge-input{@apply flex-1 min-w-[120px] outline-none bg-transparent text-[#141414] placeholder:text-[#6B7080] h-auto;flex-basis:120px}.input-badge-input--default,.input-badge-input--focused,.input-badge-input--filled,.input-badge-input--error{@apply text-[#141414];}.input-badge-input--disabled{@apply text-[#A1A3AE] cursor-not-allowed;}.input-badge-footer{@apply flex justify-between items-start font-normal text-sm;}.input-badge-footer-content{@apply flex-1;}.input-badge-hint{@apply text-xs text-[#868997] font-normal;}.input-badge-error{@apply text-xs text-[#F34050] font-normal;}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }] });
|
|
3923
|
+
}
|
|
3924
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BkChips, decorators: [{
|
|
3925
|
+
type: Component,
|
|
3926
|
+
args: [{ selector: 'bk-chips', standalone: true, imports: [CommonModule, FormsModule], providers: [
|
|
3927
|
+
{
|
|
3928
|
+
provide: NG_VALUE_ACCESSOR,
|
|
3929
|
+
useExisting: forwardRef(() => BkChips),
|
|
3930
|
+
multi: true
|
|
3931
|
+
}
|
|
3932
|
+
], template: "<div class=\"input-badge-container\">\r\n @if (label) {\r\n <label\r\n [for]=\"id\"\r\n class=\"input-badge-label\">\r\n {{ label }}\r\n @if (required) {\r\n <span class=\"input-badge-label-required\">*</span>\r\n }\r\n </label>\r\n }\r\n\r\n <div class=\"input-badge-wrapper\">\r\n <div\r\n #fieldWrapper\r\n class=\"input-badge-field-wrapper\"\r\n [ngClass]=\"{\r\n 'input-badge-field-wrapper--default': inputState === 'default',\r\n 'input-badge-field-wrapper--focused': inputState === 'focused',\r\n 'input-badge-field-wrapper--filled': inputState === 'filled',\r\n 'input-badge-field-wrapper--error': inputState === 'error',\r\n 'input-badge-field-wrapper--disabled': inputState === 'disabled',\r\n 'input-badge-field-wrapper--scrollable': needsScroll\r\n }\"\r\n (click)=\"focusInput()\"\r\n >\r\n <!-- Badges -->\r\n @for (badge of badges; track badge; let i = $index) {\r\n <div class=\"input-badge-item\">\r\n <span class=\"input-badge-item-text\">{{ badge }}</span>\r\n @if (!disabled) {\r\n <button type=\"button\" (click)=\"removeBadge(i); $event.stopPropagation()\"class=\"input-badge-item-close\" >\r\n <img src=\"../../../../assets/images/icons/global/badge-close.svg\" alt=\"Remove\" class=\"input-badge-item-close-icon\"/>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Input Field -->\r\n <input\r\n #badgeInput\r\n type=\"text\"\r\n [id]=\"id\"\r\n [name]=\"name\"\r\n [value]=\"inputValue\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (input)=\"handleInput($event)\"\r\n (focus)=\"handleFocus($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n [placeholder]=\"badges.length === 0 ? placeholder : ''\"\r\n [disabled]=\"disabled\"\r\n [readOnly]=\"readOnly\"\r\n class=\"input-badge-input\"\r\n [ngClass]=\"{\r\n 'input-badge-input--default': inputState === 'default',\r\n 'input-badge-input--focused': inputState === 'focused',\r\n 'input-badge-input--filled': inputState === 'filled',\r\n 'input-badge-input--error': inputState === 'error',\r\n 'input-badge-input--disabled': inputState === 'disabled'\r\n }\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div class=\"input-badge-footer\">\r\n <div class=\"input-badge-footer-content\">\r\n @if (hasError) {\r\n <span class=\"input-badge-error\"> {{ errorMessage }}</span>\r\n } @else if (hint) {\r\n <span class=\"input-badge-hint\"> {{ hint }}</span>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".input-badge-container{@apply flex flex-col gap-1.5 w-full;}.input-badge-label{@apply text-sm font-medium text-[#141414] block;}.input-badge-label-required{@apply text-[#E7000B] ml-0.5;}.input-badge-wrapper{@apply relative;}.input-badge-field-wrapper{@apply w-full px-3 py-2 text-sm border rounded-[4px] outline-none transition-colors duration-200 bg-white flex flex-wrap gap-2 items-start;height:40px;box-sizing:border-box;overflow-y:hidden;overflow-x:hidden}.input-badge-field-wrapper--scrollable{overflow-y:auto}.input-badge-field-wrapper--default{@apply border-[#E3E3E7] text-[#141414];}.input-badge-field-wrapper--default:focus-within{@apply border-[#6B7080];}.input-badge-field-wrapper--focused{@apply border-[#6B7080] text-[#141414];}.input-badge-field-wrapper--filled{@apply border-[#E3E3E7] text-[#141414] bg-white;}.input-badge-field-wrapper--filled:focus-within{@apply border-[#6B7080];}.input-badge-field-wrapper--error{@apply border-[#FA727A] text-[#141414];}.input-badge-field-wrapper--disabled{@apply bg-[#F4F4F6] text-[#A1A3AE] border-[#E3E3E7] cursor-not-allowed;}.input-badge-item{@apply inline-flex items-center gap-1 px-2 py-[2.5px] bg-white border border-[#E3E3E7] rounded-[4px];}.input-badge-item-text{@apply text-sm leading-[18px] font-normal text-[#6B7080];}.input-badge-item-close{@apply cursor-pointer outline-none w-3 h-3;}.input-badge-input{@apply flex-1 min-w-[120px] outline-none bg-transparent text-[#141414] placeholder:text-[#6B7080] h-auto;flex-basis:120px}.input-badge-input--default,.input-badge-input--focused,.input-badge-input--filled,.input-badge-input--error{@apply text-[#141414];}.input-badge-input--disabled{@apply text-[#A1A3AE] cursor-not-allowed;}.input-badge-footer{@apply flex justify-between items-start font-normal text-sm;}.input-badge-footer-content{@apply flex-1;}.input-badge-hint{@apply text-xs text-[#868997] font-normal;}.input-badge-error{@apply text-xs text-[#F34050] font-normal;}\n"] }]
|
|
3933
|
+
}], propDecorators: { badgeInput: [{
|
|
3934
|
+
type: ViewChild,
|
|
3935
|
+
args: ['badgeInput']
|
|
3936
|
+
}], fieldWrapper: [{
|
|
3937
|
+
type: ViewChild,
|
|
3938
|
+
args: ['fieldWrapper']
|
|
3939
|
+
}], id: [{
|
|
3940
|
+
type: Input
|
|
3941
|
+
}], name: [{
|
|
3942
|
+
type: Input
|
|
3943
|
+
}], label: [{
|
|
3944
|
+
type: Input
|
|
3945
|
+
}], placeholder: [{
|
|
3946
|
+
type: Input
|
|
3947
|
+
}], hint: [{
|
|
3948
|
+
type: Input
|
|
3949
|
+
}], required: [{
|
|
3950
|
+
type: Input
|
|
3951
|
+
}], disabled: [{
|
|
3952
|
+
type: Input
|
|
3953
|
+
}], readOnly: [{
|
|
3954
|
+
type: Input
|
|
3955
|
+
}], hasError: [{
|
|
3956
|
+
type: Input
|
|
3957
|
+
}], errorMessage: [{
|
|
3958
|
+
type: Input
|
|
3959
|
+
}], input: [{
|
|
3960
|
+
type: Output
|
|
3961
|
+
}], change: [{
|
|
3962
|
+
type: Output
|
|
3963
|
+
}], focus: [{
|
|
3964
|
+
type: Output
|
|
3965
|
+
}], blur: [{
|
|
3966
|
+
type: Output
|
|
3967
|
+
}] } });
|
|
3968
|
+
|
|
3756
3969
|
/*
|
|
3757
3970
|
* Public API Surface of brickclay-lib
|
|
3758
3971
|
*/
|
|
@@ -3762,5 +3975,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
3762
3975
|
* Generated bundle index. Do not edit.
|
|
3763
3976
|
*/
|
|
3764
3977
|
|
|
3765
|
-
export { BkBadge, BkButton, BkButtonGroup, BkCheckbox, BkCustomCalendar, BkGrid, BkIconButton, BkInput, BkPill, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTextarea, BkTimePicker, BkToggle, BrickclayIcons, BrickclayLib, CalendarManagerService, CalendarModule };
|
|
3978
|
+
export { BkBadge, BkButton, BkButtonGroup, BkCheckbox, BkChips, BkCustomCalendar, BkGrid, BkIconButton, BkInput, BkPill, BkRadioButton, BkScheduledDatePicker, BkSelect, BkSpinner, BkTextarea, BkTimePicker, BkToggle, BrickclayIcons, BrickclayLib, CalendarManagerService, CalendarModule };
|
|
3766
3979
|
//# sourceMappingURL=brickclay-org-ui.mjs.map
|