@raintonic/formaui 0.2.1 → 0.3.0

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 (169) hide show
  1. package/CHANGELOG.md +100 -3
  2. package/LICENSE +21 -0
  3. package/README.md +80 -26
  4. package/fesm2022/raintonic-formaui-components-accordion.mjs +2 -2
  5. package/fesm2022/raintonic-formaui-components-accordion.mjs.map +1 -1
  6. package/fesm2022/raintonic-formaui-components-alert.mjs +24 -5
  7. package/fesm2022/raintonic-formaui-components-alert.mjs.map +1 -1
  8. package/fesm2022/raintonic-formaui-components-autocomplete.mjs +38 -9
  9. package/fesm2022/raintonic-formaui-components-autocomplete.mjs.map +1 -1
  10. package/fesm2022/raintonic-formaui-components-badge.mjs +45 -31
  11. package/fesm2022/raintonic-formaui-components-badge.mjs.map +1 -1
  12. package/fesm2022/raintonic-formaui-components-big-menu.mjs +23 -5
  13. package/fesm2022/raintonic-formaui-components-big-menu.mjs.map +1 -1
  14. package/fesm2022/raintonic-formaui-components-breadcrumb.mjs +24 -7
  15. package/fesm2022/raintonic-formaui-components-breadcrumb.mjs.map +1 -1
  16. package/fesm2022/raintonic-formaui-components-button-group.mjs +6 -6
  17. package/fesm2022/raintonic-formaui-components-button-group.mjs.map +1 -1
  18. package/fesm2022/raintonic-formaui-components-button.mjs +63 -17
  19. package/fesm2022/raintonic-formaui-components-button.mjs.map +1 -1
  20. package/fesm2022/raintonic-formaui-components-card.mjs +8 -8
  21. package/fesm2022/raintonic-formaui-components-card.mjs.map +1 -1
  22. package/fesm2022/raintonic-formaui-components-checkbox.mjs +2 -2
  23. package/fesm2022/raintonic-formaui-components-checkbox.mjs.map +1 -1
  24. package/fesm2022/raintonic-formaui-components-data-table.mjs +67 -9
  25. package/fesm2022/raintonic-formaui-components-data-table.mjs.map +1 -1
  26. package/fesm2022/raintonic-formaui-components-date-picker.mjs +63 -16
  27. package/fesm2022/raintonic-formaui-components-date-picker.mjs.map +1 -1
  28. package/fesm2022/raintonic-formaui-components-drawer.mjs +19 -4
  29. package/fesm2022/raintonic-formaui-components-drawer.mjs.map +1 -1
  30. package/fesm2022/raintonic-formaui-components-file-upload.mjs +25 -5
  31. package/fesm2022/raintonic-formaui-components-file-upload.mjs.map +1 -1
  32. package/fesm2022/raintonic-formaui-components-form-field.mjs +21 -6
  33. package/fesm2022/raintonic-formaui-components-form-field.mjs.map +1 -1
  34. package/fesm2022/raintonic-formaui-components-icon.mjs +2 -2
  35. package/fesm2022/raintonic-formaui-components-icon.mjs.map +1 -1
  36. package/fesm2022/raintonic-formaui-components-input.mjs +1 -1
  37. package/fesm2022/raintonic-formaui-components-input.mjs.map +1 -1
  38. package/fesm2022/raintonic-formaui-components-list.mjs +4 -4
  39. package/fesm2022/raintonic-formaui-components-list.mjs.map +1 -1
  40. package/fesm2022/raintonic-formaui-components-menu.mjs +4 -4
  41. package/fesm2022/raintonic-formaui-components-menu.mjs.map +1 -1
  42. package/fesm2022/raintonic-formaui-components-number-input.mjs +20 -5
  43. package/fesm2022/raintonic-formaui-components-number-input.mjs.map +1 -1
  44. package/fesm2022/raintonic-formaui-components-paginator.mjs +27 -7
  45. package/fesm2022/raintonic-formaui-components-paginator.mjs.map +1 -1
  46. package/fesm2022/raintonic-formaui-components-password-input.mjs +23 -5
  47. package/fesm2022/raintonic-formaui-components-password-input.mjs.map +1 -1
  48. package/fesm2022/raintonic-formaui-components-popover.mjs +2 -2
  49. package/fesm2022/raintonic-formaui-components-popover.mjs.map +1 -1
  50. package/fesm2022/raintonic-formaui-components-progressbar.mjs +32 -7
  51. package/fesm2022/raintonic-formaui-components-progressbar.mjs.map +1 -1
  52. package/fesm2022/raintonic-formaui-components-radio.mjs +4 -4
  53. package/fesm2022/raintonic-formaui-components-radio.mjs.map +1 -1
  54. package/fesm2022/raintonic-formaui-components-select.mjs +19 -4
  55. package/fesm2022/raintonic-formaui-components-select.mjs.map +1 -1
  56. package/fesm2022/raintonic-formaui-components-side-panel.mjs +19 -4
  57. package/fesm2022/raintonic-formaui-components-side-panel.mjs.map +1 -1
  58. package/fesm2022/raintonic-formaui-components-sidebar.mjs +23 -5
  59. package/fesm2022/raintonic-formaui-components-sidebar.mjs.map +1 -1
  60. package/fesm2022/raintonic-formaui-components-skeleton.mjs +2 -2
  61. package/fesm2022/raintonic-formaui-components-skeleton.mjs.map +1 -1
  62. package/fesm2022/raintonic-formaui-components-slider.mjs +23 -5
  63. package/fesm2022/raintonic-formaui-components-slider.mjs.map +1 -1
  64. package/fesm2022/raintonic-formaui-components-spinner.mjs +24 -7
  65. package/fesm2022/raintonic-formaui-components-spinner.mjs.map +1 -1
  66. package/fesm2022/raintonic-formaui-components-stepper.mjs +2 -2
  67. package/fesm2022/raintonic-formaui-components-stepper.mjs.map +1 -1
  68. package/fesm2022/raintonic-formaui-components-tab.mjs +2 -2
  69. package/fesm2022/raintonic-formaui-components-tab.mjs.map +1 -1
  70. package/fesm2022/raintonic-formaui-components-tag.mjs +21 -4
  71. package/fesm2022/raintonic-formaui-components-tag.mjs.map +1 -1
  72. package/fesm2022/raintonic-formaui-components-time-picker.mjs +26 -7
  73. package/fesm2022/raintonic-formaui-components-time-picker.mjs.map +1 -1
  74. package/fesm2022/raintonic-formaui-components-toggle.mjs +2 -2
  75. package/fesm2022/raintonic-formaui-components-toggle.mjs.map +1 -1
  76. package/fesm2022/raintonic-formaui-components-toolbar.mjs +41 -7
  77. package/fesm2022/raintonic-formaui-components-toolbar.mjs.map +1 -1
  78. package/fesm2022/raintonic-formaui-components-tooltip.mjs +2 -2
  79. package/fesm2022/raintonic-formaui-components-tooltip.mjs.map +1 -1
  80. package/fesm2022/raintonic-formaui-components-tree-table.mjs +35 -6
  81. package/fesm2022/raintonic-formaui-components-tree-table.mjs.map +1 -1
  82. package/fesm2022/raintonic-formaui-components-tree.mjs +23 -5
  83. package/fesm2022/raintonic-formaui-components-tree.mjs.map +1 -1
  84. package/fesm2022/raintonic-formaui-core.mjs +25 -1
  85. package/fesm2022/raintonic-formaui-core.mjs.map +1 -1
  86. package/fesm2022/raintonic-formaui-services-dialog.mjs +3 -3
  87. package/fesm2022/raintonic-formaui-services-dialog.mjs.map +1 -1
  88. package/fesm2022/raintonic-formaui-services-notification.mjs +2 -2
  89. package/fesm2022/raintonic-formaui-services-notification.mjs.map +1 -1
  90. package/fesm2022/raintonic-formaui-services-theme.mjs +3 -3
  91. package/fesm2022/raintonic-formaui-services-theme.mjs.map +1 -1
  92. package/fesm2022/raintonic-formaui-test-utils.mjs +21 -16
  93. package/fesm2022/raintonic-formaui-test-utils.mjs.map +1 -1
  94. package/fesm2022/raintonic-formaui.mjs +1 -1
  95. package/fesm2022/raintonic-formaui.mjs.map +1 -1
  96. package/llms-full.txt +33 -25
  97. package/llms.txt +1 -2
  98. package/package.json +1 -5
  99. package/styles/index.scss +2 -2
  100. package/styles/partials/_motion.scss +25 -0
  101. package/styles/partials/_theme.scss +6 -5
  102. package/styles/partials/components/_button.scss +361 -367
  103. package/styles/partials/themes/_dark.scss +14 -0
  104. package/styles/partials/themes/_light.scss +14 -0
  105. package/types/raintonic-formaui-components-alert.d.ts +11 -1
  106. package/types/raintonic-formaui-components-alert.d.ts.map +1 -1
  107. package/types/raintonic-formaui-components-autocomplete.d.ts +25 -7
  108. package/types/raintonic-formaui-components-autocomplete.d.ts.map +1 -1
  109. package/types/raintonic-formaui-components-badge.d.ts +20 -9
  110. package/types/raintonic-formaui-components-badge.d.ts.map +1 -1
  111. package/types/raintonic-formaui-components-big-menu.d.ts +12 -1
  112. package/types/raintonic-formaui-components-big-menu.d.ts.map +1 -1
  113. package/types/raintonic-formaui-components-breadcrumb.d.ts +11 -2
  114. package/types/raintonic-formaui-components-breadcrumb.d.ts.map +1 -1
  115. package/types/raintonic-formaui-components-button-group.d.ts +6 -6
  116. package/types/raintonic-formaui-components-button.d.ts +9 -7
  117. package/types/raintonic-formaui-components-button.d.ts.map +1 -1
  118. package/types/raintonic-formaui-components-card.d.ts +4 -4
  119. package/types/raintonic-formaui-components-checkbox.d.ts +1 -1
  120. package/types/raintonic-formaui-components-data-table.d.ts +56 -16
  121. package/types/raintonic-formaui-components-data-table.d.ts.map +1 -1
  122. package/types/raintonic-formaui-components-date-picker.d.ts +32 -4
  123. package/types/raintonic-formaui-components-date-picker.d.ts.map +1 -1
  124. package/types/raintonic-formaui-components-drawer.d.ts +10 -1
  125. package/types/raintonic-formaui-components-drawer.d.ts.map +1 -1
  126. package/types/raintonic-formaui-components-file-upload.d.ts +12 -1
  127. package/types/raintonic-formaui-components-file-upload.d.ts.map +1 -1
  128. package/types/raintonic-formaui-components-form-field.d.ts +12 -2
  129. package/types/raintonic-formaui-components-form-field.d.ts.map +1 -1
  130. package/types/raintonic-formaui-components-input.d.ts +1 -1
  131. package/types/raintonic-formaui-components-number-input.d.ts +11 -2
  132. package/types/raintonic-formaui-components-number-input.d.ts.map +1 -1
  133. package/types/raintonic-formaui-components-paginator.d.ts +13 -1
  134. package/types/raintonic-formaui-components-paginator.d.ts.map +1 -1
  135. package/types/raintonic-formaui-components-password-input.d.ts +12 -2
  136. package/types/raintonic-formaui-components-password-input.d.ts.map +1 -1
  137. package/types/raintonic-formaui-components-progressbar.d.ts +14 -1
  138. package/types/raintonic-formaui-components-progressbar.d.ts.map +1 -1
  139. package/types/raintonic-formaui-components-select.d.ts.map +1 -1
  140. package/types/raintonic-formaui-components-side-panel.d.ts +10 -1
  141. package/types/raintonic-formaui-components-side-panel.d.ts.map +1 -1
  142. package/types/raintonic-formaui-components-sidebar.d.ts +12 -1
  143. package/types/raintonic-formaui-components-sidebar.d.ts.map +1 -1
  144. package/types/raintonic-formaui-components-slider.d.ts +12 -1
  145. package/types/raintonic-formaui-components-slider.d.ts.map +1 -1
  146. package/types/raintonic-formaui-components-spinner.d.ts +12 -2
  147. package/types/raintonic-formaui-components-spinner.d.ts.map +1 -1
  148. package/types/raintonic-formaui-components-tag.d.ts +10 -1
  149. package/types/raintonic-formaui-components-tag.d.ts.map +1 -1
  150. package/types/raintonic-formaui-components-time-picker.d.ts +14 -2
  151. package/types/raintonic-formaui-components-time-picker.d.ts.map +1 -1
  152. package/types/raintonic-formaui-components-toggle.d.ts +1 -1
  153. package/types/raintonic-formaui-components-toolbar.d.ts +22 -4
  154. package/types/raintonic-formaui-components-toolbar.d.ts.map +1 -1
  155. package/types/raintonic-formaui-components-tree-table.d.ts +29 -4
  156. package/types/raintonic-formaui-components-tree-table.d.ts.map +1 -1
  157. package/types/raintonic-formaui-components-tree.d.ts +12 -1
  158. package/types/raintonic-formaui-components-tree.d.ts.map +1 -1
  159. package/types/raintonic-formaui-core.d.ts +19 -2
  160. package/types/raintonic-formaui-core.d.ts.map +1 -1
  161. package/types/raintonic-formaui-services-dialog.d.ts +1 -1
  162. package/types/raintonic-formaui-services-theme.d.ts +3 -3
  163. package/types/raintonic-formaui-test-utils.d.ts +15 -2
  164. package/types/raintonic-formaui-test-utils.d.ts.map +1 -1
  165. package/types/raintonic-formaui.d.ts +1 -1
  166. package/fesm2022/raintonic-formaui-components-dynamic-form.mjs +0 -266
  167. package/fesm2022/raintonic-formaui-components-dynamic-form.mjs.map +0 -1
  168. package/types/raintonic-formaui-components-dynamic-form.d.ts +0 -412
  169. package/types/raintonic-formaui-components-dynamic-form.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"raintonic-formaui-components-autocomplete.mjs","sources":["../../../lib/components/autocomplete/autocomplete.component.ts","../../../lib/components/autocomplete/autocomplete.component.html","../../../lib/components/autocomplete/raintonic-formaui-components-autocomplete.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n contentChildren,\r\n DoCheck,\r\n effect,\r\n ElementRef,\r\n inject,\r\n InjectionToken,\r\n NgZone,\r\n input,\r\n InputSignal,\r\n OnDestroy,\r\n output,\r\n OutputEmitterRef,\r\n signal,\r\n Signal,\r\n ViewChild,\r\n ViewEncapsulation,\r\n WritableSignal,\r\n} from '@angular/core';\r\n\r\nimport {\r\n ControlValueAccessor,\r\n FormGroupDirective,\r\n NG_VALUE_ACCESSOR,\r\n NgControl,\r\n NgForm,\r\n ReactiveFormsModule,\r\n} from '@angular/forms';\r\nimport { DOCUMENT } from '@angular/common';\r\nimport { fromEvent, Subject, Subscription } from 'rxjs';\r\nimport { filter } from 'rxjs/operators';\r\nimport { injectNgControl, updateErrorState, syncRequiredState, syncNgControlDisabled } from '@raintonic/formaui/cdk/form-field';\r\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\r\nimport { FuiButtonDirective } from '@raintonic/formaui/components/button';\r\nimport { FUI_FORM_FIELD_CONTROL, FuiFormFieldControl } from '@raintonic/formaui/core';\r\nimport { DefaultErrorStateMatcher, ErrorStateMatcher } from '@raintonic/formaui/core';\r\nimport { FuiOptionComponent } from '@raintonic/formaui/components/select';\r\nimport { FuiOverlayService, FuiOverlayRef, FuiConnectedPosition } from '@raintonic/formaui/cdk/overlay';\r\n\r\n/**\r\n * Injection token used to provide the parent autocomplete to options\r\n */\r\nexport const FUI_AUTOCOMPLETE = new InjectionToken<FuiAutocompleteComponent>('FUI_AUTOCOMPLETE');\r\n\r\n/**\r\n * Selection change event object emitted when the autocomplete's selection changes\r\n */\r\nexport interface FuiAutocompleteChange {\r\n source: FuiAutocompleteComponent;\r\n value: unknown;\r\n}\r\n\r\n/**\r\n * # fui-autocomplete Component\r\n *\r\n * An autocomplete component designed to work seamlessly with fui-form-field.\r\n * Similar to Angular Material's mat-autocomplete integration with mat-form-field.\r\n * Provides full Reactive Forms support with validation, filtering, and optional\r\n * add/refresh actions.\r\n *\r\n * ## Features\r\n * - Works inside fui-form-field like mat-autocomplete\r\n * - Full Reactive Forms integration (ControlValueAccessor)\r\n * - Options via projected content (fui-option)\r\n * - Built-in search/filter input in the panel\r\n * - Optional \"Add New\" and \"Refresh\" action buttons\r\n * - Disabled and readonly states\r\n * - Full accessibility support\r\n * - Full keyboard navigation (Arrow keys, Enter, Escape, Home, End, PageUp, PageDown)\r\n * - Uses overlay service for proper positioning\r\n *\r\n * ## Usage\r\n *\r\n * ### Basic Autocomplete with Form Field\r\n * ```html\r\n * <fui-form-field>\r\n * <label>Country</label>\r\n * <fui-autocomplete placeholder=\"Search countries...\">\r\n * <fui-option value=\"us\">United States</fui-option>\r\n * <fui-option value=\"ca\">Canada</fui-option>\r\n * <fui-option value=\"mx\">Mexico</fui-option>\r\n * </fui-autocomplete>\r\n * </fui-form-field>\r\n * ```\r\n *\r\n * ### With Reactive Forms and Validation\r\n * ```html\r\n * <form [formGroup]=\"form\">\r\n * <fui-form-field>\r\n * <label>Country</label>\r\n * <fui-autocomplete formControlName=\"country\" placeholder=\"Select a country\">\r\n * <fui-option value=\"us\">United States</fui-option>\r\n * <fui-option value=\"ca\">Canada</fui-option>\r\n * </fui-autocomplete>\r\n * <fui-error *ngIf=\"form.get('country')?.hasError('required')\">\r\n * Country is required\r\n * </fui-error>\r\n * </fui-form-field>\r\n * </form>\r\n * ```\r\n *\r\n * ### With Add/Refresh Buttons\r\n * ```html\r\n * <fui-form-field>\r\n * <label>Category</label>\r\n * <fui-autocomplete\r\n * placeholder=\"Search categories...\"\r\n * [showAddButton]=\"true\"\r\n * [showRefreshButton]=\"true\"\r\n * (addNew)=\"openAddCategoryDialog()\"\r\n * (refresh)=\"refreshCategories()\">\r\n * @for (category of categories; track category.id) {\r\n * <fui-option [value]=\"category.id\">{{ category.name }}</fui-option>\r\n * }\r\n * </fui-autocomplete>\r\n * </fui-form-field>\r\n * ```\r\n */\r\n@Component({\r\n selector: 'fui-autocomplete',\r\n standalone: true,\r\n imports: [FuiIconComponent, ReactiveFormsModule, FuiButtonDirective],\r\n templateUrl: './autocomplete.component.html',\r\n styleUrls: ['./autocomplete.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n host: {\r\n class: 'fui-autocomplete',\r\n '[attr.id]': 'id',\r\n '[class.fui-autocomplete--open]': 'panelOpen()',\r\n '[class.fui-autocomplete--disabled]': 'disabled()',\r\n '[class.fui-autocomplete--focused]': 'focused()',\r\n '[class.fui-autocomplete--error]': 'errorState()',\r\n '[class.fui-autocomplete--readonly]': '_readOnly()',\r\n },\r\n providers: [\r\n {\r\n provide: NG_VALUE_ACCESSOR,\r\n useExisting: FuiAutocompleteComponent,\r\n multi: true,\r\n },\r\n {\r\n provide: FUI_FORM_FIELD_CONTROL,\r\n useExisting: FuiAutocompleteComponent,\r\n },\r\n {\r\n provide: FUI_AUTOCOMPLETE,\r\n useExisting: FuiAutocompleteComponent,\r\n },\r\n ],\r\n})\r\nexport class FuiAutocompleteComponent implements ControlValueAccessor, FuiFormFieldControl, DoCheck, OnDestroy {\r\n // Static properties\r\n static nextId = 0;\r\n readonly controlType = 'fui-autocomplete';\r\n\r\n // Inputs using signal-based API\r\n readonly placeholderInput: InputSignal<string> = input('', {\r\n alias: 'placeholder',\r\n });\r\n readonly disabledInput: InputSignal<boolean> = input(false, {\r\n alias: 'disabled',\r\n });\r\n readonly readonly: InputSignal<boolean> = input(false);\r\n readonly showAddButton: InputSignal<boolean> = input(false);\r\n readonly showRefreshButton: InputSignal<boolean> = input(false);\r\n readonly addButtonLabel: InputSignal<string> = input('Add New');\r\n readonly refreshButtonLabel: InputSignal<string> = input('Refresh');\r\n readonly noOptionsText: InputSignal<string> = input('No options found');\r\n readonly searchPlaceholder: InputSignal<string> = input('Search...');\r\n readonly errorStateMatcher: InputSignal<ErrorStateMatcher | null> = input<ErrorStateMatcher | null>(null);\r\n\r\n /**\r\n * Whether to compare option values using object identity or deep equality\r\n */\r\n readonly compareWith: InputSignal<(o1: unknown, o2: unknown) => boolean> = input<\r\n (o1: unknown, o2: unknown) => boolean\r\n >((o1, o2) => o1 === o2);\r\n\r\n // Outputs\r\n readonly valueChange: OutputEmitterRef<unknown> = output<unknown>();\r\n readonly selectionChange: OutputEmitterRef<FuiAutocompleteChange> = output<FuiAutocompleteChange>();\r\n readonly openedChange: OutputEmitterRef<boolean> = output<boolean>();\r\n readonly addNew: OutputEmitterRef<void> = output();\r\n readonly refresh: OutputEmitterRef<void> = output();\r\n readonly searchChange: OutputEmitterRef<string> = output<string>();\r\n\r\n // Internal state signals\r\n private readonly _value: WritableSignal<unknown> = signal(null);\r\n private readonly _focused: WritableSignal<boolean> = signal(false);\r\n private readonly _disabled: WritableSignal<boolean> = signal(false);\r\n readonly _readOnly: WritableSignal<boolean> = signal(false);\r\n\r\n // FuiFormFieldControl implementation\r\n readonly stateChanges = new Subject<void>();\r\n private _uid = `fui-autocomplete-${FuiAutocompleteComponent.nextId++}`;\r\n _ariaDescribedby: string | null = null;\r\n\r\n // Error state\r\n private readonly _errorState: WritableSignal<boolean> = signal(false);\r\n readonly errorState = this._errorState;\r\n\r\n // Form control references\r\n private _parentForm = inject(NgForm, { optional: true });\r\n private _parentFormGroup = inject(FormGroupDirective, { optional: true });\r\n private _defaultErrorStateMatcher = inject(DefaultErrorStateMatcher);\r\n private readonly _ngControlRef = injectNgControl();\r\n get ngControl(): NgControl | null {\r\n return this._ngControlRef.ngControl;\r\n }\r\n\r\n // Interface implementation\r\n readonly placeholder = computed(() => this.placeholderInput());\r\n private readonly _required: WritableSignal<boolean> = signal(false);\r\n readonly required = this._required;\r\n\r\n readonly value = this._value;\r\n readonly focused = this._focused;\r\n\r\n private readonly _ngControlDisabled: WritableSignal<boolean> = signal(false);\r\n readonly disabled = computed(() => this._disabled() || this.disabledInput() || this._ngControlDisabled());\r\n\r\n readonly empty = computed(() => {\r\n const val = this._value();\r\n return val === null || val === undefined;\r\n });\r\n\r\n readonly id = this._uid;\r\n\r\n // ViewChild for trigger and panel\r\n @ViewChild('trigger', { static: false }) trigger?: ElementRef<HTMLDivElement>;\r\n @ViewChild('panel', { static: false }) panel?: ElementRef<HTMLDivElement>;\r\n @ViewChild('searchInput', { static: false })\r\n searchInput?: ElementRef<HTMLInputElement>;\r\n\r\n // ContentChildren for options\r\n readonly options = contentChildren(FuiOptionComponent, { descendants: true });\r\n\r\n // Panel open/close state\r\n readonly panelOpen = signal(false);\r\n\r\n // Search term for filtering\r\n readonly searchTerm: WritableSignal<string> = signal('');\r\n\r\n // Active option index for keyboard navigation\r\n readonly activeOptionIndex: WritableSignal<number> = signal(-1);\r\n\r\n // Live announcement for screen readers\r\n readonly _liveAnnouncement = signal('');\r\n\r\n _announce(message: string): void {\r\n this._liveAnnouncement.set('');\r\n setTimeout(() => {\r\n this._liveAnnouncement.set(message);\r\n }, 50);\r\n }\r\n\r\n // Overlay reference\r\n private _overlayRef: FuiOverlayRef | null = null;\r\n private _overlaySubscriptions = new Subscription();\r\n\r\n // Services\r\n private readonly _overlayService = inject(FuiOverlayService);\r\n private readonly _elementRef = inject(ElementRef);\r\n private readonly _document = inject(DOCUMENT);\r\n private readonly _ngZone = inject(NgZone);\r\n private _outsideClickSub?: Subscription;\r\n\r\n // ControlValueAccessor callbacks\r\n private _onChange: (value: unknown) => void = () => {\r\n // Intentionally empty: will be replaced by Angular forms\r\n };\r\n private _onTouched: () => void = () => {\r\n // Intentionally empty: will be replaced by Angular forms\r\n };\r\n\r\n // Computed properties\r\n readonly displayValue: Signal<string> = computed(() => {\r\n const currentValue = this.value();\r\n const opts = this.options();\r\n\r\n if (currentValue === null || currentValue === undefined) {\r\n return '';\r\n }\r\n\r\n const selectedOption = opts.find((opt) => this.compareWith()(opt.value(), currentValue));\r\n return selectedOption ? selectedOption.getLabel() : String(currentValue);\r\n });\r\n\r\n // Filtered options based on search term\r\n readonly filteredOptions: Signal<FuiOptionComponent[]> = computed(() => {\r\n const opts = this.options();\r\n const term = this.searchTerm().toLowerCase().trim();\r\n\r\n if (!term) {\r\n return opts.filter((opt) => !opt.disabled());\r\n }\r\n\r\n return opts.filter((opt) => !opt.disabled() && opt.getLabel().toLowerCase().includes(term));\r\n });\r\n\r\n readonly hasFilteredOptions: Signal<boolean> = computed(() => {\r\n return this.filteredOptions().length > 0;\r\n });\r\n\r\n constructor() {\r\n // Set valueAccessor after NgControl is resolved\r\n void Promise.resolve().then(() => {\r\n if (this._ngControlRef.ngControl) {\r\n this._ngControlRef.ngControl.valueAccessor = this;\r\n }\r\n });\r\n\r\n // Effect to emit state changes\r\n effect(() => {\r\n // Track all reactive inputs and internal signals\r\n this.placeholderInput();\r\n this.readonly();\r\n this.disabledInput();\r\n this.errorStateMatcher();\r\n this._focused();\r\n this._disabled();\r\n this._value();\r\n this._ngControlDisabled();\r\n this._required();\r\n this._errorState();\r\n\r\n // Emit state change\r\n this.stateChanges.next();\r\n });\r\n\r\n // Effect to update options selected state when value changes\r\n effect(() => {\r\n const currentValue = this._value();\r\n const opts = this.options();\r\n const compareFn = this.compareWith();\r\n\r\n opts.forEach((option) => {\r\n const optValue = option.value();\r\n const isSelected = compareFn(currentValue, optValue);\r\n\r\n if (isSelected) {\r\n option.select();\r\n } else {\r\n option.deselect();\r\n }\r\n });\r\n\r\n // Notify form-field that state may have changed\r\n this.stateChanges.next();\r\n });\r\n }\r\n\r\n ngDoCheck(): void {\r\n if (this.ngControl) {\r\n updateErrorState(\r\n this.ngControl,\r\n this._errorState,\r\n this.errorStateMatcher(),\r\n this._defaultErrorStateMatcher,\r\n this._parentForm,\r\n this._parentFormGroup,\r\n this.stateChanges,\r\n );\r\n syncRequiredState(this.ngControl, this._required, this.stateChanges);\r\n syncNgControlDisabled(this.ngControl, this._ngControlDisabled, this.stateChanges);\r\n }\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.stateChanges.complete();\r\n this._outsideClickSub?.unsubscribe();\r\n this._disposeOverlay();\r\n }\r\n\r\n // ControlValueAccessor implementation\r\n writeValue(value: unknown): void {\r\n this._value.set(value ?? null);\r\n this.stateChanges.next();\r\n }\r\n\r\n registerOnChange(fn: (value: unknown) => void): void {\r\n this._onChange = fn;\r\n }\r\n\r\n registerOnTouched(fn: () => void): void {\r\n this._onTouched = fn;\r\n }\r\n\r\n setDisabledState(isDisabled: boolean): void {\r\n this._disabled.set(isDisabled);\r\n this.stateChanges.next();\r\n }\r\n\r\n // FuiFormFieldControl implementation\r\n onContainerClick(_event: MouseEvent): void {\r\n if (!this.disabled()) {\r\n this.toggle();\r\n }\r\n }\r\n\r\n setDescribedByIds(ids: string[]): void {\r\n this._ariaDescribedby = ids.length ? ids.join(' ') : null;\r\n }\r\n\r\n setReadOnly(readOnly: boolean): void {\r\n this._readOnly.set(readOnly);\r\n }\r\n\r\n // Public methods\r\n clear(event: Event): void {\r\n event.stopPropagation();\r\n this._value.set(null);\r\n this._onChange(null);\r\n this.valueChange.emit(null);\r\n this.selectionChange.emit({ source: this, value: null });\r\n this.stateChanges.next();\r\n }\r\n\r\n focus(): void {\r\n this.trigger?.nativeElement.focus();\r\n }\r\n\r\n blur(): void {\r\n this.trigger?.nativeElement.blur();\r\n }\r\n\r\n // Toggle panel open/close\r\n toggle(): void {\r\n if (this.disabled()) return;\r\n if (this.panelOpen()) {\r\n this.close();\r\n } else {\r\n this.open();\r\n }\r\n }\r\n\r\n // Open the dropdown panel\r\n open(): void {\r\n if (this.disabled() || this.readonly() || this.panelOpen()) return;\r\n\r\n this.panelOpen.set(true);\r\n this._focused.set(true);\r\n this.searchTerm.set('');\r\n this.openedChange.emit(true);\r\n\r\n // Set active option to currently selected or first option\r\n this._setInitialActiveOption();\r\n\r\n // Create overlay after the view updates\r\n setTimeout(() => {\r\n this._createOverlay();\r\n this._scrollToActiveOption();\r\n this._listenForOutsideClicks();\r\n // Focus the search input\r\n this.searchInput?.nativeElement.focus();\r\n }, 0);\r\n }\r\n\r\n // Close the dropdown panel\r\n close(): void {\r\n if (!this.panelOpen()) return;\r\n this._outsideClickSub?.unsubscribe();\r\n\r\n this.panelOpen.set(false);\r\n this._focused.set(false);\r\n this.activeOptionIndex.set(-1);\r\n this.searchTerm.set('');\r\n this._disposeOverlay();\r\n this.openedChange.emit(false);\r\n this._onTouched();\r\n\r\n // Clear active state on all options\r\n this.options().forEach((opt) => {\r\n opt.setInactive();\r\n });\r\n\r\n // Return focus to trigger\r\n setTimeout(() => {\r\n this.trigger?.nativeElement.focus();\r\n }, 0);\r\n }\r\n\r\n // Handle option selection (called by FuiOptionComponent or internally)\r\n _onOptionSelected(option: FuiOptionComponent): void {\r\n const newValue = option.value();\r\n\r\n // Deselect previous option\r\n const opts = this.options();\r\n opts.forEach((opt) => {\r\n if (opt !== option) {\r\n opt.deselect();\r\n }\r\n });\r\n\r\n option.select();\r\n this._value.set(newValue);\r\n this._onChange(newValue);\r\n this.valueChange.emit(newValue);\r\n this.selectionChange.emit({ source: this, value: newValue });\r\n this._announce(`${option.getLabel()} selected`);\r\n this.close();\r\n\r\n this.stateChanges.next();\r\n }\r\n\r\n // Handle search input\r\n onSearchInput(event: Event): void {\r\n const target = event.target as HTMLInputElement;\r\n const term = target.value;\r\n this.searchTerm.set(term);\r\n this.searchChange.emit(term);\r\n\r\n // Reset active index when search changes\r\n const filtered = this.filteredOptions();\r\n if (filtered.length > 0) {\r\n this._setActiveOptionIndex(0);\r\n } else {\r\n this.activeOptionIndex.set(-1);\r\n }\r\n }\r\n\r\n // Handle add new action\r\n onAddNew(): void {\r\n this.close();\r\n this.addNew.emit();\r\n }\r\n\r\n // Handle refresh action\r\n onRefresh(): void {\r\n this.refresh.emit();\r\n // Keep panel open and clear search\r\n this.searchTerm.set('');\r\n }\r\n\r\n // Get display value for trigger\r\n _getDisplayValue(): string {\r\n return this.displayValue();\r\n }\r\n\r\n // Handle keyboard navigation\r\n _handleKeydown(event: KeyboardEvent): void {\r\n if (this.disabled()) return;\r\n\r\n const isOpen = this.panelOpen();\r\n\r\n if (!isOpen) {\r\n this._handleClosedKeydown(event);\r\n } else {\r\n this._handleOpenKeydown(event);\r\n }\r\n }\r\n\r\n // Handle keydown when panel is closed\r\n private _handleClosedKeydown(event: KeyboardEvent): void {\r\n const key = event.key;\r\n\r\n switch (key) {\r\n case 'Enter':\r\n case ' ':\r\n case 'ArrowDown':\r\n case 'ArrowUp':\r\n event.preventDefault();\r\n this.open();\r\n break;\r\n }\r\n }\r\n\r\n // Handle keydown when panel is open (for search input)\r\n _handlePanelKeydown(event: KeyboardEvent): void {\r\n if (this.disabled()) return;\r\n\r\n const key = event.key;\r\n const opts = this.filteredOptions();\r\n const activeIndex = this.activeOptionIndex();\r\n\r\n switch (key) {\r\n case 'ArrowDown':\r\n event.preventDefault();\r\n this._setNextActiveOption(1);\r\n break;\r\n case 'ArrowUp':\r\n event.preventDefault();\r\n this._setNextActiveOption(-1);\r\n break;\r\n case 'Home':\r\n event.preventDefault();\r\n if (opts.length > 0) {\r\n this._setActiveOptionIndex(0);\r\n }\r\n break;\r\n case 'End':\r\n event.preventDefault();\r\n if (opts.length > 0) {\r\n this._setActiveOptionIndex(opts.length - 1);\r\n }\r\n break;\r\n case 'PageDown':\r\n event.preventDefault();\r\n if (opts.length > 0) {\r\n const pageSize = Math.min(10, opts.length);\r\n const newIndex = Math.min(activeIndex + pageSize, opts.length - 1);\r\n this._setActiveOptionIndex(newIndex);\r\n }\r\n break;\r\n case 'PageUp':\r\n event.preventDefault();\r\n if (opts.length > 0) {\r\n const pageSize = Math.min(10, opts.length);\r\n const newIndex = Math.max(activeIndex - pageSize, 0);\r\n this._setActiveOptionIndex(newIndex);\r\n }\r\n break;\r\n case 'Enter':\r\n event.preventDefault();\r\n if (activeIndex >= 0 && activeIndex < opts.length) {\r\n this._onOptionSelected(opts[activeIndex]);\r\n }\r\n break;\r\n case 'Escape':\r\n event.preventDefault();\r\n this.close();\r\n break;\r\n case 'Tab':\r\n // Allow tab to close and move to next element\r\n this.close();\r\n break;\r\n }\r\n }\r\n\r\n // Handle keydown when panel is open (for trigger)\r\n private _handleOpenKeydown(event: KeyboardEvent): void {\r\n // Delegate to panel keydown handler\r\n this._handlePanelKeydown(event);\r\n }\r\n\r\n // Set the next active option based on delta\r\n private _setNextActiveOption(delta: number): void {\r\n const opts = this.filteredOptions();\r\n if (opts.length === 0) return;\r\n\r\n let currentIndex = this.activeOptionIndex();\r\n if (currentIndex < 0) {\r\n currentIndex = delta > 0 ? -1 : opts.length;\r\n }\r\n\r\n let newIndex = currentIndex + delta;\r\n\r\n // Wrap around\r\n if (newIndex < 0) {\r\n newIndex = opts.length - 1;\r\n } else if (newIndex >= opts.length) {\r\n newIndex = 0;\r\n }\r\n\r\n this._setActiveOptionIndex(newIndex);\r\n }\r\n\r\n // Set the active option index\r\n private _setActiveOptionIndex(index: number): void {\r\n const opts = this.filteredOptions();\r\n if (index < 0 || index >= opts.length) return;\r\n\r\n // Update active state on options\r\n const allOpts = this.options();\r\n allOpts.forEach((opt) => {\r\n opt.setInactive();\r\n });\r\n\r\n const activeOption = opts[index];\r\n activeOption.setActive();\r\n this.activeOptionIndex.set(index);\r\n this._scrollToActiveOption();\r\n this._announce(`${activeOption.getLabel()}, ${index + 1} of ${opts.length}`);\r\n }\r\n\r\n // Set initial active option when opening\r\n private _setInitialActiveOption(): void {\r\n const opts = this.filteredOptions();\r\n if (opts.length === 0) {\r\n this.activeOptionIndex.set(-1);\r\n return;\r\n }\r\n\r\n const currentValue = this._value();\r\n const compareFn = this.compareWith();\r\n\r\n // Find the selected option\r\n let selectedIndex = -1;\r\n if (currentValue !== null && currentValue !== undefined) {\r\n selectedIndex = opts.findIndex((opt) => compareFn(opt.value(), currentValue));\r\n }\r\n\r\n const initialIndex = selectedIndex >= 0 ? selectedIndex : 0;\r\n this._setActiveOptionIndex(initialIndex);\r\n }\r\n\r\n // Scroll to active option\r\n private _scrollToActiveOption(): void {\r\n const opts = this.filteredOptions();\r\n const activeIndex = this.activeOptionIndex();\r\n\r\n if (activeIndex < 0 || activeIndex >= opts.length) return;\r\n\r\n const activeOption = opts[activeIndex];\r\n const element = activeOption._getHostElement();\r\n const panelElement = this.panel?.nativeElement;\r\n\r\n if (element && panelElement) {\r\n const optionsContainer = panelElement.querySelector('.fui-autocomplete__options');\r\n if (optionsContainer) {\r\n const optionTop = element.offsetTop - (optionsContainer as HTMLElement).offsetTop;\r\n const optionBottom = optionTop + element.offsetHeight;\r\n const containerTop = optionsContainer.scrollTop;\r\n const containerBottom = containerTop + optionsContainer.clientHeight;\r\n\r\n if (optionTop < containerTop) {\r\n optionsContainer.scrollTop = optionTop;\r\n } else if (optionBottom > containerBottom) {\r\n optionsContainer.scrollTop = optionBottom - optionsContainer.clientHeight;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Start listening for outside clicks when panel opens\r\n private _listenForOutsideClicks(): void {\r\n this._outsideClickSub?.unsubscribe();\r\n\r\n this._ngZone.runOutsideAngular(() => {\r\n setTimeout(() => {\r\n this._outsideClickSub = fromEvent<MouseEvent>(this._document, 'click')\r\n .pipe(\r\n filter(() => this.panelOpen()),\r\n filter((event) => {\r\n const target = event.target as HTMLElement;\r\n const triggerElement = this.trigger?.nativeElement;\r\n const panelElement = this.panel?.nativeElement;\r\n const overlayElement = this._overlayRef?.overlayElement;\r\n return (\r\n !triggerElement?.contains(target) &&\r\n !panelElement?.contains(target) &&\r\n !overlayElement?.contains(target)\r\n );\r\n }),\r\n )\r\n .subscribe(() => {\r\n this._ngZone.run(() => {\r\n this.close();\r\n });\r\n });\r\n });\r\n });\r\n }\r\n\r\n // Create overlay for panel\r\n private _createOverlay(): void {\r\n if (this._overlayRef || !this.panel || !this.trigger) return;\r\n\r\n const triggerElement = this.trigger.nativeElement;\r\n const triggerWidth = triggerElement.getBoundingClientRect().width;\r\n\r\n const positions: FuiConnectedPosition[] = [\r\n {\r\n originX: 'start',\r\n originY: 'bottom',\r\n overlayX: 'start',\r\n overlayY: 'top',\r\n offsetY: 4,\r\n },\r\n {\r\n originX: 'start',\r\n originY: 'top',\r\n overlayX: 'start',\r\n overlayY: 'bottom',\r\n offsetY: -4,\r\n },\r\n ];\r\n\r\n const positionStrategy = this._overlayService\r\n .position()\r\n .connectedTo(triggerElement, positions)\r\n .withPush(true)\r\n .withViewportMargin(8);\r\n\r\n this._overlayRef = this._overlayService.create({\r\n positionStrategy,\r\n scrollStrategy: this._overlayService.scrollStrategies.reposition(),\r\n hasBackdrop: true,\r\n backdropClass: 'fui-autocomplete-backdrop',\r\n backdropClickBehavior: 'close',\r\n panelClass: ['fui-autocomplete-overlay-panel'],\r\n minWidth: triggerWidth,\r\n });\r\n\r\n // Track overlay subscriptions for proper cleanup\r\n this._overlaySubscriptions.unsubscribe();\r\n this._overlaySubscriptions = new Subscription();\r\n\r\n this._overlaySubscriptions.add(\r\n this._overlayRef.backdropClick.subscribe(() => {\r\n this.close();\r\n }),\r\n );\r\n\r\n this._overlaySubscriptions.add(\r\n this._overlayRef.keydownEvents.subscribe((event) => {\r\n if (event.key === 'Escape') {\r\n this.close();\r\n }\r\n }),\r\n );\r\n\r\n // Attach panel to overlay\r\n const panelElement = this.panel.nativeElement;\r\n this._overlayRef.attach(panelElement);\r\n }\r\n\r\n // Dispose overlay\r\n private _disposeOverlay(): void {\r\n this._overlaySubscriptions.unsubscribe();\r\n if (this._overlayRef) {\r\n this._overlayRef.dispose();\r\n this._overlayRef = null;\r\n }\r\n }\r\n\r\n // Get the active option's id for aria-activedescendant\r\n _getActiveDescendant(): string | null {\r\n const opts = this.filteredOptions();\r\n const activeIndex = this.activeOptionIndex();\r\n if (activeIndex >= 0 && activeIndex < opts.length) {\r\n return opts[activeIndex].id;\r\n }\r\n return null;\r\n }\r\n\r\n // Set active option by index (for template use)\r\n setActiveOption(index: number, option: FuiOptionComponent): void {\r\n const allOpts = this.options();\r\n allOpts.forEach((opt) => {\r\n opt.setInactive();\r\n });\r\n option.setActive();\r\n this.activeOptionIndex.set(index);\r\n }\r\n\r\n // Mat-autocomplete compatibility methods\r\n get selected(): unknown {\r\n return this.value;\r\n }\r\n}\r\n","<!-- Autocomplete Trigger -->\r\n<div\r\n #trigger\r\n [id]=\"id\"\r\n class=\"fui-autocomplete__trigger\"\r\n [attr.tabindex]=\"disabled() ? -1 : 0\"\r\n [attr.role]=\"'combobox'\"\r\n [attr.aria-haspopup]=\"'listbox'\"\r\n [attr.aria-expanded]=\"panelOpen()\"\r\n [attr.aria-disabled]=\"disabled()\"\r\n [attr.aria-invalid]=\"errorState()\"\r\n [attr.aria-describedby]=\"_ariaDescribedby\"\r\n [attr.aria-required]=\"required()\"\r\n aria-autocomplete=\"list\"\r\n [attr.aria-activedescendant]=\"panelOpen() ? _getActiveDescendant() : null\"\r\n [attr.aria-controls]=\"panelOpen() ? id + '-panel' : null\"\r\n (keydown)=\"_handleKeydown($event)\"\r\n>\r\n <span class=\"fui-autocomplete__value\">\r\n @if (empty()) {\r\n <span class=\"fui-autocomplete__placeholder\">{{ placeholder() }}</span>\r\n } @else {\r\n <span class=\"fui-autocomplete__value-text\">{{ _getDisplayValue() }}</span>\r\n }\r\n </span>\r\n\r\n @if (!_readOnly()) {\r\n <!-- Clear button — visible only when a value is selected and not disabled -->\r\n @if (!empty() && !disabled()) {\r\n <span class=\"fui-autocomplete__clear\" role=\"button\" aria-label=\"Clear selection\" (click)=\"clear($event)\">\r\n <svg viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">\r\n <path\r\n d=\"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z\"\r\n />\r\n </svg>\r\n </span>\r\n }\r\n\r\n <!-- Dropdown arrow icon -->\r\n <svg\r\n class=\"fui-autocomplete__arrow\"\r\n [class.fui-autocomplete__arrow--open]=\"panelOpen()\"\r\n viewBox=\"0 0 16 16\"\r\n fill=\"currentColor\"\r\n aria-hidden=\"true\"\r\n >\r\n <path d=\"M8 11L3 6l.7-.7L8 9.6l4.3-4.3L13 6z\" />\r\n </svg>\r\n }\r\n</div>\r\n\r\n<!-- Hidden container for projected options (used for data binding) -->\r\n<div class=\"fui-autocomplete__options-source\">\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n<!-- Dropdown Panel -->\r\n@if (panelOpen()) {\r\n <div #panel [id]=\"id + '-panel'\" class=\"fui-autocomplete__panel\" [attr.aria-label]=\"placeholder()\">\r\n <!-- Search Input -->\r\n <div class=\"fui-autocomplete__search\">\r\n <fui-icon name=\"magnifying-glass\" size=\"sm\" class=\"fui-autocomplete__search-icon\"> </fui-icon>\r\n <input\r\n #searchInput\r\n type=\"text\"\r\n class=\"fui-autocomplete__search-input\"\r\n [placeholder]=\"searchPlaceholder()\"\r\n [value]=\"searchTerm()\"\r\n autocomplete=\"off\"\r\n role=\"searchbox\"\r\n [attr.aria-label]=\"searchPlaceholder()\"\r\n [attr.aria-controls]=\"id + '-panel-listbox'\"\r\n [attr.aria-activedescendant]=\"_getActiveDescendant()\"\r\n (input)=\"onSearchInput($event)\"\r\n (keydown)=\"_handlePanelKeydown($event)\"\r\n />\r\n </div>\r\n <!-- Live region for announcing result count to screen readers -->\r\n <div class=\"fui-visually-hidden\" aria-live=\"assertive\" aria-atomic=\"true\">\r\n @if (_liveAnnouncement()) {\r\n {{ _liveAnnouncement() }}\r\n } @else if (hasFilteredOptions()) {\r\n {{ filteredOptions().length }} results available.\r\n } @else {\r\n No results available.\r\n }\r\n </div>\r\n\r\n <!-- Action Buttons -->\r\n @if (showAddButton() || showRefreshButton()) {\r\n <div class=\"fui-autocomplete__actions\">\r\n @if (showAddButton()) {\r\n <button\r\n type=\"button\"\r\n fuiButton\r\n variant=\"ghost\"\r\n size=\"sm\"\r\n class=\"fui-autocomplete__action-button\"\r\n (click)=\"onAddNew()\"\r\n >\r\n <fui-icon name=\"plus\" size=\"sm\"></fui-icon>\r\n {{ addButtonLabel() }}\r\n </button>\r\n }\r\n @if (showRefreshButton()) {\r\n <button\r\n type=\"button\"\r\n fuiButton\r\n variant=\"ghost\"\r\n size=\"sm\"\r\n class=\"fui-autocomplete__action-button\"\r\n (click)=\"onRefresh()\"\r\n >\r\n <fui-icon name=\"refresh-cw\" size=\"sm\"></fui-icon>\r\n {{ refreshButtonLabel() }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Options List -->\r\n <div\r\n class=\"fui-autocomplete__options\"\r\n [id]=\"id + '-panel-listbox'\"\r\n role=\"listbox\"\r\n [attr.aria-label]=\"placeholder()\"\r\n >\r\n @if (hasFilteredOptions()) {\r\n @for (option of filteredOptions(); track option.id; let i = $index) {\r\n <div\r\n class=\"fui-autocomplete__option\"\r\n [class.fui-autocomplete__option--active]=\"activeOptionIndex() === i\"\r\n [class.fui-autocomplete__option--selected]=\"option._selected()\"\r\n role=\"option\"\r\n [attr.id]=\"option.id\"\r\n [attr.aria-selected]=\"option._selected()\"\r\n (click)=\"_onOptionSelected(option)\"\r\n (mouseenter)=\"setActiveOption(i, option)\"\r\n (mouseleave)=\"option.setInactive()\"\r\n >\r\n <span class=\"fui-autocomplete__option-text\">{{ option.getLabel() }}</span>\r\n @if (option._selected()) {\r\n <fui-icon name=\"check\" size=\"sm\" class=\"fui-autocomplete__option-check\"></fui-icon>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <div class=\"fui-autocomplete__no-options\">\r\n {{ noOptionsText() }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"raintonic-formaui-components-autocomplete.mjs","sources":["../../../lib/components/autocomplete/autocomplete.intl.ts","../../../lib/components/autocomplete/autocomplete.component.ts","../../../lib/components/autocomplete/autocomplete.component.html","../../../lib/components/autocomplete/raintonic-formaui-components-autocomplete.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\r\nimport { FuiIntlBase } from '@raintonic/formaui/core';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class FuiAutocompleteIntl extends FuiIntlBase {\r\n addButtonLabel = 'Add New';\r\n refreshButtonLabel = 'Refresh';\r\n noOptionsText = 'No options found';\r\n searchPlaceholder = 'Search...';\r\n clearSelectionAriaLabel = 'Clear selection';\r\n noResultsAvailableText = 'No results available.';\r\n\r\n resultsAvailableText(count: number): string {\r\n return `${count} results available.`;\r\n }\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n computed,\r\n contentChildren,\r\n DoCheck,\r\n effect,\r\n ElementRef,\r\n inject,\r\n InjectionToken,\r\n NgZone,\r\n input,\r\n InputSignal,\r\n OnDestroy,\r\n output,\r\n OutputEmitterRef,\r\n signal,\r\n Signal,\r\n ViewChild,\r\n ViewEncapsulation,\r\n WritableSignal,\r\n} from '@angular/core';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\n\r\nimport {\r\n ControlValueAccessor,\r\n FormGroupDirective,\r\n NG_VALUE_ACCESSOR,\r\n NgControl,\r\n NgForm,\r\n ReactiveFormsModule,\r\n} from '@angular/forms';\r\nimport { DOCUMENT } from '@angular/common';\r\nimport { fromEvent, Subject, Subscription } from 'rxjs';\r\nimport { filter } from 'rxjs/operators';\r\nimport { injectNgControl, updateErrorState, syncRequiredState, syncNgControlDisabled } from '@raintonic/formaui/cdk/form-field';\r\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\r\nimport { FuiButtonDirective } from '@raintonic/formaui/components/button';\r\nimport { FUI_FORM_FIELD_CONTROL, FuiFormFieldControl } from '@raintonic/formaui/core';\r\nimport { DefaultErrorStateMatcher, ErrorStateMatcher } from '@raintonic/formaui/core';\r\nimport { FuiOptionComponent } from '@raintonic/formaui/components/select';\r\nimport { FuiOverlayService, FuiOverlayRef, FuiConnectedPosition } from '@raintonic/formaui/cdk/overlay';\r\nimport { FuiAutocompleteIntl } from './autocomplete.intl';\r\n\r\n/**\r\n * Injection token used to provide the parent autocomplete to options\r\n */\r\nexport const FUI_AUTOCOMPLETE = new InjectionToken<FuiAutocompleteComponent>('FUI_AUTOCOMPLETE');\r\n\r\n/**\r\n * Selection change event object emitted when the autocomplete's selection changes\r\n */\r\nexport interface FuiAutocompleteChange {\r\n source: FuiAutocompleteComponent;\r\n value: unknown;\r\n}\r\n\r\n/**\r\n * # fui-autocomplete Component\r\n *\r\n * An autocomplete component designed to work seamlessly with fui-form-field.\r\n * Similar to Angular Material's mat-autocomplete integration with mat-form-field.\r\n * Provides full Reactive Forms support with validation, filtering, and optional\r\n * add/refresh actions.\r\n *\r\n * ## Features\r\n * - Works inside fui-form-field like mat-autocomplete\r\n * - Full Reactive Forms integration (ControlValueAccessor)\r\n * - Options via projected content (fui-option)\r\n * - Built-in search/filter input in the panel\r\n * - Optional \"Add New\" and \"Refresh\" action buttons\r\n * - Disabled and readonly states\r\n * - Full accessibility support\r\n * - Full keyboard navigation (Arrow keys, Enter, Escape, Home, End, PageUp, PageDown)\r\n * - Uses overlay service for proper positioning\r\n *\r\n * ## Usage\r\n *\r\n * ### Basic Autocomplete with Form Field\r\n * ```html\r\n * <fui-form-field>\r\n * <label>Country</label>\r\n * <fui-autocomplete placeholder=\"Search countries...\">\r\n * <fui-option value=\"us\">United States</fui-option>\r\n * <fui-option value=\"ca\">Canada</fui-option>\r\n * <fui-option value=\"mx\">Mexico</fui-option>\r\n * </fui-autocomplete>\r\n * </fui-form-field>\r\n * ```\r\n *\r\n * ### With Reactive Forms and Validation\r\n * ```html\r\n * <form [formGroup]=\"form\">\r\n * <fui-form-field>\r\n * <label>Country</label>\r\n * <fui-autocomplete formControlName=\"country\" placeholder=\"Select a country\">\r\n * <fui-option value=\"us\">United States</fui-option>\r\n * <fui-option value=\"ca\">Canada</fui-option>\r\n * </fui-autocomplete>\r\n * <fui-error *ngIf=\"form.get('country')?.hasError('required')\">\r\n * Country is required\r\n * </fui-error>\r\n * </fui-form-field>\r\n * </form>\r\n * ```\r\n *\r\n * ### With Add/Refresh Buttons\r\n * ```html\r\n * <fui-form-field>\r\n * <label>Category</label>\r\n * <fui-autocomplete\r\n * placeholder=\"Search categories...\"\r\n * [showAddButton]=\"true\"\r\n * [showRefreshButton]=\"true\"\r\n * (addNew)=\"openAddCategoryDialog()\"\r\n * (refresh)=\"refreshCategories()\">\r\n * @for (category of categories; track category.id) {\r\n * <fui-option [value]=\"category.id\">{{ category.name }}</fui-option>\r\n * }\r\n * </fui-autocomplete>\r\n * </fui-form-field>\r\n * ```\r\n */\r\n@Component({\r\n selector: 'fui-autocomplete',\r\n standalone: true,\r\n imports: [FuiIconComponent, ReactiveFormsModule, FuiButtonDirective],\r\n templateUrl: './autocomplete.component.html',\r\n styleUrls: ['./autocomplete.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n host: {\r\n class: 'fui-autocomplete',\r\n '[attr.id]': 'id',\r\n '[class.fui-autocomplete--open]': 'panelOpen()',\r\n '[class.fui-autocomplete--disabled]': 'disabled()',\r\n '[class.fui-autocomplete--focused]': 'focused()',\r\n '[class.fui-autocomplete--error]': 'errorState()',\r\n '[class.fui-autocomplete--readonly]': '_readOnly()',\r\n },\r\n providers: [\r\n {\r\n provide: NG_VALUE_ACCESSOR,\r\n useExisting: FuiAutocompleteComponent,\r\n multi: true,\r\n },\r\n {\r\n provide: FUI_FORM_FIELD_CONTROL,\r\n useExisting: FuiAutocompleteComponent,\r\n },\r\n {\r\n provide: FUI_AUTOCOMPLETE,\r\n useExisting: FuiAutocompleteComponent,\r\n },\r\n ],\r\n})\r\nexport class FuiAutocompleteComponent implements ControlValueAccessor, FuiFormFieldControl, DoCheck, OnDestroy {\r\n // Static properties\r\n static nextId = 0;\r\n readonly controlType = 'fui-autocomplete';\r\n\r\n // Injected dependencies required by input resolvers (must be declared before computed fields below)\r\n readonly intl = inject(FuiAutocompleteIntl);\r\n private readonly _cdr = inject(ChangeDetectorRef);\r\n\r\n // Inputs using signal-based API\r\n readonly placeholderInput: InputSignal<string> = input('', {\r\n alias: 'placeholder',\r\n });\r\n readonly disabledInput: InputSignal<boolean> = input(false, {\r\n alias: 'disabled',\r\n });\r\n readonly readonly: InputSignal<boolean> = input(false);\r\n readonly showAddButton: InputSignal<boolean> = input(false);\r\n readonly showRefreshButton: InputSignal<boolean> = input(false);\r\n readonly addButtonLabel = input<string | undefined>(undefined);\r\n readonly refreshButtonLabel = input<string | undefined>(undefined);\r\n readonly noOptionsText = input<string | undefined>(undefined);\r\n readonly searchPlaceholder = input<string | undefined>(undefined);\r\n readonly errorStateMatcher: InputSignal<ErrorStateMatcher | null> = input<ErrorStateMatcher | null>(null);\r\n\r\n // Resolved i18n labels: per-instance input wins, Intl service is fallback\r\n readonly resolvedAddButtonLabel = computed(() => this.addButtonLabel() ?? this.intl.addButtonLabel);\r\n readonly resolvedRefreshButtonLabel = computed(() => this.refreshButtonLabel() ?? this.intl.refreshButtonLabel);\r\n readonly resolvedNoOptionsText = computed(() => this.noOptionsText() ?? this.intl.noOptionsText);\r\n readonly resolvedSearchPlaceholder = computed(() => this.searchPlaceholder() ?? this.intl.searchPlaceholder);\r\n\r\n /**\r\n * Whether to compare option values using object identity or deep equality\r\n */\r\n readonly compareWith: InputSignal<(o1: unknown, o2: unknown) => boolean> = input<\r\n (o1: unknown, o2: unknown) => boolean\r\n >((o1, o2) => o1 === o2);\r\n\r\n // Outputs\r\n readonly valueChange: OutputEmitterRef<unknown> = output<unknown>();\r\n readonly selectionChange: OutputEmitterRef<FuiAutocompleteChange> = output<FuiAutocompleteChange>();\r\n readonly openedChange: OutputEmitterRef<boolean> = output<boolean>();\r\n readonly addNew: OutputEmitterRef<void> = output();\r\n readonly refresh: OutputEmitterRef<void> = output();\r\n readonly searchChange: OutputEmitterRef<string> = output<string>();\r\n\r\n // Internal state signals\r\n private readonly _value: WritableSignal<unknown> = signal(null);\r\n private readonly _focused: WritableSignal<boolean> = signal(false);\r\n private readonly _disabled: WritableSignal<boolean> = signal(false);\r\n readonly _readOnly: WritableSignal<boolean> = signal(false);\r\n\r\n // FuiFormFieldControl implementation\r\n readonly stateChanges = new Subject<void>();\r\n private _uid = `fui-autocomplete-${FuiAutocompleteComponent.nextId++}`;\r\n _ariaDescribedby: string | null = null;\r\n\r\n // Error state\r\n private readonly _errorState: WritableSignal<boolean> = signal(false);\r\n readonly errorState = this._errorState;\r\n\r\n // Form control references\r\n private _parentForm = inject(NgForm, { optional: true });\r\n private _parentFormGroup = inject(FormGroupDirective, { optional: true });\r\n private _defaultErrorStateMatcher = inject(DefaultErrorStateMatcher);\r\n private readonly _ngControlRef = injectNgControl();\r\n get ngControl(): NgControl | null {\r\n return this._ngControlRef.ngControl;\r\n }\r\n\r\n // Interface implementation\r\n readonly placeholder = computed(() => this.placeholderInput());\r\n private readonly _required: WritableSignal<boolean> = signal(false);\r\n readonly required = this._required;\r\n\r\n readonly value = this._value;\r\n readonly focused = this._focused;\r\n\r\n private readonly _ngControlDisabled: WritableSignal<boolean> = signal(false);\r\n readonly disabled = computed(() => this._disabled() || this.disabledInput() || this._ngControlDisabled());\r\n\r\n readonly empty = computed(() => {\r\n const val = this._value();\r\n return val === null || val === undefined;\r\n });\r\n\r\n readonly id = this._uid;\r\n\r\n // ViewChild for trigger and panel\r\n @ViewChild('trigger', { static: false }) trigger?: ElementRef<HTMLDivElement>;\r\n @ViewChild('panel', { static: false }) panel?: ElementRef<HTMLDivElement>;\r\n @ViewChild('searchInput', { static: false })\r\n searchInput?: ElementRef<HTMLInputElement>;\r\n\r\n // ContentChildren for options\r\n readonly options = contentChildren(FuiOptionComponent, { descendants: true });\r\n\r\n // Panel open/close state\r\n readonly panelOpen = signal(false);\r\n\r\n // Search term for filtering\r\n readonly searchTerm: WritableSignal<string> = signal('');\r\n\r\n // Active option index for keyboard navigation\r\n readonly activeOptionIndex: WritableSignal<number> = signal(-1);\r\n\r\n // Live announcement for screen readers\r\n readonly _liveAnnouncement = signal('');\r\n\r\n _announce(message: string): void {\r\n this._liveAnnouncement.set('');\r\n setTimeout(() => {\r\n this._liveAnnouncement.set(message);\r\n }, 50);\r\n }\r\n\r\n // Overlay reference\r\n private _overlayRef: FuiOverlayRef | null = null;\r\n private _overlaySubscriptions = new Subscription();\r\n\r\n // Services\r\n private readonly _overlayService = inject(FuiOverlayService);\r\n private readonly _elementRef = inject(ElementRef);\r\n private readonly _document = inject(DOCUMENT);\r\n private readonly _ngZone = inject(NgZone);\r\n private _outsideClickSub?: Subscription;\r\n\r\n // ControlValueAccessor callbacks\r\n private _onChange: (value: unknown) => void = () => {\r\n // Intentionally empty: will be replaced by Angular forms\r\n };\r\n private _onTouched: () => void = () => {\r\n // Intentionally empty: will be replaced by Angular forms\r\n };\r\n\r\n // Computed properties\r\n readonly displayValue: Signal<string> = computed(() => {\r\n const currentValue = this.value();\r\n const opts = this.options();\r\n\r\n if (currentValue === null || currentValue === undefined) {\r\n return '';\r\n }\r\n\r\n const selectedOption = opts.find((opt) => this.compareWith()(opt.value(), currentValue));\r\n return selectedOption ? selectedOption.getLabel() : String(currentValue);\r\n });\r\n\r\n // Filtered options based on search term\r\n readonly filteredOptions: Signal<FuiOptionComponent[]> = computed(() => {\r\n const opts = this.options();\r\n const term = this.searchTerm().toLowerCase().trim();\r\n\r\n if (!term) {\r\n return opts.filter((opt) => !opt.disabled());\r\n }\r\n\r\n return opts.filter((opt) => !opt.disabled() && opt.getLabel().toLowerCase().includes(term));\r\n });\r\n\r\n readonly hasFilteredOptions: Signal<boolean> = computed(() => {\r\n return this.filteredOptions().length > 0;\r\n });\r\n\r\n constructor() {\r\n // Set valueAccessor after NgControl is resolved\r\n void Promise.resolve().then(() => {\r\n if (this._ngControlRef.ngControl) {\r\n this._ngControlRef.ngControl.valueAccessor = this;\r\n }\r\n });\r\n\r\n // Subscribe to Intl changes to trigger re-render when labels mutate at runtime\r\n this.intl.changes.pipe(takeUntilDestroyed()).subscribe(() => { this._cdr.markForCheck(); });\r\n\r\n // Effect to emit state changes\r\n effect(() => {\r\n // Track all reactive inputs and internal signals\r\n this.placeholderInput();\r\n this.readonly();\r\n this.disabledInput();\r\n this.errorStateMatcher();\r\n this._focused();\r\n this._disabled();\r\n this._value();\r\n this._ngControlDisabled();\r\n this._required();\r\n this._errorState();\r\n\r\n // Emit state change\r\n this.stateChanges.next();\r\n });\r\n\r\n // Effect to update options selected state when value changes\r\n effect(() => {\r\n const currentValue = this._value();\r\n const opts = this.options();\r\n const compareFn = this.compareWith();\r\n\r\n opts.forEach((option) => {\r\n const optValue = option.value();\r\n const isSelected = compareFn(currentValue, optValue);\r\n\r\n if (isSelected) {\r\n option.select();\r\n } else {\r\n option.deselect();\r\n }\r\n });\r\n\r\n // Notify form-field that state may have changed\r\n this.stateChanges.next();\r\n });\r\n }\r\n\r\n ngDoCheck(): void {\r\n if (this.ngControl) {\r\n updateErrorState(\r\n this.ngControl,\r\n this._errorState,\r\n this.errorStateMatcher(),\r\n this._defaultErrorStateMatcher,\r\n this._parentForm,\r\n this._parentFormGroup,\r\n this.stateChanges,\r\n );\r\n syncRequiredState(this.ngControl, this._required, this.stateChanges);\r\n syncNgControlDisabled(this.ngControl, this._ngControlDisabled, this.stateChanges);\r\n }\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.stateChanges.complete();\r\n this._outsideClickSub?.unsubscribe();\r\n this._disposeOverlay();\r\n }\r\n\r\n // ControlValueAccessor implementation\r\n writeValue(value: unknown): void {\r\n this._value.set(value ?? null);\r\n this.stateChanges.next();\r\n }\r\n\r\n registerOnChange(fn: (value: unknown) => void): void {\r\n this._onChange = fn;\r\n }\r\n\r\n registerOnTouched(fn: () => void): void {\r\n this._onTouched = fn;\r\n }\r\n\r\n setDisabledState(isDisabled: boolean): void {\r\n this._disabled.set(isDisabled);\r\n this.stateChanges.next();\r\n }\r\n\r\n // FuiFormFieldControl implementation\r\n onContainerClick(_event: MouseEvent): void {\r\n if (!this.disabled()) {\r\n this.toggle();\r\n }\r\n }\r\n\r\n setDescribedByIds(ids: string[]): void {\r\n this._ariaDescribedby = ids.length ? ids.join(' ') : null;\r\n }\r\n\r\n setReadOnly(readOnly: boolean): void {\r\n this._readOnly.set(readOnly);\r\n }\r\n\r\n // Public methods\r\n clear(event: Event): void {\r\n event.stopPropagation();\r\n this._value.set(null);\r\n this._onChange(null);\r\n this.valueChange.emit(null);\r\n this.selectionChange.emit({ source: this, value: null });\r\n this.stateChanges.next();\r\n }\r\n\r\n focus(): void {\r\n this.trigger?.nativeElement.focus();\r\n }\r\n\r\n blur(): void {\r\n this.trigger?.nativeElement.blur();\r\n }\r\n\r\n // Toggle panel open/close\r\n toggle(): void {\r\n if (this.disabled()) return;\r\n if (this.panelOpen()) {\r\n this.close();\r\n } else {\r\n this.open();\r\n }\r\n }\r\n\r\n // Open the dropdown panel\r\n open(): void {\r\n if (this.disabled() || this.readonly() || this.panelOpen()) return;\r\n\r\n this.panelOpen.set(true);\r\n this._focused.set(true);\r\n this.searchTerm.set('');\r\n this.openedChange.emit(true);\r\n\r\n // Set active option to currently selected or first option\r\n this._setInitialActiveOption();\r\n\r\n // Create overlay after the view updates\r\n setTimeout(() => {\r\n this._createOverlay();\r\n this._scrollToActiveOption();\r\n this._listenForOutsideClicks();\r\n // Focus the search input\r\n this.searchInput?.nativeElement.focus();\r\n }, 0);\r\n }\r\n\r\n // Close the dropdown panel\r\n close(): void {\r\n if (!this.panelOpen()) return;\r\n this._outsideClickSub?.unsubscribe();\r\n\r\n this.panelOpen.set(false);\r\n this._focused.set(false);\r\n this.activeOptionIndex.set(-1);\r\n this.searchTerm.set('');\r\n this._disposeOverlay();\r\n this.openedChange.emit(false);\r\n this._onTouched();\r\n\r\n // Clear active state on all options\r\n this.options().forEach((opt) => {\r\n opt.setInactive();\r\n });\r\n\r\n // Return focus to trigger\r\n setTimeout(() => {\r\n this.trigger?.nativeElement.focus();\r\n }, 0);\r\n }\r\n\r\n // Handle option selection (called by FuiOptionComponent or internally)\r\n _onOptionSelected(option: FuiOptionComponent): void {\r\n const newValue = option.value();\r\n\r\n // Deselect previous option\r\n const opts = this.options();\r\n opts.forEach((opt) => {\r\n if (opt !== option) {\r\n opt.deselect();\r\n }\r\n });\r\n\r\n option.select();\r\n this._value.set(newValue);\r\n this._onChange(newValue);\r\n this.valueChange.emit(newValue);\r\n this.selectionChange.emit({ source: this, value: newValue });\r\n this._announce(`${option.getLabel()} selected`);\r\n this.close();\r\n\r\n this.stateChanges.next();\r\n }\r\n\r\n // Handle search input\r\n onSearchInput(event: Event): void {\r\n const target = event.target as HTMLInputElement;\r\n const term = target.value;\r\n this.searchTerm.set(term);\r\n this.searchChange.emit(term);\r\n\r\n // Reset active index when search changes\r\n const filtered = this.filteredOptions();\r\n if (filtered.length > 0) {\r\n this._setActiveOptionIndex(0);\r\n } else {\r\n this.activeOptionIndex.set(-1);\r\n }\r\n }\r\n\r\n // Handle add new action\r\n onAddNew(): void {\r\n this.close();\r\n this.addNew.emit();\r\n }\r\n\r\n // Handle refresh action\r\n onRefresh(): void {\r\n this.refresh.emit();\r\n // Keep panel open and clear search\r\n this.searchTerm.set('');\r\n }\r\n\r\n // Get display value for trigger\r\n _getDisplayValue(): string {\r\n return this.displayValue();\r\n }\r\n\r\n // Handle keyboard navigation\r\n _handleKeydown(event: KeyboardEvent): void {\r\n if (this.disabled()) return;\r\n\r\n const isOpen = this.panelOpen();\r\n\r\n if (!isOpen) {\r\n this._handleClosedKeydown(event);\r\n } else {\r\n this._handleOpenKeydown(event);\r\n }\r\n }\r\n\r\n // Handle keydown when panel is closed\r\n private _handleClosedKeydown(event: KeyboardEvent): void {\r\n const key = event.key;\r\n\r\n switch (key) {\r\n case 'Enter':\r\n case ' ':\r\n case 'ArrowDown':\r\n case 'ArrowUp':\r\n event.preventDefault();\r\n this.open();\r\n break;\r\n }\r\n }\r\n\r\n // Handle keydown when panel is open (for search input)\r\n _handlePanelKeydown(event: KeyboardEvent): void {\r\n if (this.disabled()) return;\r\n\r\n const key = event.key;\r\n const opts = this.filteredOptions();\r\n const activeIndex = this.activeOptionIndex();\r\n\r\n switch (key) {\r\n case 'ArrowDown':\r\n event.preventDefault();\r\n this._setNextActiveOption(1);\r\n break;\r\n case 'ArrowUp':\r\n event.preventDefault();\r\n this._setNextActiveOption(-1);\r\n break;\r\n case 'Home':\r\n event.preventDefault();\r\n if (opts.length > 0) {\r\n this._setActiveOptionIndex(0);\r\n }\r\n break;\r\n case 'End':\r\n event.preventDefault();\r\n if (opts.length > 0) {\r\n this._setActiveOptionIndex(opts.length - 1);\r\n }\r\n break;\r\n case 'PageDown':\r\n event.preventDefault();\r\n if (opts.length > 0) {\r\n const pageSize = Math.min(10, opts.length);\r\n const newIndex = Math.min(activeIndex + pageSize, opts.length - 1);\r\n this._setActiveOptionIndex(newIndex);\r\n }\r\n break;\r\n case 'PageUp':\r\n event.preventDefault();\r\n if (opts.length > 0) {\r\n const pageSize = Math.min(10, opts.length);\r\n const newIndex = Math.max(activeIndex - pageSize, 0);\r\n this._setActiveOptionIndex(newIndex);\r\n }\r\n break;\r\n case 'Enter':\r\n event.preventDefault();\r\n if (activeIndex >= 0 && activeIndex < opts.length) {\r\n this._onOptionSelected(opts[activeIndex]);\r\n }\r\n break;\r\n case 'Escape':\r\n event.preventDefault();\r\n this.close();\r\n break;\r\n case 'Tab':\r\n // Allow tab to close and move to next element\r\n this.close();\r\n break;\r\n }\r\n }\r\n\r\n // Handle keydown when panel is open (for trigger)\r\n private _handleOpenKeydown(event: KeyboardEvent): void {\r\n // Delegate to panel keydown handler\r\n this._handlePanelKeydown(event);\r\n }\r\n\r\n // Set the next active option based on delta\r\n private _setNextActiveOption(delta: number): void {\r\n const opts = this.filteredOptions();\r\n if (opts.length === 0) return;\r\n\r\n let currentIndex = this.activeOptionIndex();\r\n if (currentIndex < 0) {\r\n currentIndex = delta > 0 ? -1 : opts.length;\r\n }\r\n\r\n let newIndex = currentIndex + delta;\r\n\r\n // Wrap around\r\n if (newIndex < 0) {\r\n newIndex = opts.length - 1;\r\n } else if (newIndex >= opts.length) {\r\n newIndex = 0;\r\n }\r\n\r\n this._setActiveOptionIndex(newIndex);\r\n }\r\n\r\n // Set the active option index\r\n private _setActiveOptionIndex(index: number): void {\r\n const opts = this.filteredOptions();\r\n if (index < 0 || index >= opts.length) return;\r\n\r\n // Update active state on options\r\n const allOpts = this.options();\r\n allOpts.forEach((opt) => {\r\n opt.setInactive();\r\n });\r\n\r\n const activeOption = opts[index];\r\n activeOption.setActive();\r\n this.activeOptionIndex.set(index);\r\n this._scrollToActiveOption();\r\n this._announce(`${activeOption.getLabel()}, ${index + 1} of ${opts.length}`);\r\n }\r\n\r\n // Set initial active option when opening\r\n private _setInitialActiveOption(): void {\r\n const opts = this.filteredOptions();\r\n if (opts.length === 0) {\r\n this.activeOptionIndex.set(-1);\r\n return;\r\n }\r\n\r\n const currentValue = this._value();\r\n const compareFn = this.compareWith();\r\n\r\n // Find the selected option\r\n let selectedIndex = -1;\r\n if (currentValue !== null && currentValue !== undefined) {\r\n selectedIndex = opts.findIndex((opt) => compareFn(opt.value(), currentValue));\r\n }\r\n\r\n const initialIndex = selectedIndex >= 0 ? selectedIndex : 0;\r\n this._setActiveOptionIndex(initialIndex);\r\n }\r\n\r\n // Scroll to active option\r\n private _scrollToActiveOption(): void {\r\n const opts = this.filteredOptions();\r\n const activeIndex = this.activeOptionIndex();\r\n\r\n if (activeIndex < 0 || activeIndex >= opts.length) return;\r\n\r\n const activeOption = opts[activeIndex];\r\n const element = activeOption._getHostElement();\r\n const panelElement = this.panel?.nativeElement;\r\n\r\n if (element && panelElement) {\r\n const optionsContainer = panelElement.querySelector('.fui-autocomplete__options');\r\n if (optionsContainer) {\r\n const optionTop = element.offsetTop - (optionsContainer as HTMLElement).offsetTop;\r\n const optionBottom = optionTop + element.offsetHeight;\r\n const containerTop = optionsContainer.scrollTop;\r\n const containerBottom = containerTop + optionsContainer.clientHeight;\r\n\r\n if (optionTop < containerTop) {\r\n optionsContainer.scrollTop = optionTop;\r\n } else if (optionBottom > containerBottom) {\r\n optionsContainer.scrollTop = optionBottom - optionsContainer.clientHeight;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Start listening for outside clicks when panel opens\r\n private _listenForOutsideClicks(): void {\r\n this._outsideClickSub?.unsubscribe();\r\n\r\n this._ngZone.runOutsideAngular(() => {\r\n setTimeout(() => {\r\n this._outsideClickSub = fromEvent<MouseEvent>(this._document, 'click')\r\n .pipe(\r\n filter(() => this.panelOpen()),\r\n filter((event) => {\r\n const target = event.target as HTMLElement;\r\n const triggerElement = this.trigger?.nativeElement;\r\n const panelElement = this.panel?.nativeElement;\r\n const overlayElement = this._overlayRef?.overlayElement;\r\n return (\r\n !triggerElement?.contains(target) &&\r\n !panelElement?.contains(target) &&\r\n !overlayElement?.contains(target)\r\n );\r\n }),\r\n )\r\n .subscribe(() => {\r\n this._ngZone.run(() => {\r\n this.close();\r\n });\r\n });\r\n });\r\n });\r\n }\r\n\r\n // Create overlay for panel\r\n private _createOverlay(): void {\r\n if (this._overlayRef || !this.panel || !this.trigger) return;\r\n\r\n const triggerElement = this.trigger.nativeElement;\r\n const triggerWidth = triggerElement.getBoundingClientRect().width;\r\n\r\n const positions: FuiConnectedPosition[] = [\r\n {\r\n originX: 'start',\r\n originY: 'bottom',\r\n overlayX: 'start',\r\n overlayY: 'top',\r\n offsetY: 4,\r\n },\r\n {\r\n originX: 'start',\r\n originY: 'top',\r\n overlayX: 'start',\r\n overlayY: 'bottom',\r\n offsetY: -4,\r\n },\r\n ];\r\n\r\n const positionStrategy = this._overlayService\r\n .position()\r\n .connectedTo(triggerElement, positions)\r\n .withPush(true)\r\n .withViewportMargin(8);\r\n\r\n this._overlayRef = this._overlayService.create({\r\n positionStrategy,\r\n scrollStrategy: this._overlayService.scrollStrategies.reposition(),\r\n hasBackdrop: true,\r\n backdropClass: 'fui-autocomplete-backdrop',\r\n backdropClickBehavior: 'close',\r\n panelClass: ['fui-autocomplete-overlay-panel'],\r\n minWidth: triggerWidth,\r\n });\r\n\r\n // Track overlay subscriptions for proper cleanup\r\n this._overlaySubscriptions.unsubscribe();\r\n this._overlaySubscriptions = new Subscription();\r\n\r\n this._overlaySubscriptions.add(\r\n this._overlayRef.backdropClick.subscribe(() => {\r\n this.close();\r\n }),\r\n );\r\n\r\n this._overlaySubscriptions.add(\r\n this._overlayRef.keydownEvents.subscribe((event) => {\r\n if (event.key === 'Escape') {\r\n this.close();\r\n }\r\n }),\r\n );\r\n\r\n // Attach panel to overlay\r\n const panelElement = this.panel.nativeElement;\r\n this._overlayRef.attach(panelElement);\r\n }\r\n\r\n // Dispose overlay\r\n private _disposeOverlay(): void {\r\n this._overlaySubscriptions.unsubscribe();\r\n if (this._overlayRef) {\r\n this._overlayRef.dispose();\r\n this._overlayRef = null;\r\n }\r\n }\r\n\r\n // Get the active option's id for aria-activedescendant\r\n _getActiveDescendant(): string | null {\r\n const opts = this.filteredOptions();\r\n const activeIndex = this.activeOptionIndex();\r\n if (activeIndex >= 0 && activeIndex < opts.length) {\r\n return opts[activeIndex].id;\r\n }\r\n return null;\r\n }\r\n\r\n // Set active option by index (for template use)\r\n setActiveOption(index: number, option: FuiOptionComponent): void {\r\n const allOpts = this.options();\r\n allOpts.forEach((opt) => {\r\n opt.setInactive();\r\n });\r\n option.setActive();\r\n this.activeOptionIndex.set(index);\r\n }\r\n\r\n // Mat-autocomplete compatibility methods\r\n get selected(): unknown {\r\n return this.value;\r\n }\r\n}\r\n","<!-- Autocomplete Trigger -->\r\n<div\r\n #trigger\r\n [id]=\"id\"\r\n class=\"fui-autocomplete__trigger\"\r\n [attr.tabindex]=\"disabled() ? -1 : 0\"\r\n [attr.role]=\"'combobox'\"\r\n [attr.aria-haspopup]=\"'listbox'\"\r\n [attr.aria-expanded]=\"panelOpen()\"\r\n [attr.aria-disabled]=\"disabled()\"\r\n [attr.aria-invalid]=\"errorState()\"\r\n [attr.aria-describedby]=\"_ariaDescribedby\"\r\n [attr.aria-required]=\"required()\"\r\n aria-autocomplete=\"list\"\r\n [attr.aria-activedescendant]=\"panelOpen() ? _getActiveDescendant() : null\"\r\n [attr.aria-controls]=\"panelOpen() ? id + '-panel' : null\"\r\n (keydown)=\"_handleKeydown($event)\"\r\n>\r\n <span class=\"fui-autocomplete__value\">\r\n @if (empty()) {\r\n <span class=\"fui-autocomplete__placeholder\">{{ placeholder() }}</span>\r\n } @else {\r\n <span class=\"fui-autocomplete__value-text\">{{ _getDisplayValue() }}</span>\r\n }\r\n </span>\r\n\r\n @if (!_readOnly()) {\r\n <!-- Clear button — visible only when a value is selected and not disabled -->\r\n @if (!empty() && !disabled()) {\r\n <span class=\"fui-autocomplete__clear\" role=\"button\" [attr.aria-label]=\"intl.clearSelectionAriaLabel\" (click)=\"clear($event)\">\r\n <svg viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">\r\n <path\r\n d=\"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z\"\r\n />\r\n </svg>\r\n </span>\r\n }\r\n\r\n <!-- Dropdown arrow icon -->\r\n <svg\r\n class=\"fui-autocomplete__arrow\"\r\n [class.fui-autocomplete__arrow--open]=\"panelOpen()\"\r\n viewBox=\"0 0 16 16\"\r\n fill=\"currentColor\"\r\n aria-hidden=\"true\"\r\n >\r\n <path d=\"M8 11L3 6l.7-.7L8 9.6l4.3-4.3L13 6z\" />\r\n </svg>\r\n }\r\n</div>\r\n\r\n<!-- Hidden container for projected options (used for data binding) -->\r\n<div class=\"fui-autocomplete__options-source\">\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n<!-- Dropdown Panel -->\r\n@if (panelOpen()) {\r\n <div #panel [id]=\"id + '-panel'\" class=\"fui-autocomplete__panel\" [attr.aria-label]=\"placeholder()\">\r\n <!-- Search Input -->\r\n <div class=\"fui-autocomplete__search\">\r\n <fui-icon name=\"magnifying-glass\" size=\"sm\" class=\"fui-autocomplete__search-icon\"> </fui-icon>\r\n <input\r\n #searchInput\r\n type=\"text\"\r\n class=\"fui-autocomplete__search-input\"\r\n [placeholder]=\"resolvedSearchPlaceholder()\"\r\n [value]=\"searchTerm()\"\r\n autocomplete=\"off\"\r\n role=\"searchbox\"\r\n [attr.aria-label]=\"resolvedSearchPlaceholder()\"\r\n [attr.aria-controls]=\"id + '-panel-listbox'\"\r\n [attr.aria-activedescendant]=\"_getActiveDescendant()\"\r\n (input)=\"onSearchInput($event)\"\r\n (keydown)=\"_handlePanelKeydown($event)\"\r\n />\r\n </div>\r\n <!-- Live region for announcing result count to screen readers -->\r\n <div class=\"fui-sr-only\" aria-live=\"assertive\" aria-atomic=\"true\">\r\n @if (_liveAnnouncement()) {\r\n {{ _liveAnnouncement() }}\r\n } @else if (hasFilteredOptions()) {\r\n {{ intl.resultsAvailableText(filteredOptions().length) }}\r\n } @else {\r\n {{ intl.noResultsAvailableText }}\r\n }\r\n </div>\r\n\r\n <!-- Action Buttons -->\r\n @if (showAddButton() || showRefreshButton()) {\r\n <div class=\"fui-autocomplete__actions\">\r\n @if (showAddButton()) {\r\n <button\r\n type=\"button\"\r\n fuiButton\r\n variant=\"tertiary\"\r\n size=\"sm\"\r\n class=\"fui-autocomplete__action-button\"\r\n (click)=\"onAddNew()\"\r\n >\r\n <fui-icon name=\"plus\" size=\"sm\"></fui-icon>\r\n {{ resolvedAddButtonLabel() }}\r\n </button>\r\n }\r\n @if (showRefreshButton()) {\r\n <button\r\n type=\"button\"\r\n fuiButton\r\n variant=\"tertiary\"\r\n size=\"sm\"\r\n class=\"fui-autocomplete__action-button\"\r\n (click)=\"onRefresh()\"\r\n >\r\n <fui-icon name=\"refresh-cw\" size=\"sm\"></fui-icon>\r\n {{ resolvedRefreshButtonLabel() }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Options List -->\r\n <div\r\n class=\"fui-autocomplete__options\"\r\n [id]=\"id + '-panel-listbox'\"\r\n role=\"listbox\"\r\n [attr.aria-label]=\"placeholder()\"\r\n >\r\n @if (hasFilteredOptions()) {\r\n @for (option of filteredOptions(); track option.id; let i = $index) {\r\n <div\r\n class=\"fui-autocomplete__option\"\r\n [class.fui-autocomplete__option--active]=\"activeOptionIndex() === i\"\r\n [class.fui-autocomplete__option--selected]=\"option._selected()\"\r\n role=\"option\"\r\n [attr.id]=\"option.id\"\r\n [attr.aria-selected]=\"option._selected()\"\r\n (click)=\"_onOptionSelected(option)\"\r\n (mouseenter)=\"setActiveOption(i, option)\"\r\n (mouseleave)=\"option.setInactive()\"\r\n >\r\n <span class=\"fui-autocomplete__option-text\">{{ option.getLabel() }}</span>\r\n @if (option._selected()) {\r\n <fui-icon name=\"check\" size=\"sm\" class=\"fui-autocomplete__option-check\"></fui-icon>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <div class=\"fui-autocomplete__no-options\">\r\n {{ resolvedNoOptionsText() }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -21,7 +21,9 @@ const FUI_BADGE_VARIANTS = [
21
21
  *
22
22
  * @input label - (required) Text content of the badge.
23
23
  * @input icon - Optional Phosphor icon name displayed before the label.
24
- * @input customColor - Optional hex color that overrides the variant palette.
24
+ * @input customColor - Optional hex color or `{ label, background }` object that overrides the variant palette.
25
+ * - Hex string: used as label color; background is the same hex with 16% alpha.
26
+ * - Object: `{ label, background }` both as hex; applied as-is.
25
27
  * @input size - Badge size: 'sm' | 'md' | 'lg'. Default 'md'.
26
28
  * @input variant - Color variant: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info'. Default 'primary'.
27
29
  * @input ariaLabel - Accessible label override for screen readers.
@@ -30,43 +32,49 @@ const FUI_BADGE_VARIANTS = [
30
32
  * <fui-badge label="Active" variant="success" icon="check-circle"></fui-badge>
31
33
  */
32
34
  class FuiBadgeComponent {
33
- /** Pattern allowing hex, rgb/rgba, hsl/hsla, and CSS named colors */
34
- static _SAFE_COLOR_PATTERN = /^(#[0-9a-fA-F]{3,8}|(?:rgb|hsl)a?\([^)]+\)|[a-zA-Z]+)$/;
35
+ /** Hex pattern: #rgb, #rgba, #rrggbb, #rrggbbaa */
36
+ static _HEX_PATTERN = /^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
35
37
  label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
36
38
  icon = input(null, ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
37
39
  customColor = input(null, ...(ngDevMode ? [{ debugName: "customColor" }] : /* istanbul ignore next */ []));
38
40
  size = input('md', { ...(ngDevMode ? { debugName: "size" } : /* istanbul ignore next */ {}), transform: (v) => (FUI_BADGE_SIZES.includes(v) ? v : 'md') });
39
41
  variant = input('primary', { ...(ngDevMode ? { debugName: "variant" } : /* istanbul ignore next */ {}), transform: (v) => (FUI_BADGE_VARIANTS.includes(v) ? v : 'primary') });
40
42
  ariaLabel = input(null, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
41
- /** Validated custom color - returns null for invalid values to prevent CSS injection */
42
- sanitizedColor = computed(() => {
43
- const color = this.customColor();
44
- if (!color)
45
- return null;
46
- if (!FuiBadgeComponent._SAFE_COLOR_PATTERN.test(color)) {
47
- console.warn(`[FormaUI] Invalid badge color: "${color}"`);
43
+ /**
44
+ * Resolved custom color pair (label + background).
45
+ * - String input: must be a valid hex → used as label color, background is same hex with 16% alpha.
46
+ * - Object input: `{ label, background }` used directly (both must be valid hex).
47
+ * Returns null for invalid values to prevent CSS injection.
48
+ */
49
+ resolvedCustomColor = computed(() => {
50
+ const value = this.customColor();
51
+ if (!value)
48
52
  return null;
53
+ if (typeof value === 'string') {
54
+ if (!FuiBadgeComponent._HEX_PATTERN.test(value)) {
55
+ console.warn(`[FormaUI] Invalid badge color: "${value}"`);
56
+ return null;
57
+ }
58
+ return { label: value, background: this.hexToRgba(value, 0.16) };
49
59
  }
50
- return color;
51
- }, ...(ngDevMode ? [{ debugName: "sanitizedColor" }] : /* istanbul ignore next */ []));
52
- computedTextColor = computed(() => {
53
- const color = this.sanitizedColor();
54
- if (!color)
60
+ const { label, background } = value;
61
+ if (!FuiBadgeComponent._HEX_PATTERN.test(label) || !FuiBadgeComponent._HEX_PATTERN.test(background)) {
62
+ console.warn(`[FormaUI] Invalid badge color object:`, value);
55
63
  return null;
56
- const luminance = this.getRelativeLuminance(color);
57
- return luminance < 0.5 ? '#ffffff' : '#000000';
58
- }, ...(ngDevMode ? [{ debugName: "computedTextColor" }] : /* istanbul ignore next */ []));
64
+ }
65
+ return { label, background };
66
+ }, ...(ngDevMode ? [{ debugName: "resolvedCustomColor" }] : /* istanbul ignore next */ []));
59
67
  computedStyles = computed(() => {
60
- const color = this.sanitizedColor();
61
- if (!color)
68
+ const resolved = this.resolvedCustomColor();
69
+ if (!resolved)
62
70
  return {};
63
71
  return {
64
- 'background-color': color,
65
- color: this.computedTextColor() ?? '#000000',
72
+ 'background-color': resolved.background,
73
+ color: resolved.label,
66
74
  };
67
75
  }, ...(ngDevMode ? [{ debugName: "computedStyles" }] : /* istanbul ignore next */ []));
68
76
  computedClasses = computed(() => {
69
- const effectiveVariant = this.sanitizedColor() ? 'custom' : this.variant();
77
+ const effectiveVariant = this.resolvedCustomColor() ? 'custom' : this.variant();
70
78
  const classes = ['fui-badge', `fui-badge--${effectiveVariant}`, `fui-badge--${this.size()}`];
71
79
  if (this.icon()) {
72
80
  classes.push('fui-badge--with-icon');
@@ -79,15 +87,21 @@ class FuiBadgeComponent {
79
87
  return 'md';
80
88
  return 'sm';
81
89
  }, ...(ngDevMode ? [{ debugName: "iconSize" }] : /* istanbul ignore next */ []));
82
- getRelativeLuminance(hex) {
83
- const r = parseInt(hex.slice(1, 3), 16) / 255;
84
- const g = parseInt(hex.slice(3, 5), 16) / 255;
85
- const b = parseInt(hex.slice(5, 7), 16) / 255;
86
- const linearize = (channel) => channel <= 0.03928 ? channel / 12.92 : Math.pow((channel + 0.055) / 1.055, 2.4);
87
- return 0.2126 * linearize(r) + 0.7152 * linearize(g) + 0.0722 * linearize(b);
90
+ hexToRgba(hex, alpha) {
91
+ let h = hex.slice(1);
92
+ if (h.length === 3 || h.length === 4) {
93
+ h = h
94
+ .split('')
95
+ .map((c) => c + c)
96
+ .join('');
97
+ }
98
+ const r = parseInt(h.slice(0, 2), 16);
99
+ const g = parseInt(h.slice(2, 4), 16);
100
+ const b = parseInt(h.slice(4, 6), 16);
101
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
88
102
  }
89
103
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
90
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiBadgeComponent, isStandalone: true, selector: "fui-badge", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, customColor: { classPropertyName: "customColor", publicName: "customColor", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "status" }, properties: { "class": "computedClasses()", "style": "computedStyles()", "attr.aria-label": "ariaLabel() || null" } }, ngImport: i0, template: "<div class=\"fui-badge__content\">\r\n @if (icon()) {\r\n <fui-icon class=\"fui-badge__icon\" [name]=\"icon()!\" [size]=\"iconSize()\" aria-hidden=\"true\" />\r\n }\r\n <span class=\"fui-badge__label\">{{ label() }}</span>\r\n</div>\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}:host.fui-badge{--fui-badge-bg: transparent;--fui-badge-color: inherit;--fui-badge-font-size: var(--fui-font-size-01);--fui-badge-font-weight: var(--fui-font-weight-medium);--fui-badge-border-radius: var(--fui-border-radius-pill);--fui-badge-gap: var(--fui-spacing-02);--fui-badge-height-sm: 1.25rem;--fui-badge-height-md: 1.5rem;--fui-badge-height-lg: 2rem;contain:content;display:inline-flex;align-items:center;justify-content:center;font-family:var(--fui-font-family-sans);font-size:var(--fui-badge-font-size);font-weight:var(--fui-badge-font-weight);border-radius:var(--fui-badge-border-radius);background-color:var(--fui-badge-bg);color:var(--fui-badge-color);white-space:nowrap;transition:all var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}:host.fui-badge .fui-badge__content{display:flex;align-items:center;gap:var(--fui-badge-gap)}:host.fui-badge .fui-badge__label{line-height:1}:host.fui-badge .fui-badge__icon{display:inline-flex;align-items:center;justify-content:center}:host.fui-badge--sm{height:var(--fui-badge-height-sm);padding:0 var(--fui-spacing-03);font-size:var(--fui-font-size-01)}:host.fui-badge--md{height:var(--fui-badge-height-md);padding:0 var(--fui-spacing-04);font-size:var(--fui-font-size-02)}:host.fui-badge--lg{height:var(--fui-badge-height-lg);padding:0 var(--fui-spacing-05);font-size:var(--fui-font-size-03)}:host.fui-badge--primary{--fui-badge-bg: var(--fui-primary-20);--fui-badge-color: var(--fui-primary)}:host.fui-badge--secondary{--fui-badge-bg: var(--fui-secondary-20);--fui-badge-color: var(--fui-secondary-80)}:host.fui-badge--success{--fui-badge-bg: var(--fui-success-20);--fui-badge-color: var(--fui-success-80)}:host.fui-badge--info{--fui-badge-bg: var(--fui-info-20);--fui-badge-color: var(--fui-info-80)}:host.fui-badge--warning{--fui-badge-bg: var(--fui-warning-20);--fui-badge-color: var(--fui-warning-80)}:host.fui-badge--error{--fui-badge-bg: var(--fui-danger-20);--fui-badge-color: var(--fui-danger-80)}:host.fui-badge--custom{--fui-badge-bg: transparent;--fui-badge-color: inherit}@media(prefers-reduced-motion:reduce){:host.fui-badge{transition:none}}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
104
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiBadgeComponent, isStandalone: true, selector: "fui-badge", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, customColor: { classPropertyName: "customColor", publicName: "customColor", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "status" }, properties: { "class": "computedClasses()", "style": "computedStyles()", "attr.aria-label": "ariaLabel() || null" } }, ngImport: i0, template: "<div class=\"fui-badge__content\">\r\n @if (icon()) {\r\n <fui-icon class=\"fui-badge__icon\" [name]=\"icon()!\" [size]=\"iconSize()\" aria-hidden=\"true\" />\r\n }\r\n <span class=\"fui-badge__label\">{{ label() }}</span>\r\n</div>\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}@keyframes fui-popover-enter{0%{opacity:0;transform:translateY(-14px)}60%{opacity:1}to{opacity:1;transform:translateY(0)}}:host.fui-badge{--fui-badge-bg: transparent;--fui-badge-color: inherit;--fui-badge-font-size: var(--fui-font-size-01);--fui-badge-font-weight: var(--fui-font-weight-medium);--fui-badge-border-radius: var(--fui-border-radius-pill);--fui-badge-gap: var(--fui-spacing-02);--fui-badge-height-sm: 1.25rem;--fui-badge-height-md: 1.5rem;--fui-badge-height-lg: 2rem;contain:content;display:inline-flex;align-items:center;justify-content:center;font-family:var(--fui-font-family-sans);font-size:var(--fui-badge-font-size);font-weight:var(--fui-badge-font-weight);border-radius:var(--fui-badge-border-radius);background-color:var(--fui-badge-bg);color:var(--fui-badge-color);white-space:nowrap;transition:all var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}:host.fui-badge .fui-badge__content{display:flex;align-items:center;gap:var(--fui-badge-gap)}:host.fui-badge .fui-badge__label{line-height:1}:host.fui-badge .fui-badge__icon{display:inline-flex;align-items:center;justify-content:center}:host.fui-badge--sm{height:var(--fui-badge-height-sm);padding:0 var(--fui-spacing-03);font-size:var(--fui-font-size-01)}:host.fui-badge--md{height:var(--fui-badge-height-md);padding:0 var(--fui-spacing-04);font-size:var(--fui-font-size-02)}:host.fui-badge--lg{height:var(--fui-badge-height-lg);padding:0 var(--fui-spacing-05);font-size:var(--fui-font-size-03)}:host.fui-badge--primary{--fui-badge-bg: var(--fui-primary-20);--fui-badge-color: var(--fui-primary)}:host.fui-badge--secondary{--fui-badge-bg: var(--fui-secondary-20);--fui-badge-color: var(--fui-secondary-80)}:host.fui-badge--success{--fui-badge-bg: var(--fui-success-20);--fui-badge-color: var(--fui-success-80)}:host.fui-badge--info{--fui-badge-bg: var(--fui-info-20);--fui-badge-color: var(--fui-info-80)}:host.fui-badge--warning{--fui-badge-bg: var(--fui-warning-20);--fui-badge-color: var(--fui-warning-80)}:host.fui-badge--error{--fui-badge-bg: var(--fui-danger-20);--fui-badge-color: var(--fui-danger-80)}:host.fui-badge--custom{--fui-badge-bg: transparent;--fui-badge-color: inherit}@media(prefers-reduced-motion:reduce){:host.fui-badge{transition:none}}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
91
105
  }
92
106
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiBadgeComponent, decorators: [{
93
107
  type: Component,
@@ -96,7 +110,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
96
110
  '[style]': 'computedStyles()',
97
111
  role: 'status',
98
112
  '[attr.aria-label]': 'ariaLabel() || null',
99
- }, template: "<div class=\"fui-badge__content\">\r\n @if (icon()) {\r\n <fui-icon class=\"fui-badge__icon\" [name]=\"icon()!\" [size]=\"iconSize()\" aria-hidden=\"true\" />\r\n }\r\n <span class=\"fui-badge__label\">{{ label() }}</span>\r\n</div>\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}:host.fui-badge{--fui-badge-bg: transparent;--fui-badge-color: inherit;--fui-badge-font-size: var(--fui-font-size-01);--fui-badge-font-weight: var(--fui-font-weight-medium);--fui-badge-border-radius: var(--fui-border-radius-pill);--fui-badge-gap: var(--fui-spacing-02);--fui-badge-height-sm: 1.25rem;--fui-badge-height-md: 1.5rem;--fui-badge-height-lg: 2rem;contain:content;display:inline-flex;align-items:center;justify-content:center;font-family:var(--fui-font-family-sans);font-size:var(--fui-badge-font-size);font-weight:var(--fui-badge-font-weight);border-radius:var(--fui-badge-border-radius);background-color:var(--fui-badge-bg);color:var(--fui-badge-color);white-space:nowrap;transition:all var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}:host.fui-badge .fui-badge__content{display:flex;align-items:center;gap:var(--fui-badge-gap)}:host.fui-badge .fui-badge__label{line-height:1}:host.fui-badge .fui-badge__icon{display:inline-flex;align-items:center;justify-content:center}:host.fui-badge--sm{height:var(--fui-badge-height-sm);padding:0 var(--fui-spacing-03);font-size:var(--fui-font-size-01)}:host.fui-badge--md{height:var(--fui-badge-height-md);padding:0 var(--fui-spacing-04);font-size:var(--fui-font-size-02)}:host.fui-badge--lg{height:var(--fui-badge-height-lg);padding:0 var(--fui-spacing-05);font-size:var(--fui-font-size-03)}:host.fui-badge--primary{--fui-badge-bg: var(--fui-primary-20);--fui-badge-color: var(--fui-primary)}:host.fui-badge--secondary{--fui-badge-bg: var(--fui-secondary-20);--fui-badge-color: var(--fui-secondary-80)}:host.fui-badge--success{--fui-badge-bg: var(--fui-success-20);--fui-badge-color: var(--fui-success-80)}:host.fui-badge--info{--fui-badge-bg: var(--fui-info-20);--fui-badge-color: var(--fui-info-80)}:host.fui-badge--warning{--fui-badge-bg: var(--fui-warning-20);--fui-badge-color: var(--fui-warning-80)}:host.fui-badge--error{--fui-badge-bg: var(--fui-danger-20);--fui-badge-color: var(--fui-danger-80)}:host.fui-badge--custom{--fui-badge-bg: transparent;--fui-badge-color: inherit}@media(prefers-reduced-motion:reduce){:host.fui-badge{transition:none}}\n"] }]
113
+ }, template: "<div class=\"fui-badge__content\">\r\n @if (icon()) {\r\n <fui-icon class=\"fui-badge__icon\" [name]=\"icon()!\" [size]=\"iconSize()\" aria-hidden=\"true\" />\r\n }\r\n <span class=\"fui-badge__label\">{{ label() }}</span>\r\n</div>\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition:opacity var(--fui-duration-fast-02) var(--fui-ease-entrance) 0ms}.fui-motion-fade-out{transition:opacity var(--fui-duration-fast-01) var(--fui-ease-exit) 0ms}.fui-motion-slide-in-bottom{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition:transform var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition:transform,opacity var(--fui-duration-moderate-01) var(--fui-ease-entrance) 0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-moderate-01) var(--fui-ease-entrance)}@keyframes fui-popover-enter{0%{opacity:0;transform:translateY(-14px)}60%{opacity:1}to{opacity:1;transform:translateY(0)}}:host.fui-badge{--fui-badge-bg: transparent;--fui-badge-color: inherit;--fui-badge-font-size: var(--fui-font-size-01);--fui-badge-font-weight: var(--fui-font-weight-medium);--fui-badge-border-radius: var(--fui-border-radius-pill);--fui-badge-gap: var(--fui-spacing-02);--fui-badge-height-sm: 1.25rem;--fui-badge-height-md: 1.5rem;--fui-badge-height-lg: 2rem;contain:content;display:inline-flex;align-items:center;justify-content:center;font-family:var(--fui-font-family-sans);font-size:var(--fui-badge-font-size);font-weight:var(--fui-badge-font-weight);border-radius:var(--fui-badge-border-radius);background-color:var(--fui-badge-bg);color:var(--fui-badge-color);white-space:nowrap;transition:all var(--fui-duration-fast-02) var(--fui-ease-standard) 0ms}:host.fui-badge .fui-badge__content{display:flex;align-items:center;gap:var(--fui-badge-gap)}:host.fui-badge .fui-badge__label{line-height:1}:host.fui-badge .fui-badge__icon{display:inline-flex;align-items:center;justify-content:center}:host.fui-badge--sm{height:var(--fui-badge-height-sm);padding:0 var(--fui-spacing-03);font-size:var(--fui-font-size-01)}:host.fui-badge--md{height:var(--fui-badge-height-md);padding:0 var(--fui-spacing-04);font-size:var(--fui-font-size-02)}:host.fui-badge--lg{height:var(--fui-badge-height-lg);padding:0 var(--fui-spacing-05);font-size:var(--fui-font-size-03)}:host.fui-badge--primary{--fui-badge-bg: var(--fui-primary-20);--fui-badge-color: var(--fui-primary)}:host.fui-badge--secondary{--fui-badge-bg: var(--fui-secondary-20);--fui-badge-color: var(--fui-secondary-80)}:host.fui-badge--success{--fui-badge-bg: var(--fui-success-20);--fui-badge-color: var(--fui-success-80)}:host.fui-badge--info{--fui-badge-bg: var(--fui-info-20);--fui-badge-color: var(--fui-info-80)}:host.fui-badge--warning{--fui-badge-bg: var(--fui-warning-20);--fui-badge-color: var(--fui-warning-80)}:host.fui-badge--error{--fui-badge-bg: var(--fui-danger-20);--fui-badge-color: var(--fui-danger-80)}:host.fui-badge--custom{--fui-badge-bg: transparent;--fui-badge-color: inherit}@media(prefers-reduced-motion:reduce){:host.fui-badge{transition:none}}\n"] }]
100
114
  }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], customColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "customColor", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
101
115
 
102
116
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"raintonic-formaui-components-badge.mjs","sources":["../../../lib/components/badge/badge.types.ts","../../../lib/components/badge/badge.component.ts","../../../lib/components/badge/badge.component.html","../../../lib/components/badge/raintonic-formaui-components-badge.ts"],"sourcesContent":["export type FuiBadgeSize = 'sm' | 'md' | 'lg';\r\n\r\nexport type FuiBadgeVariant = 'primary' | 'secondary' | 'success' | 'info' | 'warning' | 'error' | 'custom';\r\n\r\nexport const FUI_BADGE_SIZES: readonly FuiBadgeSize[] = ['sm', 'md', 'lg'] as const;\r\n\r\nexport const FUI_BADGE_VARIANTS: readonly FuiBadgeVariant[] = [\r\n 'primary',\r\n 'secondary',\r\n 'success',\r\n 'info',\r\n 'warning',\r\n 'error',\r\n 'custom',\r\n] as const;\r\n","import { ChangeDetectionStrategy, Component, computed, input, Signal } from '@angular/core';\r\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\r\nimport { FuiBadgeSize, FuiBadgeVariant, FUI_BADGE_SIZES, FUI_BADGE_VARIANTS } from './badge.types';\r\n\r\n/**\r\n * @component FuiBadgeComponent\r\n * @selector fui-badge\r\n * @description Displays a small label badge with optional icon and color variants.\r\n * Supports custom colors with automatic text contrast calculation.\r\n *\r\n * @input label - (required) Text content of the badge.\r\n * @input icon - Optional Phosphor icon name displayed before the label.\r\n * @input customColor - Optional hex color that overrides the variant palette.\r\n * @input size - Badge size: 'sm' | 'md' | 'lg'. Default 'md'.\r\n * @input variant - Color variant: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info'. Default 'primary'.\r\n * @input ariaLabel - Accessible label override for screen readers.\r\n *\r\n * @example\r\n * <fui-badge label=\"Active\" variant=\"success\" icon=\"check-circle\"></fui-badge>\r\n */\r\n@Component({\r\n selector: 'fui-badge',\r\n standalone: true,\r\n imports: [FuiIconComponent],\r\n templateUrl: './badge.component.html',\r\n styleUrls: ['./badge.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n '[class]': 'computedClasses()',\r\n '[style]': 'computedStyles()',\r\n role: 'status',\r\n '[attr.aria-label]': 'ariaLabel() || null',\r\n },\r\n})\r\nexport class FuiBadgeComponent {\r\n /** Pattern allowing hex, rgb/rgba, hsl/hsla, and CSS named colors */\r\n private static readonly _SAFE_COLOR_PATTERN = /^(#[0-9a-fA-F]{3,8}|(?:rgb|hsl)a?\\([^)]+\\)|[a-zA-Z]+)$/;\r\n\r\n readonly label = input.required<string>();\r\n\r\n readonly icon = input<string | null>(null);\r\n\r\n readonly customColor = input<string | null>(null);\r\n\r\n readonly size = input<FuiBadgeSize, FuiBadgeSize | string>('md', {\r\n transform: (v) => ((FUI_BADGE_SIZES as readonly string[]).includes(v) ? (v as FuiBadgeSize) : 'md'),\r\n });\r\n\r\n readonly variant = input<FuiBadgeVariant, FuiBadgeVariant | string>('primary', {\r\n transform: (v) => ((FUI_BADGE_VARIANTS as readonly string[]).includes(v) ? (v as FuiBadgeVariant) : 'primary'),\r\n });\r\n\r\n readonly ariaLabel = input<string | null>(null);\r\n\r\n /** Validated custom color - returns null for invalid values to prevent CSS injection */\r\n readonly sanitizedColor: Signal<string | null> = computed(() => {\r\n const color = this.customColor();\r\n if (!color) return null;\r\n if (!FuiBadgeComponent._SAFE_COLOR_PATTERN.test(color)) {\r\n console.warn(`[FormaUI] Invalid badge color: \"${color}\"`);\r\n return null;\r\n }\r\n return color;\r\n });\r\n\r\n readonly computedTextColor: Signal<string | null> = computed(() => {\r\n const color = this.sanitizedColor();\r\n if (!color) return null;\r\n const luminance = this.getRelativeLuminance(color);\r\n return luminance < 0.5 ? '#ffffff' : '#000000';\r\n });\r\n\r\n readonly computedStyles = computed(() => {\r\n const color = this.sanitizedColor();\r\n if (!color) return {} as Record<string, string>;\r\n return {\r\n 'background-color': color,\r\n color: this.computedTextColor() ?? '#000000',\r\n } as Record<string, string>;\r\n });\r\n\r\n readonly computedClasses: Signal<string> = computed(() => {\r\n const effectiveVariant = this.sanitizedColor() ? 'custom' : this.variant();\r\n const classes: string[] = ['fui-badge', `fui-badge--${effectiveVariant}`, `fui-badge--${this.size()}`];\r\n\r\n if (this.icon()) {\r\n classes.push('fui-badge--with-icon');\r\n }\r\n\r\n return classes.join(' ');\r\n });\r\n\r\n readonly iconSize: Signal<'sm' | 'md' | 'lg'> = computed(() => {\r\n const size = this.size();\r\n if (size === 'lg') return 'md';\r\n return 'sm';\r\n });\r\n\r\n private getRelativeLuminance(hex: string): number {\r\n const r = parseInt(hex.slice(1, 3), 16) / 255;\r\n const g = parseInt(hex.slice(3, 5), 16) / 255;\r\n const b = parseInt(hex.slice(5, 7), 16) / 255;\r\n\r\n const linearize = (channel: number): number =>\r\n channel <= 0.03928 ? channel / 12.92 : Math.pow((channel + 0.055) / 1.055, 2.4);\r\n\r\n return 0.2126 * linearize(r) + 0.7152 * linearize(g) + 0.0722 * linearize(b);\r\n }\r\n}\r\n","<div class=\"fui-badge__content\">\r\n @if (icon()) {\r\n <fui-icon class=\"fui-badge__icon\" [name]=\"icon()!\" [size]=\"iconSize()\" aria-hidden=\"true\" />\r\n }\r\n <span class=\"fui-badge__label\">{{ label() }}</span>\r\n</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"raintonic-formaui-components-badge.mjs","sources":["../../../lib/components/badge/badge.types.ts","../../../lib/components/badge/badge.component.ts","../../../lib/components/badge/badge.component.html","../../../lib/components/badge/raintonic-formaui-components-badge.ts"],"sourcesContent":["export type FuiBadgeSize = 'sm' | 'md' | 'lg';\r\n\r\nexport interface FuiBadgeCustomColorObject {\r\n label: string;\r\n background: string;\r\n}\r\n\r\nexport type FuiBadgeCustomColor = string | FuiBadgeCustomColorObject;\r\n\r\nexport type FuiBadgeVariant = 'primary' | 'secondary' | 'success' | 'info' | 'warning' | 'error' | 'custom';\r\n\r\nexport const FUI_BADGE_SIZES: readonly FuiBadgeSize[] = ['sm', 'md', 'lg'] as const;\r\n\r\nexport const FUI_BADGE_VARIANTS: readonly FuiBadgeVariant[] = [\r\n 'primary',\r\n 'secondary',\r\n 'success',\r\n 'info',\r\n 'warning',\r\n 'error',\r\n 'custom',\r\n] as const;\r\n","import { ChangeDetectionStrategy, Component, computed, input, Signal } from '@angular/core';\r\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\r\nimport {\r\n FuiBadgeCustomColor,\r\n FuiBadgeCustomColorObject,\r\n FuiBadgeSize,\r\n FuiBadgeVariant,\r\n FUI_BADGE_SIZES,\r\n FUI_BADGE_VARIANTS,\r\n} from './badge.types';\r\n\r\n/**\r\n * @component FuiBadgeComponent\r\n * @selector fui-badge\r\n * @description Displays a small label badge with optional icon and color variants.\r\n * Supports custom colors with automatic text contrast calculation.\r\n *\r\n * @input label - (required) Text content of the badge.\r\n * @input icon - Optional Phosphor icon name displayed before the label.\r\n * @input customColor - Optional hex color or `{ label, background }` object that overrides the variant palette.\r\n * - Hex string: used as label color; background is the same hex with 16% alpha.\r\n * - Object: `{ label, background }` both as hex; applied as-is.\r\n * @input size - Badge size: 'sm' | 'md' | 'lg'. Default 'md'.\r\n * @input variant - Color variant: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info'. Default 'primary'.\r\n * @input ariaLabel - Accessible label override for screen readers.\r\n *\r\n * @example\r\n * <fui-badge label=\"Active\" variant=\"success\" icon=\"check-circle\"></fui-badge>\r\n */\r\n@Component({\r\n selector: 'fui-badge',\r\n standalone: true,\r\n imports: [FuiIconComponent],\r\n templateUrl: './badge.component.html',\r\n styleUrls: ['./badge.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n '[class]': 'computedClasses()',\r\n '[style]': 'computedStyles()',\r\n role: 'status',\r\n '[attr.aria-label]': 'ariaLabel() || null',\r\n },\r\n})\r\nexport class FuiBadgeComponent {\r\n /** Hex pattern: #rgb, #rgba, #rrggbb, #rrggbbaa */\r\n private static readonly _HEX_PATTERN = /^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;\r\n\r\n readonly label = input.required<string>();\r\n\r\n readonly icon = input<string | null>(null);\r\n\r\n readonly customColor = input<FuiBadgeCustomColor | null>(null);\r\n\r\n readonly size = input<FuiBadgeSize, FuiBadgeSize | string>('md', {\r\n transform: (v) => ((FUI_BADGE_SIZES as readonly string[]).includes(v) ? (v as FuiBadgeSize) : 'md'),\r\n });\r\n\r\n readonly variant = input<FuiBadgeVariant, FuiBadgeVariant | string>('primary', {\r\n transform: (v) => ((FUI_BADGE_VARIANTS as readonly string[]).includes(v) ? (v as FuiBadgeVariant) : 'primary'),\r\n });\r\n\r\n readonly ariaLabel = input<string | null>(null);\r\n\r\n /**\r\n * Resolved custom color pair (label + background).\r\n * - String input: must be a valid hex → used as label color, background is same hex with 16% alpha.\r\n * - Object input: `{ label, background }` used directly (both must be valid hex).\r\n * Returns null for invalid values to prevent CSS injection.\r\n */\r\n readonly resolvedCustomColor: Signal<FuiBadgeCustomColorObject | null> = computed(() => {\r\n const value = this.customColor();\r\n if (!value) return null;\r\n\r\n if (typeof value === 'string') {\r\n if (!FuiBadgeComponent._HEX_PATTERN.test(value)) {\r\n console.warn(`[FormaUI] Invalid badge color: \"${value}\"`);\r\n return null;\r\n }\r\n return { label: value, background: this.hexToRgba(value, 0.16) };\r\n }\r\n\r\n const { label, background } = value;\r\n if (!FuiBadgeComponent._HEX_PATTERN.test(label) || !FuiBadgeComponent._HEX_PATTERN.test(background)) {\r\n console.warn(`[FormaUI] Invalid badge color object:`, value);\r\n return null;\r\n }\r\n return { label, background };\r\n });\r\n\r\n readonly computedStyles = computed(() => {\r\n const resolved = this.resolvedCustomColor();\r\n if (!resolved) return {} as Record<string, string>;\r\n return {\r\n 'background-color': resolved.background,\r\n color: resolved.label,\r\n } as Record<string, string>;\r\n });\r\n\r\n readonly computedClasses: Signal<string> = computed(() => {\r\n const effectiveVariant = this.resolvedCustomColor() ? 'custom' : this.variant();\r\n const classes: string[] = ['fui-badge', `fui-badge--${effectiveVariant}`, `fui-badge--${this.size()}`];\r\n\r\n if (this.icon()) {\r\n classes.push('fui-badge--with-icon');\r\n }\r\n\r\n return classes.join(' ');\r\n });\r\n\r\n readonly iconSize: Signal<'sm' | 'md' | 'lg'> = computed(() => {\r\n const size = this.size();\r\n if (size === 'lg') return 'md';\r\n return 'sm';\r\n });\r\n\r\n private hexToRgba(hex: string, alpha: number): string {\r\n let h = hex.slice(1);\r\n if (h.length === 3 || h.length === 4) {\r\n h = h\r\n .split('')\r\n .map((c) => c + c)\r\n .join('');\r\n }\r\n const r = parseInt(h.slice(0, 2), 16);\r\n const g = parseInt(h.slice(2, 4), 16);\r\n const b = parseInt(h.slice(4, 6), 16);\r\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\r\n }\r\n}\r\n","<div class=\"fui-badge__content\">\r\n @if (icon()) {\r\n <fui-icon class=\"fui-badge__icon\" [name]=\"icon()!\" [size]=\"iconSize()\" aria-hidden=\"true\" />\r\n }\r\n <span class=\"fui-badge__label\">{{ label() }}</span>\r\n</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}