@memberjunction/ng-ui-components 6.1.4 → 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.
- package/README.md +35 -9
- package/dist/lib/a11y/named-control.base.d.ts +91 -0
- package/dist/lib/a11y/named-control.base.d.ts.map +1 -0
- package/dist/lib/a11y/named-control.base.js +121 -0
- package/dist/lib/a11y/named-control.base.js.map +1 -0
- package/dist/lib/a11y/unnamed-control-guard.d.ts +52 -0
- package/dist/lib/a11y/unnamed-control-guard.d.ts.map +1 -0
- package/dist/lib/a11y/unnamed-control-guard.js +94 -0
- package/dist/lib/a11y/unnamed-control-guard.js.map +1 -0
- package/dist/lib/accordion/accordion.component.d.ts +16 -4
- package/dist/lib/accordion/accordion.component.d.ts.map +1 -1
- package/dist/lib/accordion/accordion.component.js +36 -12
- package/dist/lib/accordion/accordion.component.js.map +1 -1
- package/dist/lib/applied-filters/applied-filters.component.js.map +1 -1
- package/dist/lib/button/button.directive.d.ts +34 -6
- package/dist/lib/button/button.directive.d.ts.map +1 -1
- package/dist/lib/button/button.directive.js +85 -25
- package/dist/lib/button/button.directive.js.map +1 -1
- package/dist/lib/card-grid/card-grid.component.d.ts +3 -1
- package/dist/lib/card-grid/card-grid.component.d.ts.map +1 -1
- package/dist/lib/card-grid/card-grid.component.js +13 -9
- package/dist/lib/card-grid/card-grid.component.js.map +1 -1
- package/dist/lib/clickable/clickable.directive.d.ts +11 -3
- package/dist/lib/clickable/clickable.directive.d.ts.map +1 -1
- package/dist/lib/clickable/clickable.directive.js +25 -5
- package/dist/lib/clickable/clickable.directive.js.map +1 -1
- package/dist/lib/combobox/combobox.component.d.ts +44 -3
- package/dist/lib/combobox/combobox.component.d.ts.map +1 -1
- package/dist/lib/combobox/combobox.component.js +135 -51
- package/dist/lib/combobox/combobox.component.js.map +1 -1
- package/dist/lib/confirm-dialog/confirm-dialog.component.d.ts +6 -0
- package/dist/lib/confirm-dialog/confirm-dialog.component.d.ts.map +1 -1
- package/dist/lib/confirm-dialog/confirm-dialog.component.js +16 -4
- package/dist/lib/confirm-dialog/confirm-dialog.component.js.map +1 -1
- package/dist/lib/datepicker/datepicker.component.d.ts +25 -2
- package/dist/lib/datepicker/datepicker.component.d.ts.map +1 -1
- package/dist/lib/datepicker/datepicker.component.js +98 -42
- package/dist/lib/datepicker/datepicker.component.js.map +1 -1
- package/dist/lib/dialog/dialog.component.d.ts +4 -0
- package/dist/lib/dialog/dialog.component.d.ts.map +1 -1
- package/dist/lib/dialog/dialog.component.js +12 -4
- package/dist/lib/dialog/dialog.component.js.map +1 -1
- package/dist/lib/dialog/dialog.service.js.map +1 -1
- package/dist/lib/dropdown/dropdown.component.d.ts +19 -44
- package/dist/lib/dropdown/dropdown.component.d.ts.map +1 -1
- package/dist/lib/dropdown/dropdown.component.js +37 -76
- package/dist/lib/dropdown/dropdown.component.js.map +1 -1
- package/dist/lib/dropdown/dropdown.scss +0 -16
- package/dist/lib/filter-panel/filter-panel.component.d.ts +8 -0
- package/dist/lib/filter-panel/filter-panel.component.d.ts.map +1 -1
- package/dist/lib/filter-panel/filter-panel.component.js +25 -9
- package/dist/lib/filter-panel/filter-panel.component.js.map +1 -1
- package/dist/lib/numeric-input/numeric-input.component.d.ts +15 -1
- package/dist/lib/numeric-input/numeric-input.component.d.ts.map +1 -1
- package/dist/lib/numeric-input/numeric-input.component.js +36 -9
- package/dist/lib/numeric-input/numeric-input.component.js.map +1 -1
- package/dist/lib/page-search/page-search.component.d.ts +32 -3
- package/dist/lib/page-search/page-search.component.d.ts.map +1 -1
- package/dist/lib/page-search/page-search.component.js +68 -12
- package/dist/lib/page-search/page-search.component.js.map +1 -1
- package/dist/lib/switch/switch.component.d.ts +22 -1
- package/dist/lib/switch/switch.component.d.ts.map +1 -1
- package/dist/lib/switch/switch.component.js +50 -16
- package/dist/lib/switch/switch.component.js.map +1 -1
- package/dist/lib/tabs/tab-chrome-guard.d.ts +2 -0
- package/dist/lib/tabs/tab-chrome-guard.d.ts.map +1 -1
- package/dist/lib/tabs/tab-chrome-guard.js +5 -1
- package/dist/lib/tabs/tab-chrome-guard.js.map +1 -1
- package/dist/lib/window/window.component.d.ts +10 -0
- package/dist/lib/window/window.component.d.ts.map +1 -1
- package/dist/lib/window/window.component.js +27 -7
- package/dist/lib/window/window.component.js.map +1 -1
- package/dist/lib/workspace-tabs/workspace-tab-strip.component.d.ts +10 -0
- package/dist/lib/workspace-tabs/workspace-tab-strip.component.d.ts.map +1 -1
- package/dist/lib/workspace-tabs/workspace-tab-strip.component.js +27 -7
- package/dist/lib/workspace-tabs/workspace-tab-strip.component.js.map +1 -1
- package/dist/public-api.d.ts +2 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +2 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card-grid.component.js","sourceRoot":"","sources":["../../../src/lib/card-grid/card-grid.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Directive,\n Input,\n Output,\n EventEmitter,\n TemplateRef,\n ContentChild,\n HostListener,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n inject,\n OnInit,\n OnDestroy,\n OnChanges,\n SimpleChanges\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { BehaviorSubject, Subscription } from 'rxjs';\n\nlet nextCardId = 0;\n\n/**\n * Directive to provide a custom template for the Card Title.\n */\n@Directive({\n selector: '[mjCardTitle]',\n standalone: true,\n})\nexport class MJCardTitleDirective {\n constructor(public templateRef: TemplateRef<unknown>) {}\n}\n\n/**\n * Directive to provide custom action controls in the Card Header.\n */\n@Directive({\n selector: '[mjCardActions]',\n standalone: true,\n})\nexport class MJCardActionsDirective {\n constructor(public templateRef: TemplateRef<unknown>) {}\n}\n\n/**\n * Directive to provide custom tools/badges in the Card Header.\n */\n@Directive({\n selector: '[mjCardTools]',\n standalone: true,\n})\nexport class MJCardToolsDirective {\n constructor(public templateRef: TemplateRef<unknown>) {}\n}\n\n/**\n * Directive to provide a custom template for the Card Footer.\n */\n@Directive({\n selector: '[mjCardFooter]',\n standalone: true,\n})\nexport class MJCardFooterDirective {\n constructor(public templateRef: TemplateRef<unknown>) {}\n}\n\nconst CARD_GRID_CSS = `\n:host {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-width: 0;\n box-sizing: border-box;\n}\n\n.mj-card-grid {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n align-items: stretch;\n gap: var(--mj-card-grid-gap, var(--mj-space-4, 16px));\n width: 100%;\n position: relative;\n box-sizing: border-box;\n transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.mj-card-grid--has-maximized {\n grid-template-columns: 1fr !important;\n}\n\n@media (max-width: 640px) {\n .mj-card-grid {\n grid-template-columns: 1fr !important;\n }\n}\n\nmj-card {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.mj-card {\n display: flex;\n flex-direction: column;\n flex: 1 1 100%;\n height: 100%;\n min-height: 290px;\n background: var(--mj-bg-surface-card, var(--mj-bg-surface, #141f33));\n border: 1px solid var(--mj-border-default, #2a3852);\n border-radius: var(--mj-radius-xl, 16px);\n box-shadow: var(--mj-shadow-sm, 0 1px 3px rgba(0, 0, 0, 0.08));\n padding: var(--mj-space-4, 16px) var(--mj-space-5, 20px);\n box-sizing: border-box;\n transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;\n position: relative;\n min-width: 0;\n}\n\n.mj-card:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary, #38bdf8) 40%, var(--mj-border-default, #2a3852));\n}\n\n.mj-card--maximized {\n grid-column: 1 / -1;\n width: 100%;\n min-height: 480px;\n box-shadow: var(--mj-shadow-lg, 0 10px 25px rgba(0, 0, 0, 0.25));\n border-color: var(--mj-brand-primary, #38bdf8);\n z-index: 10;\n}\n\n.mj-card--hidden {\n display: none !important;\n}\n\n.mj-card__header {\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--mj-space-3, 12px);\n margin-bottom: var(--mj-space-3, 12px);\n min-height: 28px;\n width: 100%;\n}\n\n.mj-card__title-group {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n flex: 1 1 auto;\n}\n\n.mj-card__title-row {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: var(--mj-space-2, 8px);\n min-width: 0;\n}\n\n.mj-card__icon {\n color: var(--mj-brand-primary, #38bdf8);\n font-size: 14px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.mj-card__title {\n font-size: 14px;\n font-weight: 700;\n color: var(--mj-text-primary, #ffffff);\n letter-spacing: -0.01em;\n margin: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-card__subtitle {\n font-size: 11.5px;\n font-weight: 500;\n color: var(--mj-text-muted, #94a3b8);\n margin: 0;\n padding-left: 22px;\n}\n\n.mj-card__actions {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: var(--mj-space-2, 8px);\n flex-shrink: 0;\n margin-left: auto;\n}\n\n.mj-card__toggle-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: var(--mj-radius-sm, 6px);\n background: transparent;\n border: 1px solid transparent;\n color: var(--mj-text-muted, #94a3b8);\n cursor: pointer;\n padding: 0;\n font-size: 12px;\n transition: all 0.15s ease;\n}\n\n.mj-card__toggle-btn:hover {\n color: var(--mj-text-primary, #ffffff);\n background: var(--mj-bg-surface-sunken, rgba(255, 255, 255, 0.06));\n border-color: var(--mj-border-default, #2a3852);\n}\n\n.mj-card__toggle-btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary, #38bdf8);\n outline-offset: 1px;\n}\n\n.mj-card__body {\n flex: 1 1 auto;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n min-width: 0;\n}\n\n.mj-card__footer {\n margin-top: auto;\n padding-top: var(--mj-space-3, 12px);\n border-top: 1px solid var(--mj-border-default, #2a3852);\n}\n`;\n\n/**\n * Responsive Card Grid container that manages responsive layout and card maximization state.\n */\n@Component({\n selector: 'mj-card-grid',\n standalone: true,\n imports: [CommonModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n styles: [CARD_GRID_CSS],\n template: `\n <div class=\"mj-card-grid\"\n [class.mj-card-grid--has-maximized]=\"!!MaximizedCardId\"\n [style.--mj-card-grid-columns]=\"Columns\"\n [style.--mj-card-grid-gap]=\"Gap\">\n <ng-content></ng-content>\n </div>\n `,\n})\nexport class MJCardGridComponent implements OnChanges {\n private cdr = inject(ChangeDetectorRef);\n\n /** Stream of the currently maximized card ID across all children. */\n public readonly maximizedCard$ = new BehaviorSubject<string | null>(null);\n\n /** Number of columns for standard layout (defaults to 2). */\n @Input() Columns: number | string = 2;\n\n /** CSS gap between cards (defaults to var(--mj-space-4)). */\n @Input() Gap = 'var(--mj-space-4, 16px)';\n\n /** Currently maximized card ID. When set, only this card is shown full-width. */\n @Input() MaximizedCardId: string | null = null;\n\n /** Emits when the maximized card ID changes (two-way binding support). */\n @Output() MaximizedCardIdChange = new EventEmitter<string | null>();\n\n /** Emits the card ID when a card is maximized. */\n @Output() CardMaximized = new EventEmitter<string>();\n\n /** Emits when the maximized card is restored back to the grid view. */\n @Output() CardRestored = new EventEmitter<void>();\n\n public ngOnChanges(changes: SimpleChanges): void {\n if (changes['MaximizedCardId'] && !changes['MaximizedCardId'].firstChange) {\n this.maximizedCard$.next(this.MaximizedCardId);\n }\n }\n\n /** Pressing Escape restores the grid view if a card is maximized. */\n @HostListener('window:keydown.escape')\n public OnEscape(): void {\n if (this.MaximizedCardId) {\n this.Restore();\n }\n }\n\n public MaximizeCard(cardId: string): void {\n this.MaximizedCardId = cardId;\n this.maximizedCard$.next(cardId);\n this.MaximizedCardIdChange.emit(cardId);\n this.CardMaximized.emit(cardId);\n this.cdr.markForCheck();\n }\n\n public Restore(): void {\n if (!this.MaximizedCardId) return;\n this.MaximizedCardId = null;\n this.maximizedCard$.next(null);\n this.MaximizedCardIdChange.emit(null);\n this.CardRestored.emit();\n this.cdr.markForCheck();\n }\n\n public IsCardMaximized(cardId: string): boolean {\n return this.MaximizedCardId === cardId;\n }\n\n public IsCardHidden(cardId: string): boolean {\n return !!this.MaximizedCardId && this.MaximizedCardId !== cardId;\n }\n}\n\n/**\n * Modular card component with header title, icon, actions, and maximize/restore capability.\n */\n@Component({\n selector: 'mj-card',\n standalone: true,\n imports: [CommonModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n styles: [CARD_GRID_CSS],\n template: `\n <div class=\"mj-card\"\n [class.mj-card--maximized]=\"IsMaximized\"\n [class.mj-card--hidden]=\"IsHidden\"\n role=\"region\"\n [attr.aria-label]=\"Title || 'Card'\">\n \n <!-- Card Header -->\n @if (ShowHeader) {\n <div class=\"mj-card__header\">\n <div class=\"mj-card__title-group\">\n <div class=\"mj-card__title-row\">\n @if (Icon) {\n <span class=\"mj-card__icon\" aria-hidden=\"true\">\n <i [class]=\"Icon\"></i>\n </span>\n }\n @if (TitleTemplate) {\n <ng-container [ngTemplateOutlet]=\"TitleTemplate.templateRef\"></ng-container>\n } @else if (Title) {\n <h3 class=\"mj-card__title\">{{ Title }}</h3>\n }\n </div>\n @if (Subtitle) {\n <span class=\"mj-card__subtitle\">{{ Subtitle }}</span>\n }\n </div>\n\n <div class=\"mj-card__actions\">\n @if (ToolsTemplate) {\n <ng-container [ngTemplateOutlet]=\"ToolsTemplate.templateRef\"></ng-container>\n }\n @if (ActionsTemplate) {\n <ng-container [ngTemplateOutlet]=\"ActionsTemplate.templateRef\"></ng-container>\n }\n @if (AllowMaximize) {\n <button type=\"button\"\n class=\"mj-card__toggle-btn\"\n [title]=\"IsMaximized ? RestoreTooltip : MaximizeTooltip\"\n [attr.aria-label]=\"IsMaximized ? RestoreTooltip : MaximizeTooltip\"\n (click)=\"ToggleMaximize($event)\">\n @if (IsMaximized) {\n <i class=\"fa-solid fa-compress\" aria-hidden=\"true\"></i>\n } @else {\n <i class=\"fa-solid fa-expand\" aria-hidden=\"true\"></i>\n }\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Card Body -->\n <div class=\"mj-card__body\">\n <ng-content></ng-content>\n </div>\n\n <!-- Card Footer -->\n @if (FooterTemplate) {\n <div class=\"mj-card__footer\">\n <ng-container [ngTemplateOutlet]=\"FooterTemplate.templateRef\"></ng-container>\n </div>\n }\n </div>\n `,\n})\nexport class MJCardComponent implements OnInit, OnDestroy {\n private grid = inject(MJCardGridComponent, { optional: true });\n private cdr = inject(ChangeDetectorRef);\n private sub?: Subscription;\n\n @Input() CardId = `mj-card-${++nextCardId}`;\n @Input() Title?: string;\n @Input() Subtitle?: string;\n @Input() Icon?: string;\n @Input() AllowMaximize = true;\n @Input() MaximizeTooltip = 'Expand card';\n @Input() RestoreTooltip = 'Restore view';\n @Input() ShowHeader = true;\n\n @Output() Maximize = new EventEmitter<void>();\n @Output() Restore = new EventEmitter<void>();\n\n @ContentChild(MJCardTitleDirective) TitleTemplate?: MJCardTitleDirective;\n @ContentChild(MJCardActionsDirective) ActionsTemplate?: MJCardActionsDirective;\n @ContentChild(MJCardToolsDirective) ToolsTemplate?: MJCardToolsDirective;\n @ContentChild(MJCardFooterDirective) FooterTemplate?: MJCardFooterDirective;\n\n public get IsMaximized(): boolean {\n if (this.grid) {\n return this.grid.IsCardMaximized(this.CardId);\n }\n return false;\n }\n\n public get IsHidden(): boolean {\n if (this.grid) {\n return this.grid.IsCardHidden(this.CardId);\n }\n return false;\n }\n\n public ngOnInit(): void {\n if (!this.CardId) {\n this.CardId = `mj-card-${++nextCardId}`;\n }\n if (this.grid) {\n this.sub = this.grid.maximizedCard$.subscribe(() => {\n this.cdr.markForCheck();\n });\n }\n }\n\n public ngOnDestroy(): void {\n this.sub?.unsubscribe();\n }\n\n public ToggleMaximize(event?: MouseEvent): void {\n if (event) {\n event.stopPropagation();\n }\n if (this.IsMaximized) {\n this.grid?.Restore();\n this.Restore.emit();\n } else {\n this.grid?.MaximizeCard(this.CardId);\n this.Maximize.emit();\n }\n this.cdr.markForCheck();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"card-grid.component.js","sourceRoot":"","sources":["../../../src/lib/card-grid/card-grid.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Directive,\n Input,\n Output,\n EventEmitter,\n TemplateRef,\n ContentChild,\n HostListener,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n inject,\n OnInit,\n OnDestroy,\n OnChanges,\n SimpleChanges\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { BehaviorSubject, Subscription } from 'rxjs';\n\nlet nextCardId = 0;\n\n/**\n * Directive to provide a custom template for the Card Title.\n */\n@Directive({\n selector: '[mjCardTitle]',\n standalone: true,\n})\nexport class MJCardTitleDirective {\n constructor(public templateRef: TemplateRef<unknown>) {} // case-violation-ok-legacy-back-compat: object literals are assigned to this class, so an accessor stub changes what they must supply\n}\n\n/**\n * Directive to provide custom action controls in the Card Header.\n */\n@Directive({\n selector: '[mjCardActions]',\n standalone: true,\n})\nexport class MJCardActionsDirective {\n constructor(public templateRef: TemplateRef<unknown>) {} // case-violation-ok-legacy-back-compat: object literals are assigned to this class, so an accessor stub changes what they must supply\n}\n\n/**\n * Directive to provide custom tools/badges in the Card Header.\n */\n@Directive({\n selector: '[mjCardTools]',\n standalone: true,\n})\nexport class MJCardToolsDirective {\n constructor(public templateRef: TemplateRef<unknown>) {} // case-violation-ok-legacy-back-compat: object literals are assigned to this class, so an accessor stub changes what they must supply\n}\n\n/**\n * Directive to provide a custom template for the Card Footer.\n */\n@Directive({\n selector: '[mjCardFooter]',\n standalone: true,\n})\nexport class MJCardFooterDirective {\n constructor(public templateRef: TemplateRef<unknown>) {} // case-violation-ok-legacy-back-compat: object literals are assigned to this class, so an accessor stub changes what they must supply\n}\n\nconst CARD_GRID_CSS = `\n:host {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-width: 0;\n box-sizing: border-box;\n}\n\n.mj-card-grid {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n align-items: stretch;\n gap: var(--mj-card-grid-gap, var(--mj-space-4, 16px));\n width: 100%;\n position: relative;\n box-sizing: border-box;\n transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.mj-card-grid--has-maximized {\n grid-template-columns: 1fr !important;\n}\n\n@media (max-width: 640px) {\n .mj-card-grid {\n grid-template-columns: 1fr !important;\n }\n}\n\nmj-card {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.mj-card {\n display: flex;\n flex-direction: column;\n flex: 1 1 100%;\n height: 100%;\n min-height: 290px;\n background: var(--mj-bg-surface-card, var(--mj-bg-surface, #141f33));\n border: 1px solid var(--mj-border-default, #2a3852);\n border-radius: var(--mj-radius-xl, 16px);\n box-shadow: var(--mj-shadow-sm, 0 1px 3px rgba(0, 0, 0, 0.08));\n padding: var(--mj-space-4, 16px) var(--mj-space-5, 20px);\n box-sizing: border-box;\n transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;\n position: relative;\n min-width: 0;\n}\n\n.mj-card:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary, #38bdf8) 40%, var(--mj-border-default, #2a3852));\n}\n\n.mj-card--maximized {\n grid-column: 1 / -1;\n width: 100%;\n min-height: 480px;\n box-shadow: var(--mj-shadow-lg, 0 10px 25px rgba(0, 0, 0, 0.25));\n border-color: var(--mj-brand-primary, #38bdf8);\n z-index: 10;\n}\n\n.mj-card--hidden {\n display: none !important;\n}\n\n.mj-card__header {\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--mj-space-3, 12px);\n margin-bottom: var(--mj-space-3, 12px);\n min-height: 28px;\n width: 100%;\n}\n\n.mj-card__title-group {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n flex: 1 1 auto;\n}\n\n.mj-card__title-row {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: var(--mj-space-2, 8px);\n min-width: 0;\n}\n\n.mj-card__icon {\n color: var(--mj-brand-primary, #38bdf8);\n font-size: 14px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.mj-card__title {\n font-size: 14px;\n font-weight: 700;\n color: var(--mj-text-primary, #ffffff);\n letter-spacing: -0.01em;\n margin: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-card__subtitle {\n font-size: 11.5px;\n font-weight: 500;\n color: var(--mj-text-muted, #94a3b8);\n margin: 0;\n padding-left: 22px;\n}\n\n.mj-card__actions {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: var(--mj-space-2, 8px);\n flex-shrink: 0;\n margin-left: auto;\n}\n\n.mj-card__toggle-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: var(--mj-radius-sm, 6px);\n background: transparent;\n border: 1px solid transparent;\n color: var(--mj-text-muted, #94a3b8);\n cursor: pointer;\n padding: 0;\n font-size: 12px;\n transition: all 0.15s ease;\n}\n\n.mj-card__toggle-btn:hover {\n color: var(--mj-text-primary, #ffffff);\n background: var(--mj-bg-surface-sunken, rgba(255, 255, 255, 0.06));\n border-color: var(--mj-border-default, #2a3852);\n}\n\n.mj-card__toggle-btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary, #38bdf8);\n outline-offset: 1px;\n}\n\n.mj-card__body {\n flex: 1 1 auto;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n min-width: 0;\n}\n\n.mj-card__footer {\n margin-top: auto;\n padding-top: var(--mj-space-3, 12px);\n border-top: 1px solid var(--mj-border-default, #2a3852);\n}\n`;\n\n/**\n * Responsive Card Grid container that manages responsive layout and card maximization state.\n */\n@Component({\n selector: 'mj-card-grid',\n standalone: true,\n imports: [CommonModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n styles: [CARD_GRID_CSS],\n template: `\n <div class=\"mj-card-grid\"\n [class.mj-card-grid--has-maximized]=\"!!MaximizedCardId\"\n [style.--mj-card-grid-columns]=\"Columns\"\n [style.--mj-card-grid-gap]=\"Gap\">\n <ng-content></ng-content>\n </div>\n `,\n})\nexport class MJCardGridComponent implements OnChanges {\n private cdr = inject(ChangeDetectorRef);\n\n /** Stream of the currently maximized card ID across all children. */\n public readonly MaximizedCard$ = new BehaviorSubject<string | null>(null);\n\n /** @deprecated Use {@link MaximizedCard$}. */\n public get maximizedCard$() {\n return this.MaximizedCard$;\n }\n\n /** Number of columns for standard layout (defaults to 2). */\n @Input() Columns: number | string = 2;\n\n /** CSS gap between cards (defaults to var(--mj-space-4)). */\n @Input() Gap = 'var(--mj-space-4, 16px)';\n\n /** Currently maximized card ID. When set, only this card is shown full-width. */\n @Input() MaximizedCardId: string | null = null;\n\n /** Emits when the maximized card ID changes (two-way binding support). */\n @Output() MaximizedCardIdChange = new EventEmitter<string | null>();\n\n /** Emits the card ID when a card is maximized. */\n @Output() CardMaximized = new EventEmitter<string>();\n\n /** Emits when the maximized card is restored back to the grid view. */\n @Output() CardRestored = new EventEmitter<void>();\n\n public ngOnChanges(changes: SimpleChanges): void {\n if (changes['MaximizedCardId'] && !changes['MaximizedCardId'].firstChange) {\n this.MaximizedCard$.next(this.MaximizedCardId);\n }\n }\n\n /** Pressing Escape restores the grid view if a card is maximized. */\n @HostListener('window:keydown.escape')\n public OnEscape(): void {\n if (this.MaximizedCardId) {\n this.Restore();\n }\n }\n\n public MaximizeCard(cardId: string): void {\n this.MaximizedCardId = cardId;\n this.MaximizedCard$.next(cardId);\n this.MaximizedCardIdChange.emit(cardId);\n this.CardMaximized.emit(cardId);\n this.cdr.markForCheck();\n }\n\n public Restore(): void {\n if (!this.MaximizedCardId) return;\n this.MaximizedCardId = null;\n this.MaximizedCard$.next(null);\n this.MaximizedCardIdChange.emit(null);\n this.CardRestored.emit();\n this.cdr.markForCheck();\n }\n\n public IsCardMaximized(cardId: string): boolean {\n return this.MaximizedCardId === cardId;\n }\n\n public IsCardHidden(cardId: string): boolean {\n return !!this.MaximizedCardId && this.MaximizedCardId !== cardId;\n }\n}\n\n/**\n * Modular card component with header title, icon, actions, and maximize/restore capability.\n */\n@Component({\n selector: 'mj-card',\n standalone: true,\n imports: [CommonModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n styles: [CARD_GRID_CSS],\n template: `\n <div class=\"mj-card\"\n [class.mj-card--maximized]=\"IsMaximized\"\n [class.mj-card--hidden]=\"IsHidden\"\n role=\"region\"\n [attr.aria-label]=\"Title || 'Card'\">\n \n <!-- Card Header -->\n @if (ShowHeader) {\n <div class=\"mj-card__header\">\n <div class=\"mj-card__title-group\">\n <div class=\"mj-card__title-row\">\n @if (Icon) {\n <span class=\"mj-card__icon\" aria-hidden=\"true\">\n <i [class]=\"Icon\"></i>\n </span>\n }\n @if (TitleTemplate) {\n <ng-container [ngTemplateOutlet]=\"TitleTemplate.templateRef\"></ng-container>\n } @else if (Title) {\n <h3 class=\"mj-card__title\">{{ Title }}</h3>\n }\n </div>\n @if (Subtitle) {\n <span class=\"mj-card__subtitle\">{{ Subtitle }}</span>\n }\n </div>\n\n <div class=\"mj-card__actions\">\n @if (ToolsTemplate) {\n <ng-container [ngTemplateOutlet]=\"ToolsTemplate.templateRef\"></ng-container>\n }\n @if (ActionsTemplate) {\n <ng-container [ngTemplateOutlet]=\"ActionsTemplate.templateRef\"></ng-container>\n }\n @if (AllowMaximize) {\n <button type=\"button\"\n class=\"mj-card__toggle-btn\"\n [title]=\"IsMaximized ? RestoreTooltip : MaximizeTooltip\"\n [attr.aria-label]=\"IsMaximized ? RestoreTooltip : MaximizeTooltip\"\n (click)=\"ToggleMaximize($event)\">\n @if (IsMaximized) {\n <i class=\"fa-solid fa-compress\" aria-hidden=\"true\"></i>\n } @else {\n <i class=\"fa-solid fa-expand\" aria-hidden=\"true\"></i>\n }\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Card Body -->\n <div class=\"mj-card__body\">\n <ng-content></ng-content>\n </div>\n\n <!-- Card Footer -->\n @if (FooterTemplate) {\n <div class=\"mj-card__footer\">\n <ng-container [ngTemplateOutlet]=\"FooterTemplate.templateRef\"></ng-container>\n </div>\n }\n </div>\n `,\n})\nexport class MJCardComponent implements OnInit, OnDestroy {\n private grid = inject(MJCardGridComponent, { optional: true });\n private cdr = inject(ChangeDetectorRef);\n private sub?: Subscription;\n\n @Input() CardId = `mj-card-${++nextCardId}`;\n @Input() Title?: string;\n @Input() Subtitle?: string;\n @Input() Icon?: string;\n @Input() AllowMaximize = true;\n @Input() MaximizeTooltip = 'Expand card';\n @Input() RestoreTooltip = 'Restore view';\n @Input() ShowHeader = true;\n\n @Output() Maximize = new EventEmitter<void>();\n @Output() Restore = new EventEmitter<void>();\n\n @ContentChild(MJCardTitleDirective) TitleTemplate?: MJCardTitleDirective;\n @ContentChild(MJCardActionsDirective) ActionsTemplate?: MJCardActionsDirective;\n @ContentChild(MJCardToolsDirective) ToolsTemplate?: MJCardToolsDirective;\n @ContentChild(MJCardFooterDirective) FooterTemplate?: MJCardFooterDirective;\n\n public get IsMaximized(): boolean {\n if (this.grid) {\n return this.grid.IsCardMaximized(this.CardId);\n }\n return false;\n }\n\n public get IsHidden(): boolean {\n if (this.grid) {\n return this.grid.IsCardHidden(this.CardId);\n }\n return false;\n }\n\n public ngOnInit(): void {\n if (!this.CardId) {\n this.CardId = `mj-card-${++nextCardId}`;\n }\n if (this.grid) {\n this.sub = this.grid.maximizedCard$.subscribe(() => {\n this.cdr.markForCheck();\n });\n }\n }\n\n public ngOnDestroy(): void {\n this.sub?.unsubscribe();\n }\n\n public ToggleMaximize(event?: MouseEvent): void {\n if (event) {\n event.stopPropagation();\n }\n if (this.IsMaximized) {\n this.grid?.Restore();\n this.Restore.emit();\n } else {\n this.grid?.MaximizeCard(this.CardId);\n this.Maximize.emit();\n }\n this.cdr.markForCheck();\n }\n}\n"]}
|
|
@@ -45,9 +45,17 @@ export declare class MJClickableDirective implements AfterContentInit {
|
|
|
45
45
|
/** ARIA role to expose. `'button'` (default) for actions, `'link'` for navigation-like targets. */
|
|
46
46
|
role: MjClickableRole;
|
|
47
47
|
/** Optional stable automation/test hook emitted as `data-testid` (no convention enforced here). */
|
|
48
|
-
|
|
48
|
+
TestId?: string;
|
|
49
|
+
/** @deprecated Use {@link TestId}. */
|
|
50
|
+
set testId(value: string | undefined);
|
|
51
|
+
/** @deprecated Use {@link TestId}. */
|
|
52
|
+
get testId(): string | undefined;
|
|
49
53
|
/** Set `false` to skip making the element keyboard-focusable (rare; e.g. focus handled elsewhere). */
|
|
50
|
-
|
|
54
|
+
Focusable: boolean;
|
|
55
|
+
/** @deprecated Use {@link Focusable}. */
|
|
56
|
+
set focusable(value: MJClickableDirective['Focusable']);
|
|
57
|
+
/** @deprecated Use {@link Focusable}. */
|
|
58
|
+
get focusable(): MJClickableDirective['Focusable'];
|
|
51
59
|
constructor(host: ElementRef<HTMLElement>);
|
|
52
60
|
get roleAttr(): string;
|
|
53
61
|
get tabIndexAttr(): string | null;
|
|
@@ -63,6 +71,6 @@ export declare class MJClickableDirective implements AfterContentInit {
|
|
|
63
71
|
/** Dev-only guard: warn when the control ends up with no accessible name. No-op in production. */
|
|
64
72
|
ngAfterContentInit(): void;
|
|
65
73
|
static ɵfac: i0.ɵɵFactoryDeclaration<MJClickableDirective, never>;
|
|
66
|
-
static ɵdir: i0.ɵɵDirectiveDeclaration<MJClickableDirective, "[mjClickable]", never, { "label": { "alias": "mjClickable"; "required": false; }; "role": { "alias": "role"; "required": false; }; "testId": { "alias": "testId"; "required": false; }; "focusable": { "alias": "focusable"; "required": false; }; }, {}, never, never, true, never>;
|
|
74
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<MJClickableDirective, "[mjClickable]", never, { "label": { "alias": "mjClickable"; "required": false; }; "role": { "alias": "role"; "required": false; }; "TestId": { "alias": "TestId"; "required": false; }; "testId": { "alias": "testId"; "required": false; }; "Focusable": { "alias": "Focusable"; "required": false; }; "focusable": { "alias": "focusable"; "required": false; }; }, {}, never, never, true, never>;
|
|
67
75
|
}
|
|
68
76
|
//# sourceMappingURL=clickable.directive.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clickable.directive.d.ts","sourceRoot":"","sources":["../../../src/lib/clickable/clickable.directive.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,UAAU,EACV,gBAAgB,EAEjB,MAAM,eAAe,CAAC;;AAEvB,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAIa,oBAAqB,YAAW,gBAAgB;
|
|
1
|
+
{"version":3,"file":"clickable.directive.d.ts","sourceRoot":"","sources":["../../../src/lib/clickable/clickable.directive.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,UAAU,EACV,gBAAgB,EAEjB,MAAM,eAAe,CAAC;;AAEvB,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAIa,oBAAqB,YAAW,gBAAgB;IAsC/C,OAAO,CAAC,QAAQ,CAAC,IAAI;IArCjC;;;;;OAKG;IACmB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAM;IAE5D,mGAAmG;IAC1F,IAAI,EAAE,eAAe,CAAY;IAE1C,mGAAmG;IAC1F,MAAM,CAAC,EAAE,MAAM,CAAC;IAEzB,sCAAsC;IACtC,IAAa,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAE5C;IACD,sCAAsC;IACtC,IAAI,MAAM,IAAI,MAAM,GAAG,SAAS,CAE/B;IAED,sGAAsG;IAC7F,SAAS,UAAQ;IAE1B,yCAAyC;IACzC,IAAa,SAAS,CAAC,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EAE9D;IACD,yCAAyC;IACzC,IAAI,SAAS,IAAI,oBAAoB,CAAC,WAAW,CAAC,CAEjD;gBAI4B,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC;IAE1D,IAA8B,QAAQ,IAAI,MAAM,CAE/C;IACD,IAAkC,YAAY,IAAI,MAAM,GAAG,IAAI,CAE9D;IACD,IAAoC,aAAa,IAAI,MAAM,GAAG,IAAI,CAEjE;IACD,IAAqC,UAAU,IAAI,MAAM,GAAG,IAAI,CAE/D;IAED;;;;;OAKG;IAEH,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAOrC,kGAAkG;IAClG,kBAAkB,IAAI,IAAI;yCApEf,oBAAoB;2CAApB,oBAAoB;CAiFhC"}
|
|
@@ -44,9 +44,25 @@ export class MJClickableDirective {
|
|
|
44
44
|
/** ARIA role to expose. `'button'` (default) for actions, `'link'` for navigation-like targets. */
|
|
45
45
|
role = 'button';
|
|
46
46
|
/** Optional stable automation/test hook emitted as `data-testid` (no convention enforced here). */
|
|
47
|
-
|
|
47
|
+
TestId;
|
|
48
|
+
/** @deprecated Use {@link TestId}. */
|
|
49
|
+
set testId(value) {
|
|
50
|
+
this.TestId = value;
|
|
51
|
+
}
|
|
52
|
+
/** @deprecated Use {@link TestId}. */
|
|
53
|
+
get testId() {
|
|
54
|
+
return this.TestId;
|
|
55
|
+
}
|
|
48
56
|
/** Set `false` to skip making the element keyboard-focusable (rare; e.g. focus handled elsewhere). */
|
|
49
|
-
|
|
57
|
+
Focusable = true;
|
|
58
|
+
/** @deprecated Use {@link Focusable}. */
|
|
59
|
+
set focusable(value) {
|
|
60
|
+
this.Focusable = value;
|
|
61
|
+
}
|
|
62
|
+
/** @deprecated Use {@link Focusable}. */
|
|
63
|
+
get focusable() {
|
|
64
|
+
return this.Focusable;
|
|
65
|
+
}
|
|
50
66
|
// Constructor injection (not inject()) so the directive can be unit-tested via direct
|
|
51
67
|
// instantiation with a stub ElementRef — the established pattern in this package's specs.
|
|
52
68
|
constructor(host) {
|
|
@@ -56,13 +72,13 @@ export class MJClickableDirective {
|
|
|
56
72
|
return this.role;
|
|
57
73
|
}
|
|
58
74
|
get tabIndexAttr() {
|
|
59
|
-
return this.
|
|
75
|
+
return this.Focusable ? '0' : null;
|
|
60
76
|
}
|
|
61
77
|
get ariaLabelAttr() {
|
|
62
78
|
return this.label?.trim() ? this.label.trim() : null;
|
|
63
79
|
}
|
|
64
80
|
get testIdAttr() {
|
|
65
|
-
return this.
|
|
81
|
+
return this.TestId ?? null;
|
|
66
82
|
}
|
|
67
83
|
/**
|
|
68
84
|
* Keyboard activation: Enter / Space activate a `role="button"`/`"link"` exactly as they would a
|
|
@@ -92,7 +108,7 @@ export class MJClickableDirective {
|
|
|
92
108
|
i0.ɵɵlistener("keydown", function MJClickableDirective_keydown_HostBindingHandler($event) { return ctx.onKeydown($event); });
|
|
93
109
|
} if (rf & 2) {
|
|
94
110
|
i0.ɵɵattribute("role", ctx.roleAttr)("tabindex", ctx.tabIndexAttr)("aria-label", ctx.ariaLabelAttr)("data-testid", ctx.testIdAttr);
|
|
95
|
-
} }, inputs: { label: [0, "mjClickable", "label"], role: "role", testId: "testId", focusable: "focusable" } });
|
|
111
|
+
} }, inputs: { label: [0, "mjClickable", "label"], role: "role", TestId: "TestId", testId: "testId", Focusable: "Focusable", focusable: "focusable" } });
|
|
96
112
|
}
|
|
97
113
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJClickableDirective, [{
|
|
98
114
|
type: Directive,
|
|
@@ -105,8 +121,12 @@ export class MJClickableDirective {
|
|
|
105
121
|
args: ['mjClickable']
|
|
106
122
|
}], role: [{
|
|
107
123
|
type: Input
|
|
124
|
+
}], TestId: [{
|
|
125
|
+
type: Input
|
|
108
126
|
}], testId: [{
|
|
109
127
|
type: Input
|
|
128
|
+
}], Focusable: [{
|
|
129
|
+
type: Input
|
|
110
130
|
}], focusable: [{
|
|
111
131
|
type: Input
|
|
112
132
|
}], roleAttr: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clickable.directive.js","sourceRoot":"","sources":["../../../src/lib/clickable/clickable.directive.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,EACL,WAAW,EACX,YAAY,EAGZ,SAAS,EACV,MAAM,eAAe,CAAC;;AAIvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,MAAM,OAAO,oBAAoB;
|
|
1
|
+
{"version":3,"file":"clickable.directive.js","sourceRoot":"","sources":["../../../src/lib/clickable/clickable.directive.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Directive,\n Input,\n HostBinding,\n HostListener,\n ElementRef,\n AfterContentInit,\n isDevMode\n} from '@angular/core';\n\nexport type MjClickableRole = 'button' | 'link';\n\n/**\n * mjClickable — Attribute directive that upgrades a non-semantic element (a `<div>`/`<span>` that\n * has a `(click)` handler) into a proper, accessible, keyboard-operable control **without changing\n * its tag or styling**.\n *\n * ## Why this exists\n * A `<div (click)=\"…\">` is invisible as a control to anyone (and anything) that consumes the\n * **accessibility tree** rather than pixels:\n * - screen-reader and keyboard users can't reach or operate it (no role, no focus, no Enter/Space);\n * - DOM/accessibility-tree AI agents (e.g. computer-use driving a live browser) can't enumerate it\n * as a clickable or find it by name — it resolves to `role=generic` with no accessible name.\n *\n * Converting such a `<div>` to a native `<button>` is the ideal fix, but often forces CSS churn for\n * already-styled tiles/rows. `mjClickable` is the low-risk alternative: it keeps the element and its\n * styles, and adds the missing semantics — `role`, `tabindex`, an accessible name (`aria-label`),\n * Enter/Space activation (which dispatches a native `click`, so your existing `(click)` handler runs\n * for both mouse and keyboard), and an optional stable `data-testid` automation hook.\n *\n * Prefer a real `<button mjButton>`/`<a>` for NEW markup; reach for `mjClickable` to retrofit existing\n * clickable `<div>`/`<span>` widgets (nav tiles, list rows, cards) cheaply.\n *\n * @example\n * ```html\n * <!-- Retrofit a clickable app tile: stays a styled <div>, becomes a named, keyboard-operable button -->\n * <div class=\"app-card\" [mjClickable]=\"app.Name\" [testId]=\"'app-tile-' + app.Name\" (click)=\"open(app)\">\n * …icon + name + description…\n * </div>\n *\n * <!-- A navigation-style row -->\n * <div class=\"nav-item\" [mjClickable]=\"item.Label\" role=\"link\" (click)=\"navigate(item)\">…</div>\n * ```\n */\n@Directive({\n selector: '[mjClickable]',\n standalone: true\n})\nexport class MJClickableDirective implements AfterContentInit {\n /**\n * Accessible name for the control, surfaced as `aria-label`. Pass the human-meaningful label\n * (e.g. the app/nav-item name). Strongly recommended — without it the control is operable but\n * unnamed, so agents/AT can reach it but can't identify it. When omitted, the element's own\n * visible text becomes the name (fine when the text alone is unambiguous).\n */\n @Input('mjClickable') label: string | null | undefined = '';\n\n /** ARIA role to expose. `'button'` (default) for actions, `'link'` for navigation-like targets. */\n @Input() role: MjClickableRole = 'button';\n\n /** Optional stable automation/test hook emitted as `data-testid` (no convention enforced here). */\n @Input() TestId?: string;\n\n /** @deprecated Use {@link TestId}. */\n @Input() set testId(value: string | undefined) {\n this.TestId = value;\n }\n /** @deprecated Use {@link TestId}. */\n get testId(): string | undefined {\n return this.TestId;\n }\n\n /** Set `false` to skip making the element keyboard-focusable (rare; e.g. focus handled elsewhere). */\n @Input() Focusable = true;\n\n /** @deprecated Use {@link Focusable}. */\n @Input() set focusable(value: MJClickableDirective['Focusable']) {\n this.Focusable = value;\n }\n /** @deprecated Use {@link Focusable}. */\n get focusable(): MJClickableDirective['Focusable'] {\n return this.Focusable;\n }\n\n // Constructor injection (not inject()) so the directive can be unit-tested via direct\n // instantiation with a stub ElementRef — the established pattern in this package's specs.\n constructor(private readonly host: ElementRef<HTMLElement>) {}\n\n @HostBinding('attr.role') get roleAttr(): string {\n return this.role;\n }\n @HostBinding('attr.tabindex') get tabIndexAttr(): string | null {\n return this.Focusable ? '0' : null;\n }\n @HostBinding('attr.aria-label') get ariaLabelAttr(): string | null {\n return this.label?.trim() ? this.label.trim() : null;\n }\n @HostBinding('attr.data-testid') get testIdAttr(): string | null {\n return this.TestId ?? null;\n }\n\n /**\n * Keyboard activation: Enter / Space activate a `role=\"button\"`/`\"link\"` exactly as they would a\n * native control. We `preventDefault` (Space would otherwise scroll the page) and dispatch a native\n * `click`, so the element's existing `(click)` binding handles both mouse and keyboard with no\n * duplicate wiring.\n */\n @HostListener('keydown', ['$event'])\n onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Enter' || event.key === ' ' || event.key === 'Spacebar') {\n event.preventDefault();\n this.host.nativeElement.click();\n }\n }\n\n /** Dev-only guard: warn when the control ends up with no accessible name. No-op in production. */\n ngAfterContentInit(): void {\n if (!isDevMode()) {\n return;\n }\n const hasName = !!(this.label?.trim() || (this.host.nativeElement.textContent ?? '').trim());\n if (!hasName) {\n console.warn(\n '[mjClickable] element has no accessible name — pass mjClickable=\"<name>\" so screen readers ' +\n 'and computer-use agents can identify it.',\n this.host.nativeElement\n );\n }\n }\n}\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { EventEmitter, ElementRef, TemplateRef, OnDestroy } from '@angular/core';
|
|
1
|
+
import { AfterViewInit, EventEmitter, ElementRef, 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-combobox — Editable dropdown with filtering and optional custom values.
|
|
@@ -9,6 +10,20 @@ import * as i0 from "@angular/core";
|
|
|
9
10
|
* that filters the list as you type. When AllowCustom is true, typed text that
|
|
10
11
|
* doesn't match any item is emitted as the value.
|
|
11
12
|
*
|
|
13
|
+
* Every combobox needs an ACCESSIBLE NAME, or it announces as "combobox, collapsed" with no hint of
|
|
14
|
+
* what it selects (WCAG 2.1 4.1.2). Use {@link MJNamedControlBase.AriaLabelledBy} when a visible
|
|
15
|
+
* label already exists and {@link MJNamedControlBase.AriaLabel} when none does. Here the trigger is
|
|
16
|
+
* a real `<input>`, so {@link MJNamedControlBase.InputId} IS a valid `<label for>` target — unlike
|
|
17
|
+
* `mj-dropdown`, whose trigger is a div.
|
|
18
|
+
*
|
|
19
|
+
* @example With a visible label (preferred)
|
|
20
|
+
* ```html
|
|
21
|
+
* <span id="category-label">Category</span>
|
|
22
|
+
* <mj-combobox AriaLabelledBy="category-label" [Data]="categories" TextField="text"
|
|
23
|
+
* ValueField="value" [(ngModel)]="selectedCategory" [ValuePrimitive]="true">
|
|
24
|
+
* </mj-combobox>
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
12
27
|
* @example
|
|
13
28
|
* ```html
|
|
14
29
|
* <mj-combobox
|
|
@@ -23,7 +38,7 @@ import * as i0 from "@angular/core";
|
|
|
23
38
|
* </mj-combobox>
|
|
24
39
|
* ```
|
|
25
40
|
*/
|
|
26
|
-
export declare class MJComboboxComponent implements ControlValueAccessor, OnDestroy {
|
|
41
|
+
export declare class MJComboboxComponent extends MJNamedControlBase implements ControlValueAccessor, AfterViewInit, OnDestroy {
|
|
27
42
|
set Data(value: Record<string, unknown>[] | string[] | readonly unknown[] | null);
|
|
28
43
|
get Data(): Record<string, unknown>[] | string[] | readonly unknown[] | null;
|
|
29
44
|
private _data;
|
|
@@ -61,6 +76,31 @@ export declare class MJComboboxComponent implements ControlValueAccessor, OnDest
|
|
|
61
76
|
TriggerWidth: number;
|
|
62
77
|
InputText: string;
|
|
63
78
|
Positions: ConnectedPosition[];
|
|
79
|
+
/**
|
|
80
|
+
* Id of the popup listbox, so the input can point `aria-controls` at it while open — the half of
|
|
81
|
+
* the combobox pattern that makes "collapsed/expanded" refer to something a screen reader can
|
|
82
|
+
* find.
|
|
83
|
+
*/
|
|
84
|
+
get ListboxId(): string;
|
|
85
|
+
/** Id of one rendered option, referenced by {@link ActiveDescendantId}. */
|
|
86
|
+
OptionId(index: number): string;
|
|
87
|
+
/**
|
|
88
|
+
* `aria-activedescendant` for the input: the option the arrow keys have moved to. Focus stays in
|
|
89
|
+
* the input the whole time, so without this the highlight is a CSS class and nothing else — a
|
|
90
|
+
* screen-reader user arrowing through the list hears no change at all.
|
|
91
|
+
*/
|
|
92
|
+
get ActiveDescendantId(): string | null;
|
|
93
|
+
/** `aria-labelledby` id list for the clear button when a VISIBLE label names the combobox. */
|
|
94
|
+
get ClearLabelledBy(): string;
|
|
95
|
+
/** `aria-label` for the clear button in the no-visible-label case. */
|
|
96
|
+
get ClearLabel(): string;
|
|
97
|
+
/** `aria-labelledby` id list for the toggle button when a VISIBLE label names the combobox. */
|
|
98
|
+
get ToggleLabelledBy(): string;
|
|
99
|
+
/**
|
|
100
|
+
* `aria-label` for the toggle button in the no-visible-label case. It had no name at all before
|
|
101
|
+
* #4116 — an unnamed button next to a named input, which announces as "button".
|
|
102
|
+
*/
|
|
103
|
+
get ToggleLabel(): string;
|
|
64
104
|
private onChange;
|
|
65
105
|
private onTouched;
|
|
66
106
|
private isBlurring;
|
|
@@ -95,7 +135,7 @@ export declare class MJComboboxComponent implements ControlValueAccessor, OnDest
|
|
|
95
135
|
private syncDisabled;
|
|
96
136
|
SelectItem(item: unknown, event?: Event): void;
|
|
97
137
|
/** Commit the current input text as a value (for AllowCustom or matching item) */
|
|
98
|
-
private
|
|
138
|
+
private commitValue;
|
|
99
139
|
IsItemSelected(item: unknown): boolean;
|
|
100
140
|
OnKeyDown(event: KeyboardEvent): void;
|
|
101
141
|
GetItemText(item: unknown): string;
|
|
@@ -105,6 +145,7 @@ export declare class MJComboboxComponent implements ControlValueAccessor, OnDest
|
|
|
105
145
|
registerOnChange(fn: (value: unknown) => void): void;
|
|
106
146
|
registerOnTouched(fn: () => void): void;
|
|
107
147
|
setDisabledState(isDisabled: boolean): void;
|
|
148
|
+
ngAfterViewInit(): void;
|
|
108
149
|
ngOnDestroy(): void;
|
|
109
150
|
private getDisplayText;
|
|
110
151
|
private getSelectedIndex;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combobox.component.d.ts","sourceRoot":"","sources":["../../../src/lib/combobox/combobox.component.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"combobox.component.d.ts","sourceRoot":"","sources":["../../../src/lib/combobox/combobox.component.ts"],"names":[],"mappings":"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"}
|