ngx-com 0.0.19 → 0.0.21

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 (56) hide show
  1. package/fesm2022/ngx-com-components-alert.mjs +346 -0
  2. package/fesm2022/ngx-com-components-alert.mjs.map +1 -0
  3. package/fesm2022/ngx-com-components-button.mjs +1 -1
  4. package/fesm2022/ngx-com-components-button.mjs.map +1 -1
  5. package/fesm2022/ngx-com-components-calendar.mjs +29 -36
  6. package/fesm2022/ngx-com-components-calendar.mjs.map +1 -1
  7. package/fesm2022/ngx-com-components-card.mjs +1 -1
  8. package/fesm2022/ngx-com-components-card.mjs.map +1 -1
  9. package/fesm2022/ngx-com-components-carousel.mjs +708 -0
  10. package/fesm2022/ngx-com-components-carousel.mjs.map +1 -0
  11. package/fesm2022/ngx-com-components-checkbox.mjs +17 -8
  12. package/fesm2022/ngx-com-components-checkbox.mjs.map +1 -1
  13. package/fesm2022/ngx-com-components-code-block.mjs +158 -0
  14. package/fesm2022/ngx-com-components-code-block.mjs.map +1 -0
  15. package/fesm2022/ngx-com-components-collapsible.mjs +1 -1
  16. package/fesm2022/ngx-com-components-collapsible.mjs.map +1 -1
  17. package/fesm2022/ngx-com-components-confirm.mjs +3 -3
  18. package/fesm2022/ngx-com-components-confirm.mjs.map +1 -1
  19. package/fesm2022/ngx-com-components-dialog.mjs +703 -0
  20. package/fesm2022/ngx-com-components-dialog.mjs.map +1 -0
  21. package/fesm2022/ngx-com-components-dropdown.mjs +36 -31
  22. package/fesm2022/ngx-com-components-dropdown.mjs.map +1 -1
  23. package/fesm2022/ngx-com-components-form-field.mjs +48 -8
  24. package/fesm2022/ngx-com-components-form-field.mjs.map +1 -1
  25. package/fesm2022/ngx-com-components-item.mjs +1 -1
  26. package/fesm2022/ngx-com-components-item.mjs.map +1 -1
  27. package/fesm2022/ngx-com-components-paginator.mjs +3 -3
  28. package/fesm2022/ngx-com-components-paginator.mjs.map +1 -1
  29. package/fesm2022/ngx-com-components-radio.mjs +16 -9
  30. package/fesm2022/ngx-com-components-radio.mjs.map +1 -1
  31. package/fesm2022/ngx-com-components-segmented-control.mjs +1 -1
  32. package/fesm2022/ngx-com-components-segmented-control.mjs.map +1 -1
  33. package/fesm2022/ngx-com-components-separator.mjs +102 -0
  34. package/fesm2022/ngx-com-components-separator.mjs.map +1 -0
  35. package/fesm2022/ngx-com-components-switch.mjs +258 -0
  36. package/fesm2022/ngx-com-components-switch.mjs.map +1 -0
  37. package/fesm2022/ngx-com-components-table.mjs +631 -0
  38. package/fesm2022/ngx-com-components-table.mjs.map +1 -0
  39. package/fesm2022/ngx-com-components-tabs.mjs +2 -2
  40. package/fesm2022/ngx-com-components-tabs.mjs.map +1 -1
  41. package/fesm2022/ngx-com-components-toast.mjs +783 -0
  42. package/fesm2022/ngx-com-components-toast.mjs.map +1 -0
  43. package/package.json +33 -1
  44. package/types/ngx-com-components-alert.d.ts +166 -0
  45. package/types/ngx-com-components-carousel.d.ts +281 -0
  46. package/types/ngx-com-components-checkbox.d.ts +7 -2
  47. package/types/ngx-com-components-code-block.d.ts +66 -0
  48. package/types/ngx-com-components-confirm.d.ts +2 -2
  49. package/types/ngx-com-components-dialog.d.ts +264 -0
  50. package/types/ngx-com-components-dropdown.d.ts +8 -5
  51. package/types/ngx-com-components-form-field.d.ts +19 -3
  52. package/types/ngx-com-components-radio.d.ts +5 -3
  53. package/types/ngx-com-components-separator.d.ts +75 -0
  54. package/types/ngx-com-components-switch.d.ts +110 -0
  55. package/types/ngx-com-components-table.d.ts +377 -0
  56. package/types/ngx-com-components-toast.d.ts +217 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngx-com-components-dialog.mjs","sources":["../../../projects/com/components/dialog/dialog-ref.ts","../../../projects/com/components/dialog/dialog.providers.ts","../../../projects/com/components/dialog/dialog-container-ref.token.ts","../../../projects/com/components/dialog/dialog.variants.ts","../../../projects/com/components/dialog/dialog.utils.ts","../../../projects/com/components/dialog/dialog-container.component.ts","../../../projects/com/components/dialog/dialog.models.ts","../../../projects/com/components/dialog/dialog.service.ts","../../../projects/com/components/dialog/dialog-title.directive.ts","../../../projects/com/components/dialog/dialog-content.directive.ts","../../../projects/com/components/dialog/dialog-actions.directive.ts","../../../projects/com/components/dialog/dialog-close.directive.ts","../../../projects/com/components/dialog/index.ts","../../../projects/com/components/dialog/ngx-com-components-dialog.ts"],"sourcesContent":["import { Observable, Subject } from 'rxjs';\nimport type { OverlayRef } from '@angular/cdk/overlay';\n\n/**\n * Reference to an open dialog instance.\n * Returned by `ComDialog.open()` for programmatic control.\n */\nexport class ComDialogRef<R = unknown> {\n private readonly afterClosedSubject = new Subject<R | undefined>();\n private readonly backdropClickSubject = new Subject<MouseEvent>();\n private closed = false;\n\n /** @internal */\n _overlayRef: OverlayRef | null = null;\n\n /** @internal */\n _closeFn: ((result?: R) => void) | null = null;\n\n /**\n * Close the dialog, optionally passing a result value.\n */\n close(result?: R): void {\n if (this.closed) return;\n this._closeFn?.(result);\n }\n\n /**\n * Emits the result once after the dialog is fully closed and disposed.\n */\n afterClosed(): Observable<R | undefined> {\n return this.afterClosedSubject.asObservable();\n }\n\n /**\n * Emits each time the backdrop is clicked.\n */\n backdropClick(): Observable<MouseEvent> {\n return this.backdropClickSubject.asObservable();\n }\n\n /**\n * Proxies keydown events from the overlay.\n */\n keydownEvents(): Observable<KeyboardEvent> {\n return this._overlayRef?.keydownEvents() ?? new Observable();\n }\n\n /** @internal Called by the service after exit animation completes. */\n _notifyClosed(result?: R): void {\n if (this.closed) return;\n this.closed = true;\n this.afterClosedSubject.next(result);\n this.afterClosedSubject.complete();\n this.backdropClickSubject.complete();\n }\n\n /** @internal Forward backdrop click from overlay. */\n _notifyBackdropClick(event: MouseEvent): void {\n this.backdropClickSubject.next(event);\n }\n}\n","import { InjectionToken } from '@angular/core';\nimport type { Provider } from '@angular/core';\nimport type { ComDialogConfig } from './dialog.models';\n\n/**\n * Injection token for data passed to a dialog component.\n *\n * @example\n * ```typescript\n * readonly data = inject<MyData>(COM_DIALOG_DATA);\n * ```\n */\nexport const COM_DIALOG_DATA: InjectionToken<unknown> =\n new InjectionToken<unknown>('COM_DIALOG_DATA');\n\n/**\n * Injection token for global dialog configuration defaults.\n * @internal\n */\nexport const COM_DIALOG_CONFIG: InjectionToken<ComDialogConfig> =\n new InjectionToken<ComDialogConfig>('COM_DIALOG_CONFIG');\n\n/**\n * Provides global dialog configuration defaults.\n *\n * @example\n * ```typescript\n * bootstrapApplication(AppComponent, {\n * providers: [\n * provideComDialogConfig({ size: 'lg', hasBackdrop: true }),\n * ],\n * });\n * ```\n */\nexport function provideComDialogConfig(config: ComDialogConfig): Provider {\n return { provide: COM_DIALOG_CONFIG, useValue: config };\n}\n","import { InjectionToken } from '@angular/core';\n\n/** Interface for the dialog container that directives can register with. */\nexport interface DialogContainerRef {\n registerTitleId(id: string): void;\n registerContentId(id: string): void;\n}\n\n/**\n * Injection token allowing dialog directives to register their element IDs\n * with the container for ARIA binding.\n * @internal\n */\nexport const COM_DIALOG_CONTAINER_REF: InjectionToken<DialogContainerRef> =\n new InjectionToken<DialogContainerRef>('COM_DIALOG_CONTAINER_REF');\n","import { cva } from 'class-variance-authority';\nimport type { VariantProps } from 'class-variance-authority';\n\n/**\n * CVA variants for the dialog backdrop.\n *\n * @tokens `--color-backdrop`\n */\nexport const dialogBackdropVariants: (props?: {\n visible?: boolean;\n}) => string = cva(\n [\n 'fixed',\n 'inset-0',\n 'z-50',\n 'bg-backdrop',\n 'backdrop-blur-sm',\n ],\n {\n variants: {\n visible: {\n true: 'animate-in fade-in-0',\n false: 'animate-out fade-out-0',\n },\n },\n defaultVariants: {\n visible: true,\n },\n },\n);\n\n/**\n * CVA variants for the dialog panel container.\n *\n * @tokens `--color-popover`, `--color-popover-foreground`, `--color-border`,\n * `--shadow-xl`, `--radius-overlay`\n */\nexport const dialogPanelVariants: (props?: {\n size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';\n visible?: boolean;\n}) => string = cva(\n [\n 'com-dialog-panel',\n 'fixed',\n 'left-1/2',\n 'top-1/2',\n '-translate-x-1/2',\n '-translate-y-1/2',\n 'z-50',\n 'flex',\n 'flex-col',\n 'border',\n 'border-border',\n 'bg-popover',\n 'text-popover-foreground',\n 'shadow-xl',\n 'rounded-overlay',\n 'outline-none',\n ],\n {\n variants: {\n size: {\n sm: 'w-full max-w-sm max-h-[85vh] p-6',\n md: 'w-full max-w-lg max-h-[85vh] p-6',\n lg: 'w-full max-w-2xl max-h-[85vh] p-6',\n xl: 'w-full max-w-4xl max-h-[85vh] p-6',\n full: 'w-screen h-screen max-w-none max-h-none rounded-none border-none p-6',\n },\n visible: {\n true: 'animate-in fade-in-0 zoom-in-95',\n false: 'animate-out fade-out-0 zoom-out-95',\n },\n },\n defaultVariants: {\n size: 'md',\n visible: true,\n },\n },\n);\n\n/** Type helper for dialog panel variant props. */\nexport type DialogPanelVariantProps = VariantProps<typeof dialogPanelVariants>;\n\n/**\n * CVA variants for the dialog title.\n *\n * @tokens `--color-foreground`\n */\nexport const dialogTitleVariants: () => string = cva([\n 'font-heading',\n 'text-lg',\n 'font-semibold',\n 'tracking-tight',\n 'text-foreground',\n]);\n\n/**\n * CVA variants for the dialog content area.\n *\n * @tokens `--color-muted-foreground`\n */\nexport const dialogContentVariants: () => string = cva([\n 'flex-1',\n 'overflow-y-auto',\n 'py-4',\n 'text-sm',\n 'text-muted-foreground',\n]);\n\n/**\n * CVA variants for the dialog actions area.\n */\nexport const dialogActionsVariants: () => string = cva([\n 'flex',\n 'flex-col-reverse',\n 'sm:flex-row',\n 'sm:justify-end',\n 'gap-2',\n 'pt-4',\n]);\n","export { mergeClasses } from 'ngx-com/utils';\n\nlet dialogIdCounter = 0;\n\n/** Generate a unique ID for a dialog title element. */\nexport function generateDialogTitleId(): string {\n return `com-dialog-title-${++dialogIdCounter}`;\n}\n\n/** Generate a unique ID for a dialog content element. */\nexport function generateDialogContentId(): string {\n return `com-dialog-content-${++dialogIdCounter}`;\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n ElementRef,\n inject,\n Injector,\n signal,\n viewChild,\n} from '@angular/core';\nimport type { AfterViewInit, Signal, TemplateRef, WritableSignal } from '@angular/core';\nimport { NgComponentOutlet, NgTemplateOutlet } from '@angular/common';\nimport { FocusTrap, FocusTrapFactory } from '@angular/cdk/a11y';\nimport type { ComponentType } from '@angular/cdk/portal';\nimport { ComDialogRef } from './dialog-ref';\nimport { COM_DIALOG_DATA } from './dialog.providers';\nimport { COM_DIALOG_CONTAINER_REF } from './dialog-container-ref.token';\nimport type { DialogContainerRef } from './dialog-container-ref.token';\nimport { dialogBackdropVariants, dialogPanelVariants } from './dialog.variants';\nimport { mergeClasses } from './dialog.utils';\nimport type {\n ComDialogResolvedConfig,\n ComDialogTemplateContext,\n} from './dialog.models';\n\n/** Fallback timeout for exit animation when animationend doesn't fire. */\nconst ANIMATION_FALLBACK_MS = 200;\n\n/**\n * Internal dialog container component rendered inside the CDK overlay.\n * Hosts the user's component or template and manages focus trap, animation, and ARIA.\n *\n * @internal Not exported in public API\n *\n * @tokens `--color-popover`, `--color-popover-foreground`, `--color-border`,\n * `--color-foreground`, `--color-muted-foreground`, `--color-backdrop`,\n * `--shadow-xl`, `--radius-overlay`, `--color-ring`\n */\n@Component({\n selector: 'com-dialog-container',\n template: `\n @if (config()?.hasBackdrop) {\n <div\n [class]=\"backdropClasses()\"\n [attr.data-state]=\"visible() ? 'open' : 'closed'\"\n aria-hidden=\"true\"\n (click)=\"onBackdropClick($event)\"\n ></div>\n }\n <div\n #panelElement\n [class]=\"panelClasses()\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"titleId() || null\"\n [attr.aria-describedby]=\"contentId() || null\"\n [attr.aria-label]=\"!titleId() && config()?.ariaLabel ? config()!.ariaLabel : null\"\n [attr.data-state]=\"visible() ? 'open' : 'closed'\"\n tabindex=\"-1\"\n (animationend)=\"onAnimationEnd()\"\n >\n @if (isTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"templateContent()!\"\n [ngTemplateOutletContext]=\"templateContext()\"\n />\n } @else if (componentContent(); as comp) {\n @if (contentInjector(); as inj) {\n <ng-container\n *ngComponentOutlet=\"comp; injector: inj\"\n />\n }\n }\n </div>\n `,\n styles: `\n :host {\n display: contents;\n }\n\n [data-state='open'] {\n --tw-enter-opacity: 0;\n --tw-enter-scale: 0.95;\n }\n\n [data-state='closed'] {\n --tw-exit-opacity: 0;\n --tw-exit-scale: 0.95;\n }\n\n @media (prefers-reduced-motion: reduce) {\n [data-state='open'],\n [data-state='closed'] {\n animation: none;\n }\n }\n `,\n imports: [NgTemplateOutlet, NgComponentOutlet],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ComDialogContainerComponent implements AfterViewInit, DialogContainerRef {\n private readonly focusTrapFactory = inject(FocusTrapFactory);\n private focusTrap: FocusTrap | null = null;\n private animationFallback: ReturnType<typeof setTimeout> | null = null;\n private closing = false;\n private pendingResult: unknown = undefined;\n\n private readonly panelElement = viewChild<ElementRef<HTMLElement>>('panelElement');\n\n /** Resolved dialog configuration, set by the service. */\n readonly config: WritableSignal<ComDialogResolvedConfig | null> = signal(null);\n\n /** Whether the panel is visible (for animation state). */\n readonly visible: WritableSignal<boolean> = signal(false);\n\n /** The dialog ref for this instance, set by the service. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly dialogRef: WritableSignal<ComDialogRef<any> | null> = signal(null);\n\n /** Injector for content component, set by the service. */\n readonly contentInjector: WritableSignal<Injector | null> = signal(null);\n\n // ─── Content signals (set by service) ───\n\n /** Whether the content is a TemplateRef. */\n readonly isTemplate: WritableSignal<boolean> = signal(false);\n\n /** Template ref content (when isTemplate is true). */\n readonly templateContent: WritableSignal<TemplateRef<unknown> | null> = signal(null);\n\n /** Component type content (when isTemplate is false). */\n readonly componentContent: WritableSignal<ComponentType<unknown> | null> = signal(null);\n\n // ─── ARIA ID registration ───\n\n /** ID of the title directive for aria-labelledby. */\n readonly titleId: WritableSignal<string> = signal('');\n\n /** ID of the content directive for aria-describedby. */\n readonly contentId: WritableSignal<string> = signal('');\n\n /** Register a title element ID (called by ComDialogTitle directive). */\n registerTitleId(id: string): void {\n this.titleId.set(id);\n }\n\n /** Register a content element ID (called by ComDialogContent directive). */\n registerContentId(id: string): void {\n this.contentId.set(id);\n }\n\n // ─── Computed classes ───\n\n protected readonly backdropClasses: Signal<string> = computed(() =>\n mergeClasses(dialogBackdropVariants({ visible: this.visible() })),\n );\n\n protected readonly panelClasses: Signal<string> = computed(() =>\n mergeClasses(\n dialogPanelVariants({\n size: this.config()?.size ?? 'md',\n visible: this.visible(),\n }),\n this.config()?.panelClass ?? '',\n ),\n );\n\n /** Template context for TemplateRef-based dialogs. */\n protected readonly templateContext: Signal<ComDialogTemplateContext> = computed(() => ({\n $implicit: this.dialogRef()!,\n data: this.config()?.data,\n }));\n\n ngAfterViewInit(): void {\n this.setupFocusTrap();\n }\n\n /** Handle backdrop click. */\n protected onBackdropClick(event: MouseEvent): void {\n const ref = this.dialogRef();\n if (ref) {\n ref._notifyBackdropClick(event);\n }\n if (!this.config()?.disableClose) {\n this.dialogRef()?.close();\n }\n }\n\n /** Start the close animation sequence. */\n startClose(result?: unknown): void {\n if (this.closing) return;\n this.closing = true;\n this.pendingResult = result;\n this.visible.set(false);\n\n // Fallback in case animationend doesn't fire\n this.animationFallback = setTimeout(() => this.finishClose(), ANIMATION_FALLBACK_MS);\n }\n\n /** Handle animation end on the panel. */\n protected onAnimationEnd(): void {\n if (this.closing) {\n this.finishClose();\n }\n }\n\n /** Clean up focus trap. */\n destroyFocusTrap(): void {\n this.focusTrap?.destroy();\n this.focusTrap = null;\n }\n\n private finishClose(): void {\n if (this.animationFallback !== null) {\n clearTimeout(this.animationFallback);\n this.animationFallback = null;\n }\n this.destroyFocusTrap();\n this.dialogRef()?._notifyClosed(this.pendingResult);\n }\n\n private setupFocusTrap(): void {\n const panelEl = this.panelElement()?.nativeElement;\n if (!panelEl) return;\n\n this.focusTrap = this.focusTrapFactory.create(panelEl);\n\n const autoFocus = this.config()?.autoFocus ?? 'first-tabbable';\n if (autoFocus === 'first-tabbable') {\n this.focusTrap.focusInitialElementWhenReady();\n } else if (autoFocus === 'dialog') {\n panelEl.focus();\n }\n // autoFocus === false: don't move focus\n }\n}\n","import type { TemplateRef } from '@angular/core';\nimport type { ComponentType } from '@angular/cdk/portal';\n\n/** Available dialog size variants. */\nexport type ComDialogSize = 'sm' | 'md' | 'lg' | 'xl' | 'full';\n\n/** Configuration for opening a dialog. */\nexport interface ComDialogConfig<D = unknown> {\n /** Data to inject via COM_DIALOG_DATA. */\n data?: D;\n /** Dialog panel width variant. */\n size?: ComDialogSize;\n /** Prevent Escape and backdrop click from closing. */\n disableClose?: boolean;\n /** Show backdrop overlay. */\n hasBackdrop?: boolean;\n /** Additional CSS class on the backdrop. */\n backdropClass?: string;\n /** Additional CSS class on the container panel. */\n panelClass?: string;\n /** Where to send focus on open. */\n autoFocus?: 'first-tabbable' | 'dialog' | false;\n /** Return focus to trigger element on close. */\n restoreFocus?: boolean;\n /** Fallback aria-label if no comDialogTitle is projected. */\n ariaLabel?: string;\n}\n\n/** Resolved config with all defaults applied. */\nexport type ComDialogResolvedConfig<D = unknown> = Required<ComDialogConfig<D>>;\n\n/** Default dialog configuration values. */\nexport const COM_DIALOG_DEFAULTS: ComDialogResolvedConfig = {\n data: undefined,\n size: 'md',\n disableClose: false,\n hasBackdrop: true,\n backdropClass: '',\n panelClass: '',\n autoFocus: 'first-tabbable',\n restoreFocus: true,\n ariaLabel: '',\n};\n\n/** Content that can be opened in a dialog. */\nexport type ComDialogContent<T = unknown> = ComponentType<T> | TemplateRef<T>;\n\n/** Template context when opening a TemplateRef dialog. */\nexport interface ComDialogTemplateContext<R = unknown, D = unknown> {\n $implicit: import('./dialog-ref').ComDialogRef<R>;\n data: D;\n}\n\n/** @internal Data passed to the dialog container. */\nexport interface ComDialogContainerData<D = unknown> {\n content: ComDialogContent;\n config: ComDialogResolvedConfig<D>;\n isTemplate: boolean;\n}\n","import {\n DestroyRef,\n inject,\n Injectable,\n Injector,\n PLATFORM_ID,\n TemplateRef,\n} from '@angular/core';\nimport type { ComponentType } from '@angular/cdk/portal';\nimport { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Overlay } from '@angular/cdk/overlay';\nimport type { OverlayRef } from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport { filter } from 'rxjs/operators';\nimport { ComDialogRef } from './dialog-ref';\nimport { ComDialogContainerComponent } from './dialog-container.component';\nimport { COM_DIALOG_CONTAINER_REF } from './dialog-container-ref.token';\nimport { COM_DIALOG_CONFIG, COM_DIALOG_DATA } from './dialog.providers';\nimport { COM_DIALOG_DEFAULTS } from './dialog.models';\nimport type {\n ComDialogConfig,\n ComDialogContent,\n ComDialogResolvedConfig,\n} from './dialog.models';\n\n/**\n * Service for opening dialog modals imperatively.\n *\n * @example\n * ```typescript\n * const dialog = inject(ComDialog);\n *\n * // Open a component\n * const ref = dialog.open<boolean>(ConfirmComponent, { data: { id: 123 } });\n * ref.afterClosed().subscribe(result => {\n * if (result) performAction();\n * });\n *\n * // Open a template\n * dialog.open(templateRef, { size: 'sm' });\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class ComDialog {\n private readonly overlay = inject(Overlay);\n private readonly injector = inject(Injector);\n private readonly destroyRef = inject(DestroyRef);\n private readonly platformId = inject(PLATFORM_ID);\n private readonly document = inject(DOCUMENT);\n private readonly globalConfig = inject(COM_DIALOG_CONFIG, { optional: true });\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private readonly openDialogs: ComDialogRef<any>[] = [];\n\n /**\n * Open a dialog with the given component or template.\n *\n * @param content - The component class or TemplateRef to render inside the dialog.\n * @param config - Optional dialog configuration.\n * @returns A reference to the opened dialog.\n */\n open<R = unknown, D = unknown>(\n content: ComDialogContent,\n config?: ComDialogConfig<D>,\n ): ComDialogRef<R> {\n if (!isPlatformBrowser(this.platformId)) {\n return new ComDialogRef<R>();\n }\n\n const resolvedConfig = this.resolveConfig(config);\n const previouslyFocused = this.document.activeElement as HTMLElement | null;\n\n // Create the dialog ref\n const dialogRef = new ComDialogRef<R>();\n\n // Create a child injector with dialog-specific providers\n const isTemplate = content instanceof TemplateRef;\n const containerRef: { registerTitleId: (id: string) => void; registerContentId: (id: string) => void } = {\n registerTitleId: () => {},\n registerContentId: () => {},\n };\n const contentInjector = Injector.create({\n providers: [\n { provide: ComDialogRef, useValue: dialogRef },\n { provide: COM_DIALOG_DATA, useValue: resolvedConfig.data },\n { provide: COM_DIALOG_CONTAINER_REF, useValue: containerRef },\n ],\n parent: this.injector,\n });\n\n // Create CDK overlay\n const positionStrategy = this.overlay\n .position()\n .global()\n .centerHorizontally()\n .centerVertically();\n\n const overlayRef = this.overlay.create({\n positionStrategy,\n scrollStrategy: this.overlay.scrollStrategies.block(),\n hasBackdrop: false, // We handle backdrop ourselves for animation control\n panelClass: 'com-dialog-overlay',\n disposeOnNavigation: false,\n });\n\n dialogRef._overlayRef = overlayRef;\n\n // Attach the container component\n const portal = new ComponentPortal(\n ComDialogContainerComponent,\n null,\n contentInjector,\n );\n const containerComponentRef = overlayRef.attach(portal);\n const container = containerComponentRef.instance;\n\n // Wire up the container ref for ARIA registration\n containerRef.registerTitleId = (id: string) => container.registerTitleId(id);\n containerRef.registerContentId = (id: string) => container.registerContentId(id);\n\n // Configure the container\n container.config.set(resolvedConfig);\n container.dialogRef.set(dialogRef);\n container.isTemplate.set(isTemplate);\n\n if (isTemplate) {\n container.templateContent.set(content as TemplateRef<unknown>);\n } else {\n container.componentContent.set(content as ComponentType<unknown>);\n container.contentInjector.set(contentInjector);\n }\n\n // Wire up the close function\n dialogRef._closeFn = (result?: R) => {\n container.startClose(result);\n };\n\n // Subscribe to Escape key\n overlayRef\n .keydownEvents()\n .pipe(\n filter((event) => event.key === 'Escape'),\n takeUntilDestroyed(this.destroyRef),\n )\n .subscribe((event) => {\n if (!resolvedConfig.disableClose) {\n event.preventDefault();\n event.stopPropagation();\n dialogRef.close();\n }\n });\n\n // Track open dialog\n this.openDialogs.push(dialogRef);\n\n // Clean up after close\n dialogRef.afterClosed().subscribe(() => {\n const idx = this.openDialogs.indexOf(dialogRef);\n if (idx !== -1) {\n this.openDialogs.splice(idx, 1);\n }\n overlayRef.dispose();\n\n // Restore focus\n if (resolvedConfig.restoreFocus && previouslyFocused) {\n previouslyFocused.focus();\n }\n });\n\n // Show panel after a microtask to allow initial styles to apply\n requestAnimationFrame(() => {\n container.visible.set(true);\n });\n\n return dialogRef;\n }\n\n /** Close all open dialogs. */\n closeAll(): void {\n for (const ref of [...this.openDialogs]) {\n ref.close();\n }\n }\n\n /** Number of currently open dialogs. */\n get openDialogCount(): number {\n return this.openDialogs.length;\n }\n\n private resolveConfig<D>(config?: ComDialogConfig<D>): ComDialogResolvedConfig<D> {\n return {\n ...COM_DIALOG_DEFAULTS,\n ...this.globalConfig,\n ...config,\n } as ComDialogResolvedConfig<D>;\n }\n}\n","import { Directive, inject, signal } from '@angular/core';\nimport type { OnInit, Signal, WritableSignal } from '@angular/core';\nimport { generateDialogTitleId } from './dialog.utils';\nimport { COM_DIALOG_CONTAINER_REF } from './dialog-container-ref.token';\nimport { dialogTitleVariants } from './dialog.variants';\nimport { mergeClasses } from './dialog.utils';\n\n/**\n * Marks an element as the dialog title. Sets up aria-labelledby\n * binding on the dialog container.\n *\n * @example\n * ```html\n * <h2 comDialogTitle>Delete item</h2>\n * ```\n *\n * @tokens `--color-foreground`\n */\n@Directive({\n selector: '[comDialogTitle]',\n exportAs: 'comDialogTitle',\n host: {\n '[id]': 'id()',\n '[class]': 'classes()',\n },\n})\nexport class ComDialogTitle implements OnInit {\n private readonly containerRef = inject(COM_DIALOG_CONTAINER_REF, { optional: true });\n\n /** Unique ID for aria-labelledby binding. */\n readonly id: WritableSignal<string> = signal(generateDialogTitleId());\n\n /** Computed CSS classes. */\n readonly classes: WritableSignal<string> = signal(mergeClasses(dialogTitleVariants()));\n\n ngOnInit(): void {\n this.containerRef?.registerTitleId(this.id());\n }\n}\n","import { Directive, inject, signal } from '@angular/core';\nimport type { OnInit, Signal, WritableSignal } from '@angular/core';\nimport { generateDialogContentId } from './dialog.utils';\nimport { COM_DIALOG_CONTAINER_REF } from './dialog-container-ref.token';\nimport { dialogContentVariants } from './dialog.variants';\nimport { mergeClasses } from './dialog.utils';\n\n/**\n * Marks an element as the dialog content area. Sets up aria-describedby\n * binding on the dialog container.\n *\n * @example\n * ```html\n * <div comDialogContent>\n * <p>Are you sure you want to delete this item?</p>\n * </div>\n * ```\n *\n * @tokens `--color-muted-foreground`\n */\n@Directive({\n selector: '[comDialogContent]',\n exportAs: 'comDialogContent',\n host: {\n '[id]': 'id()',\n '[class]': 'classes()',\n },\n})\nexport class ComDialogContent implements OnInit {\n private readonly containerRef = inject(COM_DIALOG_CONTAINER_REF, { optional: true });\n\n /** Unique ID for aria-describedby binding. */\n readonly id: WritableSignal<string> = signal(generateDialogContentId());\n\n /** Computed CSS classes. */\n readonly classes: WritableSignal<string> = signal(mergeClasses(dialogContentVariants()));\n\n ngOnInit(): void {\n this.containerRef?.registerContentId(this.id());\n }\n}\n","import { Directive, signal } from '@angular/core';\nimport type { WritableSignal } from '@angular/core';\nimport { dialogActionsVariants } from './dialog.variants';\nimport { mergeClasses } from './dialog.utils';\n\n/**\n * Marks an element as the dialog actions area (footer with buttons).\n *\n * @example\n * ```html\n * <div comDialogActions>\n * <button comButton variant=\"outline\" [comDialogClose]=\"false\">Cancel</button>\n * <button comButton [comDialogClose]=\"true\">Confirm</button>\n * </div>\n * ```\n */\n@Directive({\n selector: '[comDialogActions]',\n exportAs: 'comDialogActions',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class ComDialogActions {\n /** Computed CSS classes. */\n readonly classes: WritableSignal<string> = signal(mergeClasses(dialogActionsVariants()));\n}\n","import { Directive, inject, input } from '@angular/core';\nimport type { InputSignal } from '@angular/core';\nimport { ComDialogRef } from './dialog-ref';\n\n/**\n * Closes the nearest dialog when the host element is clicked.\n * Optionally passes a result value.\n *\n * @example\n * ```html\n * <button comButton [comDialogClose]=\"false\">Cancel</button>\n * <button comButton [comDialogClose]=\"true\">Confirm</button>\n * ```\n */\n@Directive({\n selector: '[comDialogClose]',\n exportAs: 'comDialogClose',\n host: {\n '(click)': 'onClick()',\n },\n})\nexport class ComDialogClose {\n private readonly dialogRef = inject(ComDialogRef);\n\n /** The result value to pass when closing the dialog. */\n readonly comDialogClose: InputSignal<unknown> = input<unknown>(undefined);\n\n protected onClick(): void {\n this.dialogRef.close(this.comDialogClose());\n }\n}\n","// Public API for the dialog system\n\n// Service\nexport { ComDialog } from './dialog.service';\n\n// Ref\nexport { ComDialogRef } from './dialog-ref';\n\n// Directives\nexport { ComDialogTitle } from './dialog-title.directive';\nexport { ComDialogContent } from './dialog-content.directive';\nexport { ComDialogActions } from './dialog-actions.directive';\nexport { ComDialogClose } from './dialog-close.directive';\n\n// Types\nexport type {\n ComDialogConfig,\n ComDialogSize,\n ComDialogTemplateContext,\n} from './dialog.models';\n\n// Providers\nexport { COM_DIALOG_DATA, COM_DIALOG_CONFIG, provideComDialogConfig } from './dialog.providers';\n\n// Variants (for advanced customization)\nexport {\n dialogBackdropVariants,\n dialogPanelVariants,\n dialogTitleVariants,\n dialogContentVariants,\n dialogActionsVariants,\n} from './dialog.variants';\nexport type { DialogPanelVariantProps } from './dialog.variants';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { viewChild, input, output, computed, ChangeDetectionStrategy, Component, inject, DestroyRef, signal, TemplateRef, Directive, ElementRef, ViewContainerRef, contentChild, linkedSignal, forwardRef } from '@angular/core';
2
+ import { viewChild, input, output, computed, ChangeDetectionStrategy, Component, inject, DestroyRef, signal, TemplateRef, Directive, ElementRef, ViewContainerRef, contentChild, model, linkedSignal, forwardRef } from '@angular/core';
3
3
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
4
  import { NgTemplateOutlet } from '@angular/common';
5
5
  import { NgForm, FormGroupDirective, NgControl } from '@angular/forms';
@@ -30,14 +30,12 @@ const dropdownTriggerVariants = cva([
30
30
  'border',
31
31
  'bg-input-background',
32
32
  'text-input-foreground',
33
- 'ring-offset-background',
34
33
  'transition-colors',
35
34
  'duration-150',
36
35
  'placeholder:text-input-placeholder',
37
- 'focus:outline-none',
38
- 'focus:ring-2',
39
- 'focus:ring-offset-2',
40
- 'focus:ring-ring',
36
+ 'focus-visible:outline-[1px]',
37
+ 'focus-visible:outline-offset-2',
38
+ 'focus-visible:outline-ring',
41
39
  'disabled:cursor-not-allowed',
42
40
  'disabled:bg-disabled',
43
41
  'disabled:text-disabled-foreground',
@@ -67,8 +65,7 @@ const dropdownTriggerVariants = cva([
67
65
  'border-transparent',
68
66
  'bg-transparent',
69
67
  'shadow-none',
70
- 'focus:ring-0',
71
- 'focus:ring-offset-0',
68
+ 'focus-visible:outline-none',
72
69
  'rounded-none',
73
70
  ],
74
71
  },
@@ -81,15 +78,15 @@ const dropdownTriggerVariants = cva([
81
78
  default: [],
82
79
  error: [
83
80
  'border-warn',
84
- 'focus:ring-warn',
81
+ 'focus-visible:outline-warn',
85
82
  ],
86
83
  success: [
87
84
  'border-success',
88
- 'focus:ring-success',
85
+ 'focus-visible:outline-success',
89
86
  ],
90
87
  },
91
88
  open: {
92
- true: ['ring-2', 'ring-ring', 'border-primary'],
89
+ true: ['outline-[1px]', 'outline-ring', 'border-primary'],
93
90
  false: [],
94
91
  },
95
92
  },
@@ -108,19 +105,19 @@ const dropdownTriggerVariants = cva([
108
105
  {
109
106
  open: true,
110
107
  variant: 'naked',
111
- class: ['ring-0', 'border-transparent'],
108
+ class: ['outline-none', 'border-transparent'],
112
109
  },
113
110
  // Naked variant should not show error border (form-field provides error styling)
114
111
  {
115
112
  state: 'error',
116
113
  variant: 'naked',
117
- class: ['border-transparent', 'focus:ring-0'],
114
+ class: ['border-transparent', 'focus-visible:outline-none'],
118
115
  },
119
116
  // Naked variant should not show success border (form-field provides styling)
120
117
  {
121
118
  state: 'success',
122
119
  variant: 'naked',
123
- class: ['border-transparent', 'focus:ring-0'],
120
+ class: ['border-transparent', 'focus-visible:outline-none'],
124
121
  },
125
122
  ],
126
123
  defaultVariants: {
@@ -293,9 +290,9 @@ const dropdownTagRemoveVariants = cva([
293
290
  'text-muted-foreground',
294
291
  'transition-colors',
295
292
  'hover:text-foreground',
296
- 'focus:outline-none',
297
- 'focus:ring-1',
298
- 'focus:ring-ring',
293
+ 'focus-visible:outline-[1px]',
294
+ 'focus-visible:outline-offset-2',
295
+ 'focus-visible:outline-ring',
299
296
  ], {
300
297
  variants: {
301
298
  size: {
@@ -397,9 +394,9 @@ const dropdownClearVariants = cva([
397
394
  'text-muted-foreground',
398
395
  'transition-colors',
399
396
  'hover:text-foreground',
400
- 'focus:outline-none',
401
- 'focus:ring-1',
402
- 'focus:ring-ring',
397
+ 'focus-visible:outline-[1px]',
398
+ 'focus-visible:outline-offset-2',
399
+ 'focus-visible:outline-ring',
403
400
  ], {
404
401
  variants: {
405
402
  size: {
@@ -977,7 +974,7 @@ class ComDropdownSearch {
977
974
  @if (showClear()) {
978
975
  <button
979
976
  type="button"
980
- class="absolute right-3 flex h-4 w-4 items-center justify-center rounded-interactive-sm text-muted-foreground transition-colors hover:text-foreground focus:outline-none focus:ring-1 focus:ring-ring"
977
+ class="absolute right-3 flex h-4 w-4 items-center justify-center rounded-interactive-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-[1px] focus-visible:outline-offset-2 focus-visible:outline-ring"
981
978
  [attr.aria-label]="'Clear search'"
982
979
  (click)="clearSearch()"
983
980
  >
@@ -1039,7 +1036,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
1039
1036
  @if (showClear()) {
1040
1037
  <button
1041
1038
  type="button"
1042
- class="absolute right-3 flex h-4 w-4 items-center justify-center rounded-interactive-sm text-muted-foreground transition-colors hover:text-foreground focus:outline-none focus:ring-1 focus:ring-ring"
1039
+ class="absolute right-3 flex h-4 w-4 items-center justify-center rounded-interactive-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-[1px] focus-visible:outline-offset-2 focus-visible:outline-ring"
1043
1040
  [attr.aria-label]="'Clear search'"
1044
1041
  (click)="clearSearch()"
1045
1042
  >
@@ -1605,7 +1602,7 @@ class ComDropdown {
1605
1602
  /** Array of options to display. */
1606
1603
  options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
1607
1604
  /** Current value (single or array for multiple). */
1608
- value = input(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
1605
+ value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
1609
1606
  /** Placeholder text when no value is selected. */
1610
1607
  placeholder = input('Select...', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
1611
1608
  /** Enable multi-select mode. */
@@ -1650,9 +1647,11 @@ class ComDropdown {
1650
1647
  maxVisibleTags = input(2, ...(ngDevMode ? [{ debugName: "maxVisibleTags" }] : []));
1651
1648
  /** Custom error state matcher for determining when to show errors. */
1652
1649
  errorStateMatcher = input(...(ngDevMode ? [undefined, { debugName: "errorStateMatcher" }] : []));
1650
+ // Signal Forms inputs — set automatically by [formField] via setInputOnDirectives
1651
+ touched = model(false, ...(ngDevMode ? [{ debugName: "touched" }] : []));
1652
+ invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : []));
1653
+ sfErrors = input([], { ...(ngDevMode ? { debugName: "sfErrors" } : {}), alias: 'errors' });
1653
1654
  // ============ OUTPUTS ============
1654
- /** Emitted when the value changes. */
1655
- valueChange = output();
1656
1655
  /** Emitted when search query changes. */
1657
1656
  searchChange = output();
1658
1657
  /** Emitted when panel opens. */
@@ -1700,13 +1699,19 @@ class ComDropdown {
1700
1699
  shouldLabelFloat = computed(() => this.focused() || this.hasValue(), ...(ngDevMode ? [{ debugName: "shouldLabelFloat" }] : []));
1701
1700
  /** Whether the control is in an error state. Implements FormFieldControl. */
1702
1701
  errorState = computed(() => {
1703
- // Read reactive dependencies to trigger re-evaluation
1702
+ if (!this.ngControl) {
1703
+ // Signal Forms: gate on invalid AND touched (mirrors ErrorStateMatcher default)
1704
+ return this.invalid() && this.touched();
1705
+ }
1706
+ // Reactive Forms: use ErrorStateMatcher (existing logic)
1704
1707
  this.isOpen();
1705
1708
  this.hasValue();
1706
1709
  const matcher = this.errorStateMatcher() ?? this.defaultErrorStateMatcher;
1707
1710
  const form = this.parentFormGroup ?? this.parentForm;
1708
- return matcher.isErrorState(this.ngControl?.control ?? null, form);
1711
+ return matcher.isErrorState(this.ngControl.control ?? null, form);
1709
1712
  }, ...(ngDevMode ? [{ debugName: "errorState" }] : []));
1713
+ /** Structured validation errors from Signal Forms, exposed for the parent form field. */
1714
+ errors = computed(() => !this.ngControl ? this.sfErrors() : null, ...(ngDevMode ? [{ debugName: "errors" }] : []));
1710
1715
  /** Unique ID for the control. Implements FormFieldControl. */
1711
1716
  id = this.triggerId;
1712
1717
  /**
@@ -1935,6 +1940,7 @@ class ComDropdown {
1935
1940
  this.activeOptionId.set(null);
1936
1941
  this.closed.emit();
1937
1942
  this.onTouched();
1943
+ this.touched.set(true);
1938
1944
  }
1939
1945
  /** Toggles the dropdown panel. */
1940
1946
  toggle() {
@@ -2171,9 +2177,8 @@ class ComDropdown {
2171
2177
  return { width: config };
2172
2178
  }
2173
2179
  updateValue(value) {
2174
- this.internalValue.set(value);
2180
+ this.value.set(value);
2175
2181
  this.onChange(value);
2176
- this.valueChange.emit(value);
2177
2182
  // Announce selection
2178
2183
  if (value !== null && !Array.isArray(value)) {
2179
2184
  this.announce(`${this.displayWith()(value)} selected`);
@@ -2275,7 +2280,7 @@ class ComDropdown {
2275
2280
  this.liveAnnouncer.announce(message, 'polite');
2276
2281
  }
2277
2282
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComDropdown, deps: [], target: i0.ɵɵFactoryTarget.Component });
2278
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComDropdown, isStandalone: true, selector: "com-dropdown", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, displayWith: { classPropertyName: "displayWith", publicName: "displayWith", isSignal: true, isRequired: false, transformFunction: null }, filterWith: { classPropertyName: "filterWith", publicName: "filterWith", isSignal: true, isRequired: false, transformFunction: null }, groupBy: { classPropertyName: "groupBy", publicName: "groupBy", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, panelWidth: { classPropertyName: "panelWidth", publicName: "panelWidth", isSignal: true, isRequired: false, transformFunction: null }, searchDebounceMs: { classPropertyName: "searchDebounceMs", publicName: "searchDebounceMs", isSignal: true, isRequired: false, transformFunction: null }, virtualScrollThreshold: { classPropertyName: "virtualScrollThreshold", publicName: "virtualScrollThreshold", isSignal: true, isRequired: false, transformFunction: null }, maxVisibleTags: { classPropertyName: "maxVisibleTags", publicName: "maxVisibleTags", isSignal: true, isRequired: false, transformFunction: null }, errorStateMatcher: { classPropertyName: "errorStateMatcher", publicName: "errorStateMatcher", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", searchChange: "searchChange", opened: "opened", closed: "closed" }, host: { properties: { "class.com-dropdown-disabled": "disabled()", "class.com-dropdown-open": "isOpen()" }, classAttribute: "com-dropdown-host inline-block" }, providers: [{ provide: FormFieldControl, useExisting: forwardRef(() => ComDropdown) }], queries: [{ propertyName: "optionTemplate", first: true, predicate: (ComDropdownOptionTpl), descendants: true, isSignal: true }, { propertyName: "selectedTemplate", first: true, predicate: (ComDropdownSelectedTpl), descendants: true, isSignal: true }, { propertyName: "emptyTemplate", first: true, predicate: ComDropdownEmptyTpl, descendants: true, isSignal: true }, { propertyName: "groupTemplate", first: true, predicate: ComDropdownGroupTpl, descendants: true, isSignal: true }, { propertyName: "tagTemplate", first: true, predicate: (ComDropdownTagTpl), descendants: true, isSignal: true }], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerElement"], descendants: true, isSignal: true }, { propertyName: "panelTemplateRef", first: true, predicate: ["panelTemplate"], descendants: true, isSignal: true }], exportAs: ["comDropdown"], ngImport: i0, template: `
2283
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComDropdown, isStandalone: true, selector: "com-dropdown", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, displayWith: { classPropertyName: "displayWith", publicName: "displayWith", isSignal: true, isRequired: false, transformFunction: null }, filterWith: { classPropertyName: "filterWith", publicName: "filterWith", isSignal: true, isRequired: false, transformFunction: null }, groupBy: { classPropertyName: "groupBy", publicName: "groupBy", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, panelWidth: { classPropertyName: "panelWidth", publicName: "panelWidth", isSignal: true, isRequired: false, transformFunction: null }, searchDebounceMs: { classPropertyName: "searchDebounceMs", publicName: "searchDebounceMs", isSignal: true, isRequired: false, transformFunction: null }, virtualScrollThreshold: { classPropertyName: "virtualScrollThreshold", publicName: "virtualScrollThreshold", isSignal: true, isRequired: false, transformFunction: null }, maxVisibleTags: { classPropertyName: "maxVisibleTags", publicName: "maxVisibleTags", isSignal: true, isRequired: false, transformFunction: null }, errorStateMatcher: { classPropertyName: "errorStateMatcher", publicName: "errorStateMatcher", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, sfErrors: { classPropertyName: "sfErrors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange", searchChange: "searchChange", opened: "opened", closed: "closed" }, host: { properties: { "class.com-dropdown-disabled": "disabled()", "class.com-dropdown-open": "isOpen()" }, classAttribute: "com-dropdown-host inline-block" }, providers: [{ provide: FormFieldControl, useExisting: forwardRef(() => ComDropdown) }], queries: [{ propertyName: "optionTemplate", first: true, predicate: (ComDropdownOptionTpl), descendants: true, isSignal: true }, { propertyName: "selectedTemplate", first: true, predicate: (ComDropdownSelectedTpl), descendants: true, isSignal: true }, { propertyName: "emptyTemplate", first: true, predicate: ComDropdownEmptyTpl, descendants: true, isSignal: true }, { propertyName: "groupTemplate", first: true, predicate: ComDropdownGroupTpl, descendants: true, isSignal: true }, { propertyName: "tagTemplate", first: true, predicate: (ComDropdownTagTpl), descendants: true, isSignal: true }], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerElement"], descendants: true, isSignal: true }, { propertyName: "panelTemplateRef", first: true, predicate: ["panelTemplate"], descendants: true, isSignal: true }], exportAs: ["comDropdown"], ngImport: i0, template: `
2279
2284
  <!-- Trigger button -->
2280
2285
  <button
2281
2286
  #triggerElement
@@ -2681,7 +2686,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
2681
2686
  '[class.com-dropdown-disabled]': 'disabled()',
2682
2687
  '[class.com-dropdown-open]': 'isOpen()',
2683
2688
  }, styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
2684
- }], ctorParameters: () => [], propDecorators: { triggerRef: [{ type: i0.ViewChild, args: ['triggerElement', { isSignal: true }] }], panelTemplateRef: [{ type: i0.ViewChild, args: ['panelTemplate', { isSignal: true }] }], optionTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ComDropdownOptionTpl), { isSignal: true }] }], selectedTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ComDropdownSelectedTpl), { isSignal: true }] }], emptyTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ComDropdownEmptyTpl), { isSignal: true }] }], groupTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ComDropdownGroupTpl), { isSignal: true }] }], tagTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ComDropdownTagTpl), { isSignal: true }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], displayWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayWith", required: false }] }], filterWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterWith", required: false }] }], groupBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupBy", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], panelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelClass", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], panelWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelWidth", required: false }] }], searchDebounceMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchDebounceMs", required: false }] }], virtualScrollThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScrollThreshold", required: false }] }], maxVisibleTags: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxVisibleTags", required: false }] }], errorStateMatcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorStateMatcher", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
2689
+ }], ctorParameters: () => [], propDecorators: { triggerRef: [{ type: i0.ViewChild, args: ['triggerElement', { isSignal: true }] }], panelTemplateRef: [{ type: i0.ViewChild, args: ['panelTemplate', { isSignal: true }] }], optionTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ComDropdownOptionTpl), { isSignal: true }] }], selectedTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ComDropdownSelectedTpl), { isSignal: true }] }], emptyTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ComDropdownEmptyTpl), { isSignal: true }] }], groupTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ComDropdownGroupTpl), { isSignal: true }] }], tagTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ComDropdownTagTpl), { isSignal: true }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], displayWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayWith", required: false }] }], filterWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterWith", required: false }] }], groupBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupBy", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], panelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelClass", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], panelWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelWidth", required: false }] }], searchDebounceMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchDebounceMs", required: false }] }], virtualScrollThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScrollThreshold", required: false }] }], maxVisibleTags: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxVisibleTags", required: false }] }], errorStateMatcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorStateMatcher", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], sfErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
2685
2690
 
2686
2691
  // Public API for the dropdown component
2687
2692
  // Main component