@memberjunction/ng-ui-components 6.2.0-edge.0 → 6.2.0-edge.1

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 (81) hide show
  1. package/README.md +35 -9
  2. package/dist/lib/a11y/named-control.base.d.ts +91 -0
  3. package/dist/lib/a11y/named-control.base.d.ts.map +1 -0
  4. package/dist/lib/a11y/named-control.base.js +121 -0
  5. package/dist/lib/a11y/named-control.base.js.map +1 -0
  6. package/dist/lib/a11y/unnamed-control-guard.d.ts +52 -0
  7. package/dist/lib/a11y/unnamed-control-guard.d.ts.map +1 -0
  8. package/dist/lib/a11y/unnamed-control-guard.js +94 -0
  9. package/dist/lib/a11y/unnamed-control-guard.js.map +1 -0
  10. package/dist/lib/accordion/accordion.component.d.ts +16 -4
  11. package/dist/lib/accordion/accordion.component.d.ts.map +1 -1
  12. package/dist/lib/accordion/accordion.component.js +36 -12
  13. package/dist/lib/accordion/accordion.component.js.map +1 -1
  14. package/dist/lib/applied-filters/applied-filters.component.js.map +1 -1
  15. package/dist/lib/button/button.directive.d.ts +34 -6
  16. package/dist/lib/button/button.directive.d.ts.map +1 -1
  17. package/dist/lib/button/button.directive.js +85 -25
  18. package/dist/lib/button/button.directive.js.map +1 -1
  19. package/dist/lib/card-grid/card-grid.component.d.ts +3 -1
  20. package/dist/lib/card-grid/card-grid.component.d.ts.map +1 -1
  21. package/dist/lib/card-grid/card-grid.component.js +13 -9
  22. package/dist/lib/card-grid/card-grid.component.js.map +1 -1
  23. package/dist/lib/clickable/clickable.directive.d.ts +11 -3
  24. package/dist/lib/clickable/clickable.directive.d.ts.map +1 -1
  25. package/dist/lib/clickable/clickable.directive.js +25 -5
  26. package/dist/lib/clickable/clickable.directive.js.map +1 -1
  27. package/dist/lib/combobox/combobox.component.d.ts +44 -3
  28. package/dist/lib/combobox/combobox.component.d.ts.map +1 -1
  29. package/dist/lib/combobox/combobox.component.js +135 -51
  30. package/dist/lib/combobox/combobox.component.js.map +1 -1
  31. package/dist/lib/confirm-dialog/confirm-dialog.component.d.ts +6 -0
  32. package/dist/lib/confirm-dialog/confirm-dialog.component.d.ts.map +1 -1
  33. package/dist/lib/confirm-dialog/confirm-dialog.component.js +16 -4
  34. package/dist/lib/confirm-dialog/confirm-dialog.component.js.map +1 -1
  35. package/dist/lib/datepicker/datepicker.component.d.ts +25 -2
  36. package/dist/lib/datepicker/datepicker.component.d.ts.map +1 -1
  37. package/dist/lib/datepicker/datepicker.component.js +98 -42
  38. package/dist/lib/datepicker/datepicker.component.js.map +1 -1
  39. package/dist/lib/dialog/dialog.component.d.ts +4 -0
  40. package/dist/lib/dialog/dialog.component.d.ts.map +1 -1
  41. package/dist/lib/dialog/dialog.component.js +12 -4
  42. package/dist/lib/dialog/dialog.component.js.map +1 -1
  43. package/dist/lib/dialog/dialog.service.js.map +1 -1
  44. package/dist/lib/dropdown/dropdown.component.d.ts +19 -44
  45. package/dist/lib/dropdown/dropdown.component.d.ts.map +1 -1
  46. package/dist/lib/dropdown/dropdown.component.js +37 -76
  47. package/dist/lib/dropdown/dropdown.component.js.map +1 -1
  48. package/dist/lib/dropdown/dropdown.scss +0 -16
  49. package/dist/lib/filter-panel/filter-panel.component.d.ts +8 -0
  50. package/dist/lib/filter-panel/filter-panel.component.d.ts.map +1 -1
  51. package/dist/lib/filter-panel/filter-panel.component.js +25 -9
  52. package/dist/lib/filter-panel/filter-panel.component.js.map +1 -1
  53. package/dist/lib/numeric-input/numeric-input.component.d.ts +15 -1
  54. package/dist/lib/numeric-input/numeric-input.component.d.ts.map +1 -1
  55. package/dist/lib/numeric-input/numeric-input.component.js +36 -9
  56. package/dist/lib/numeric-input/numeric-input.component.js.map +1 -1
  57. package/dist/lib/page-search/page-search.component.d.ts +32 -3
  58. package/dist/lib/page-search/page-search.component.d.ts.map +1 -1
  59. package/dist/lib/page-search/page-search.component.js +68 -12
  60. package/dist/lib/page-search/page-search.component.js.map +1 -1
  61. package/dist/lib/switch/switch.component.d.ts +22 -1
  62. package/dist/lib/switch/switch.component.d.ts.map +1 -1
  63. package/dist/lib/switch/switch.component.js +50 -16
  64. package/dist/lib/switch/switch.component.js.map +1 -1
  65. package/dist/lib/tabs/tab-chrome-guard.d.ts +2 -0
  66. package/dist/lib/tabs/tab-chrome-guard.d.ts.map +1 -1
  67. package/dist/lib/tabs/tab-chrome-guard.js +5 -1
  68. package/dist/lib/tabs/tab-chrome-guard.js.map +1 -1
  69. package/dist/lib/window/window.component.d.ts +10 -0
  70. package/dist/lib/window/window.component.d.ts.map +1 -1
  71. package/dist/lib/window/window.component.js +27 -7
  72. package/dist/lib/window/window.component.js.map +1 -1
  73. package/dist/lib/workspace-tabs/workspace-tab-strip.component.d.ts +10 -0
  74. package/dist/lib/workspace-tabs/workspace-tab-strip.component.d.ts.map +1 -1
  75. package/dist/lib/workspace-tabs/workspace-tab-strip.component.js +27 -7
  76. package/dist/lib/workspace-tabs/workspace-tab-strip.component.js.map +1 -1
  77. package/dist/public-api.d.ts +2 -0
  78. package/dist/public-api.d.ts.map +1 -1
  79. package/dist/public-api.js +2 -0
  80. package/dist/public-api.js.map +1 -1
  81. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.service.js","sourceRoot":"","sources":["../../../src/lib/dialog/dialog.service.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Injectable,\n ComponentRef,\n Type,\n ViewContainerRef,\n ApplicationRef,\n Injector,\n createComponent,\n inject\n} from '@angular/core';\nimport { Subject, Observable } from 'rxjs';\n\n/**\n * Result returned when a dialog action button is clicked.\n */\nexport interface MJDialogAction {\n text: string;\n primary?: boolean;\n themeColor?: string;\n}\n\n/**\n * Options for opening a dialog programmatically.\n */\nexport interface MJDialogSettings {\n /** Dialog title */\n title?: string;\n /** Content: either a string message or a Component class */\n content?: string | Type<unknown>;\n /** Action buttons shown in the footer */\n actions?: MJDialogAction[];\n /** Dialog width in pixels */\n width?: number;\n /** Dialog minimum width in pixels */\n minWidth?: number;\n /** Dialog height in pixels */\n height?: number;\n /** ViewContainerRef to attach the dialog to (for proper DI context) */\n appendTo?: ViewContainerRef;\n}\n\n/**\n * Reference to an open dialog. Used to access content instance and subscribe to results.\n */\nexport class MJDialogRef {\n private resultSubject = new Subject<unknown>();\n private containerRef: ComponentRef<MJDialogContainerComponent> | null = null;\n\n /** The content component instance (when content is a Component class) */\n Content: { instance: Record<string, unknown> } | null = null;\n\n /** Observable that emits when the dialog is closed */\n get Result(): Observable<unknown> {\n return this.resultSubject.asObservable();\n }\n\n /** @internal */\n SetContainerRef(ref: ComponentRef<MJDialogContainerComponent>): void {\n this.containerRef = ref;\n }\n\n /** Close the dialog with a result */\n Close(result?: unknown): void {\n this.resultSubject.next(result);\n this.resultSubject.complete();\n this.containerRef?.location.nativeElement.remove();\n this.containerRef?.destroy();\n }\n}\n\n/**\n * Internal container component that wraps dialog content.\n * This is dynamically created by MJDialogService.\n */\nimport { Component, Input, Output, EventEmitter } from '@angular/core';\n\n@Component({\n selector: 'mj-dialog-container-internal',\n standalone: true,\n template: `\n <div class=\"mj-dialog-backdrop\" (click)=\"OnBackdropClick()\">\n <div class=\"mj-dialog-container\"\n [style.width]=\"Width ? Width + 'px' : '450px'\"\n [style.min-width]=\"MinWidth ? MinWidth + 'px' : null\"\n [style.height]=\"Height ? Height + 'px' : null\"\n (click)=\"$event.stopPropagation()\"\n role=\"dialog\"\n aria-modal=\"true\">\n\n @if (Title) {\n <div class=\"mj-dialog-titlebar\">\n <h3 class=\"mj-dialog-title\">{{ Title }}</h3>\n <button class=\"mj-dialog-close\" (click)=\"OnCloseClick()\" aria-label=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n\n <div class=\"mj-dialog-body\">\n @if (StringContent) {\n <p>{{ StringContent }}</p>\n }\n <div #contentHost></div>\n </div>\n\n @if (Actions && Actions.length > 0) {\n <div class=\"mj-dialog-actions\">\n @for (action of Actions; track action.text) {\n <button\n class=\"mj-btn\"\n [class.mj-btn--primary]=\"action.primary\"\n [class.mj-btn--danger]=\"action.themeColor === 'error'\"\n (click)=\"OnActionClick(action)\">\n {{ action.text }}\n </button>\n }\n </div>\n }\n </div>\n </div>\n `,\n styles: [`\n .mj-dialog-backdrop {\n position: fixed;\n top: 0; left: 0; right: 0; bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 10001;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .mj-dialog-container {\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-xl, 0 20px 60px color-mix(in srgb, var(--mj-text-primary) 30%, transparent));\n display: flex;\n flex-direction: column;\n max-height: 90vh;\n max-width: 90vw;\n overflow: hidden;\n }\n\n .mj-dialog-titlebar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n }\n\n .mj-dialog-title {\n margin: 0;\n font-size: 1.1rem;\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n }\n\n .mj-dialog-close {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n background: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n border-radius: var(--mj-radius-sm);\n transition: var(--mj-transition-colors);\n }\n .mj-dialog-close:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n }\n\n .mj-dialog-body {\n flex: 1;\n /* CONTRACT: the body pads only STRING content (the \"> p\" rule below). A COMPONENT body arrives with no\n inset and pads itself — see rating-dialog and input-dialog in ng-conversations, which both apply\n 4px 20px 8px. Padding here would double-pad them and break deliberately full-bleed bodies (About,\n Profile, the action gallery, the sharing centre). If a third component rediscovers this, add a\n padded setting to MJDialogSettings rather than a special case. */\n padding: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n min-height: 0;\n }\n\n .mj-dialog-body > p {\n padding: 20px;\n }\n\n .mj-dialog-body > div {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n min-height: 0;\n }\n\n .mj-dialog-body p {\n margin: 0;\n color: var(--mj-text-primary);\n line-height: 1.5;\n }\n\n .mj-dialog-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 20px;\n border-top: 1px solid var(--mj-border-default);\n }\n\n .mj-btn {\n padding: 8px 16px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n cursor: pointer;\n font-size: 0.875rem;\n transition: var(--mj-transition-colors);\n }\n .mj-btn:hover { background: var(--mj-bg-surface-hover); }\n .mj-btn--primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n }\n .mj-btn--primary:hover { background: var(--mj-brand-primary-hover); }\n .mj-btn--danger {\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n border-color: var(--mj-status-error);\n }\n\n @media (max-width: 767px) {\n .mj-dialog-container {\n width: 100vw !important;\n height: 100vh !important;\n max-width: 100vw;\n max-height: 100vh;\n border-radius: 0;\n }\n }\n `]\n})\nexport class MJDialogContainerComponent {\n @Input() Title = '';\n @Input() StringContent = '';\n @Input() Width: number | null = null;\n @Input() MinWidth: number | null = null;\n @Input() Height: number | null = null;\n @Input() Actions: MJDialogAction[] = [];\n @Output() ActionClicked = new EventEmitter<MJDialogAction>();\n @Output() CloseClicked = new EventEmitter<void>();\n\n OnBackdropClick(): void {\n this.CloseClicked.emit();\n }\n\n OnCloseClick(): void {\n this.CloseClicked.emit();\n }\n\n OnActionClick(action: MJDialogAction): void {\n this.ActionClicked.emit(action);\n }\n}\n\n/**\n * MJDialogService — Programmatic dialog opening. Replaces Kendo `DialogService`.\n *\n * @example\n * ```typescript\n * // Simple confirm\n * const dialogRef = this.dialogService.Open({\n * title: 'Confirm',\n * content: 'Are you sure?',\n * actions: [\n * { text: 'OK', primary: true },\n * { text: 'Cancel' }\n * ]\n * });\n * dialogRef.Result.subscribe(result => { ... });\n *\n * // Component content\n * const dialogRef = this.dialogService.Open({\n * content: MyDialogComponent,\n * width: 500\n * });\n * dialogRef.Content.instance.someInput = 'value';\n * dialogRef.Result.subscribe(result => { ... });\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class MJDialogService {\n private appRef = inject(ApplicationRef);\n private injector = inject(Injector);\n\n /**\n * Open a dialog programmatically.\n *\n * Kendo-compatible API: accepts `content` as string or Component class,\n * returns a ref with `.Content.instance` and `.Result` observable.\n */\n Open(settings: MJDialogSettings): MJDialogRef {\n const dialogRef = new MJDialogRef();\n const injector = settings.appendTo?.injector ?? this.injector;\n\n const containerRef = this.createContainer(injector);\n this.configureContainer(containerRef, settings, dialogRef);\n this.attachToDOM(containerRef, settings);\n this.attachContentComponent(containerRef, settings, dialogRef, injector);\n\n containerRef.changeDetectorRef.detectChanges();\n return dialogRef;\n }\n\n private createContainer(injector: Injector): ComponentRef<MJDialogContainerComponent> {\n return createComponent(MJDialogContainerComponent, {\n environmentInjector: this.appRef.injector,\n elementInjector: injector\n });\n }\n\n private configureContainer(\n containerRef: ComponentRef<MJDialogContainerComponent>,\n settings: MJDialogSettings,\n dialogRef: MJDialogRef\n ): void {\n containerRef.instance.Title = settings.title ?? '';\n containerRef.instance.Width = settings.width ?? null;\n containerRef.instance.MinWidth = settings.minWidth ?? null;\n containerRef.instance.Height = settings.height ?? null;\n containerRef.instance.Actions = settings.actions ?? [];\n\n if (typeof settings.content === 'string') {\n containerRef.instance.StringContent = settings.content;\n }\n\n containerRef.instance.CloseClicked.subscribe(() => dialogRef.Close(undefined));\n containerRef.instance.ActionClicked.subscribe((action: MJDialogAction) => dialogRef.Close(action));\n dialogRef.SetContainerRef(containerRef);\n }\n\n private attachToDOM(containerRef: ComponentRef<MJDialogContainerComponent>, settings: MJDialogSettings): void {\n if (settings.appendTo) {\n settings.appendTo.insert(containerRef.hostView);\n } else {\n document.body.appendChild(containerRef.location.nativeElement);\n this.appRef.attachView(containerRef.hostView);\n }\n }\n\n private attachContentComponent(\n containerRef: ComponentRef<MJDialogContainerComponent>,\n settings: MJDialogSettings,\n dialogRef: MJDialogRef,\n injector: Injector\n ): void {\n if (!settings.content || typeof settings.content === 'string') return;\n\n const contentHost = containerRef.location.nativeElement.querySelector('.mj-dialog-body div');\n if (!contentHost) return;\n\n const contentRef = createComponent(settings.content as Type<unknown>, {\n environmentInjector: this.appRef.injector,\n elementInjector: injector,\n hostElement: contentHost\n });\n this.appRef.attachView(contentRef.hostView);\n dialogRef.Content = { instance: contentRef.instance as Record<string, unknown> };\n }\n\n /**\n * Kendo-compatible alias — lowercase `open` for easier migration.\n */\n open(settings: MJDialogSettings): MJDialogRef {\n return this.Open(settings);\n }\n}\n"]}
1
+ {"version":3,"file":"dialog.service.js","sourceRoot":"","sources":["../../../src/lib/dialog/dialog.service.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Injectable,\n ComponentRef,\n Type,\n ViewContainerRef,\n ApplicationRef,\n Injector,\n createComponent,\n inject\n} from '@angular/core';\nimport { Subject, Observable } from 'rxjs';\n\n/**\n * Result returned when a dialog action button is clicked.\n */\nexport interface MJDialogAction {\n text: string;\n primary?: boolean;\n themeColor?: string;\n}\n\n/**\n * Options for opening a dialog programmatically.\n */\nexport interface MJDialogSettings {\n /** Dialog title */\n title?: string;\n /** Content: either a string message or a Component class */\n content?: string | Type<unknown>;\n /** Action buttons shown in the footer */\n actions?: MJDialogAction[];\n /** Dialog width in pixels */\n width?: number;\n /** Dialog minimum width in pixels */\n minWidth?: number;\n /** Dialog height in pixels */\n height?: number;\n /** ViewContainerRef to attach the dialog to (for proper DI context) */\n appendTo?: ViewContainerRef;\n}\n\n/**\n * Reference to an open dialog. Used to access content instance and subscribe to results.\n */\nexport class MJDialogRef {\n private resultSubject = new Subject<unknown>();\n private containerRef: ComponentRef<MJDialogContainerComponent> | null = null;\n\n /** The content component instance (when content is a Component class) */\n Content: { instance: Record<string, unknown> } | null = null;\n\n /** Observable that emits when the dialog is closed */\n get Result(): Observable<unknown> {\n return this.resultSubject.asObservable();\n }\n\n /** @internal */\n SetContainerRef(ref: ComponentRef<MJDialogContainerComponent>): void {\n this.containerRef = ref;\n }\n\n /** Close the dialog with a result */\n Close(result?: unknown): void {\n this.resultSubject.next(result);\n this.resultSubject.complete();\n this.containerRef?.location.nativeElement.remove();\n this.containerRef?.destroy();\n }\n}\n\n/**\n * Internal container component that wraps dialog content.\n * This is dynamically created by MJDialogService.\n */\nimport { Component, Input, Output, EventEmitter } from '@angular/core';\n\n@Component({\n selector: 'mj-dialog-container-internal',\n standalone: true,\n template: `\n <div class=\"mj-dialog-backdrop\" (click)=\"OnBackdropClick()\">\n <div class=\"mj-dialog-container\"\n [style.width]=\"Width ? Width + 'px' : '450px'\"\n [style.min-width]=\"MinWidth ? MinWidth + 'px' : null\"\n [style.height]=\"Height ? Height + 'px' : null\"\n (click)=\"$event.stopPropagation()\"\n role=\"dialog\"\n aria-modal=\"true\">\n\n @if (Title) {\n <div class=\"mj-dialog-titlebar\">\n <h3 class=\"mj-dialog-title\">{{ Title }}</h3>\n <button class=\"mj-dialog-close\" (click)=\"OnCloseClick()\" aria-label=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n }\n\n <div class=\"mj-dialog-body\">\n @if (StringContent) {\n <p>{{ StringContent }}</p>\n }\n <div #contentHost></div>\n </div>\n\n @if (Actions && Actions.length > 0) {\n <div class=\"mj-dialog-actions\">\n @for (action of Actions; track action.text) {\n <button\n class=\"mj-btn\"\n [class.mj-btn--primary]=\"action.primary\"\n [class.mj-btn--danger]=\"action.themeColor === 'error'\"\n (click)=\"OnActionClick(action)\">\n {{ action.text }}\n </button>\n }\n </div>\n }\n </div>\n </div>\n `,\n styles: [`\n .mj-dialog-backdrop {\n position: fixed;\n top: 0; left: 0; right: 0; bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 10001;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .mj-dialog-container {\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-xl, 0 20px 60px color-mix(in srgb, var(--mj-text-primary) 30%, transparent));\n display: flex;\n flex-direction: column;\n max-height: 90vh;\n max-width: 90vw;\n overflow: hidden;\n }\n\n .mj-dialog-titlebar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n }\n\n .mj-dialog-title {\n margin: 0;\n font-size: 1.1rem;\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n }\n\n .mj-dialog-close {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n background: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n border-radius: var(--mj-radius-sm);\n transition: var(--mj-transition-colors);\n }\n .mj-dialog-close:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n }\n\n .mj-dialog-body {\n flex: 1;\n /* CONTRACT: the body pads only STRING content (the \"> p\" rule below). A COMPONENT body arrives with no\n inset and pads itself — see rating-dialog and input-dialog in ng-conversations, which both apply\n 4px 20px 8px. Padding here would double-pad them and break deliberately full-bleed bodies (About,\n Profile, the action gallery, the sharing centre). If a third component rediscovers this, add a\n padded setting to MJDialogSettings rather than a special case. */\n padding: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n min-height: 0;\n }\n\n .mj-dialog-body > p {\n padding: 20px;\n }\n\n .mj-dialog-body > div {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n min-height: 0;\n }\n\n .mj-dialog-body p {\n margin: 0;\n color: var(--mj-text-primary);\n line-height: 1.5;\n }\n\n .mj-dialog-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 20px;\n border-top: 1px solid var(--mj-border-default);\n }\n\n .mj-btn {\n padding: 8px 16px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n cursor: pointer;\n font-size: 0.875rem;\n transition: var(--mj-transition-colors);\n }\n .mj-btn:hover { background: var(--mj-bg-surface-hover); }\n .mj-btn--primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n }\n .mj-btn--primary:hover { background: var(--mj-brand-primary-hover); }\n .mj-btn--danger {\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n border-color: var(--mj-status-error);\n }\n\n @media (max-width: 767px) {\n .mj-dialog-container {\n width: 100vw !important;\n height: 100vh !important;\n max-width: 100vw;\n max-height: 100vh;\n border-radius: 0;\n }\n }\n `]\n})\nexport class MJDialogContainerComponent {\n @Input() Title = '';\n @Input() StringContent = '';\n @Input() Width: number | null = null;\n @Input() MinWidth: number | null = null;\n @Input() Height: number | null = null;\n @Input() Actions: MJDialogAction[] = [];\n @Output() ActionClicked = new EventEmitter<MJDialogAction>();\n @Output() CloseClicked = new EventEmitter<void>();\n\n OnBackdropClick(): void {\n this.CloseClicked.emit();\n }\n\n OnCloseClick(): void {\n this.CloseClicked.emit();\n }\n\n OnActionClick(action: MJDialogAction): void {\n this.ActionClicked.emit(action);\n }\n}\n\n/**\n * MJDialogService — Programmatic dialog opening. Replaces Kendo `DialogService`.\n *\n * @example\n * ```typescript\n * // Simple confirm\n * const dialogRef = this.dialogService.Open({\n * title: 'Confirm',\n * content: 'Are you sure?',\n * actions: [\n * { text: 'OK', primary: true },\n * { text: 'Cancel' }\n * ]\n * });\n * dialogRef.Result.subscribe(result => { ... });\n *\n * // Component content\n * const dialogRef = this.dialogService.Open({\n * content: MyDialogComponent,\n * width: 500\n * });\n * dialogRef.Content.instance.someInput = 'value';\n * dialogRef.Result.subscribe(result => { ... });\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class MJDialogService {\n private appRef = inject(ApplicationRef);\n private injector = inject(Injector);\n\n /**\n * Open a dialog programmatically.\n *\n * Kendo-compatible API: accepts `content` as string or Component class,\n * returns a ref with `.Content.instance` and `.Result` observable.\n */\n Open(settings: MJDialogSettings): MJDialogRef {\n const dialogRef = new MJDialogRef();\n const injector = settings.appendTo?.injector ?? this.injector;\n\n const containerRef = this.createContainer(injector);\n this.configureContainer(containerRef, settings, dialogRef);\n this.attachToDOM(containerRef, settings);\n this.attachContentComponent(containerRef, settings, dialogRef, injector);\n\n containerRef.changeDetectorRef.detectChanges();\n return dialogRef;\n }\n\n private createContainer(injector: Injector): ComponentRef<MJDialogContainerComponent> {\n return createComponent(MJDialogContainerComponent, {\n environmentInjector: this.appRef.injector,\n elementInjector: injector\n });\n }\n\n private configureContainer(\n containerRef: ComponentRef<MJDialogContainerComponent>,\n settings: MJDialogSettings,\n dialogRef: MJDialogRef\n ): void {\n containerRef.instance.Title = settings.title ?? '';\n containerRef.instance.Width = settings.width ?? null;\n containerRef.instance.MinWidth = settings.minWidth ?? null;\n containerRef.instance.Height = settings.height ?? null;\n containerRef.instance.Actions = settings.actions ?? [];\n\n if (typeof settings.content === 'string') {\n containerRef.instance.StringContent = settings.content;\n }\n\n containerRef.instance.CloseClicked.subscribe(() => dialogRef.Close(undefined));\n containerRef.instance.ActionClicked.subscribe((action: MJDialogAction) => dialogRef.Close(action));\n dialogRef.SetContainerRef(containerRef);\n }\n\n private attachToDOM(containerRef: ComponentRef<MJDialogContainerComponent>, settings: MJDialogSettings): void {\n if (settings.appendTo) {\n settings.appendTo.insert(containerRef.hostView);\n } else {\n document.body.appendChild(containerRef.location.nativeElement);\n this.appRef.attachView(containerRef.hostView);\n }\n }\n\n private attachContentComponent(\n containerRef: ComponentRef<MJDialogContainerComponent>,\n settings: MJDialogSettings,\n dialogRef: MJDialogRef,\n injector: Injector\n ): void {\n if (!settings.content || typeof settings.content === 'string') return;\n\n const contentHost = containerRef.location.nativeElement.querySelector('.mj-dialog-body div');\n if (!contentHost) return;\n\n const contentRef = createComponent(settings.content as Type<unknown>, {\n environmentInjector: this.appRef.injector,\n elementInjector: injector,\n hostElement: contentHost\n });\n this.appRef.attachView(contentRef.hostView);\n dialogRef.Content = { instance: contentRef.instance as Record<string, unknown> };\n }\n\n /**\n * Kendo-compatible alias — lowercase `open` for easier migration.\n */\n open(settings: MJDialogSettings): MJDialogRef { // case-violation-ok-legacy-back-compat: the PascalCase name is already taken in this scope\n return this.Open(settings);\n }\n}\n"]}
@@ -1,6 +1,7 @@
1
- import { EventEmitter, TemplateRef, OnDestroy } from '@angular/core';
1
+ import { AfterViewInit, EventEmitter, TemplateRef, OnDestroy } from '@angular/core';
2
2
  import { ControlValueAccessor } from '@angular/forms';
3
3
  import { ConnectedPosition } from '@angular/cdk/overlay';
4
+ import { MJNamedControlBase } from '../a11y/named-control.base';
4
5
  import * as i0 from "@angular/core";
5
6
  /**
6
7
  * mj-dropdown — Dropdown select component using CDK Overlay.
@@ -38,31 +39,7 @@ import * as i0 from "@angular/core";
38
39
  * </mj-dropdown>
39
40
  * ```
40
41
  */
41
- export declare class MJDropdownComponent implements ControlValueAccessor, OnDestroy {
42
- /**
43
- * Accessible name for the combobox (#3860). Without one — and with no visible label wired via
44
- * {@link AriaLabelledBy} — the control announces as an UNNAMED combobox, which fails WCAG 2.1
45
- * 4.1.2 (Name, Role, Value): "combobox, collapsed" with no hint of what it selects. Applied as
46
- * `aria-label` on the trigger AND on the popup listbox, so both halves announce the same name.
47
- */
48
- AriaLabel: string;
49
- /**
50
- * The id of a VISIBLE label element that names this control — the preferred wiring when a label
51
- * already exists on screen (an `aria-label` would duplicate its text and drift on rename). This,
52
- * not `<label for>`, is the visible-label path: the trigger is a `div[role=combobox]`, and the
53
- * label-for association only names labelable form elements. `aria-labelledby` beats `AriaLabel`
54
- * in the accessible-name computation where both are present. Applied to trigger AND listbox.
55
- */
56
- AriaLabelledBy: string;
57
- /**
58
- * `id` for the combobox trigger, so other markup can REFERENCE it — `aria-controls`, hint text,
59
- * test hooks. It is deliberately not documented as a `<label for>` target: the trigger is a div,
60
- * which `label[for]` neither names nor focuses. To name the control from a visible label, put an
61
- * id on the LABEL and pass it as {@link AriaLabelledBy}.
62
- */
63
- InputId: string;
64
- /** `aria-describedby` passthrough for hint/error text — same shape of gap as the name. */
65
- AriaDescribedBy: string;
42
+ export declare class MJDropdownComponent extends MJNamedControlBase implements ControlValueAccessor, AfterViewInit, OnDestroy {
66
43
  Data: Record<string, unknown>[] | string[] | readonly unknown[] | null;
67
44
  TextField: string;
68
45
  ValueField: string;
@@ -80,37 +57,34 @@ export declare class MJDropdownComponent implements ControlValueAccessor, OnDest
80
57
  DefaultItem: Record<string, unknown> | string | null;
81
58
  FilterChange: EventEmitter<string>;
82
59
  ValueChange: EventEmitter<unknown>;
83
- itemTemplate: TemplateRef<{
60
+ ItemTemplate: TemplateRef<{
61
+ $implicit: unknown;
62
+ }> | null;
63
+ /** @deprecated Use {@link ItemTemplate}. */
64
+ get itemTemplate(): TemplateRef<{
84
65
  $implicit: unknown;
85
66
  }> | null;
67
+ /** @deprecated Use {@link ItemTemplate}. */
68
+ set itemTemplate(value: TemplateRef<{
69
+ $implicit: unknown;
70
+ }> | null);
86
71
  private triggerEl;
87
72
  private filterInputEl;
88
73
  readonly hostClass = true;
89
74
  private cdr;
90
- private static nextId;
91
- DropdownId: number;
75
+ /** This dropdown's id suffix — the shared named-control counter, kept under its own name. */
76
+ readonly DropdownId: number;
92
77
  /**
93
78
  * Id of the popup listbox, so the trigger can point `aria-controls` at it while open — the half of
94
79
  * the combobox pattern that makes "collapsed/expanded" refer to something a screen reader can
95
- * find. Generated per instance from the same `static nextId` counter `dialog`, `window` and
96
- * `accordion` use in this package.
80
+ * find. Generated per instance from the shared named-control counter.
97
81
  */
98
82
  get ListboxId(): string;
99
83
  /** Id of the hidden "Filter" word, composed into the filter box's name via an id list. */
100
84
  get FilterWordId(): string;
101
- /**
102
- * `aria-labelledby` for the filter box when the dropdown is named by a VISIBLE label: "Filter"
103
- * plus that label's own text, composed by the accessibility tree. Empty when there is no such
104
- * label, in which case {@link FilterLabel} supplies a string instead.
105
- */
85
+ /** `aria-labelledby` for the filter box when a VISIBLE label names the dropdown. */
106
86
  get FilterLabelledBy(): string;
107
- /**
108
- * `aria-label` for the filter box in the no-visible-label case.
109
- *
110
- * The "filter" guard is not cosmetic: this repo's house habit is `AriaLabel="Filter roles"`, and
111
- * an unconditional prefix announces that box as "Filter Filter roles". A name that already begins
112
- * with the word is used as-is.
113
- */
87
+ /** `aria-label` for the filter box in the no-visible-label case. */
114
88
  get FilterLabel(): string;
115
89
  IsOpen: boolean;
116
90
  /**
@@ -160,6 +134,7 @@ export declare class MJDropdownComponent implements ControlValueAccessor, OnDest
160
134
  OnFilterInput(event: Event): void;
161
135
  OnKeyDown(event: KeyboardEvent): void;
162
136
  OnBlur(): void;
137
+ ngAfterViewInit(): void;
163
138
  GetItemText(item: unknown): string;
164
139
  GetItemValue(item: unknown): unknown;
165
140
  TrackByIndex(index: number): number;
@@ -170,6 +145,6 @@ export declare class MJDropdownComponent implements ControlValueAccessor, OnDest
170
145
  ngOnDestroy(): void;
171
146
  private getSelectedIndex;
172
147
  static ɵfac: i0.ɵɵFactoryDeclaration<MJDropdownComponent, never>;
173
- static ɵcmp: i0.ɵɵComponentDeclaration<MJDropdownComponent, "mj-dropdown", never, { "AriaLabel": { "alias": "AriaLabel"; "required": false; }; "AriaLabelledBy": { "alias": "AriaLabelledBy"; "required": false; }; "InputId": { "alias": "InputId"; "required": false; }; "AriaDescribedBy": { "alias": "AriaDescribedBy"; "required": false; }; "Data": { "alias": "Data"; "required": false; }; "TextField": { "alias": "TextField"; "required": false; }; "ValueField": { "alias": "ValueField"; "required": false; }; "Filterable": { "alias": "Filterable"; "required": false; }; "ValuePrimitive": { "alias": "ValuePrimitive"; "required": false; }; "Disabled": { "alias": "Disabled"; "required": false; }; "Placeholder": { "alias": "Placeholder"; "required": false; }; "DefaultItem": { "alias": "DefaultItem"; "required": false; }; }, { "FilterChange": "FilterChange"; "ValueChange": "ValueChange"; }, ["itemTemplate"], never, true, never>;
148
+ static ɵcmp: i0.ɵɵComponentDeclaration<MJDropdownComponent, "mj-dropdown", never, { "Data": { "alias": "Data"; "required": false; }; "TextField": { "alias": "TextField"; "required": false; }; "ValueField": { "alias": "ValueField"; "required": false; }; "Filterable": { "alias": "Filterable"; "required": false; }; "ValuePrimitive": { "alias": "ValuePrimitive"; "required": false; }; "Disabled": { "alias": "Disabled"; "required": false; }; "Placeholder": { "alias": "Placeholder"; "required": false; }; "DefaultItem": { "alias": "DefaultItem"; "required": false; }; }, { "FilterChange": "FilterChange"; "ValueChange": "ValueChange"; }, ["ItemTemplate"], never, true, never>;
174
149
  }
175
150
  //# sourceMappingURL=dropdown.component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown.component.d.ts","sourceRoot":"","sources":["../../../src/lib/dropdown/dropdown.component.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dropdown.component.d.ts","sourceRoot":"","sources":["../../../src/lib/dropdown/dropdown.component.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,8 @@ import { Component, Input, Output, EventEmitter, forwardRef, HostBinding, ViewCh
2
2
  import { NgTemplateOutlet } from '@angular/common';
3
3
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
4
4
  import { OverlayModule } from '@angular/cdk/overlay';
5
+ import { MJNamedControlBase } from '../a11y/named-control.base';
6
+ import { WarnIfUnnamed } from '../a11y/unnamed-control-guard';
5
7
  import * as i0 from "@angular/core";
6
8
  import * as i1 from "@angular/cdk/overlay";
7
9
  const _c0 = ["mjDropdownItem"];
@@ -129,31 +131,7 @@ function MJDropdownComponent_ng_template_6_Template(rf, ctx) { if (rf & 1) {
129
131
  * </mj-dropdown>
130
132
  * ```
131
133
  */
132
- export class MJDropdownComponent {
133
- /**
134
- * Accessible name for the combobox (#3860). Without one — and with no visible label wired via
135
- * {@link AriaLabelledBy} — the control announces as an UNNAMED combobox, which fails WCAG 2.1
136
- * 4.1.2 (Name, Role, Value): "combobox, collapsed" with no hint of what it selects. Applied as
137
- * `aria-label` on the trigger AND on the popup listbox, so both halves announce the same name.
138
- */
139
- AriaLabel = '';
140
- /**
141
- * The id of a VISIBLE label element that names this control — the preferred wiring when a label
142
- * already exists on screen (an `aria-label` would duplicate its text and drift on rename). This,
143
- * not `<label for>`, is the visible-label path: the trigger is a `div[role=combobox]`, and the
144
- * label-for association only names labelable form elements. `aria-labelledby` beats `AriaLabel`
145
- * in the accessible-name computation where both are present. Applied to trigger AND listbox.
146
- */
147
- AriaLabelledBy = '';
148
- /**
149
- * `id` for the combobox trigger, so other markup can REFERENCE it — `aria-controls`, hint text,
150
- * test hooks. It is deliberately not documented as a `<label for>` target: the trigger is a div,
151
- * which `label[for]` neither names nor focuses. To name the control from a visible label, put an
152
- * id on the LABEL and pass it as {@link AriaLabelledBy}.
153
- */
154
- InputId = '';
155
- /** `aria-describedby` passthrough for hint/error text — same shape of gap as the name. */
156
- AriaDescribedBy = '';
134
+ export class MJDropdownComponent extends MJNamedControlBase {
157
135
  Data = [];
158
136
  TextField = '';
159
137
  ValueField = '';
@@ -176,41 +154,33 @@ export class MJDropdownComponent {
176
154
  DefaultItem = null;
177
155
  FilterChange = new EventEmitter();
178
156
  ValueChange = new EventEmitter();
179
- itemTemplate = null;
157
+ ItemTemplate = null;
158
+ /** @deprecated Use {@link ItemTemplate}. */
159
+ get itemTemplate() {
160
+ return this.ItemTemplate;
161
+ }
162
+ /** @deprecated Use {@link ItemTemplate}. */
163
+ set itemTemplate(value) {
164
+ this.ItemTemplate = value;
165
+ }
180
166
  triggerEl;
181
167
  filterInputEl;
182
168
  hostClass = true;
183
169
  cdr = inject(ChangeDetectorRef);
184
- static nextId = 0;
185
- DropdownId = MJDropdownComponent.nextId++;
170
+ /** This dropdown's id suffix — the shared named-control counter, kept under its own name. */
171
+ DropdownId = this.NamedControlId;
186
172
  /**
187
173
  * Id of the popup listbox, so the trigger can point `aria-controls` at it while open — the half of
188
174
  * the combobox pattern that makes "collapsed/expanded" refer to something a screen reader can
189
- * find. Generated per instance from the same `static nextId` counter `dialog`, `window` and
190
- * `accordion` use in this package.
175
+ * find. Generated per instance from the shared named-control counter.
191
176
  */
192
177
  get ListboxId() { return `mj-dropdown-listbox-${this.DropdownId}`; }
193
178
  /** Id of the hidden "Filter" word, composed into the filter box's name via an id list. */
194
- get FilterWordId() { return `mj-dropdown-filter-word-${this.DropdownId}`; }
195
- /**
196
- * `aria-labelledby` for the filter box when the dropdown is named by a VISIBLE label: "Filter"
197
- * plus that label's own text, composed by the accessibility tree. Empty when there is no such
198
- * label, in which case {@link FilterLabel} supplies a string instead.
199
- */
200
- get FilterLabelledBy() { return this.AriaLabelledBy ? `${this.FilterWordId} ${this.AriaLabelledBy}` : ''; }
201
- /**
202
- * `aria-label` for the filter box in the no-visible-label case.
203
- *
204
- * The "filter" guard is not cosmetic: this repo's house habit is `AriaLabel="Filter roles"`, and
205
- * an unconditional prefix announces that box as "Filter Filter roles". A name that already begins
206
- * with the word is used as-is.
207
- */
208
- get FilterLabel() {
209
- const name = this.AriaLabel.trim();
210
- if (!name)
211
- return 'Filter options';
212
- return /^filter\b/i.test(name) ? name : `Filter ${name}`;
213
- }
179
+ get FilterWordId() { return this.SecondaryWordId('filter-word'); }
180
+ /** `aria-labelledby` for the filter box when a VISIBLE label names the dropdown. */
181
+ get FilterLabelledBy() { return this.SecondaryLabelledBy('filter-word'); }
182
+ /** `aria-label` for the filter box in the no-visible-label case. */
183
+ get FilterLabel() { return this.SecondaryLabel('Filter', 'Filter options'); }
214
184
  IsOpen = false;
215
185
  /**
216
186
  * The single gate on `Toggle()` / `Open()` — true when EITHER the `Disabled` input or Angular
@@ -381,6 +351,7 @@ export class MJDropdownComponent {
381
351
  }
382
352
  }
383
353
  OnBlur() { this.onTouched(); }
354
+ ngAfterViewInit() { WarnIfUnnamed(this.triggerEl?.nativeElement, 'mj-dropdown'); }
384
355
  GetItemText(item) {
385
356
  if (item == null)
386
357
  return '';
@@ -408,12 +379,12 @@ export class MJDropdownComponent {
408
379
  return -1;
409
380
  return this.FilteredItems.findIndex(item => this.IsItemSelected(item));
410
381
  }
411
- static ɵfac = function MJDropdownComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MJDropdownComponent)(); };
382
+ static ɵfac = /*@__PURE__*/ (() => { let ɵMJDropdownComponent_BaseFactory; return function MJDropdownComponent_Factory(__ngFactoryType__) { return (ɵMJDropdownComponent_BaseFactory || (ɵMJDropdownComponent_BaseFactory = i0.ɵɵgetInheritedFactory(MJDropdownComponent)))(__ngFactoryType__ || MJDropdownComponent); }; })();
412
383
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJDropdownComponent, selectors: [["mj-dropdown"]], contentQueries: function MJDropdownComponent_ContentQueries(rf, ctx, dirIndex) { if (rf & 1) {
413
384
  i0.ɵɵcontentQuery(dirIndex, _c0, 5);
414
385
  } if (rf & 2) {
415
386
  let _t;
416
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.itemTemplate = _t.first);
387
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.ItemTemplate = _t.first);
417
388
  } }, viewQuery: function MJDropdownComponent_Query(rf, ctx) { if (rf & 1) {
418
389
  i0.ɵɵviewQuery(_c1, 5)(_c2, 5);
419
390
  } if (rf & 2) {
@@ -422,11 +393,11 @@ export class MJDropdownComponent {
422
393
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.filterInputEl = _t.first);
423
394
  } }, hostVars: 2, hostBindings: function MJDropdownComponent_HostBindings(rf, ctx) { if (rf & 2) {
424
395
  i0.ɵɵclassProp("mj-dropdown-host", ctx.hostClass);
425
- } }, inputs: { AriaLabel: "AriaLabel", AriaLabelledBy: "AriaLabelledBy", InputId: "InputId", AriaDescribedBy: "AriaDescribedBy", Data: "Data", TextField: "TextField", ValueField: "ValueField", Filterable: "Filterable", ValuePrimitive: "ValuePrimitive", Disabled: "Disabled", Placeholder: "Placeholder", DefaultItem: "DefaultItem" }, outputs: { FilterChange: "FilterChange", ValueChange: "ValueChange" }, features: [i0.ɵɵProvidersFeature([{
396
+ } }, inputs: { Data: "Data", TextField: "TextField", ValueField: "ValueField", Filterable: "Filterable", ValuePrimitive: "ValuePrimitive", Disabled: "Disabled", Placeholder: "Placeholder", DefaultItem: "DefaultItem" }, outputs: { FilterChange: "FilterChange", ValueChange: "ValueChange" }, features: [i0.ɵɵProvidersFeature([{
426
397
  provide: NG_VALUE_ACCESSOR,
427
398
  useExisting: forwardRef(() => MJDropdownComponent),
428
399
  multi: true
429
- }])], decls: 7, vars: 20, consts: [["trigger", "", "overlayOrigin", "cdkOverlayOrigin"], ["filterInput", ""], ["cdkOverlayOrigin", "", "role", "combobox", "aria-haspopup", "listbox", 1, "mj-dropdown", 3, "click", "keydown", "blur"], [1, "mj-dropdown-value"], [1, "fa-solid", "fa-chevron-down", "mj-dropdown-arrow"], ["cdkConnectedOverlay", "", "cdkConnectedOverlayBackdropClass", "mj-dropdown-backdrop", 3, "backdropClick", "detach", "cdkConnectedOverlayOrigin", "cdkConnectedOverlayOpen", "cdkConnectedOverlayPositions", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHasBackdrop"], ["role", "listbox", 1, "mj-dropdown-panel"], [1, "mj-dropdown-filter-wrap"], ["role", "option", 1, "mj-dropdown-option", "mj-dropdown-option--default", 3, "mj-dropdown-option--selected", "mj-dropdown-option--highlighted"], ["role", "option", 1, "mj-dropdown-option", 3, "mj-dropdown-option--selected", "mj-dropdown-option--highlighted"], [1, "mj-dropdown-no-data"], [1, "mj-dropdown-sr-only"], ["type", "text", "placeholder", "Filter...", 1, "mj-input", "mj-dropdown-filter", 3, "input", "keydown", "value"], ["role", "option", 1, "mj-dropdown-option", "mj-dropdown-option--default", 3, "click"], ["role", "option", 1, "mj-dropdown-option", 3, "click"], [4, "ngTemplateOutlet", "ngTemplateOutletContext"]], template: function MJDropdownComponent_Template(rf, ctx) { if (rf & 1) {
400
+ }]), i0.ɵɵInheritDefinitionFeature], decls: 7, vars: 20, consts: [["trigger", "", "overlayOrigin", "cdkOverlayOrigin"], ["filterInput", ""], ["cdkOverlayOrigin", "", "role", "combobox", "aria-haspopup", "listbox", 1, "mj-dropdown", 3, "click", "keydown", "blur"], [1, "mj-dropdown-value"], [1, "fa-solid", "fa-chevron-down", "mj-dropdown-arrow"], ["cdkConnectedOverlay", "", "cdkConnectedOverlayBackdropClass", "mj-dropdown-backdrop", 3, "backdropClick", "detach", "cdkConnectedOverlayOrigin", "cdkConnectedOverlayOpen", "cdkConnectedOverlayPositions", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHasBackdrop"], ["role", "listbox", 1, "mj-dropdown-panel"], [1, "mj-dropdown-filter-wrap"], ["role", "option", 1, "mj-dropdown-option", "mj-dropdown-option--default", 3, "mj-dropdown-option--selected", "mj-dropdown-option--highlighted"], ["role", "option", 1, "mj-dropdown-option", 3, "mj-dropdown-option--selected", "mj-dropdown-option--highlighted"], [1, "mj-dropdown-no-data"], ["aria-hidden", "true", 1, "mj-dropdown-sr-only"], ["type", "text", "placeholder", "Filter...", 1, "mj-input", "mj-dropdown-filter", 3, "input", "keydown", "value"], ["role", "option", 1, "mj-dropdown-option", "mj-dropdown-option--default", 3, "click"], ["role", "option", 1, "mj-dropdown-option", 3, "click"], [4, "ngTemplateOutlet", "ngTemplateOutletContext"]], template: function MJDropdownComponent_Template(rf, ctx) { if (rf & 1) {
430
401
  i0.ɵɵelementStart(0, "div", 2, 0);
431
402
  i0.ɵɵlistener("click", function MJDropdownComponent_Template_div_click_0_listener() { return ctx.Toggle(); })("keydown", function MJDropdownComponent_Template_div_keydown_0_listener($event) { return ctx.OnKeyDown($event); })("blur", function MJDropdownComponent_Template_div_blur_0_listener() { return ctx.OnBlur(); });
432
403
  i0.ɵɵelementStart(3, "span", 3);
@@ -446,15 +417,11 @@ export class MJDropdownComponent {
446
417
  i0.ɵɵtextInterpolate1(" ", ctx.DisplayText, " ");
447
418
  i0.ɵɵadvance(2);
448
419
  i0.ɵɵproperty("cdkConnectedOverlayOrigin", overlayOrigin_r7)("cdkConnectedOverlayOpen", ctx.IsOpen)("cdkConnectedOverlayPositions", ctx.Positions)("cdkConnectedOverlayWidth", ctx.TriggerWidth)("cdkConnectedOverlayHasBackdrop", true);
449
- } }, dependencies: [NgTemplateOutlet, OverlayModule, i1.CdkConnectedOverlay, i1.CdkOverlayOrigin], encapsulation: 2 });
420
+ } }, dependencies: [NgTemplateOutlet, OverlayModule, i1.CdkConnectedOverlay, i1.CdkOverlayOrigin], styles: ["\n\n\n\n\n\n\n\n\n .mj-dropdown-sr-only[_ngcontent-%COMP%] {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }"] });
450
421
  }
451
422
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJDropdownComponent, [{
452
423
  type: Component,
453
- args: [{
454
- selector: 'mj-dropdown',
455
- standalone: true,
456
- imports: [NgTemplateOutlet, OverlayModule],
457
- template: `
424
+ args: [{ selector: 'mj-dropdown', standalone: true, imports: [NgTemplateOutlet, OverlayModule], template: `
458
425
  <div
459
426
  class="mj-dropdown"
460
427
  #trigger
@@ -504,8 +471,12 @@ export class MJDropdownComponent {
504
471
  composed by the accessibility tree without this component ever seeing that text.
505
472
  Without it, every filterable dropdown on a form named this way announces as an
506
473
  identical "Filter options".
474
+
475
+ A hidden node that is DIRECTLY referenced by aria-labelledby is still included in the
476
+ name (accname §4.1), so aria-hidden keeps the word out of the reading order without
477
+ costing the composed name.
507
478
  -->
508
- <span class="mj-dropdown-sr-only" [attr.id]="FilterWordId">Filter</span>
479
+ <span class="mj-dropdown-sr-only" aria-hidden="true" [attr.id]="FilterWordId">Filter</span>
509
480
  <input
510
481
  #filterInput
511
482
  class="mj-input mj-dropdown-filter"
@@ -549,22 +520,12 @@ export class MJDropdownComponent {
549
520
  }
550
521
  </div>
551
522
  </ng-template>
552
- `,
553
- providers: [{
523
+ `, providers: [{
554
524
  provide: NG_VALUE_ACCESSOR,
555
525
  useExisting: forwardRef(() => MJDropdownComponent),
556
526
  multi: true
557
- }]
558
- }]
559
- }], null, { AriaLabel: [{
560
- type: Input
561
- }], AriaLabelledBy: [{
562
- type: Input
563
- }], InputId: [{
564
- type: Input
565
- }], AriaDescribedBy: [{
566
- type: Input
567
- }], Data: [{
527
+ }], styles: ["\n /*\n * Component-scoped ON PURPOSE, unlike the rest of this control's styling, which ships as a global\n * stylesheet the host application imports. A host that skips that import gets unstyled chrome \u2014\n * survivable \u2014 but a hidden-word span that is not hidden renders its word as literal text in the\n * middle of the field. The rule that hides it therefore has to travel with the component.\n *\n * Not display:none or visibility:hidden \u2014 both remove the element from the accessibility tree,\n * which is the one thing this element exists to be in.\n */\n .mj-dropdown-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n "] }]
528
+ }], null, { Data: [{
568
529
  type: Input
569
530
  }], TextField: [{
570
531
  type: Input
@@ -584,7 +545,7 @@ export class MJDropdownComponent {
584
545
  type: Output
585
546
  }], ValueChange: [{
586
547
  type: Output
587
- }], itemTemplate: [{
548
+ }], ItemTemplate: [{
588
549
  type: ContentChild,
589
550
  args: ['mjDropdownItem']
590
551
  }], triggerEl: [{
@@ -597,5 +558,5 @@ export class MJDropdownComponent {
597
558
  type: HostBinding,
598
559
  args: ['class.mj-dropdown-host']
599
560
  }] }); })();
600
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJDropdownComponent, { className: "MJDropdownComponent", filePath: "lib/dropdown/dropdown.component.ts", lineNumber: 162 }); })();
561
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJDropdownComponent, { className: "MJDropdownComponent", filePath: "lib/dropdown/dropdown.component.ts", lineNumber: 191 }); })();
601
562
  //# sourceMappingURL=dropdown.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown.component.js","sourceRoot":"","sources":["../../../src/lib/dropdown/dropdown.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n forwardRef,\n HostBinding,\n ElementRef,\n ViewChild,\n ContentChild,\n TemplateRef,\n OnDestroy,\n inject,\n ChangeDetectorRef\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';\nimport { OverlayModule, ConnectedPosition } from '@angular/cdk/overlay';\n\n/**\n * mj-dropdown — Dropdown select component using CDK Overlay.\n *\n * Replaces `<kendo-dropdownlist>`.\n *\n * Every dropdown needs an ACCESSIBLE NAME, or it announces as \"combobox, collapsed\" with no hint of\n * what it selects (WCAG 2.1 4.1.2). Use {@link AriaLabelledBy} when a visible label already exists —\n * `<label for>` cannot name a `div[role=combobox]` — and {@link AriaLabel} when none does.\n *\n * @example With a visible label (preferred)\n * ```html\n * <span id=\"persona-label\">Interview persona</span>\n * <mj-dropdown\n * AriaLabelledBy=\"persona-label\"\n * [Data]=\"items\"\n * TextField=\"name\"\n * ValueField=\"id\"\n * [(ngModel)]=\"selectedId\"\n * [ValuePrimitive]=\"true\">\n * </mj-dropdown>\n * ```\n *\n * @example With no visible label\n * ```html\n * <mj-dropdown\n * AriaLabel=\"Interview persona\"\n * [Data]=\"items\"\n * TextField=\"name\"\n * ValueField=\"id\"\n * [(ngModel)]=\"selectedId\"\n * [ValuePrimitive]=\"true\"\n * [Filterable]=\"true\"\n * (FilterChange)=\"onFilter($event)\">\n * </mj-dropdown>\n * ```\n */\n@Component({\n selector: 'mj-dropdown',\n standalone: true,\n imports: [NgTemplateOutlet, OverlayModule],\n template: `\n <div\n class=\"mj-dropdown\"\n #trigger\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n [class.mj-dropdown--open]=\"IsOpen\"\n [class.mj-dropdown--disabled]=\"IsDisabled\"\n role=\"combobox\"\n [attr.id]=\"InputId || null\"\n [attr.aria-label]=\"AriaLabel || null\"\n [attr.aria-labelledby]=\"AriaLabelledBy || null\"\n [attr.aria-describedby]=\"AriaDescribedBy || null\"\n [attr.aria-expanded]=\"IsOpen\"\n aria-haspopup=\"listbox\"\n [attr.aria-controls]=\"IsOpen ? ListboxId : null\"\n [attr.aria-disabled]=\"IsDisabled ? 'true' : null\"\n [attr.tabindex]=\"IsDisabled ? -1 : 0\"\n (click)=\"Toggle()\"\n (keydown)=\"OnKeyDown($event)\"\n (blur)=\"OnBlur()\">\n <span class=\"mj-dropdown-value\" [class.mj-dropdown-placeholder]=\"!HasValue\">\n {{ DisplayText }}\n </span>\n <i class=\"fa-solid fa-chevron-down mj-dropdown-arrow\"></i>\n </div>\n\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"IsOpen\"\n [cdkConnectedOverlayPositions]=\"Positions\"\n [cdkConnectedOverlayWidth]=\"TriggerWidth\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"mj-dropdown-backdrop\"\n (backdropClick)=\"Close()\"\n (detach)=\"Close()\">\n <div class=\"mj-dropdown-panel\" role=\"listbox\"\n [attr.id]=\"ListboxId\"\n [attr.aria-label]=\"AriaLabel || null\"\n [attr.aria-labelledby]=\"AriaLabelledBy || null\">\n @if (Filterable) {\n <div class=\"mj-dropdown-filter-wrap\">\n <!--\n The word \"Filter\" lives in a hidden span rather than in a concatenated string so the\n AriaLabelledBy path can NAME this box from the same visible label that names the\n dropdown: aria-labelledby takes an ID LIST, so \"Filter\" plus the label's own text is\n composed by the accessibility tree without this component ever seeing that text.\n Without it, every filterable dropdown on a form named this way announces as an\n identical \"Filter options\".\n -->\n <span class=\"mj-dropdown-sr-only\" [attr.id]=\"FilterWordId\">Filter</span>\n <input\n #filterInput\n class=\"mj-input mj-dropdown-filter\"\n type=\"text\"\n placeholder=\"Filter...\"\n [attr.aria-labelledby]=\"FilterLabelledBy\"\n [attr.aria-label]=\"FilterLabelledBy ? null : FilterLabel\"\n [value]=\"filterText\"\n (input)=\"OnFilterInput($event)\"\n (keydown)=\"OnKeyDown($event)\" />\n </div>\n }\n @if (DefaultItem != null) {\n <div\n class=\"mj-dropdown-option mj-dropdown-option--default\"\n [class.mj-dropdown-option--selected]=\"SelectedValue == null\"\n [class.mj-dropdown-option--highlighted]=\"HighlightedIndex === -1\"\n role=\"option\"\n [attr.aria-selected]=\"SelectedValue == null\"\n (click)=\"SelectItem(null, $event)\">\n {{ GetItemText(DefaultItem) }}\n </div>\n }\n @for (item of FilteredItems; track TrackByIndex($index)) {\n <div\n class=\"mj-dropdown-option\"\n [class.mj-dropdown-option--selected]=\"IsItemSelected(item)\"\n [class.mj-dropdown-option--highlighted]=\"HighlightedIndex === $index\"\n role=\"option\"\n [attr.aria-selected]=\"IsItemSelected(item)\"\n (click)=\"SelectItem(item, $event)\">\n @if (itemTemplate) {\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\"></ng-container>\n } @else {\n {{ GetItemText(item) }}\n }\n </div>\n }\n @if (FilteredItems.length === 0) {\n <div class=\"mj-dropdown-no-data\">No data found</div>\n }\n </div>\n </ng-template>\n `,\n providers: [{\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => MJDropdownComponent),\n multi: true\n }]\n})\nexport class MJDropdownComponent implements ControlValueAccessor, OnDestroy {\n /**\n * Accessible name for the combobox (#3860). Without one — and with no visible label wired via\n * {@link AriaLabelledBy} — the control announces as an UNNAMED combobox, which fails WCAG 2.1\n * 4.1.2 (Name, Role, Value): \"combobox, collapsed\" with no hint of what it selects. Applied as\n * `aria-label` on the trigger AND on the popup listbox, so both halves announce the same name.\n */\n @Input() AriaLabel = '';\n\n /**\n * The id of a VISIBLE label element that names this control — the preferred wiring when a label\n * already exists on screen (an `aria-label` would duplicate its text and drift on rename). This,\n * not `<label for>`, is the visible-label path: the trigger is a `div[role=combobox]`, and the\n * label-for association only names labelable form elements. `aria-labelledby` beats `AriaLabel`\n * in the accessible-name computation where both are present. Applied to trigger AND listbox.\n */\n @Input() AriaLabelledBy = '';\n\n /**\n * `id` for the combobox trigger, so other markup can REFERENCE it — `aria-controls`, hint text,\n * test hooks. It is deliberately not documented as a `<label for>` target: the trigger is a div,\n * which `label[for]` neither names nor focuses. To name the control from a visible label, put an\n * id on the LABEL and pass it as {@link AriaLabelledBy}.\n */\n @Input() InputId = '';\n\n /** `aria-describedby` passthrough for hint/error text — same shape of gap as the name. */\n @Input() AriaDescribedBy = '';\n\n @Input() Data: Record<string, unknown>[] | string[] | readonly unknown[] | null = [];\n @Input() TextField = '';\n @Input() ValueField = '';\n @Input() Filterable = false;\n @Input() ValuePrimitive = false;\n /**\n * Host-driven disable. Composed with Angular Forms' `setDisabledState()` into `IsDisabled`\n * (the actual gate) — see `syncDisabled`. A setter, not a bare field, because this input is\n * routinely bound to an expression that changes over the control's lifetime\n * (`[Disabled]=\"!draft.CompanyID\"`), and the gate has to follow it every time.\n */\n @Input()\n set Disabled(value: boolean) {\n this.disabledInput = value;\n this.syncDisabled();\n }\n get Disabled(): boolean {\n return this.disabledInput;\n }\n @Input() Placeholder = 'Select...';\n @Input() DefaultItem: Record<string, unknown> | string | null = null;\n\n @Output() FilterChange = new EventEmitter<string>();\n @Output() ValueChange = new EventEmitter<unknown>();\n\n @ContentChild('mjDropdownItem') itemTemplate: TemplateRef<{ $implicit: unknown }> | null = null;\n\n @ViewChild('trigger') private triggerEl!: ElementRef<HTMLElement>;\n @ViewChild('filterInput') private filterInputEl: ElementRef<HTMLInputElement> | undefined;\n\n @HostBinding('class.mj-dropdown-host') readonly hostClass = true;\n\n private cdr = inject(ChangeDetectorRef);\n private static nextId = 0;\n\n DropdownId = MJDropdownComponent.nextId++;\n\n /**\n * Id of the popup listbox, so the trigger can point `aria-controls` at it while open — the half of\n * the combobox pattern that makes \"collapsed/expanded\" refer to something a screen reader can\n * find. Generated per instance from the same `static nextId` counter `dialog`, `window` and\n * `accordion` use in this package.\n */\n get ListboxId(): string { return `mj-dropdown-listbox-${this.DropdownId}`; }\n\n /** Id of the hidden \"Filter\" word, composed into the filter box's name via an id list. */\n get FilterWordId(): string { return `mj-dropdown-filter-word-${this.DropdownId}`; }\n\n /**\n * `aria-labelledby` for the filter box when the dropdown is named by a VISIBLE label: \"Filter\"\n * plus that label's own text, composed by the accessibility tree. Empty when there is no such\n * label, in which case {@link FilterLabel} supplies a string instead.\n */\n get FilterLabelledBy(): string { return this.AriaLabelledBy ? `${this.FilterWordId} ${this.AriaLabelledBy}` : ''; }\n\n /**\n * `aria-label` for the filter box in the no-visible-label case.\n *\n * The \"filter\" guard is not cosmetic: this repo's house habit is `AriaLabel=\"Filter roles\"`, and\n * an unconditional prefix announces that box as \"Filter Filter roles\". A name that already begins\n * with the word is used as-is.\n */\n get FilterLabel(): string {\n const name = this.AriaLabel.trim();\n if (!name) return 'Filter options';\n return /^filter\\b/i.test(name) ? name : `Filter ${name}`;\n }\n IsOpen = false;\n /**\n * The single gate on `Toggle()` / `Open()` — true when EITHER the `Disabled` input or Angular\n * Forms says so. Never assign it directly; go through `syncDisabled()` so both sources are\n * always composed and a lock closes an open panel.\n */\n IsDisabled = false;\n HighlightedIndex = -1;\n SelectedValue: unknown = null;\n TriggerWidth = 0;\n\n filterText = '';\n\n Positions: ConnectedPosition[] = [\n { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' },\n { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom' }\n ];\n\n private onChange: (value: unknown) => void = () => {};\n private onTouched: () => void = () => {};\n\n /** Backing field for the `Disabled` input. */\n private disabledInput = false;\n /** The forms-driven disabled state, kept SEPARATE so neither source can stomp the other. */\n private formDisabled = false;\n\n /**\n * Recompute the gate from both of its sources. Called whenever either changes.\n *\n * `IsDisabled` is derived state, and the only thing that assigned it was `setDisabledState()`.\n * The forms-driven half was in fact fine — `setUpControl` also wires `registerOnDisabledChange`,\n * so that hook fires on every `control.disable()`/`enable()`, not just at registration. What had\n * no recompute path at all was the `Disabled` @Input: a plain field, so the gate froze at\n * whatever the first compose produced and every later change to the input was dropped.\n *\n * That is how a `[Disabled]=\"!draft.CompanyID\"` picker stayed dead for the life of the\n * component after the company was finally chosen.\n */\n private syncDisabled(): void {\n const disabled = this.disabledInput || this.formDisabled;\n if (disabled === this.IsDisabled) return;\n this.IsDisabled = disabled;\n // Becoming disabled while the panel is open would otherwise leave an interactive list\n // hanging off a control the user can no longer operate.\n if (disabled) this.resetPanelState();\n this.cdr.markForCheck();\n }\n\n get FilteredItems(): unknown[] {\n const data = (this.Data ?? []) as unknown[];\n if (!this.Filterable || !this.filterText) return data;\n const search = this.filterText.toLowerCase();\n return data.filter(item => this.GetItemText(item).toLowerCase().includes(search));\n }\n\n get HasValue(): boolean { return this.SelectedValue != null; }\n\n get DisplayText(): string {\n if (this.SelectedValue == null) {\n if (this.DefaultItem != null) return this.GetItemText(this.DefaultItem);\n return this.Placeholder;\n }\n if (this.ValuePrimitive && this.ValueField) {\n const found = ((this.Data ?? []) as unknown[]).find(item => this.GetItemValue(item) === this.SelectedValue);\n return found ? this.GetItemText(found) : String(this.SelectedValue);\n }\n return this.GetItemText(this.SelectedValue as Record<string, unknown> | string);\n }\n\n Toggle(): void {\n if (this.IsDisabled) return;\n this.IsOpen ? this.Close() : this.Open();\n }\n\n Open(): void {\n if (this.IsDisabled || this.IsOpen) return;\n this.TriggerWidth = this.triggerEl?.nativeElement.offsetWidth ?? 200;\n this.IsOpen = true;\n this.HighlightedIndex = this.getSelectedIndex();\n this.cdr.detectChanges();\n if (this.Filterable) setTimeout(() => this.filterInputEl?.nativeElement.focus(), 0);\n }\n\n Close(): void {\n if (!this.IsOpen) return;\n this.resetPanelState();\n this.cdr.detectChanges();\n }\n\n /**\n * Panel state only — no change detection. Split out of `Close()` because `syncDisabled()` can\n * run from an @Input setter, i.e. DURING the parent's change-detection pass, where a nested\n * `detectChanges()` re-enters CD and trips NG0100 on the parent's own bindings.\n */\n private resetPanelState(): void {\n this.IsOpen = false;\n this.filterText = '';\n this.HighlightedIndex = -1;\n }\n\n SelectItem(item: unknown | null, event?: Event): void {\n event?.stopPropagation();\n if (item == null) {\n this.SelectedValue = null;\n this.onChange(null);\n this.ValueChange.emit(null);\n } else if (this.ValuePrimitive && this.ValueField) {\n const value = this.GetItemValue(item);\n this.SelectedValue = value;\n this.onChange(value);\n this.ValueChange.emit(value);\n } else {\n this.SelectedValue = item;\n this.onChange(item);\n this.ValueChange.emit(item);\n }\n this.Close();\n }\n\n IsItemSelected(item: unknown): boolean {\n if (this.SelectedValue == null) return false;\n if (this.ValuePrimitive && this.ValueField) return this.GetItemValue(item) === this.SelectedValue;\n if (this.ValueField && typeof item === 'object' && typeof this.SelectedValue === 'object')\n return this.GetItemValue(item) === this.GetItemValue(this.SelectedValue);\n return item === this.SelectedValue;\n }\n\n OnFilterInput(event: Event): void {\n this.filterText = (event.target as HTMLInputElement).value;\n this.HighlightedIndex = 0;\n this.FilterChange.emit(this.filterText);\n }\n\n OnKeyDown(event: KeyboardEvent): void {\n const items = this.FilteredItems;\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n if (!this.IsOpen) this.Open();\n else this.HighlightedIndex = Math.min(this.HighlightedIndex + 1, items.length - 1);\n break;\n case 'ArrowUp':\n event.preventDefault();\n if (this.IsOpen) this.HighlightedIndex = Math.max(this.HighlightedIndex - 1, 0);\n break;\n case 'Enter':\n event.preventDefault();\n if (this.IsOpen && this.HighlightedIndex >= 0 && this.HighlightedIndex < items.length)\n this.SelectItem(items[this.HighlightedIndex]);\n else if (!this.IsOpen) this.Open();\n break;\n case 'Escape': event.preventDefault(); this.Close(); break;\n case 'Home': if (this.IsOpen) { event.preventDefault(); this.HighlightedIndex = 0; } break;\n case 'End': if (this.IsOpen) { event.preventDefault(); this.HighlightedIndex = items.length - 1; } break;\n }\n }\n\n OnBlur(): void { this.onTouched(); }\n\n GetItemText(item: unknown): string {\n if (item == null) return '';\n if (typeof item === 'string') return item;\n if (this.TextField && typeof item === 'object') return String((item as Record<string, unknown>)[this.TextField] ?? '');\n return String(item);\n }\n\n GetItemValue(item: unknown): unknown {\n if (typeof item === 'string') return item;\n if (this.ValueField && typeof item === 'object' && item != null) return (item as Record<string, unknown>)[this.ValueField];\n return item;\n }\n\n TrackByIndex(index: number): number { return index; }\n\n writeValue(value: unknown): void { this.SelectedValue = value; }\n registerOnChange(fn: (value: unknown) => void): void { this.onChange = fn; }\n registerOnTouched(fn: () => void): void { this.onTouched = fn; }\n setDisabledState(isDisabled: boolean): void { this.formDisabled = isDisabled; this.syncDisabled(); }\n ngOnDestroy(): void { this.Close(); }\n\n private getSelectedIndex(): number {\n if (this.SelectedValue == null) return -1;\n return this.FilteredItems.findIndex(item => this.IsItemSelected(item));\n }\n}\n"]}
1
+ {"version":3,"file":"dropdown.component.js","sourceRoot":"","sources":["../../../src/lib/dropdown/dropdown.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n AfterViewInit,\n Component,\n Input,\n Output,\n EventEmitter,\n forwardRef,\n HostBinding,\n ElementRef,\n ViewChild,\n ContentChild,\n TemplateRef,\n OnDestroy,\n inject,\n ChangeDetectorRef\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';\nimport { OverlayModule, ConnectedPosition } from '@angular/cdk/overlay';\nimport { MJNamedControlBase } from '../a11y/named-control.base';\nimport { WarnIfUnnamed } from '../a11y/unnamed-control-guard';\n\n/**\n * mj-dropdown — Dropdown select component using CDK Overlay.\n *\n * Replaces `<kendo-dropdownlist>`.\n *\n * Every dropdown needs an ACCESSIBLE NAME, or it announces as \"combobox, collapsed\" with no hint of\n * what it selects (WCAG 2.1 4.1.2). Use {@link AriaLabelledBy} when a visible label already exists —\n * `<label for>` cannot name a `div[role=combobox]` — and {@link AriaLabel} when none does.\n *\n * @example With a visible label (preferred)\n * ```html\n * <span id=\"persona-label\">Interview persona</span>\n * <mj-dropdown\n * AriaLabelledBy=\"persona-label\"\n * [Data]=\"items\"\n * TextField=\"name\"\n * ValueField=\"id\"\n * [(ngModel)]=\"selectedId\"\n * [ValuePrimitive]=\"true\">\n * </mj-dropdown>\n * ```\n *\n * @example With no visible label\n * ```html\n * <mj-dropdown\n * AriaLabel=\"Interview persona\"\n * [Data]=\"items\"\n * TextField=\"name\"\n * ValueField=\"id\"\n * [(ngModel)]=\"selectedId\"\n * [ValuePrimitive]=\"true\"\n * [Filterable]=\"true\"\n * (FilterChange)=\"onFilter($event)\">\n * </mj-dropdown>\n * ```\n */\n@Component({\n selector: 'mj-dropdown',\n standalone: true,\n imports: [NgTemplateOutlet, OverlayModule],\n template: `\n <div\n class=\"mj-dropdown\"\n #trigger\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n [class.mj-dropdown--open]=\"IsOpen\"\n [class.mj-dropdown--disabled]=\"IsDisabled\"\n role=\"combobox\"\n [attr.id]=\"InputId || null\"\n [attr.aria-label]=\"AriaLabel || null\"\n [attr.aria-labelledby]=\"AriaLabelledBy || null\"\n [attr.aria-describedby]=\"AriaDescribedBy || null\"\n [attr.aria-expanded]=\"IsOpen\"\n aria-haspopup=\"listbox\"\n [attr.aria-controls]=\"IsOpen ? ListboxId : null\"\n [attr.aria-disabled]=\"IsDisabled ? 'true' : null\"\n [attr.tabindex]=\"IsDisabled ? -1 : 0\"\n (click)=\"Toggle()\"\n (keydown)=\"OnKeyDown($event)\"\n (blur)=\"OnBlur()\">\n <span class=\"mj-dropdown-value\" [class.mj-dropdown-placeholder]=\"!HasValue\">\n {{ DisplayText }}\n </span>\n <i class=\"fa-solid fa-chevron-down mj-dropdown-arrow\"></i>\n </div>\n\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"IsOpen\"\n [cdkConnectedOverlayPositions]=\"Positions\"\n [cdkConnectedOverlayWidth]=\"TriggerWidth\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n cdkConnectedOverlayBackdropClass=\"mj-dropdown-backdrop\"\n (backdropClick)=\"Close()\"\n (detach)=\"Close()\">\n <div class=\"mj-dropdown-panel\" role=\"listbox\"\n [attr.id]=\"ListboxId\"\n [attr.aria-label]=\"AriaLabel || null\"\n [attr.aria-labelledby]=\"AriaLabelledBy || null\">\n @if (Filterable) {\n <div class=\"mj-dropdown-filter-wrap\">\n <!--\n The word \"Filter\" lives in a hidden span rather than in a concatenated string so the\n AriaLabelledBy path can NAME this box from the same visible label that names the\n dropdown: aria-labelledby takes an ID LIST, so \"Filter\" plus the label's own text is\n composed by the accessibility tree without this component ever seeing that text.\n Without it, every filterable dropdown on a form named this way announces as an\n identical \"Filter options\".\n\n A hidden node that is DIRECTLY referenced by aria-labelledby is still included in the\n name (accname §4.1), so aria-hidden keeps the word out of the reading order without\n costing the composed name.\n -->\n <span class=\"mj-dropdown-sr-only\" aria-hidden=\"true\" [attr.id]=\"FilterWordId\">Filter</span>\n <input\n #filterInput\n class=\"mj-input mj-dropdown-filter\"\n type=\"text\"\n placeholder=\"Filter...\"\n [attr.aria-labelledby]=\"FilterLabelledBy\"\n [attr.aria-label]=\"FilterLabelledBy ? null : FilterLabel\"\n [value]=\"filterText\"\n (input)=\"OnFilterInput($event)\"\n (keydown)=\"OnKeyDown($event)\" />\n </div>\n }\n @if (DefaultItem != null) {\n <div\n class=\"mj-dropdown-option mj-dropdown-option--default\"\n [class.mj-dropdown-option--selected]=\"SelectedValue == null\"\n [class.mj-dropdown-option--highlighted]=\"HighlightedIndex === -1\"\n role=\"option\"\n [attr.aria-selected]=\"SelectedValue == null\"\n (click)=\"SelectItem(null, $event)\">\n {{ GetItemText(DefaultItem) }}\n </div>\n }\n @for (item of FilteredItems; track TrackByIndex($index)) {\n <div\n class=\"mj-dropdown-option\"\n [class.mj-dropdown-option--selected]=\"IsItemSelected(item)\"\n [class.mj-dropdown-option--highlighted]=\"HighlightedIndex === $index\"\n role=\"option\"\n [attr.aria-selected]=\"IsItemSelected(item)\"\n (click)=\"SelectItem(item, $event)\">\n @if (itemTemplate) {\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\"></ng-container>\n } @else {\n {{ GetItemText(item) }}\n }\n </div>\n }\n @if (FilteredItems.length === 0) {\n <div class=\"mj-dropdown-no-data\">No data found</div>\n }\n </div>\n </ng-template>\n `,\n styles: [`\n /*\n * Component-scoped ON PURPOSE, unlike the rest of this control's styling, which ships as a global\n * stylesheet the host application imports. A host that skips that import gets unstyled chrome —\n * survivable — but a hidden-word span that is not hidden renders its word as literal text in the\n * middle of the field. The rule that hides it therefore has to travel with the component.\n *\n * Not display:none or visibility:hidden — both remove the element from the accessibility tree,\n * which is the one thing this element exists to be in.\n */\n .mj-dropdown-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n `],\n providers: [{\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => MJDropdownComponent),\n multi: true\n }]\n})\nexport class MJDropdownComponent extends MJNamedControlBase implements ControlValueAccessor, AfterViewInit, OnDestroy {\n @Input() Data: Record<string, unknown>[] | string[] | readonly unknown[] | null = [];\n @Input() TextField = '';\n @Input() ValueField = '';\n @Input() Filterable = false;\n @Input() ValuePrimitive = false;\n /**\n * Host-driven disable. Composed with Angular Forms' `setDisabledState()` into `IsDisabled`\n * (the actual gate) — see `syncDisabled`. A setter, not a bare field, because this input is\n * routinely bound to an expression that changes over the control's lifetime\n * (`[Disabled]=\"!draft.CompanyID\"`), and the gate has to follow it every time.\n */\n @Input()\n set Disabled(value: boolean) {\n this.disabledInput = value;\n this.syncDisabled();\n }\n get Disabled(): boolean {\n return this.disabledInput;\n }\n @Input() Placeholder = 'Select...';\n @Input() DefaultItem: Record<string, unknown> | string | null = null;\n\n @Output() FilterChange = new EventEmitter<string>();\n @Output() ValueChange = new EventEmitter<unknown>();\n\n @ContentChild('mjDropdownItem') ItemTemplate: TemplateRef<{ $implicit: unknown }> | null = null;\n\n /** @deprecated Use {@link ItemTemplate}. */\n get itemTemplate(): TemplateRef<{ $implicit: unknown }> | null {\n return this.ItemTemplate;\n }\n /** @deprecated Use {@link ItemTemplate}. */\n set itemTemplate(value: TemplateRef<{ $implicit: unknown }> | null) {\n this.ItemTemplate = value;\n }\n\n @ViewChild('trigger') private triggerEl!: ElementRef<HTMLElement>;\n @ViewChild('filterInput') private filterInputEl: ElementRef<HTMLInputElement> | undefined;\n\n @HostBinding('class.mj-dropdown-host') readonly hostClass = true;\n\n private cdr = inject(ChangeDetectorRef);\n\n /** This dropdown's id suffix — the shared named-control counter, kept under its own name. */\n readonly DropdownId = this.NamedControlId;\n\n /**\n * Id of the popup listbox, so the trigger can point `aria-controls` at it while open — the half of\n * the combobox pattern that makes \"collapsed/expanded\" refer to something a screen reader can\n * find. Generated per instance from the shared named-control counter.\n */\n get ListboxId(): string { return `mj-dropdown-listbox-${this.DropdownId}`; }\n\n /** Id of the hidden \"Filter\" word, composed into the filter box's name via an id list. */\n get FilterWordId(): string { return this.SecondaryWordId('filter-word'); }\n\n /** `aria-labelledby` for the filter box when a VISIBLE label names the dropdown. */\n get FilterLabelledBy(): string { return this.SecondaryLabelledBy('filter-word'); }\n\n /** `aria-label` for the filter box in the no-visible-label case. */\n get FilterLabel(): string { return this.SecondaryLabel('Filter', 'Filter options'); }\n\n IsOpen = false;\n /**\n * The single gate on `Toggle()` / `Open()` — true when EITHER the `Disabled` input or Angular\n * Forms says so. Never assign it directly; go through `syncDisabled()` so both sources are\n * always composed and a lock closes an open panel.\n */\n IsDisabled = false;\n HighlightedIndex = -1;\n SelectedValue: unknown = null;\n TriggerWidth = 0;\n\n filterText = '';\n\n Positions: ConnectedPosition[] = [\n { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' },\n { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom' }\n ];\n\n private onChange: (value: unknown) => void = () => {};\n private onTouched: () => void = () => {};\n\n /** Backing field for the `Disabled` input. */\n private disabledInput = false;\n /** The forms-driven disabled state, kept SEPARATE so neither source can stomp the other. */\n private formDisabled = false;\n\n /**\n * Recompute the gate from both of its sources. Called whenever either changes.\n *\n * `IsDisabled` is derived state, and the only thing that assigned it was `setDisabledState()`.\n * The forms-driven half was in fact fine — `setUpControl` also wires `registerOnDisabledChange`,\n * so that hook fires on every `control.disable()`/`enable()`, not just at registration. What had\n * no recompute path at all was the `Disabled` @Input: a plain field, so the gate froze at\n * whatever the first compose produced and every later change to the input was dropped.\n *\n * That is how a `[Disabled]=\"!draft.CompanyID\"` picker stayed dead for the life of the\n * component after the company was finally chosen.\n */\n private syncDisabled(): void {\n const disabled = this.disabledInput || this.formDisabled;\n if (disabled === this.IsDisabled) return;\n this.IsDisabled = disabled;\n // Becoming disabled while the panel is open would otherwise leave an interactive list\n // hanging off a control the user can no longer operate.\n if (disabled) this.resetPanelState();\n this.cdr.markForCheck();\n }\n\n get FilteredItems(): unknown[] {\n const data = (this.Data ?? []) as unknown[];\n if (!this.Filterable || !this.filterText) return data;\n const search = this.filterText.toLowerCase();\n return data.filter(item => this.GetItemText(item).toLowerCase().includes(search));\n }\n\n get HasValue(): boolean { return this.SelectedValue != null; }\n\n get DisplayText(): string {\n if (this.SelectedValue == null) {\n if (this.DefaultItem != null) return this.GetItemText(this.DefaultItem);\n return this.Placeholder;\n }\n if (this.ValuePrimitive && this.ValueField) {\n const found = ((this.Data ?? []) as unknown[]).find(item => this.GetItemValue(item) === this.SelectedValue);\n return found ? this.GetItemText(found) : String(this.SelectedValue);\n }\n return this.GetItemText(this.SelectedValue as Record<string, unknown> | string);\n }\n\n Toggle(): void {\n if (this.IsDisabled) return;\n this.IsOpen ? this.Close() : this.Open();\n }\n\n Open(): void {\n if (this.IsDisabled || this.IsOpen) return;\n this.TriggerWidth = this.triggerEl?.nativeElement.offsetWidth ?? 200;\n this.IsOpen = true;\n this.HighlightedIndex = this.getSelectedIndex();\n this.cdr.detectChanges();\n if (this.Filterable) setTimeout(() => this.filterInputEl?.nativeElement.focus(), 0);\n }\n\n Close(): void {\n if (!this.IsOpen) return;\n this.resetPanelState();\n this.cdr.detectChanges();\n }\n\n /**\n * Panel state only — no change detection. Split out of `Close()` because `syncDisabled()` can\n * run from an @Input setter, i.e. DURING the parent's change-detection pass, where a nested\n * `detectChanges()` re-enters CD and trips NG0100 on the parent's own bindings.\n */\n private resetPanelState(): void {\n this.IsOpen = false;\n this.filterText = '';\n this.HighlightedIndex = -1;\n }\n\n SelectItem(item: unknown | null, event?: Event): void {\n event?.stopPropagation();\n if (item == null) {\n this.SelectedValue = null;\n this.onChange(null);\n this.ValueChange.emit(null);\n } else if (this.ValuePrimitive && this.ValueField) {\n const value = this.GetItemValue(item);\n this.SelectedValue = value;\n this.onChange(value);\n this.ValueChange.emit(value);\n } else {\n this.SelectedValue = item;\n this.onChange(item);\n this.ValueChange.emit(item);\n }\n this.Close();\n }\n\n IsItemSelected(item: unknown): boolean {\n if (this.SelectedValue == null) return false;\n if (this.ValuePrimitive && this.ValueField) return this.GetItemValue(item) === this.SelectedValue;\n if (this.ValueField && typeof item === 'object' && typeof this.SelectedValue === 'object')\n return this.GetItemValue(item) === this.GetItemValue(this.SelectedValue);\n return item === this.SelectedValue;\n }\n\n OnFilterInput(event: Event): void {\n this.filterText = (event.target as HTMLInputElement).value;\n this.HighlightedIndex = 0;\n this.FilterChange.emit(this.filterText);\n }\n\n OnKeyDown(event: KeyboardEvent): void {\n const items = this.FilteredItems;\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n if (!this.IsOpen) this.Open();\n else this.HighlightedIndex = Math.min(this.HighlightedIndex + 1, items.length - 1);\n break;\n case 'ArrowUp':\n event.preventDefault();\n if (this.IsOpen) this.HighlightedIndex = Math.max(this.HighlightedIndex - 1, 0);\n break;\n case 'Enter':\n event.preventDefault();\n if (this.IsOpen && this.HighlightedIndex >= 0 && this.HighlightedIndex < items.length)\n this.SelectItem(items[this.HighlightedIndex]);\n else if (!this.IsOpen) this.Open();\n break;\n case 'Escape': event.preventDefault(); this.Close(); break;\n case 'Home': if (this.IsOpen) { event.preventDefault(); this.HighlightedIndex = 0; } break;\n case 'End': if (this.IsOpen) { event.preventDefault(); this.HighlightedIndex = items.length - 1; } break;\n }\n }\n\n OnBlur(): void { this.onTouched(); }\n\n ngAfterViewInit(): void { WarnIfUnnamed(this.triggerEl?.nativeElement, 'mj-dropdown'); }\n\n GetItemText(item: unknown): string {\n if (item == null) return '';\n if (typeof item === 'string') return item;\n if (this.TextField && typeof item === 'object') return String((item as Record<string, unknown>)[this.TextField] ?? '');\n return String(item);\n }\n\n GetItemValue(item: unknown): unknown {\n if (typeof item === 'string') return item;\n if (this.ValueField && typeof item === 'object' && item != null) return (item as Record<string, unknown>)[this.ValueField];\n return item;\n }\n\n TrackByIndex(index: number): number { return index; }\n\n writeValue(value: unknown): void { this.SelectedValue = value; }\n registerOnChange(fn: (value: unknown) => void): void { this.onChange = fn; }\n registerOnTouched(fn: () => void): void { this.onTouched = fn; }\n setDisabledState(isDisabled: boolean): void { this.formDisabled = isDisabled; this.syncDisabled(); }\n ngOnDestroy(): void { this.Close(); }\n\n private getSelectedIndex(): number {\n if (this.SelectedValue == null) return -1;\n return this.FilteredItems.findIndex(item => this.IsItemSelected(item));\n }\n}\n"]}
@@ -66,19 +66,3 @@
66
66
  .mj-dropdown-no-data { padding: 16px 12px; color: var(--mj-text-muted); text-align: center; font-size: var(--mj-text-sm); }
67
67
 
68
68
  @media (max-width: 767px) { .mj-dropdown-panel { max-height: 50vh; } }
69
-
70
- /* Visually hidden, still in the accessibility tree — carries the word "Filter" that composes the
71
- filter box's name with the dropdown's own visible label via an aria-labelledby id list (#3860).
72
- Not `display:none` or `visibility:hidden`: both remove the element from the accessibility tree,
73
- which is the one thing this element exists to be in. */
74
- .mj-dropdown-sr-only {
75
- position: absolute;
76
- width: 1px;
77
- height: 1px;
78
- padding: 0;
79
- margin: -1px;
80
- overflow: hidden;
81
- clip: rect(0, 0, 0, 0);
82
- white-space: nowrap;
83
- border: 0;
84
- }
@@ -70,11 +70,19 @@ export declare class MJFilterPanelComponent {
70
70
  ResetLabel: string;
71
71
  ValuesChange: EventEmitter<Record<string, unknown>>;
72
72
  Reset: EventEmitter<void>;
73
+ GetValue(key: string): unknown;
74
+ /** @deprecated Use {@link GetValue}. */
73
75
  getValue(key: string): unknown;
76
+ SetValue(key: string, value: unknown): void;
77
+ /** @deprecated Use {@link SetValue}. */
74
78
  setValue(key: string, value: unknown): void;
75
79
  /** Whether a chip option is currently active (handles single + multi). */
80
+ IsChipActive(field: FilterFieldConfig, optValue: FilterOptionValue): boolean;
81
+ /** @deprecated Use {@link IsChipActive}. */
76
82
  isChipActive(field: FilterFieldConfig, optValue: FilterOptionValue): boolean;
77
83
  /** Chip click: replace (single-select) or toggle in/out of the array (multi). */
84
+ OnChipClick(field: FilterFieldConfig, optValue: FilterOptionValue): void;
85
+ /** @deprecated Use {@link OnChipClick}. */
78
86
  onChipClick(field: FilterFieldConfig, optValue: FilterOptionValue): void;
79
87
  static ɵfac: i0.ɵɵFactoryDeclaration<MJFilterPanelComponent, never>;
80
88
  static ɵcmp: i0.ɵɵComponentDeclaration<MJFilterPanelComponent, "mj-filter-panel", never, { "Fields": { "alias": "Fields"; "required": false; }; "Values": { "alias": "Values"; "required": false; }; "ShowReset": { "alias": "ShowReset"; "required": false; }; "ResetLabel": { "alias": "ResetLabel"; "required": false; }; }, { "ValuesChange": "ValuesChange"; "Reset": "Reset"; }, never, ["*"], true, never>;