@egose/shadcn-theme-ng 0.0.12 → 0.0.14

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.
Files changed (44) hide show
  1. package/accordion/fesm2022/accordion.mjs +10 -10
  2. package/alert/fesm2022/alert.mjs +30 -30
  3. package/autocomplete/fesm2022/autocomplete.mjs +34 -15
  4. package/autocomplete/fesm2022/autocomplete.mjs.map +1 -1
  5. package/autocomplete/index.d.ts +5 -1
  6. package/badge/fesm2022/badge.mjs +70 -79
  7. package/badge/fesm2022/badge.mjs.map +1 -1
  8. package/badge/index.d.ts +9 -9
  9. package/basic-alert/fesm2022/basic-alert.mjs +15 -23
  10. package/basic-alert/fesm2022/basic-alert.mjs.map +1 -1
  11. package/basic-alert/index.d.ts +7 -7
  12. package/button/fesm2022/button.mjs +148 -168
  13. package/button/fesm2022/button.mjs.map +1 -1
  14. package/button/index.d.ts +19 -19
  15. package/calendar/fesm2022/calendar.mjs +78 -78
  16. package/confirmation-dialog/fesm2022/confirmation-dialog.mjs +10 -10
  17. package/date-picker/fesm2022/date-picker.mjs +11 -11
  18. package/dialog/fesm2022/dialog.mjs +9 -9
  19. package/exports.json +1 -1
  20. package/form-date-picker/fesm2022/form-date-picker.mjs +9 -9
  21. package/form-field/fesm2022/form-field.mjs +3 -3
  22. package/form-searchable-multiselect/README.md +64 -0
  23. package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs +124 -0
  24. package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs.map +1 -0
  25. package/form-searchable-multiselect/index.d.ts +28 -0
  26. package/form-select/fesm2022/form-select.mjs +9 -9
  27. package/form-text-input/fesm2022/form-text-input.mjs +9 -9
  28. package/form-textarea/fesm2022/form-textarea.mjs +9 -9
  29. package/input/fesm2022/input.mjs +3 -3
  30. package/label/fesm2022/label.mjs +1 -1
  31. package/package.json +9 -1
  32. package/popover/fesm2022/popover.mjs +2 -2
  33. package/radio-group/fesm2022/radio-group.mjs +5 -5
  34. package/searchable-multiselect/README.md +64 -0
  35. package/searchable-multiselect/fesm2022/searchable-multiselect.mjs +221 -0
  36. package/searchable-multiselect/fesm2022/searchable-multiselect.mjs.map +1 -0
  37. package/searchable-multiselect/index.d.ts +50 -0
  38. package/select/fesm2022/select.mjs +18 -18
  39. package/separator/fesm2022/separator.mjs +1 -1
  40. package/sonner/fesm2022/sonner.mjs +4 -4
  41. package/spinner/fesm2022/spinner.mjs +6 -6
  42. package/switch/fesm2022/switch.mjs +2 -2
  43. package/tabs/fesm2022/tabs.mjs +12 -12
  44. package/tooltip/fesm2022/tooltip.mjs +5 -5
@@ -33,13 +33,13 @@ class EgFormTextarea {
33
33
  errorClass = input('', ...(ngDevMode ? [{ debugName: "errorClass" }] : []));
34
34
  hintClass = input('', ...(ngDevMode ? [{ debugName: "hintClass" }] : []));
35
35
  // Computed class bindings
36
- $userClass = computed(() => hlm('tw:flex tw:flex-col', this.userClass()), ...(ngDevMode ? [{ debugName: "$userClass" }] : []));
37
- $labelClass = computed(() => hlm('tw:mb-1 tw:gap-0', this.labelClass()), ...(ngDevMode ? [{ debugName: "$labelClass" }] : []));
38
- $textareaClass = computed(() => hlm('tw:mb-1', this.textareaClass()), ...(ngDevMode ? [{ debugName: "$textareaClass" }] : []));
39
- $errorClass = computed(() => hlm('tw:mt-0', this.errorClass()), ...(ngDevMode ? [{ debugName: "$errorClass" }] : []));
40
- $hintClass = computed(() => hlm('tw:mt-0', this.hintClass()), ...(ngDevMode ? [{ debugName: "$hintClass" }] : []));
36
+ $userClass = computed(() => hlm('flex flex-col', this.userClass()), ...(ngDevMode ? [{ debugName: "$userClass" }] : []));
37
+ $labelClass = computed(() => hlm('mb-1 gap-0', this.labelClass()), ...(ngDevMode ? [{ debugName: "$labelClass" }] : []));
38
+ $textareaClass = computed(() => hlm('mb-1', this.textareaClass()), ...(ngDevMode ? [{ debugName: "$textareaClass" }] : []));
39
+ $errorClass = computed(() => hlm('mt-0', this.errorClass()), ...(ngDevMode ? [{ debugName: "$errorClass" }] : []));
40
+ $hintClass = computed(() => hlm('mt-0', this.hintClass()), ...(ngDevMode ? [{ debugName: "$hintClass" }] : []));
41
41
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: EgFormTextarea, deps: [], target: i0.ɵɵFactoryTarget.Component });
42
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: EgFormTextarea, isStandalone: true, selector: "eg-form-textarea", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, controlName: { classPropertyName: "controlName", publicName: "controlName", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, maxlength: { classPropertyName: "maxlength", publicName: "maxlength", isSignal: true, isRequired: false, transformFunction: null }, minlength: { classPropertyName: "minlength", publicName: "minlength", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, cols: { classPropertyName: "cols", publicName: "cols", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, labelClass: { classPropertyName: "labelClass", publicName: "labelClass", isSignal: true, isRequired: false, transformFunction: null }, textareaClass: { classPropertyName: "textareaClass", publicName: "textareaClass", isSignal: true, isRequired: false, transformFunction: null }, errorClass: { classPropertyName: "errorClass", publicName: "errorClass", isSignal: true, isRequired: false, transformFunction: null }, hintClass: { classPropertyName: "hintClass", publicName: "hintClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "tw:w-full" }, providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }], ngImport: i0, template: `
42
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: EgFormTextarea, isStandalone: true, selector: "eg-form-textarea", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, controlName: { classPropertyName: "controlName", publicName: "controlName", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, maxlength: { classPropertyName: "maxlength", publicName: "maxlength", isSignal: true, isRequired: false, transformFunction: null }, minlength: { classPropertyName: "minlength", publicName: "minlength", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, cols: { classPropertyName: "cols", publicName: "cols", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, labelClass: { classPropertyName: "labelClass", publicName: "labelClass", isSignal: true, isRequired: false, transformFunction: null }, textareaClass: { classPropertyName: "textareaClass", publicName: "textareaClass", isSignal: true, isRequired: false, transformFunction: null }, errorClass: { classPropertyName: "errorClass", publicName: "errorClass", isSignal: true, isRequired: false, transformFunction: null }, hintClass: { classPropertyName: "hintClass", publicName: "hintClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "w-full" }, providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }], ngImport: i0, template: `
43
43
  @let lbl = label();
44
44
  @let nm = controlName();
45
45
  @let err = error();
@@ -50,7 +50,7 @@ class EgFormTextarea {
50
50
  @if (lbl) {
51
51
  <span hlmLabel [class]="$labelClass()">{{ lbl }}
52
52
  @if (rqrd) {
53
- <span class="tw:text-red-500">*</span>
53
+ <span class="text-red-500">*</span>
54
54
  }
55
55
  </span>
56
56
  }
@@ -91,7 +91,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
91
91
  selector: 'eg-form-textarea',
92
92
  standalone: true,
93
93
  host: {
94
- class: 'tw:w-full',
94
+ class: 'w-full',
95
95
  },
96
96
  imports: [ReactiveFormsModule, HlmFormField, HlmError, HlmHint, HlmLabel, HlmInput],
97
97
  providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }],
@@ -107,7 +107,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
107
107
  @if (lbl) {
108
108
  <span hlmLabel [class]="$labelClass()">{{ lbl }}
109
109
  @if (rqrd) {
110
- <span class="tw:text-red-500">*</span>
110
+ <span class="text-red-500">*</span>
111
111
  }
112
112
  </span>
113
113
  }
@@ -6,11 +6,11 @@ import { ErrorStateMatcher, ErrorStateTracker } from '@spartan-ng/brain/forms';
6
6
  import { hlm } from '@egose/shadcn-theme-ng/utils';
7
7
  import { cva } from 'class-variance-authority';
8
8
 
9
- const inputVariants = cva('tw:file:text-foreground tw:placeholder:text-muted-foreground tw:selection:bg-primary tw:selection:text-primary-foreground tw:dark:bg-input/10 tw:border-input tw:shadow-xs tw:focus-visible:border-ring tw:focus-visible:ring-ring/50 tw:flex tw:h-9 tw:w-full tw:min-w-0 tw:rounded-md tw:border tw:bg-transparent tw:px-3 tw:py-1 tw:text-base tw:outline-none tw:transition-[color,box-shadow] tw:file:inline-flex tw:file:h-7 tw:file:border-0 tw:file:bg-transparent tw:file:text-sm tw:file:font-medium tw:focus-visible:ring-[3px] tw:disabled:pointer-events-none tw:disabled:cursor-not-allowed tw:disabled:opacity-50 md:text-sm', {
9
+ const inputVariants = cva('file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/10 border-input shadow-xs focus-visible:border-ring focus-visible:ring-ring/50 flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base outline-none transition-[color,box-shadow] file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-[3px] disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm', {
10
10
  variants: {
11
11
  error: {
12
- auto: 'tw:[&.ng-invalid.ng-touched]:text-destructive/20 tw:dark:[&.ng-invalid.ng-touched]:text-destructive/40 tw:[&.ng-invalid.ng-touched]:border-destructive tw:[&.ng-invalid.ng-touched]:focus-visible:ring-destructive',
13
- true: 'tw:text-destructive/90 dark:text-destructive/60 tw:border-destructive tw:focus-visible:ring-destructive',
12
+ auto: '[&.ng-invalid.ng-touched]:text-destructive/20 dark:[&.ng-invalid.ng-touched]:text-destructive/40 [&.ng-invalid.ng-touched]:border-destructive [&.ng-invalid.ng-touched]:focus-visible:ring-destructive',
13
+ true: 'text-destructive/90 dark:text-destructive/60 border-destructive focus-visible:ring-destructive',
14
14
  },
15
15
  },
16
16
  defaultVariants: {
@@ -6,7 +6,7 @@ import { hlm } from '@egose/shadcn-theme-ng/utils';
6
6
 
7
7
  class HlmLabel {
8
8
  userClass = input('', ...(ngDevMode ? [{ debugName: "userClass", alias: 'class' }] : [{ alias: 'class' }]));
9
- _computedClass = computed(() => hlm('tw:flex tw:select-none tw:items-center tw:gap-2 tw:text-sm tw:font-medium tw:leading-none tw:peer-disabled:cursor-not-allowed tw:peer-disabled:opacity-50 tw:has-[[disabled]]:cursor-not-allowed tw:has-[[disabled]]:opacity-50 tw:group-data-[disabled=true]:pointer-events-none tw:group-data-[disabled=true]:opacity-50 tw:peer-data-[disabled]:cursor-not-allowed tw:peer-data-[disabled]:opacity-50', this.userClass()), ...(ngDevMode ? [{ debugName: "_computedClass" }] : []));
9
+ _computedClass = computed(() => hlm('flex select-none items-center gap-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-50 has-[[disabled]]:cursor-not-allowed has-[[disabled]]:opacity-50 group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-data-[disabled]:cursor-not-allowed peer-data-[disabled]:opacity-50', this.userClass()), ...(ngDevMode ? [{ debugName: "_computedClass" }] : []));
10
10
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: HlmLabel, deps: [], target: i0.ɵɵFactoryTarget.Directive });
11
11
  static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.1", type: HlmLabel, isStandalone: true, selector: "[hlmLabel]", inputs: { userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "_computedClass()" } }, hostDirectives: [{ directive: i1.BrnLabel, inputs: ["id", "id"] }], ngImport: i0 });
12
12
  }
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.12",
2
+ "version": "0.0.14",
3
3
  "description": "Angular shadcn UI theme",
4
4
  "license": "MIT",
5
5
  "sideEffects": false,
@@ -126,6 +126,14 @@
126
126
  "./autocomplete": {
127
127
  "types": "./autocomplete/index.d.ts",
128
128
  "default": "./autocomplete/fesm2022/autocomplete.mjs"
129
+ },
130
+ "./searchable-multiselect": {
131
+ "types": "./searchable-multiselect/index.d.ts",
132
+ "default": "./searchable-multiselect/fesm2022/searchable-multiselect.mjs"
133
+ },
134
+ "./form-searchable-multiselect": {
135
+ "types": "./form-searchable-multiselect/index.d.ts",
136
+ "default": "./form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs"
129
137
  }
130
138
  }
131
139
  }
@@ -5,7 +5,7 @@ import { injectExposesStateProvider } from '@spartan-ng/brain/core';
5
5
 
6
6
  class HlmPopoverClose {
7
7
  userClass = input('', ...(ngDevMode ? [{ debugName: "userClass", alias: 'class' }] : [{ alias: 'class' }]));
8
- _computedClass = computed(() => hlm('tw:ring-offset-background tw:focus:ring-ring tw:data-[state=open]:bg-accent tw:data-[state=open]:text-muted-foreground tw:absolute tw:right-4 tw:top-4 tw:rounded-sm tw:opacity-70 tw:transition-opacity tw:hover:opacity-100 tw:focus:outline-none tw:focus:ring-2 tw:focus:ring-offset-2 tw:disabled:pointer-events-none', this.userClass()), ...(ngDevMode ? [{ debugName: "_computedClass" }] : []));
8
+ _computedClass = computed(() => hlm('ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none', this.userClass()), ...(ngDevMode ? [{ debugName: "_computedClass" }] : []));
9
9
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: HlmPopoverClose, deps: [], target: i0.ɵɵFactoryTarget.Directive });
10
10
  static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.1", type: HlmPopoverClose, isStandalone: true, selector: "[hlmPopoverClose],[brnPopoverClose][hlm]", inputs: { userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "_computedClass()" } }, ngImport: i0 });
11
11
  }
@@ -30,7 +30,7 @@ class HlmPopoverContent {
30
30
  });
31
31
  }
32
32
  userClass = input('', ...(ngDevMode ? [{ debugName: "userClass", alias: 'class' }] : [{ alias: 'class' }]));
33
- _computedClass = computed(() => hlm('tw:border-border tw:bg-popover tw:text-popover-foreground tw:data-[state=open]:animate-in tw:data-[state=closed]:animate-out tw:data-[state=closed]:fade-out-0 tw:data-[state=open]:fade-in-0 tw:data-[state=closed]:zoom-out-95 tw:data-[state=open]:zoom-in-95 tw:data-[side=bottom]:slide-in-from-top-2 tw:data-[side=left]:slide-in-from-right-2 tw:data-[side=right]:slide-in-from-left-2 tw:data-[side=top]:slide-in-from-bottom-2 tw:relative tw:w-72 tw:rounded-md tw:border tw:p-4 tw:shadow-md tw:outline-none', this.userClass()), ...(ngDevMode ? [{ debugName: "_computedClass" }] : []));
33
+ _computedClass = computed(() => hlm('border-border bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative w-72 rounded-md border p-4 shadow-md outline-none', this.userClass()), ...(ngDevMode ? [{ debugName: "_computedClass" }] : []));
34
34
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: HlmPopoverContent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
35
35
  static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.1", type: HlmPopoverContent, isStandalone: true, selector: "[hlmPopoverContent],[brnPopoverContent][hlm]", inputs: { userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "_computedClass()" } }, ngImport: i0 });
36
36
  }
@@ -11,7 +11,7 @@ class HlmRadio {
11
11
  _elementRef = inject(ElementRef);
12
12
  _isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
13
13
  userClass = input('', ...(ngDevMode ? [{ debugName: "userClass", alias: 'class' }] : [{ alias: 'class' }]));
14
- _computedClass = computed(() => hlm('tw:group tw:flex tw:items-center tw:gap-x-3', this.userClass(), this._state().disabled() ? 'tw:cursor-not-allowed tw:opacity-50' : ''), ...(ngDevMode ? [{ debugName: "_computedClass" }] : []));
14
+ _computedClass = computed(() => hlm('group flex items-center gap-x-3', this.userClass(), this._state().disabled() ? 'cursor-not-allowed opacity-50' : ''), ...(ngDevMode ? [{ debugName: "_computedClass" }] : []));
15
15
  /** Used to set the id on the underlying brn element. */
16
16
  id = input(undefined, ...(ngDevMode ? [{ debugName: "id" }] : []));
17
17
  /** Used to set the aria-label attribute on the underlying brn element. */
@@ -104,7 +104,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
104
104
 
105
105
  class HlmRadioGroup {
106
106
  userClass = input('', ...(ngDevMode ? [{ debugName: "userClass", alias: 'class' }] : [{ alias: 'class' }]));
107
- _computedClass = computed(() => hlm('tw:grid tw:gap-3', this.userClass()), ...(ngDevMode ? [{ debugName: "_computedClass" }] : []));
107
+ _computedClass = computed(() => hlm('grid gap-3', this.userClass()), ...(ngDevMode ? [{ debugName: "_computedClass" }] : []));
108
108
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: HlmRadioGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
109
109
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.1", type: HlmRadioGroup, isStandalone: true, selector: "hlm-radio-group", inputs: { userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "_computedClass()" } }, hostDirectives: [{ directive: i1.BrnRadioGroup, inputs: ["name", "name", "value", "value", "disabled", "disabled", "required", "required", "direction", "direction"], outputs: ["valueChange", "valueChange"] }], ngImport: i0, template: '<ng-content />', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
110
110
  }
@@ -129,9 +129,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
129
129
 
130
130
  class HlmRadioIndicator {
131
131
  userClass = input('', ...(ngDevMode ? [{ debugName: "userClass", alias: 'class' }] : [{ alias: 'class' }]));
132
- _computedClass = computed(() => hlm('tw:border-input tw:text-primary tw:group-has-[:focus-visible]:border-ring tw:group-has-[:focus-visible]:ring-ring/50 tw:dark:bg-input/10 tw:shadow-xs tw:group-data=[disabled=true]:cursor-not-allowed tw:group-data=[disabled=true]:opacity-50 tw:relative tw:flex tw:aspect-square tw:size-4 tw:shrink-0 tw:items-center tw:justify-center tw:rounded-full tw:border tw:outline-none tw:transition-[color,box-shadow] tw:group-has-[:focus-visible]:ring-[3px]', this.userClass()), ...(ngDevMode ? [{ debugName: "_computedClass" }] : []));
132
+ _computedClass = computed(() => hlm('border-input text-primary group-has-[:focus-visible]:border-ring group-has-[:focus-visible]:ring-ring/50 dark:bg-input/10 shadow-xs group-data=[disabled=true]:cursor-not-allowed group-data=[disabled=true]:opacity-50 relative flex aspect-square size-4 shrink-0 items-center justify-center rounded-full border outline-none transition-[color,box-shadow] group-has-[:focus-visible]:ring-[3px]', this.userClass()), ...(ngDevMode ? [{ debugName: "_computedClass" }] : []));
133
133
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: HlmRadioIndicator, deps: [], target: i0.ɵɵFactoryTarget.Component });
134
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.1", type: HlmRadioIndicator, isStandalone: true, selector: "hlm-radio-indicator", inputs: { userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "_computedClass()" } }, ngImport: i0, template: ` <div class="tw:group-data-[checked=true]:bg-primary tw:size-2 tw:rounded-full tw:bg-transparent"></div> `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
134
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.1", type: HlmRadioIndicator, isStandalone: true, selector: "hlm-radio-indicator", inputs: { userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "_computedClass()" } }, ngImport: i0, template: ` <div class="group-data-[checked=true]:bg-primary size-2 rounded-full bg-transparent"></div> `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
135
135
  }
136
136
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: HlmRadioIndicator, decorators: [{
137
137
  type: Component,
@@ -140,7 +140,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
140
140
  host: {
141
141
  '[class]': '_computedClass()',
142
142
  },
143
- template: ` <div class="tw:group-data-[checked=true]:bg-primary tw:size-2 tw:rounded-full tw:bg-transparent"></div> `,
143
+ template: ` <div class="group-data-[checked=true]:bg-primary size-2 rounded-full bg-transparent"></div> `,
144
144
  changeDetection: ChangeDetectionStrategy.OnPush,
145
145
  }]
146
146
  }] });
@@ -0,0 +1,64 @@
1
+ # MultiselectAutocomplete
2
+
3
+ This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.3.0.
4
+
5
+ ## Code scaffolding
6
+
7
+ Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
8
+
9
+ ```bash
10
+ ng generate component component-name
11
+ ```
12
+
13
+ For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
14
+
15
+ ```bash
16
+ ng generate --help
17
+ ```
18
+
19
+ ## Building
20
+
21
+ To build the library, run:
22
+
23
+ ```bash
24
+ ng build searchable-multiselect
25
+ ```
26
+
27
+ This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
28
+
29
+ ### Publishing the Library
30
+
31
+ Once the project is built, you can publish your library by following these steps:
32
+
33
+ 1. Navigate to the `dist` directory:
34
+
35
+ ```bash
36
+ cd dist/searchable-multiselect
37
+ ```
38
+
39
+ 2. Run the `npm publish` command to publish your library to the npm registry:
40
+ ```bash
41
+ npm publish
42
+ ```
43
+
44
+ ## Running unit tests
45
+
46
+ To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
47
+
48
+ ```bash
49
+ ng test
50
+ ```
51
+
52
+ ## Running end-to-end tests
53
+
54
+ For end-to-end (e2e) testing, run:
55
+
56
+ ```bash
57
+ ng e2e
58
+ ```
59
+
60
+ Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
61
+
62
+ ## Additional Resources
63
+
64
+ For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
@@ -0,0 +1,221 @@
1
+ import * as i0 from '@angular/core';
2
+ import { viewChild, input, output, signal, computed, effect, forwardRef, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { NG_VALUE_ACCESSOR } from '@angular/forms';
4
+ import { HlmAutocomplete } from '@egose/shadcn-theme-ng/autocomplete';
5
+
6
+ class EgSearchableMultiselect {
7
+ autoComplete = viewChild(HlmAutocomplete, ...(ngDevMode ? [{ debugName: "autoComplete" }] : []));
8
+ /** Full option list with labels/values */
9
+ options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
10
+ placeholder = input('Start typing to add…', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
11
+ /** Value: array of selected values (string[]) */
12
+ value = input([], ...(ngDevMode ? [{ debugName: "value" }] : []));
13
+ valueChange = output(); // emits string[] of values
14
+ /** Internal state */
15
+ search = signal('', ...(ngDevMode ? [{ debugName: "search" }] : []));
16
+ selectedItems = signal([], ...(ngDevMode ? [{ debugName: "selectedItems" }] : [])); // full objects for display
17
+ isDisabled = false;
18
+ isFormBound = false;
19
+ /** Filtered **labels** for hlm-autocomplete */
20
+ filteredOptionLabels = computed(() => (this.options() || [])
21
+ .filter((opt) => opt.label.toLowerCase().includes(this.search().toLowerCase()) &&
22
+ !this.selectedItems().some((sel) => sel.value === opt.value))
23
+ .map((opt) => opt.label), ...(ngDevMode ? [{ debugName: "filteredOptionLabels" }] : []));
24
+ /** Form callbacks */
25
+ onChange = () => { };
26
+ onTouched = () => { };
27
+ constructor() {
28
+ // Sync `value` input to selectedItems for standalone usage
29
+ effect(() => {
30
+ if (!this.isFormBound) {
31
+ this.updateSelectedFromValues(this.value() || []);
32
+ }
33
+ });
34
+ }
35
+ /** Add by label string (from autocomplete) */
36
+ addItemByLabel(label) {
37
+ const opt = this.options()?.find((o) => o.label === label);
38
+ if (opt) {
39
+ this.addItem(opt.value);
40
+ }
41
+ }
42
+ /** Add by value string */
43
+ addItem(value) {
44
+ if (!this.selectedItems().some((sel) => sel.value === value)) {
45
+ const opt = this.options()?.find((o) => o.value === value);
46
+ if (!opt)
47
+ return;
48
+ const updatedItems = [...this.selectedItems(), opt];
49
+ this.updateValueFromSelected(updatedItems);
50
+ }
51
+ }
52
+ /** Remove by value string */
53
+ removeItem(value) {
54
+ const updatedItems = this.selectedItems().filter((i) => i.value !== value);
55
+ this.updateValueFromSelected(updatedItems);
56
+ }
57
+ /** Clear autocomplete text */
58
+ clearAutocompleteText() {
59
+ this.autoComplete()?.clearText();
60
+ if (this.options().length === this.selectedItems().length) {
61
+ this.autoComplete()?.setPopoverState('closed');
62
+ }
63
+ }
64
+ handleSelect(label) {
65
+ this.clearAutocompleteText();
66
+ }
67
+ /** Map string[] values → full objects */
68
+ updateSelectedFromValues(values) {
69
+ const opts = this.options() || [];
70
+ const matched = opts.filter((o) => values.includes(o.value));
71
+ this.selectedItems.set(matched);
72
+ }
73
+ /** Map full objects → string[] values and emit */
74
+ updateValueFromSelected(items) {
75
+ this.selectedItems.set(items);
76
+ const values = items.map((i) => i.value);
77
+ this.valueChange.emit(values);
78
+ this.onChange(values);
79
+ this.onTouched();
80
+ }
81
+ // --- ControlValueAccessor ---
82
+ writeValue(values) {
83
+ this.isFormBound = true;
84
+ this.updateSelectedFromValues(values || []);
85
+ }
86
+ registerOnChange(fn) {
87
+ this.onChange = fn;
88
+ }
89
+ registerOnTouched(fn) {
90
+ this.onTouched = fn;
91
+ }
92
+ setDisabledState(isDisabled) {
93
+ this.isDisabled = isDisabled;
94
+ }
95
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: EgSearchableMultiselect, deps: [], target: i0.ɵɵFactoryTarget.Component });
96
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: EgSearchableMultiselect, isStandalone: true, selector: "eg-searchable-multiselect", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, providers: [
97
+ {
98
+ provide: NG_VALUE_ACCESSOR,
99
+ useExisting: forwardRef(() => EgSearchableMultiselect),
100
+ multi: true,
101
+ },
102
+ ], viewQueries: [{ propertyName: "autoComplete", first: true, predicate: HlmAutocomplete, descendants: true, isSignal: true }], ngImport: i0, template: `
103
+ <div class="flex flex-col gap-2 w-full">
104
+ <!-- Selected items -->
105
+ <div
106
+ class="flex gap-2 overflow-x-auto whitespace-nowrap
107
+ [scrollbar-width:none] [-ms-overflow-style:none]
108
+ [&::-webkit-scrollbar]:hidden"
109
+ >
110
+ @if (selectedItems().length === 0) {
111
+ <span
112
+ class="bg-gray-100 text-gray-400 rounded-full
113
+ px-2 py-1 inline-flex items-center text-xs"
114
+ >
115
+ {{ placeholder() }}
116
+ </span>
117
+ } @else {
118
+ @for (item of selectedItems(); track item.value) {
119
+ <span
120
+ class="bg-gray-200 rounded-full px-2 py-1
121
+ inline-flex items-center gap-2 text-xs"
122
+ >
123
+ {{ item.label }}
124
+ <button
125
+ type="button"
126
+ (click)="removeItem(item.value)"
127
+ class="bg-transparent border-0 text-gray-600
128
+ hover:text-red-500 cursor-pointer"
129
+ >
130
+ ✕
131
+ </button>
132
+ </span>
133
+ }
134
+ }
135
+ </div>
136
+
137
+ <!-- Autocomplete -->
138
+ <hlm-autocomplete
139
+ [filteredOptions]="filteredOptionLabels()"
140
+ [(search)]="search"
141
+ (valueChange)="addItemByLabel($event)"
142
+ [searchPlaceholderText]="this.selectedItems().length.toString() + ' of ' + this.options().length + ' selected'"
143
+ [onSelect]="handleSelect.bind(this)"
144
+ [disabled]="isDisabled"
145
+ />
146
+ </div>
147
+ `, isInline: true, dependencies: [{ kind: "component", type: HlmAutocomplete, selector: "hlm-autocomplete", inputs: ["onSelect", "class", "autocompleteListClass", "autocompleteEmptyClass", "filteredOptions", "value", "search", "transformValueToSearch", "optionTemplate", "loading", "searchPlaceholderText", "loadingText", "emptyText", "ariaLabelToggleButton", "inputId", "disabled"], outputs: ["valueChange", "searchChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
148
+ }
149
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: EgSearchableMultiselect, decorators: [{
150
+ type: Component,
151
+ args: [{
152
+ selector: 'eg-searchable-multiselect',
153
+ standalone: true,
154
+ imports: [HlmAutocomplete],
155
+ changeDetection: ChangeDetectionStrategy.OnPush,
156
+ providers: [
157
+ {
158
+ provide: NG_VALUE_ACCESSOR,
159
+ useExisting: forwardRef(() => EgSearchableMultiselect),
160
+ multi: true,
161
+ },
162
+ ],
163
+ template: `
164
+ <div class="flex flex-col gap-2 w-full">
165
+ <!-- Selected items -->
166
+ <div
167
+ class="flex gap-2 overflow-x-auto whitespace-nowrap
168
+ [scrollbar-width:none] [-ms-overflow-style:none]
169
+ [&::-webkit-scrollbar]:hidden"
170
+ >
171
+ @if (selectedItems().length === 0) {
172
+ <span
173
+ class="bg-gray-100 text-gray-400 rounded-full
174
+ px-2 py-1 inline-flex items-center text-xs"
175
+ >
176
+ {{ placeholder() }}
177
+ </span>
178
+ } @else {
179
+ @for (item of selectedItems(); track item.value) {
180
+ <span
181
+ class="bg-gray-200 rounded-full px-2 py-1
182
+ inline-flex items-center gap-2 text-xs"
183
+ >
184
+ {{ item.label }}
185
+ <button
186
+ type="button"
187
+ (click)="removeItem(item.value)"
188
+ class="bg-transparent border-0 text-gray-600
189
+ hover:text-red-500 cursor-pointer"
190
+ >
191
+ ✕
192
+ </button>
193
+ </span>
194
+ }
195
+ }
196
+ </div>
197
+
198
+ <!-- Autocomplete -->
199
+ <hlm-autocomplete
200
+ [filteredOptions]="filteredOptionLabels()"
201
+ [(search)]="search"
202
+ (valueChange)="addItemByLabel($event)"
203
+ [searchPlaceholderText]="this.selectedItems().length.toString() + ' of ' + this.options().length + ' selected'"
204
+ [onSelect]="handleSelect.bind(this)"
205
+ [disabled]="isDisabled"
206
+ />
207
+ </div>
208
+ `,
209
+ }]
210
+ }], ctorParameters: () => [] });
211
+
212
+ /*
213
+ * Public API Surface of searchable-multiselect
214
+ */
215
+
216
+ /**
217
+ * Generated bundle index. Do not edit.
218
+ */
219
+
220
+ export { EgSearchableMultiselect };
221
+ //# sourceMappingURL=searchable-multiselect.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"searchable-multiselect.mjs","sources":["../../../projects/searchable-multiselect/src/lib/searchable-multiselect.ts","../../../projects/searchable-multiselect/src/public-api.ts","../../../projects/searchable-multiselect/src/searchable-multiselect.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n signal,\n input,\n output,\n viewChild,\n effect,\n forwardRef,\n} from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { HlmAutocomplete } from '@egose/shadcn-theme-ng/autocomplete';\n\nexport interface SelectOption {\n label: string;\n value: string;\n}\n\n@Component({\n selector: 'eg-searchable-multiselect',\n standalone: true,\n imports: [HlmAutocomplete],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => EgSearchableMultiselect),\n multi: true,\n },\n ],\n template: `\n <div class=\"tw:flex tw:flex-col tw:gap-2 tw:w-full\">\n <!-- Selected items -->\n <div\n class=\"tw:flex tw:gap-2 tw:overflow-x-auto tw:whitespace-nowrap\n tw:[scrollbar-width:none] tw:[-ms-overflow-style:none]\n tw:[&::-webkit-scrollbar]:hidden\"\n >\n @if (selectedItems().length === 0) {\n <span\n class=\"tw:bg-gray-100 tw:text-gray-400 tw:rounded-full\n tw:px-2 tw:py-1 tw:inline-flex tw:items-center tw:text-xs\"\n >\n {{ placeholder() }}\n </span>\n } @else {\n @for (item of selectedItems(); track item.value) {\n <span\n class=\"tw:bg-gray-200 tw:rounded-full tw:px-2 tw:py-1\n tw:inline-flex tw:items-center tw:gap-2 tw:text-xs\"\n >\n {{ item.label }}\n <button\n type=\"button\"\n (click)=\"removeItem(item.value)\"\n class=\"tw:bg-transparent tw:border-0 tw:text-gray-600\n tw:hover:text-red-500 tw:cursor-pointer\"\n >\n ✕\n </button>\n </span>\n }\n }\n </div>\n\n <!-- Autocomplete -->\n <hlm-autocomplete\n [filteredOptions]=\"filteredOptionLabels()\"\n [(search)]=\"search\"\n (valueChange)=\"addItemByLabel($event)\"\n [searchPlaceholderText]=\"this.selectedItems().length.toString() + ' of ' + this.options().length + ' selected'\"\n [onSelect]=\"handleSelect.bind(this)\"\n [disabled]=\"isDisabled\"\n />\n </div>\n `,\n})\nexport class EgSearchableMultiselect implements ControlValueAccessor {\n autoComplete = viewChild(HlmAutocomplete);\n\n /** Full option list with labels/values */\n options = input<SelectOption[]>([]);\n placeholder = input<string>('Start typing to add…');\n\n /** Value: array of selected values (string[]) */\n value = input<string[]>([]);\n valueChange = output<string[]>(); // emits string[] of values\n\n /** Internal state */\n search = signal<string>('');\n selectedItems = signal<SelectOption[]>([]); // full objects for display\n isDisabled = false;\n private isFormBound = false;\n\n /** Filtered **labels** for hlm-autocomplete */\n filteredOptionLabels = computed(\n () =>\n (this.options() || [])\n .filter(\n (opt) =>\n opt.label.toLowerCase().includes(this.search().toLowerCase()) &&\n !this.selectedItems().some((sel) => sel.value === opt.value),\n )\n .map((opt) => opt.label), // convert to string[] for hlm-autocomplete\n );\n\n /** Form callbacks */\n private onChange: (value: string[]) => void = () => {};\n private onTouched: () => void = () => {};\n\n constructor() {\n // Sync `value` input to selectedItems for standalone usage\n effect(() => {\n if (!this.isFormBound) {\n this.updateSelectedFromValues(this.value() || []);\n }\n });\n }\n\n /** Add by label string (from autocomplete) */\n addItemByLabel(label: string) {\n const opt = this.options()?.find((o) => o.label === label);\n if (opt) {\n this.addItem(opt.value);\n }\n }\n\n /** Add by value string */\n addItem(value: string) {\n if (!this.selectedItems().some((sel) => sel.value === value)) {\n const opt = this.options()?.find((o) => o.value === value);\n if (!opt) return;\n const updatedItems = [...this.selectedItems(), opt];\n this.updateValueFromSelected(updatedItems);\n }\n }\n\n /** Remove by value string */\n removeItem(value: string) {\n const updatedItems = this.selectedItems().filter((i) => i.value !== value);\n this.updateValueFromSelected(updatedItems);\n }\n\n /** Clear autocomplete text */\n clearAutocompleteText() {\n this.autoComplete()?.clearText();\n\n if (this.options().length === this.selectedItems().length) {\n this.autoComplete()?.setPopoverState('closed');\n }\n }\n\n handleSelect(label: string) {\n this.clearAutocompleteText();\n }\n\n /** Map string[] values → full objects */\n private updateSelectedFromValues(values: string[]) {\n const opts = this.options() || [];\n const matched = opts.filter((o) => values.includes(o.value));\n this.selectedItems.set(matched);\n }\n\n /** Map full objects → string[] values and emit */\n private updateValueFromSelected(items: SelectOption[]) {\n this.selectedItems.set(items);\n const values = items.map((i) => i.value);\n this.valueChange.emit(values);\n this.onChange(values);\n this.onTouched();\n }\n\n // --- ControlValueAccessor ---\n writeValue(values: string[] | null): void {\n this.isFormBound = true;\n this.updateSelectedFromValues(values || []);\n }\n\n registerOnChange(fn: (value: string[]) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.isDisabled = isDisabled;\n }\n}\n","/*\n * Public API Surface of searchable-multiselect\n */\n\nexport * from './lib/searchable-multiselect';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { ControlValueAccessor } from '@angular/forms';
3
+ import { HlmAutocomplete } from '@egose/shadcn-theme-ng/autocomplete';
4
+
5
+ interface SelectOption {
6
+ label: string;
7
+ value: string;
8
+ }
9
+ declare class EgSearchableMultiselect implements ControlValueAccessor {
10
+ autoComplete: _angular_core.Signal<HlmAutocomplete<any> | undefined>;
11
+ /** Full option list with labels/values */
12
+ options: _angular_core.InputSignal<SelectOption[]>;
13
+ placeholder: _angular_core.InputSignal<string>;
14
+ /** Value: array of selected values (string[]) */
15
+ value: _angular_core.InputSignal<string[]>;
16
+ valueChange: _angular_core.OutputEmitterRef<string[]>;
17
+ /** Internal state */
18
+ search: _angular_core.WritableSignal<string>;
19
+ selectedItems: _angular_core.WritableSignal<SelectOption[]>;
20
+ isDisabled: boolean;
21
+ private isFormBound;
22
+ /** Filtered **labels** for hlm-autocomplete */
23
+ filteredOptionLabels: _angular_core.Signal<string[]>;
24
+ /** Form callbacks */
25
+ private onChange;
26
+ private onTouched;
27
+ constructor();
28
+ /** Add by label string (from autocomplete) */
29
+ addItemByLabel(label: string): void;
30
+ /** Add by value string */
31
+ addItem(value: string): void;
32
+ /** Remove by value string */
33
+ removeItem(value: string): void;
34
+ /** Clear autocomplete text */
35
+ clearAutocompleteText(): void;
36
+ handleSelect(label: string): void;
37
+ /** Map string[] values → full objects */
38
+ private updateSelectedFromValues;
39
+ /** Map full objects → string[] values and emit */
40
+ private updateValueFromSelected;
41
+ writeValue(values: string[] | null): void;
42
+ registerOnChange(fn: (value: string[]) => void): void;
43
+ registerOnTouched(fn: () => void): void;
44
+ setDisabledState(isDisabled: boolean): void;
45
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<EgSearchableMultiselect, never>;
46
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EgSearchableMultiselect, "eg-searchable-multiselect", never, { "options": { "alias": "options"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
47
+ }
48
+
49
+ export { EgSearchableMultiselect };
50
+ export type { SelectOption };