@memberjunction/ng-base-forms 5.10.1 → 5.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -531,11 +531,11 @@ export class MjRecordFormContainerComponent {
531
531
  i0.ɵɵconditional(ctx.ShowListManagement && ctx.EffectiveRecord ? 10 : -1);
532
532
  i0.ɵɵadvance();
533
533
  i0.ɵɵproperty("Sections", ctx.SectionManagerItems)("SectionOrder", ctx.SectionManagerOrder)("Visible", ctx.ShowSectionManager);
534
- } }, dependencies: [i1.RecordChangesComponent, i2.ListManagementDialogComponent, i3.MjFormToolbarComponent, i4.MjSectionManagerComponent, i5.MjIsaRelatedPanelComponent], styles: ["/* ============================================\n RECORD FORM CONTAINER\n Top-level wrapper: toolbar + scrollable content\n ============================================ */\nmj-record-form-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n position: relative;\n overflow: hidden;\n}\n\n/* ViewEncapsulation.None fallback \u2014 ensure the element itself constrains overflow */\nmj-record-form-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n position: relative;\n overflow: hidden;\n}\n\n/* ============================================\n SCROLL AREA (full-width so mouse wheel works anywhere)\n ============================================ */\n.mj-forms-scroll-area {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n background: #eef0f3;\n}\n\n/* ============================================\n PANELS CONTAINER (centered content within scroll area)\n ============================================ */\n.mj-forms-panels-container {\n padding: 24px 32px 48px;\n max-width: 920px;\n margin: 0 auto;\n width: 100%;\n box-sizing: border-box;\n}\n\n/* Widen max-width when ISA side panel is present */\n.mj-forms-panels--has-isa-panel {\n max-width: 1240px;\n}\n\n.mj-forms-panels--full-width {\n max-width: none;\n padding-left: 24px;\n padding-right: 24px;\n}\n\n/* Flex row layout: form panels + optional ISA side panel */\n.mj-forms-layout-row {\n display: flex;\n gap: 20px;\n align-items: flex-start;\n}\n\n/* All panels in a single flex container \u2014 CSS order drives sequencing */\n.mj-forms-all-panels {\n display: flex;\n flex-direction: column;\n gap: 16px;\n flex: 1;\n min-width: 0;\n}\n\n/* Hide related entity panels in edit mode (variant host class on mj-collapsible-panel) */\n.mj-forms-panels--edit-mode .mj-panel--related-entity {\n display: none;\n}\n\n/* ============================================\n EMPTY SEARCH STATE\n ============================================ */\n.mj-forms-empty-search-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 80px 24px;\n text-align: center;\n min-height: 400px;\n}\n\n.mj-forms-empty-search-icon {\n width: 80px;\n height: 80px;\n border-radius: 50%;\n background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 24px;\n}\n\n.mj-forms-empty-search-icon i {\n font-size: 32px;\n color: #9ca3af;\n}\n\n.mj-forms-empty-search-title {\n font-size: 20px;\n font-weight: 600;\n color: #1f2937;\n margin: 0 0 12px 0;\n}\n\n.mj-forms-empty-search-message {\n font-size: 14px;\n color: #6b7280;\n line-height: 1.6;\n max-width: 400px;\n margin: 0;\n}\n\n.mj-forms-empty-search-message strong {\n color: #374151;\n font-weight: 600;\n}\n\n.mj-forms-empty-search-link {\n color: #667eea;\n text-decoration: none;\n font-weight: 500;\n}\n\n.mj-forms-empty-search-link:hover {\n text-decoration: underline;\n}\n\n/* ============================================\n RESPONSIVE\n ============================================ */\n@media (max-width: 768px) {\n .mj-forms-panels-container {\n padding: 16px 12px 32px;\n }\n}\n"], encapsulation: 2, changeDetection: 0 });
534
+ } }, dependencies: [i1.RecordChangesComponent, i2.ListManagementDialogComponent, i3.MjFormToolbarComponent, i4.MjSectionManagerComponent, i5.MjIsaRelatedPanelComponent], styles: ["/* ============================================\n RECORD FORM CONTAINER \u2014 uses global --mj-* design tokens\n Top-level wrapper: toolbar + scrollable content\n ============================================ */\nmj-record-form-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n position: relative;\n overflow: hidden;\n}\n\n/* ViewEncapsulation.None fallback \u2014 ensure the element itself constrains overflow */\nmj-record-form-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n position: relative;\n overflow: hidden;\n}\n\n/* ============================================\n SCROLL AREA (full-width so mouse wheel works anywhere)\n ============================================ */\n.mj-forms-scroll-area {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n background: var(--mj-bg-page);\n}\n\n/* ============================================\n PANELS CONTAINER (centered content within scroll area)\n ============================================ */\n.mj-forms-panels-container {\n padding: 24px 32px 48px;\n max-width: 920px;\n margin: 0 auto;\n width: 100%;\n box-sizing: border-box;\n}\n\n/* Widen max-width when ISA side panel is present */\n.mj-forms-panels--has-isa-panel {\n max-width: 1240px;\n}\n\n.mj-forms-panels--full-width {\n max-width: none;\n padding-left: 24px;\n padding-right: 24px;\n}\n\n/* Flex row layout: form panels + optional ISA side panel */\n.mj-forms-layout-row {\n display: flex;\n gap: 20px;\n align-items: flex-start;\n}\n\n/* All panels in a single flex container \u2014 CSS order drives sequencing */\n.mj-forms-all-panels {\n display: flex;\n flex-direction: column;\n gap: 16px;\n flex: 1;\n min-width: 0;\n}\n\n/* Hide related entity panels in edit mode (variant host class on mj-collapsible-panel) */\n.mj-forms-panels--edit-mode .mj-panel--related-entity {\n display: none;\n}\n\n/* ============================================\n EMPTY SEARCH STATE\n ============================================ */\n.mj-forms-empty-search-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 80px 24px;\n text-align: center;\n min-height: 400px;\n}\n\n.mj-forms-empty-search-icon {\n width: 80px;\n height: 80px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-sunken);\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 24px;\n}\n\n.mj-forms-empty-search-icon i {\n font-size: 32px;\n color: var(--mj-text-muted);\n}\n\n.mj-forms-empty-search-title {\n font-size: var(--mj-text-xl);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n margin: 0 0 12px 0;\n}\n\n.mj-forms-empty-search-message {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n line-height: 1.6;\n max-width: 400px;\n margin: 0;\n}\n\n.mj-forms-empty-search-message strong {\n color: var(--mj-text-primary);\n font-weight: var(--mj-font-semibold);\n}\n\n.mj-forms-empty-search-link {\n color: var(--mj-brand-primary);\n text-decoration: none;\n font-weight: var(--mj-font-medium);\n}\n\n.mj-forms-empty-search-link:hover {\n text-decoration: underline;\n}\n\n/* ============================================\n RESPONSIVE\n ============================================ */\n@media (max-width: 768px) {\n .mj-forms-panels-container {\n padding: 16px 12px 32px;\n }\n}\n"], encapsulation: 2, changeDetection: 0 });
535
535
  }
536
536
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MjRecordFormContainerComponent, [{
537
537
  type: Component,
538
- args: [{ standalone: false, selector: 'mj-record-form-container', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<!-- ============================================\n BEFORE-TOOLBAR SLOT\n ============================================ -->\n<ng-content select=\"[before-toolbar]\"></ng-content>\n\n<!-- ============================================\n TOOLBAR (bridges FormComponent state \u2192 toolbar inputs)\n ============================================ -->\n<mj-form-toolbar\n [Record]=\"EffectiveRecord\"\n [EditMode]=\"EffectiveEditMode\"\n [UserCanEdit]=\"EffectiveUserCanEdit\"\n [UserCanDelete]=\"EffectiveUserCanDelete\"\n [IsFavorite]=\"EffectiveIsFavorite\"\n [FavoriteInitDone]=\"EffectiveFavoriteInitDone\"\n [IsDirty]=\"EffectiveIsDirty\"\n [DirtyFieldNames]=\"EffectiveDirtyFieldNames\"\n [ListCount]=\"ListCount\"\n [EntityInfo]=\"EffectiveEntityInfo\"\n [Config]=\"ToolbarConfig\"\n [IsSaving]=\"EffectiveIsSaving\"\n [VisibleSectionCount]=\"VisibleSectionCount\"\n [TotalSectionCount]=\"TotalSectionCount\"\n [ExpandedSectionCount]=\"ExpandedSectionCount\"\n [SearchFilter]=\"EffectiveSearchFilter\"\n [ShowEmptyFields]=\"EffectiveShowEmptyFields\"\n [WidthMode]=\"EffectiveWidthMode\"\n [HasCustomSectionOrder]=\"EffectiveHasCustomSectionOrder\"\n (Navigate)=\"OnNavigate($event)\"\n (EditModeChange)=\"OnEditModeChange($event)\"\n (BeforeSave)=\"BeforeSave.emit($event)\"\n (SaveRequested)=\"OnSaveRequested()\"\n (BeforeCancel)=\"BeforeCancel.emit($event)\"\n (CancelRequested)=\"OnCancelRequested()\"\n (BeforeDelete)=\"BeforeDelete.emit($event)\"\n (DeleteRequested)=\"OnDeleteRequested()\"\n (FavoriteToggled)=\"OnFavoriteToggled()\"\n (BeforeHistoryView)=\"BeforeHistoryView.emit($event)\"\n (HistoryRequested)=\"OnHistoryRequested()\"\n (BeforeListManagement)=\"BeforeListManagement.emit($event)\"\n (ListManagementRequested)=\"OnListManagementRequested()\"\n (ShowChangesRequested)=\"OnShowChangesRequested()\"\n (CustomButtonClick)=\"CustomButtonClick.emit($event)\"\n (FilterChange)=\"OnFilterChange($event)\"\n (ExpandAllRequested)=\"OnExpandAll()\"\n (CollapseAllRequested)=\"OnCollapseAll()\"\n (ShowEmptyFieldsChange)=\"OnShowEmptyFieldsChange($event)\"\n (WidthModeChange)=\"OnWidthModeChange($event)\"\n (ResetSectionOrderRequested)=\"OnResetSectionOrder()\"\n (ManageSectionsRequested)=\"OnManageSections()\">\n</mj-form-toolbar>\n\n<!-- ============================================\n SCROLL AREA (full-width so mouse wheel works anywhere)\n ============================================ -->\n<div class=\"mj-forms-scroll-area\">\n <div class=\"mj-forms-panels-container\"\n [class.mj-forms-panels--full-width]=\"EffectiveWidthMode === 'full-width'\"\n [class.mj-forms-panels--edit-mode]=\"EffectiveEditMode\"\n [class.mj-forms-panels--has-isa-panel]=\"HasIsaRelatedItems\">\n <!-- Flex row: form panels on left, ISA side panel on right -->\n <div class=\"mj-forms-layout-row\">\n <!-- All panels in a single flex container \u2014 CSS order drives sequencing -->\n <div class=\"mj-forms-all-panels\">\n <ng-content></ng-content>\n\n <!-- Empty state when no sections match search -->\n @if (EffectiveSearchFilter && VisibleSectionCount === 0) {\n <div class=\"mj-forms-empty-search-state\">\n <div class=\"mj-forms-empty-search-icon\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n </div>\n <h3 class=\"mj-forms-empty-search-title\">No sections found</h3>\n <p class=\"mj-forms-empty-search-message\">\n No sections match \"<strong>{{ EffectiveSearchFilter }}</strong>\".\n <br>Try a different search term or <a href=\"#\" (click)=\"OnFilterChange(''); $event.preventDefault()\" class=\"mj-forms-empty-search-link\">clear the search</a>.\n </p>\n </div>\n }\n </div>\n\n <!-- IS-A Related Records Side Panel -->\n <mj-isa-related-panel\n [Record]=\"EffectiveRecord\"\n [EditMode]=\"EffectiveEditMode\"\n [Collapsed]=\"EffectiveWidthMode === 'full-width'\"\n (Navigate)=\"OnNavigate($event)\">\n </mj-isa-related-panel>\n </div>\n </div>\n</div>\n\n<!-- ============================================\n RECORD CHANGES DRAWER (shown when history button clicked)\n ============================================ -->\n@if (ShowRecordChanges && EffectiveRecord) {\n <mj-record-changes\n [record]=\"EffectiveRecord\"\n (dialogClosed)=\"OnRecordChangesClosed()\">\n </mj-record-changes>\n}\n\n<!-- ============================================\n LIST MANAGEMENT DIALOG (shown when lists button clicked)\n ============================================ -->\n@if (ShowListManagement && EffectiveRecord) {\n <mj-list-management-dialog\n [visible]=\"ShowListManagement\"\n [config]=\"{\n mode: 'manage',\n entityId: EffectiveRecord.EntityInfo.ID,\n entityName: EffectiveRecord.EntityInfo.Name,\n recordIds: [EffectiveRecord.PrimaryKey.Values()[0]],\n allowCreate: true\n }\"\n (complete)=\"OnListManagementClosed()\"\n (cancel)=\"OnListManagementClosed()\">\n </mj-list-management-dialog>\n}\n\n<!-- ============================================\n SECTION MANAGER DRAWER (shown when manage-sections button clicked)\n ============================================ -->\n<mj-section-manager\n [Sections]=\"SectionManagerItems\"\n [SectionOrder]=\"SectionManagerOrder\"\n [Visible]=\"ShowSectionManager\"\n (SectionOrderChange)=\"OnSectionOrderChange($event)\"\n (ResetRequested)=\"OnSectionManagerReset()\"\n (Closed)=\"OnSectionManagerClosed()\">\n</mj-section-manager>\n", styles: ["/* ============================================\n RECORD FORM CONTAINER\n Top-level wrapper: toolbar + scrollable content\n ============================================ */\nmj-record-form-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n position: relative;\n overflow: hidden;\n}\n\n/* ViewEncapsulation.None fallback \u2014 ensure the element itself constrains overflow */\nmj-record-form-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n position: relative;\n overflow: hidden;\n}\n\n/* ============================================\n SCROLL AREA (full-width so mouse wheel works anywhere)\n ============================================ */\n.mj-forms-scroll-area {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n background: #eef0f3;\n}\n\n/* ============================================\n PANELS CONTAINER (centered content within scroll area)\n ============================================ */\n.mj-forms-panels-container {\n padding: 24px 32px 48px;\n max-width: 920px;\n margin: 0 auto;\n width: 100%;\n box-sizing: border-box;\n}\n\n/* Widen max-width when ISA side panel is present */\n.mj-forms-panels--has-isa-panel {\n max-width: 1240px;\n}\n\n.mj-forms-panels--full-width {\n max-width: none;\n padding-left: 24px;\n padding-right: 24px;\n}\n\n/* Flex row layout: form panels + optional ISA side panel */\n.mj-forms-layout-row {\n display: flex;\n gap: 20px;\n align-items: flex-start;\n}\n\n/* All panels in a single flex container \u2014 CSS order drives sequencing */\n.mj-forms-all-panels {\n display: flex;\n flex-direction: column;\n gap: 16px;\n flex: 1;\n min-width: 0;\n}\n\n/* Hide related entity panels in edit mode (variant host class on mj-collapsible-panel) */\n.mj-forms-panels--edit-mode .mj-panel--related-entity {\n display: none;\n}\n\n/* ============================================\n EMPTY SEARCH STATE\n ============================================ */\n.mj-forms-empty-search-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 80px 24px;\n text-align: center;\n min-height: 400px;\n}\n\n.mj-forms-empty-search-icon {\n width: 80px;\n height: 80px;\n border-radius: 50%;\n background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 24px;\n}\n\n.mj-forms-empty-search-icon i {\n font-size: 32px;\n color: #9ca3af;\n}\n\n.mj-forms-empty-search-title {\n font-size: 20px;\n font-weight: 600;\n color: #1f2937;\n margin: 0 0 12px 0;\n}\n\n.mj-forms-empty-search-message {\n font-size: 14px;\n color: #6b7280;\n line-height: 1.6;\n max-width: 400px;\n margin: 0;\n}\n\n.mj-forms-empty-search-message strong {\n color: #374151;\n font-weight: 600;\n}\n\n.mj-forms-empty-search-link {\n color: #667eea;\n text-decoration: none;\n font-weight: 500;\n}\n\n.mj-forms-empty-search-link:hover {\n text-decoration: underline;\n}\n\n/* ============================================\n RESPONSIVE\n ============================================ */\n@media (max-width: 768px) {\n .mj-forms-panels-container {\n padding: 16px 12px 32px;\n }\n}\n"] }]
538
+ args: [{ standalone: false, selector: 'mj-record-form-container', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<!-- ============================================\n BEFORE-TOOLBAR SLOT\n ============================================ -->\n<ng-content select=\"[before-toolbar]\"></ng-content>\n\n<!-- ============================================\n TOOLBAR (bridges FormComponent state \u2192 toolbar inputs)\n ============================================ -->\n<mj-form-toolbar\n [Record]=\"EffectiveRecord\"\n [EditMode]=\"EffectiveEditMode\"\n [UserCanEdit]=\"EffectiveUserCanEdit\"\n [UserCanDelete]=\"EffectiveUserCanDelete\"\n [IsFavorite]=\"EffectiveIsFavorite\"\n [FavoriteInitDone]=\"EffectiveFavoriteInitDone\"\n [IsDirty]=\"EffectiveIsDirty\"\n [DirtyFieldNames]=\"EffectiveDirtyFieldNames\"\n [ListCount]=\"ListCount\"\n [EntityInfo]=\"EffectiveEntityInfo\"\n [Config]=\"ToolbarConfig\"\n [IsSaving]=\"EffectiveIsSaving\"\n [VisibleSectionCount]=\"VisibleSectionCount\"\n [TotalSectionCount]=\"TotalSectionCount\"\n [ExpandedSectionCount]=\"ExpandedSectionCount\"\n [SearchFilter]=\"EffectiveSearchFilter\"\n [ShowEmptyFields]=\"EffectiveShowEmptyFields\"\n [WidthMode]=\"EffectiveWidthMode\"\n [HasCustomSectionOrder]=\"EffectiveHasCustomSectionOrder\"\n (Navigate)=\"OnNavigate($event)\"\n (EditModeChange)=\"OnEditModeChange($event)\"\n (BeforeSave)=\"BeforeSave.emit($event)\"\n (SaveRequested)=\"OnSaveRequested()\"\n (BeforeCancel)=\"BeforeCancel.emit($event)\"\n (CancelRequested)=\"OnCancelRequested()\"\n (BeforeDelete)=\"BeforeDelete.emit($event)\"\n (DeleteRequested)=\"OnDeleteRequested()\"\n (FavoriteToggled)=\"OnFavoriteToggled()\"\n (BeforeHistoryView)=\"BeforeHistoryView.emit($event)\"\n (HistoryRequested)=\"OnHistoryRequested()\"\n (BeforeListManagement)=\"BeforeListManagement.emit($event)\"\n (ListManagementRequested)=\"OnListManagementRequested()\"\n (ShowChangesRequested)=\"OnShowChangesRequested()\"\n (CustomButtonClick)=\"CustomButtonClick.emit($event)\"\n (FilterChange)=\"OnFilterChange($event)\"\n (ExpandAllRequested)=\"OnExpandAll()\"\n (CollapseAllRequested)=\"OnCollapseAll()\"\n (ShowEmptyFieldsChange)=\"OnShowEmptyFieldsChange($event)\"\n (WidthModeChange)=\"OnWidthModeChange($event)\"\n (ResetSectionOrderRequested)=\"OnResetSectionOrder()\"\n (ManageSectionsRequested)=\"OnManageSections()\">\n</mj-form-toolbar>\n\n<!-- ============================================\n SCROLL AREA (full-width so mouse wheel works anywhere)\n ============================================ -->\n<div class=\"mj-forms-scroll-area\">\n <div class=\"mj-forms-panels-container\"\n [class.mj-forms-panels--full-width]=\"EffectiveWidthMode === 'full-width'\"\n [class.mj-forms-panels--edit-mode]=\"EffectiveEditMode\"\n [class.mj-forms-panels--has-isa-panel]=\"HasIsaRelatedItems\">\n <!-- Flex row: form panels on left, ISA side panel on right -->\n <div class=\"mj-forms-layout-row\">\n <!-- All panels in a single flex container \u2014 CSS order drives sequencing -->\n <div class=\"mj-forms-all-panels\">\n <ng-content></ng-content>\n\n <!-- Empty state when no sections match search -->\n @if (EffectiveSearchFilter && VisibleSectionCount === 0) {\n <div class=\"mj-forms-empty-search-state\">\n <div class=\"mj-forms-empty-search-icon\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n </div>\n <h3 class=\"mj-forms-empty-search-title\">No sections found</h3>\n <p class=\"mj-forms-empty-search-message\">\n No sections match \"<strong>{{ EffectiveSearchFilter }}</strong>\".\n <br>Try a different search term or <a href=\"#\" (click)=\"OnFilterChange(''); $event.preventDefault()\" class=\"mj-forms-empty-search-link\">clear the search</a>.\n </p>\n </div>\n }\n </div>\n\n <!-- IS-A Related Records Side Panel -->\n <mj-isa-related-panel\n [Record]=\"EffectiveRecord\"\n [EditMode]=\"EffectiveEditMode\"\n [Collapsed]=\"EffectiveWidthMode === 'full-width'\"\n (Navigate)=\"OnNavigate($event)\">\n </mj-isa-related-panel>\n </div>\n </div>\n</div>\n\n<!-- ============================================\n RECORD CHANGES DRAWER (shown when history button clicked)\n ============================================ -->\n@if (ShowRecordChanges && EffectiveRecord) {\n <mj-record-changes\n [record]=\"EffectiveRecord\"\n (dialogClosed)=\"OnRecordChangesClosed()\">\n </mj-record-changes>\n}\n\n<!-- ============================================\n LIST MANAGEMENT DIALOG (shown when lists button clicked)\n ============================================ -->\n@if (ShowListManagement && EffectiveRecord) {\n <mj-list-management-dialog\n [visible]=\"ShowListManagement\"\n [config]=\"{\n mode: 'manage',\n entityId: EffectiveRecord.EntityInfo.ID,\n entityName: EffectiveRecord.EntityInfo.Name,\n recordIds: [EffectiveRecord.PrimaryKey.Values()[0]],\n allowCreate: true\n }\"\n (complete)=\"OnListManagementClosed()\"\n (cancel)=\"OnListManagementClosed()\">\n </mj-list-management-dialog>\n}\n\n<!-- ============================================\n SECTION MANAGER DRAWER (shown when manage-sections button clicked)\n ============================================ -->\n<mj-section-manager\n [Sections]=\"SectionManagerItems\"\n [SectionOrder]=\"SectionManagerOrder\"\n [Visible]=\"ShowSectionManager\"\n (SectionOrderChange)=\"OnSectionOrderChange($event)\"\n (ResetRequested)=\"OnSectionManagerReset()\"\n (Closed)=\"OnSectionManagerClosed()\">\n</mj-section-manager>\n", styles: ["/* ============================================\n RECORD FORM CONTAINER \u2014 uses global --mj-* design tokens\n Top-level wrapper: toolbar + scrollable content\n ============================================ */\nmj-record-form-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n position: relative;\n overflow: hidden;\n}\n\n/* ViewEncapsulation.None fallback \u2014 ensure the element itself constrains overflow */\nmj-record-form-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n position: relative;\n overflow: hidden;\n}\n\n/* ============================================\n SCROLL AREA (full-width so mouse wheel works anywhere)\n ============================================ */\n.mj-forms-scroll-area {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n background: var(--mj-bg-page);\n}\n\n/* ============================================\n PANELS CONTAINER (centered content within scroll area)\n ============================================ */\n.mj-forms-panels-container {\n padding: 24px 32px 48px;\n max-width: 920px;\n margin: 0 auto;\n width: 100%;\n box-sizing: border-box;\n}\n\n/* Widen max-width when ISA side panel is present */\n.mj-forms-panels--has-isa-panel {\n max-width: 1240px;\n}\n\n.mj-forms-panels--full-width {\n max-width: none;\n padding-left: 24px;\n padding-right: 24px;\n}\n\n/* Flex row layout: form panels + optional ISA side panel */\n.mj-forms-layout-row {\n display: flex;\n gap: 20px;\n align-items: flex-start;\n}\n\n/* All panels in a single flex container \u2014 CSS order drives sequencing */\n.mj-forms-all-panels {\n display: flex;\n flex-direction: column;\n gap: 16px;\n flex: 1;\n min-width: 0;\n}\n\n/* Hide related entity panels in edit mode (variant host class on mj-collapsible-panel) */\n.mj-forms-panels--edit-mode .mj-panel--related-entity {\n display: none;\n}\n\n/* ============================================\n EMPTY SEARCH STATE\n ============================================ */\n.mj-forms-empty-search-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 80px 24px;\n text-align: center;\n min-height: 400px;\n}\n\n.mj-forms-empty-search-icon {\n width: 80px;\n height: 80px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-sunken);\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 24px;\n}\n\n.mj-forms-empty-search-icon i {\n font-size: 32px;\n color: var(--mj-text-muted);\n}\n\n.mj-forms-empty-search-title {\n font-size: var(--mj-text-xl);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n margin: 0 0 12px 0;\n}\n\n.mj-forms-empty-search-message {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n line-height: 1.6;\n max-width: 400px;\n margin: 0;\n}\n\n.mj-forms-empty-search-message strong {\n color: var(--mj-text-primary);\n font-weight: var(--mj-font-semibold);\n}\n\n.mj-forms-empty-search-link {\n color: var(--mj-brand-primary);\n text-decoration: none;\n font-weight: var(--mj-font-medium);\n}\n\n.mj-forms-empty-search-link:hover {\n text-decoration: underline;\n}\n\n/* ============================================\n RESPONSIVE\n ============================================ */\n@media (max-width: 768px) {\n .mj-forms-panels-container {\n padding: 16px 12px 32px;\n }\n}\n"] }]
539
539
  }], null, { Record: [{
540
540
  type: Input
541
541
  }], FormComponent: [{
@@ -1 +1 @@
1
- {"version":3,"file":"explorer-entity-data-grid.component.d.ts","sourceRoot":"","sources":["../../src/lib/explorer-entity-data-grid.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAa,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,aAAa,EAA0B,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EACH,uBAAuB,EACvB,4BAA4B,EAC5B,sBAAsB,EACtB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACpB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;;AAEhE;;;;;GAKG;AACH,qBA0Ba,+BAA+B;IAChB,SAAS,EAAG,uBAAuB,CAAC;IAGnD,MAAM,EAAE,aAAa,GAAG,IAAI,CAAQ;IACpC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAM;IAC9C,SAAS,EAAE,OAAO,CAAQ;IAC1B,WAAW,EAAE,OAAO,CAAQ;IAC5B,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,CAAU;IACjD,aAAa,EAAE,iBAAiB,CAAM;IACtC,aAAa,EAAE,iBAAiB,CAAY;IAErD;;;OAGG;IACM,qBAAqB,EAAE,OAAO,CAAQ;IAGrC,mBAAmB,6CAAoD;IACvE,aAAa,uCAA8C;IAC3D,aAAa,uCAA8C;IAErE,6EAA6E;IACnE,QAAQ,oCAA2C;IAE7D,gBAAgB,CAAC,KAAK,EAAE,4BAA4B,GAAG,IAAI;IA8B3D,UAAU,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI;IAK/C,UAAU,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI;yCA7DtC,+BAA+B;2CAA/B,+BAA+B;CAiE3C"}
1
+ {"version":3,"file":"explorer-entity-data-grid.component.d.ts","sourceRoot":"","sources":["../../src/lib/explorer-entity-data-grid.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAa,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EACH,uBAAuB,EACvB,4BAA4B,EAC5B,sBAAsB,EACtB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EAEpB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;;AAEhE;;;;;GAKG;AACH,qBA0Ba,+BAA+B;IAChB,SAAS,EAAG,uBAAuB,CAAC;IAGnD,MAAM,EAAE,aAAa,GAAG,IAAI,CAAQ;IACpC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAM;IAC9C,SAAS,EAAE,OAAO,CAAQ;IAC1B,WAAW,EAAE,OAAO,CAAQ;IAC5B,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,CAAU;IACjD,aAAa,EAAE,iBAAiB,CAAM;IACtC,aAAa,EAAE,iBAAiB,CAAY;IAErD;;;OAGG;IACM,qBAAqB,EAAE,OAAO,CAAQ;IAGrC,mBAAmB,6CAAoD;IACvE,aAAa,uCAA8C;IAC3D,aAAa,uCAA8C;IAErE,6EAA6E;IACnE,QAAQ,oCAA2C;IAE7D,gBAAgB,CAAC,KAAK,EAAE,4BAA4B,GAAG,IAAI;IAoB3D,UAAU,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI;IAK/C,UAAU,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI;yCAnDtC,+BAA+B;2CAA/B,+BAA+B;CAuD3C"}
@@ -1,5 +1,5 @@
1
1
  import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
2
- import { CompositeKey, Metadata } from '@memberjunction/core';
2
+ import { buildCompositeKey } from '@memberjunction/ng-entity-viewer';
3
3
  import * as i0 from "@angular/core";
4
4
  import * as i1 from "@memberjunction/ng-entity-viewer";
5
5
  const _c0 = ["innerGrid"];
@@ -35,23 +35,16 @@ export class ExplorerEntityDataGridComponent {
35
35
  this.AfterRowDoubleClick.emit(event);
36
36
  // Emit navigation event if enabled
37
37
  if (this.NavigateOnDoubleClick && event.row) {
38
- const entity = event.row;
39
- const entityName = this.Params?.EntityName;
40
- if (!entityName)
41
- throw new Error('Misconfiguration of ExplorerEntityDataGrid - no Params.EntityName');
42
- const md = new Metadata();
43
- const entityInfo = md.EntityByName(entityName);
44
- if (entityName) {
45
- const pkey = new CompositeKey();
46
- const pkeyVals = {};
47
- entityInfo.PrimaryKeys.forEach(pk => pkeyVals[pk.Name] = entity[pk.Name]);
48
- pkey.LoadFromSimpleObject(pkeyVals);
49
- this.Navigate.emit({
50
- Kind: 'record',
51
- EntityName: entityName,
52
- PrimaryKey: pkey
53
- });
54
- }
38
+ // Use the inner grid's resolved EntityInfo - works for both ViewID and EntityName params
39
+ const entityInfo = this.innerGrid?.EntityInfo;
40
+ if (!entityInfo)
41
+ return;
42
+ const pkey = buildCompositeKey(event.row, entityInfo);
43
+ this.Navigate.emit({
44
+ Kind: 'record',
45
+ EntityName: entityInfo.Name,
46
+ PrimaryKey: pkey
47
+ });
55
48
  }
56
49
  }
57
50
  onRowClick(event) {
@@ -122,5 +115,5 @@ export class ExplorerEntityDataGridComponent {
122
115
  }], Navigate: [{
123
116
  type: Output
124
117
  }] }); })();
125
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ExplorerEntityDataGridComponent, { className: "ExplorerEntityDataGridComponent", filePath: "src/lib/explorer-entity-data-grid.component.ts", lineNumber: 45 }); })();
118
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ExplorerEntityDataGridComponent, { className: "ExplorerEntityDataGridComponent", filePath: "src/lib/explorer-entity-data-grid.component.ts", lineNumber: 46 }); })();
126
119
  //# sourceMappingURL=explorer-entity-data-grid.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"explorer-entity-data-grid.component.js","sourceRoot":"","sources":["../../src/lib/explorer-entity-data-grid.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';\nimport { RunViewParams, CompositeKey, Metadata } from '@memberjunction/core';\nimport {\n EntityDataGridComponent,\n AfterRowDoubleClickEventArgs,\n AfterRowClickEventArgs,\n AfterDataLoadEventArgs,\n GridToolbarConfig,\n GridSelectionMode\n} from '@memberjunction/ng-entity-viewer';\nimport { FormNavigationEvent } from './types/navigation-events';\n\n/**\n * Wrapper for EntityDataGridComponent that emits navigation events on row double-click.\n * The host application subscribes to Navigate events and maps them to its routing system.\n *\n * This component is used by CodeGen for related entity grids in forms.\n */\n@Component({\n standalone: false,\n selector: 'mj-explorer-entity-data-grid',\n template: `\n <mj-entity-data-grid\n #innerGrid\n [Params]=\"Params\"\n [NewRecordValues]=\"NewRecordValues\"\n [AllowLoad]=\"AllowLoad\"\n [ShowToolbar]=\"ShowToolbar\"\n [Height]=\"Height\"\n [ToolbarConfig]=\"ToolbarConfig\"\n [SelectionMode]=\"SelectionMode\"\n (AfterRowDoubleClick)=\"onRowDoubleClick($event)\"\n (AfterRowClick)=\"onRowClick($event)\"\n (AfterDataLoad)=\"onDataLoad($event)\">\n </mj-entity-data-grid>\n `,\n styles: [`\n :host {\n display: block;\n height: 100%;\n width: 100%;\n }\n `]\n})\nexport class ExplorerEntityDataGridComponent {\n @ViewChild('innerGrid') innerGrid!: EntityDataGridComponent;\n\n // Pass-through inputs from EntityDataGridComponent\n @Input() Params: RunViewParams | null = null;\n @Input() NewRecordValues: Record<string, unknown> = {};\n @Input() AllowLoad: boolean = true;\n @Input() ShowToolbar: boolean = true;\n @Input() Height: number | 'auto' | 'fit-content' = 'auto';\n @Input() ToolbarConfig: GridToolbarConfig = {};\n @Input() SelectionMode: GridSelectionMode = 'single';\n\n /**\n * When true, double-clicking a row emits a Navigate event.\n * Defaults to true.\n */\n @Input() NavigateOnDoubleClick: boolean = true;\n\n // Re-emit events for consumers who need them\n @Output() AfterRowDoubleClick = new EventEmitter<AfterRowDoubleClickEventArgs>();\n @Output() AfterRowClick = new EventEmitter<AfterRowClickEventArgs>();\n @Output() AfterDataLoad = new EventEmitter<AfterDataLoadEventArgs>();\n\n /** Emitted when a row is double-clicked and NavigateOnDoubleClick is true */\n @Output() Navigate = new EventEmitter<FormNavigationEvent>();\n\n onRowDoubleClick(event: AfterRowDoubleClickEventArgs): void {\n // Re-emit the event for any consumers\n this.AfterRowDoubleClick.emit(event);\n\n // Emit navigation event if enabled\n if (this.NavigateOnDoubleClick && event.row) {\n const entity = event.row;\n\n const entityName = this.Params?.EntityName;\n if (!entityName) \n throw new Error('Misconfiguration of ExplorerEntityDataGrid - no Params.EntityName')\n\n const md = new Metadata();\n const entityInfo = md.EntityByName(entityName);\n if (entityName) {\n const pkey: CompositeKey = new CompositeKey();\n const pkeyVals: Record<string, unknown> = {};\n entityInfo.PrimaryKeys.forEach(pk => pkeyVals[pk.Name] = entity[pk.Name])\n \n pkey.LoadFromSimpleObject(pkeyVals);\n\n this.Navigate.emit({\n Kind: 'record',\n EntityName: entityName,\n PrimaryKey: pkey\n });\n }\n }\n }\n\n onRowClick(event: AfterRowClickEventArgs): void {\n // Re-emit the event for any consumers\n this.AfterRowClick.emit(event);\n }\n\n onDataLoad(event: AfterDataLoadEventArgs): void {\n // Re-emit the event for any consumers\n this.AfterDataLoad.emit(event);\n }\n}\n"]}
1
+ {"version":3,"file":"explorer-entity-data-grid.component.js","sourceRoot":"","sources":["../../src/lib/explorer-entity-data-grid.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAElF,OAAO,EAOH,iBAAiB,EACpB,MAAM,kCAAkC,CAAC;;;;AAG1C;;;;;GAKG;AA2BH,MAAM,OAAO,+BAA+B;IAChB,SAAS,CAA2B;IAE5D,mDAAmD;IAC1C,MAAM,GAAyB,IAAI,CAAC;IACpC,eAAe,GAA4B,EAAE,CAAC;IAC9C,SAAS,GAAY,IAAI,CAAC;IAC1B,WAAW,GAAY,IAAI,CAAC;IAC5B,MAAM,GAAoC,MAAM,CAAC;IACjD,aAAa,GAAsB,EAAE,CAAC;IACtC,aAAa,GAAsB,QAAQ,CAAC;IAErD;;;OAGG;IACM,qBAAqB,GAAY,IAAI,CAAC;IAE/C,6CAA6C;IACnC,mBAAmB,GAAG,IAAI,YAAY,EAAgC,CAAC;IACvE,aAAa,GAAG,IAAI,YAAY,EAA0B,CAAC;IAC3D,aAAa,GAAG,IAAI,YAAY,EAA0B,CAAC;IAErE,6EAA6E;IACnE,QAAQ,GAAG,IAAI,YAAY,EAAuB,CAAC;IAE7D,gBAAgB,CAAC,KAAmC;QAChD,sCAAsC;QACtC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAErC,mCAAmC;QACnC,IAAI,IAAI,CAAC,qBAAqB,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;YAC1C,yFAAyF;YACzF,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;YAC9C,IAAI,CAAC,UAAU;gBAAE,OAAO;YAExB,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;YAEtD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACf,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE,UAAU,CAAC,IAAI;gBAC3B,UAAU,EAAE,IAAI;aACnB,CAAC,CAAC;QACP,CAAC;IACL,CAAC;IAED,UAAU,CAAC,KAA6B;QACpC,sCAAsC;QACtC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAED,UAAU,CAAC,KAA6B;QACpC,sCAAsC;QACtC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;yHAtDQ,+BAA+B;6DAA/B,+BAA+B;;;;;;;YAtBpC,iDAWyC;YAArC,AADA,AADA,iMAAuB,4BAAwB,KAAC,wKAC/B,sBAAkB,KAAC,wKACnB,sBAAkB,KAAC;YACxC,iBAAsB;;YAJlB,AADA,AADA,AADA,AADA,AADA,AADA,mCAAiB,wCACkB,4BACZ,gCACI,sBACV,oCACc,oCACA;;;iFAc9B,+BAA+B;cA1B3C,SAAS;6BACI,KAAK,YACL,8BAA8B,YAC9B;;;;;;;;;;;;;;KAcT;;kBAUA,SAAS;mBAAC,WAAW;;kBAGrB,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBACL,KAAK;;kBAML,KAAK;;kBAGL,MAAM;;kBACN,MAAM;;kBACN,MAAM;;kBAGN,MAAM;;kFAxBE,+BAA+B","sourcesContent":["import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';\nimport { RunViewParams } from '@memberjunction/core';\nimport {\n EntityDataGridComponent,\n AfterRowDoubleClickEventArgs,\n AfterRowClickEventArgs,\n AfterDataLoadEventArgs,\n GridToolbarConfig,\n GridSelectionMode,\n buildCompositeKey\n} from '@memberjunction/ng-entity-viewer';\nimport { FormNavigationEvent } from './types/navigation-events';\n\n/**\n * Wrapper for EntityDataGridComponent that emits navigation events on row double-click.\n * The host application subscribes to Navigate events and maps them to its routing system.\n *\n * This component is used by CodeGen for related entity grids in forms.\n */\n@Component({\n standalone: false,\n selector: 'mj-explorer-entity-data-grid',\n template: `\n <mj-entity-data-grid\n #innerGrid\n [Params]=\"Params\"\n [NewRecordValues]=\"NewRecordValues\"\n [AllowLoad]=\"AllowLoad\"\n [ShowToolbar]=\"ShowToolbar\"\n [Height]=\"Height\"\n [ToolbarConfig]=\"ToolbarConfig\"\n [SelectionMode]=\"SelectionMode\"\n (AfterRowDoubleClick)=\"onRowDoubleClick($event)\"\n (AfterRowClick)=\"onRowClick($event)\"\n (AfterDataLoad)=\"onDataLoad($event)\">\n </mj-entity-data-grid>\n `,\n styles: [`\n :host {\n display: block;\n height: 100%;\n width: 100%;\n }\n `]\n})\nexport class ExplorerEntityDataGridComponent {\n @ViewChild('innerGrid') innerGrid!: EntityDataGridComponent;\n\n // Pass-through inputs from EntityDataGridComponent\n @Input() Params: RunViewParams | null = null;\n @Input() NewRecordValues: Record<string, unknown> = {};\n @Input() AllowLoad: boolean = true;\n @Input() ShowToolbar: boolean = true;\n @Input() Height: number | 'auto' | 'fit-content' = 'auto';\n @Input() ToolbarConfig: GridToolbarConfig = {};\n @Input() SelectionMode: GridSelectionMode = 'single';\n\n /**\n * When true, double-clicking a row emits a Navigate event.\n * Defaults to true.\n */\n @Input() NavigateOnDoubleClick: boolean = true;\n\n // Re-emit events for consumers who need them\n @Output() AfterRowDoubleClick = new EventEmitter<AfterRowDoubleClickEventArgs>();\n @Output() AfterRowClick = new EventEmitter<AfterRowClickEventArgs>();\n @Output() AfterDataLoad = new EventEmitter<AfterDataLoadEventArgs>();\n\n /** Emitted when a row is double-clicked and NavigateOnDoubleClick is true */\n @Output() Navigate = new EventEmitter<FormNavigationEvent>();\n\n onRowDoubleClick(event: AfterRowDoubleClickEventArgs): void {\n // Re-emit the event for any consumers\n this.AfterRowDoubleClick.emit(event);\n\n // Emit navigation event if enabled\n if (this.NavigateOnDoubleClick && event.row) {\n // Use the inner grid's resolved EntityInfo - works for both ViewID and EntityName params\n const entityInfo = this.innerGrid?.EntityInfo;\n if (!entityInfo) return;\n\n const pkey = buildCompositeKey(event.row, entityInfo);\n\n this.Navigate.emit({\n Kind: 'record',\n EntityName: entityInfo.Name,\n PrimaryKey: pkey\n });\n }\n }\n\n onRowClick(event: AfterRowClickEventArgs): void {\n // Re-emit the event for any consumers\n this.AfterRowClick.emit(event);\n }\n\n onDataLoad(event: AfterDataLoadEventArgs): void {\n // Re-emit the event for any consumers\n this.AfterDataLoad.emit(event);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"form-field.component.d.ts","sourceRoot":"","sources":["../../../src/lib/field/form-field.component.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"form-field.component.d.ts","sourceRoot":"","sources":["../../../src/lib/field/form-field.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAsD,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAChK,OAAO,EAAE,UAAU,EAAE,eAAe,EAAiD,MAAM,sBAAsB,CAAC;AAClH,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;;AAEjE;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAOa,oBAAqB,YAAW,SAAS,EAAE,SAAS;IAC/D,OAAO,CAAC,GAAG,CAA6B;IAExC,8CAA8C;IACrC,MAAM,EAAG,UAAU,CAAC;IAE7B,uCAAuC;IAC9B,QAAQ,UAAS;IAE1B,6DAA6D;IACpD,SAAS,SAAM;IAExB;;;;;;;OAOG;IACH,IACI,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,cAAc,GAAG,MAAM,GAAG,cAAc,GAAG,gBAAgB,EAOrJ;IACD,IAAI,IAAI,IAAI,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,cAAc,GAAG,MAAM,CAE7G;IACD,OAAO,CAAC,KAAK,CAAiH;IAE9H;;;;;;OAMG;IACM,QAAQ,EAAE,OAAO,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAU;IAEhE,sCAAsC;IAC7B,SAAS,UAAQ;IAE1B,0DAA0D;IACjD,WAAW,CAAC,EAAE,WAAW,CAAC;IAInC,uCAAuC;IACvC,IAAqB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAA0B;IAElF,4CAA4C;IAC5C,IAA0B,sBAAsB,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,EAA+B;IAE9G,6EAA6E;IACpE,2BAA2B,UAAQ;IAE5C,4EAA4E;IACnE,mBAAmB,SAAM;IAElC,uDAAuD;IAC9C,sBAAsB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAQ;IAExD,2CAA2C;IACjC,WAAW;mBAAiC,MAAM;kBAAY,OAAO;kBAAY,OAAO;OAAM;IAExG,uFAAuF;IAC7E,QAAQ,oCAA2C;IAI7D,kDAAkD;IAClD,IAAI,SAAS,IAAI,eAAe,GAAG,SAAS,CAE3C;IAED,6CAA6C;IAC7C,IAAI,WAAW,IAAI,MAAM,CAkBxB;IAED,oDAAoD;IACpD,IAAI,sBAAsB,IAAI,MAAM,CAOnC;IAED,0BAA0B;IAC1B,IAAI,KAAK,IAAI,OAAO,CAEnB;IAED,2EAA2E;IAC3E,IAAI,KAAK,CAAC,QAAQ,EAAE,OAAO,EAO1B;IAED,+DAA+D;IAC/D,IAAI,eAAe,IAAI,OAAO,CAG7B;IAED,4FAA4F;IAC5F,IAAI,OAAO,IAAI,OAAO,CAIrB;IAED,oDAAoD;IACpD,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,wFAAwF;IACxF,IAAI,eAAe,IAAI,OAAO,CAM7B;IAID,gEAAgE;IAChE,OAAO,CAAC,QAAQ,CAAS;IAEzB,wDAAwD;IACxD,OAAO,CAAC,YAAY,CAA6B;IAEjD,sEAAsE;IACtE,IAAI,WAAW,IAAI,mBAAmB,EAAE,CAWvC;IAED,iFAAiF;IACjF,IAAI,cAAc,IAAI,OAAO,CAG5B;IAED,+EAA+E;IAC/E,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,+EAA+E;IAC/E,IAAI,YAAY,IAAI,OAAO,CAE1B;IAED,+CAA+C;IAC/C,IAAI,aAAa,IAAI,mBAAmB,EAAE,CAGzC;IAED,iDAAiD;IACjD,IAAI,eAAe,IAAI,mBAAmB,EAAE,CAG3C;IAED;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAc1B,oEAAoE;IACpE,IAAI,eAAe,IAAI,OAAO,CAM7B;IAED,+EAA+E;IAC/E,IAAI,cAAc,IAAI,MAAM,EAAE,CAO7B;IAED,4DAA4D;IAC5D,IAAI,gBAAgB,IAAI,OAAO,CAG9B;IAED;;;;;;OAMG;IACH,IAAI,aAAa,IAAI,MAAM,GAAG,IAAI,CAuBjC;IAED;;;OAGG;IACH,IAAI,iBAAiB,IAAI,OAAO,CAE/B;IAID,4EAA4E;IAC5E,OAAO,CAAC,eAAe,CAAwC;IAE/D,8EAA8E;IAC9E,OAAO,CAAC,gBAAgB,CAAsB;IAE9C,2CAA2C;IAC3C,OAAO,CAAC,cAAc,CAAS;IAE/B;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAkC1B,uDAAuD;IACvD,WAAW,SAAK;IAChB,YAAY,SAAK;IACjB,aAAa,SAAK;IAClB,SAAS,UAAS;IAElB,mDAAmD;IACnD,OAAO,CAAC,cAAc,CAA6B;IAEnD,mDAAmD;IACnD,IAAI,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmBlD;IAED,2EAA2E;IAC3E,OAAO,CAAC,sBAAsB;IAkB9B,2DAA2D;IAC3D,OAAO,CAAC,mBAAmB;IAqB3B,qCAAqC;IACrC,OAAO,CAAC,kBAAkB;IAO1B,+BAA+B;IAC/B,OAAO,CAAC,iBAAiB;IAWzB,qDAAqD;IACrD,aAAa,EAAE,YAAY,EAAE,CAAM;IAEnC,sFAAsF;IACtF,WAAW,UAAS;IAEpB,yCAAyC;IACzC,cAAc,UAAS;IAEvB,yFAAyF;IACzF,OAAO,CAAC,YAAY,CAAuB;IAE3C,mCAAmC;IACnC,OAAO,CAAC,gBAAgB,CAA8C;IAEtE,6DAA6D;IAC7D,OAAO,CAAC,cAAc,CAA4B;IAElD,oDAAoD;IACpD,IAAI,YAAY,IAAI,MAAM,CAGzB;IAED,2CAA2C;IAC3C,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAoB7B,kDAAkD;IAClD,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAWlC,0EAA0E;IAC1E,QAAQ,IAAI,IAAI;IAahB,0CAA0C;IAC1C,cAAc,CAAC,UAAU,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAgBjE,sCAAsC;IACtC,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAkBvC;;;OAGG;YACW,mBAAmB;IAyDjC,iDAAiD;IACjD,qBAAqB,UAAS;IAE9B,6CAA6C;IAC7C,OAAO,CAAC,gBAAgB,CAAM;IAE9B,4DAA4D;IAC5D,IAAI,sBAAsB,IAAI,MAAM,EAAE,CAIrC;IAED,mDAAmD;IACnD,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAUpC,6BAA6B;IAC7B,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAQzC,4BAA4B;IAC5B,eAAe,IAAI,IAAI;IAQvB,kDAAkD;IAClD,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAazD,oDAAoD;IACpD,kBAAkB,UAAS;IAE3B,wCAAwC;IACxC,oBAAoB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAcxC,wCAAwC;IACxC,mBAAmB,IAAI,IAAI;IAQ3B,uDAAuD;IACvD,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAY3D,gFAAgF;IAChF,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,iCAAiC;IACjC,WAAW,IAAI,MAAM;IASrB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAwBzC,WAAW,IAAI,IAAI;IASnB;;OAEG;IACH,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAuB1C;;OAEG;IACH,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAYzC;;OAEG;IACH,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAavC;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAKjC;;OAEG;IACH,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAMlC;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAKhC;;OAEG;IACH,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAKpC;;OAEG;IACH,IAAI,cAAc,IAAI,MAAM,CAM3B;yCAt0BU,oBAAoB;2CAApB,oBAAoB;CAu0BhC"}
@@ -643,6 +643,11 @@ export class MjFormFieldComponent {
643
643
  get FKDisplayName() {
644
644
  if (!this.Record || !this.HasRelatedEntity)
645
645
  return null;
646
+ // If the FK value itself is null/empty, there's nothing to display
647
+ // (the joined name field may still hold a stale cached value from the view)
648
+ const fkValue = this.Value;
649
+ if (fkValue == null || fkValue === '')
650
+ return null;
646
651
  // Fast path: name field is joined into our record's view
647
652
  const nameFieldMap = this.FieldInfo?.RelatedEntityNameFieldMap;
648
653
  if (nameFieldMap) {
@@ -1166,11 +1171,11 @@ export class MjFormFieldComponent {
1166
1171
  i0.ɵɵconditionalCreate(0, MjFormFieldComponent_Conditional_0_Template, 2, 2);
1167
1172
  } if (rf & 2) {
1168
1173
  i0.ɵɵconditional(ctx.Record && (ctx.Record.IsSaved || !ctx.IsFieldReadOnly) ? 0 : -1);
1169
- } }, dependencies: [i1.NgStyle], styles: ["\n\n\n\n[_nghost-%COMP%] {\n --mj-accent: #667eea;\n --mj-accent-light: rgba(102, 126, 234, 0.08);\n --mj-text-primary: #1f2937;\n --mj-text-secondary: #4b5563;\n --mj-text-muted: #9ca3af;\n --mj-border: #e5e7eb;\n --mj-error: #ef4444;\n --mj-warning: #f59e0b;\n --mj-card-bg: #ffffff;\n --mj-forms-field-label-width: 200px;\n --mj-forms-field-gap: 12px;\n --mj-transition: 200ms;\n\n display: contents;\n}\n\n.mj-forms-field[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: var(--mj-forms-field-label-width) 1fr;\n gap: var(--mj-forms-field-gap);\n align-items: baseline;\n padding: 8px 0;\n transition: all var(--mj-transition) ease;\n}\n\n\n\n.mj-forms-field--editing[_ngcontent-%COMP%]:hover {\n background: var(--mj-accent-light);\n border-radius: 6px;\n margin: 0 -8px;\n padding: 8px 8px;\n}\n\n\n\n\n\n.mj-forms-field-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n padding-top: 2px;\n word-break: break-word;\n}\n\n\n\n\n\n.mj-forms-field-control[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.mj-forms-field-control[_ngcontent-%COMP%] > *[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n\n\n\n\n.mj-forms-field--dirty[_ngcontent-%COMP%] .mj-forms-field-label[_ngcontent-%COMP%]::after {\n content: '';\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--mj-warning);\n margin-left: 6px;\n vertical-align: middle;\n}\n\n\n\n\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: #fef2f2;\n border-bottom-color: var(--mj-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-error);\n}\n\n\n\n\n\n.mj-forms-field-value[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-primary);\n min-height: 24px;\n display: flex;\n align-items: center;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\n.mj-forms-field-value--long[_ngcontent-%COMP%] {\n white-space: pre-line;\n max-height: 300px;\n overflow: auto;\n}\n\n\n\n.mj-forms-field--readonly[_ngcontent-%COMP%] {\n opacity: 0.7;\n}\n\n.mj-forms-field--readonly[_ngcontent-%COMP%] .mj-forms-field-value[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n\n\n\n\n.mj-forms-field-link[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-accent);\n cursor: pointer;\n font-weight: 400;\n font-size: 14px;\n transition: color var(--mj-transition);\n text-decoration: none;\n}\n\n.mj-forms-field-link[_ngcontent-%COMP%]:hover {\n color: #5a6fd6;\n}\n\n.mj-forms-field-link-icon[_ngcontent-%COMP%] {\n font-size: 11px;\n opacity: 0;\n transition: opacity var(--mj-transition);\n}\n\n.mj-forms-field-link[_ngcontent-%COMP%]:hover .mj-forms-field-link-icon[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n\n\n.mj-forms-field-link--fk[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 400;\n}\n\n\n\n\n\n.mj-forms-field-input[_ngcontent-%COMP%] {\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border);\n padding: 4px 0;\n width: 100%;\n outline: none;\n transition: border-color var(--mj-transition) ease,\n background var(--mj-transition) ease;\n}\n\n.mj-forms-field-input[_ngcontent-%COMP%]:focus {\n border-bottom-color: var(--mj-accent);\n background: var(--mj-accent-light);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-forms-field-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n\n\n.mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n resize: vertical;\n min-height: 60px;\n border: 1.5px solid var(--mj-border);\n border-radius: 6px;\n padding: 8px 10px;\n background: white;\n font-family: inherit;\n}\n\n.mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-accent);\n box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);\n background: white;\n padding: 8px 10px;\n border-radius: 6px;\n}\n\n\n\n.mj-forms-field-input--number[_ngcontent-%COMP%] {\n max-width: 200px;\n}\n\n\n\n.mj-forms-field-input--date[_ngcontent-%COMP%] {\n max-width: 220px;\n}\n\n\n\n\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n appearance: none;\n width: 18px;\n height: 18px;\n border: 2px solid var(--mj-border);\n border-radius: 4px;\n cursor: pointer;\n position: relative;\n transition: all var(--mj-transition) ease;\n flex-shrink: 0;\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:checked {\n background: var(--mj-accent);\n border-color: var(--mj-accent);\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:checked::after {\n content: '';\n position: absolute;\n left: 5px;\n top: 1px;\n width: 5px;\n height: 9px;\n border: solid white;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n\n\n\n\n.mj-custom-select-trigger[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border);\n padding: 4px 0;\n width: 100%;\n cursor: pointer;\n outline: none;\n transition: border-color var(--mj-transition) ease,\n background var(--mj-transition) ease;\n}\n\n.mj-custom-select-trigger[_ngcontent-%COMP%]:focus {\n border-bottom-color: var(--mj-accent);\n background: var(--mj-accent-light);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-custom-select-value[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mj-custom-select-value--placeholder[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n.mj-custom-select-chevron[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n transition: transform var(--mj-transition) ease;\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n.mj-custom-select-chevron--open[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n\n\n\n\n.mj-fk-search[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n}\n\n.mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n padding-right: 28px;\n}\n\n.mj-fk-search-icon[_ngcontent-%COMP%] {\n position: absolute;\n right: 4px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.mj-fk-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 2px;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 11px;\n padding: 4px 6px;\n line-height: 1;\n border-radius: 3px;\n transition: all var(--mj-transition);\n}\n\n.mj-fk-clear[_ngcontent-%COMP%]:hover {\n color: var(--mj-error);\n background: rgba(239, 68, 68, 0.08);\n}\n\n\n\n.mj-fk-search--matched[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom: 2px solid var(--mj-accent);\n}\n\n\n\n\n\n.mj-fk-dropdown[_ngcontent-%COMP%] {\n background: var(--mj-card-bg);\n border: 1px solid var(--mj-border);\n border-radius: 8px;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);\n max-height: 240px;\n overflow-y: auto;\n padding: 4px;\n animation: _ngcontent-%COMP%_mj-dropdown-in 150ms ease;\n}\n\n.mj-fk-dropdown--above[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_mj-dropdown-in-above 150ms ease;\n}\n\n.mj-fk-option[_ngcontent-%COMP%] {\n padding: 10px 14px;\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: background var(--mj-transition);\n border-radius: 6px;\n}\n\n.mj-fk-option[_ngcontent-%COMP%]:hover {\n background: var(--mj-accent-light);\n}\n\n.mj-fk-option--selected[_ngcontent-%COMP%] {\n background: var(--mj-accent-light);\n font-weight: 600;\n color: var(--mj-accent);\n}\n\n.mj-fk-option--selected[_ngcontent-%COMP%]:hover {\n background: rgba(102, 126, 234, 0.15);\n}\n\n@keyframes _ngcontent-%COMP%_mj-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n@keyframes _ngcontent-%COMP%_mj-dropdown-in-above {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n\n\n\n\n.mj-forms-field-label[_ngcontent-%COMP%] [_ngcontent-%COMP%]:global(.mj-forms-search-highlight) {\n background-color: #fef08a;\n color: #854d0e;\n padding: 0;\n border-radius: 2px;\n font-weight: 700;\n box-shadow: 0 0 0 2px #fef08a;\n}\n\n\n\n\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: #fef2f2;\n border-bottom-color: var(--mj-error);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n border-color: var(--mj-error);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-error);\n box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.08);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-error);\n border-bottom-width: 2px;\n}\n\n\n\n\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: #fffbeb;\n border-bottom-color: var(--mj-warning);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n border-color: var(--mj-warning);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-warning);\n box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.08);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-warning);\n border-bottom-width: 2px;\n}\n\n\n\n\n\n.mj-forms-field-validation[_ngcontent-%COMP%] {\n grid-column: 2;\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: -2px;\n overflow: hidden;\n animation: _ngcontent-%COMP%_mj-validation-slide-in 200ms ease-out;\n}\n\n.mj-forms-field-validation-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n font-size: 12px;\n line-height: 1.4;\n padding: 3px 0 1px;\n}\n\n.mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n\n\n.mj-forms-field-validation--error[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] {\n color: var(--mj-error);\n}\n\n.mj-forms-field-validation--error[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-error);\n}\n\n\n\n.mj-forms-field-validation--warning[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] {\n color: #b45309;\n}\n\n.mj-forms-field-validation--warning[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-warning);\n}\n\n@keyframes _ngcontent-%COMP%_mj-validation-slide-in {\n from {\n opacity: 0;\n max-height: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n max-height: 100px;\n transform: translateY(0);\n }\n}\n\n\n\n\n\n@media (max-width: 640px) {\n .mj-forms-field[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n gap: 4px;\n }\n\n .mj-forms-field-label[_ngcontent-%COMP%] {\n font-size: 12px;\n }\n\n .mj-forms-field-validation[_ngcontent-%COMP%] {\n grid-column: 1;\n }\n}"], changeDetection: 0 });
1174
+ } }, dependencies: [i1.NgStyle], styles: ["\n\n\n\n[_nghost-%COMP%] {\n --mj-forms-field-label-width: 200px;\n --mj-forms-field-gap: 12px;\n\n display: contents;\n}\n\n.mj-forms-field[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: var(--mj-forms-field-label-width) 1fr;\n gap: var(--mj-forms-field-gap);\n align-items: baseline;\n padding: 8px 0;\n transition: all var(--mj-transition-base) ease;\n}\n\n\n\n.mj-forms-field--editing[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 6px;\n margin: 0 -8px;\n padding: 8px 8px;\n}\n\n\n\n\n\n.mj-forms-field-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n padding-top: 2px;\n word-break: break-word;\n}\n\n\n\n\n\n.mj-forms-field-control[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.mj-forms-field-control[_ngcontent-%COMP%] > *[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n\n\n\n\n.mj-forms-field--dirty[_ngcontent-%COMP%] .mj-forms-field-label[_ngcontent-%COMP%]::after {\n content: '';\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--mj-status-warning);\n margin-left: 6px;\n vertical-align: middle;\n}\n\n\n\n\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n}\n\n\n\n\n\n.mj-forms-field-value[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-primary);\n min-height: 24px;\n display: flex;\n align-items: center;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\n.mj-forms-field-value--long[_ngcontent-%COMP%] {\n white-space: pre-line;\n max-height: 300px;\n overflow: auto;\n}\n\n\n\n.mj-forms-field--readonly[_ngcontent-%COMP%] {\n opacity: 0.7;\n}\n\n.mj-forms-field--readonly[_ngcontent-%COMP%] .mj-forms-field-value[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n\n\n\n\n.mj-forms-field-link[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-weight: 400;\n font-size: 14px;\n transition: color var(--mj-transition-base);\n text-decoration: none;\n}\n\n.mj-forms-field-link[_ngcontent-%COMP%]:hover {\n color: var(--mj-brand-primary-hover);\n}\n\n.mj-forms-field-link-icon[_ngcontent-%COMP%] {\n font-size: 11px;\n opacity: 0;\n transition: opacity var(--mj-transition-base);\n}\n\n.mj-forms-field-link[_ngcontent-%COMP%]:hover .mj-forms-field-link-icon[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n\n\n.mj-forms-field-link--fk[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 400;\n}\n\n\n\n\n\n.mj-forms-field-input[_ngcontent-%COMP%] {\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-forms-field-input[_ngcontent-%COMP%]:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-forms-field-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n\n\n.mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n resize: vertical;\n min-height: 60px;\n border: 1.5px solid var(--mj-border-default);\n border-radius: 6px;\n padding: 8px 10px;\n background: var(--mj-bg-surface);\n font-family: inherit;\n}\n\n.mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n background: var(--mj-bg-surface);\n padding: 8px 10px;\n border-radius: 6px;\n}\n\n\n\n.mj-forms-field-input--number[_ngcontent-%COMP%] {\n max-width: 200px;\n}\n\n\n\n.mj-forms-field-input--date[_ngcontent-%COMP%] {\n max-width: 220px;\n}\n\n\n\n\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n appearance: none;\n width: 18px;\n height: 18px;\n border: 2px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n position: relative;\n transition: all var(--mj-transition-base) ease;\n flex-shrink: 0;\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:checked {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:checked::after {\n content: '';\n position: absolute;\n left: 5px;\n top: 1px;\n width: 5px;\n height: 9px;\n border: solid var(--mj-text-inverse);\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n}\n\n.mj-forms-field-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n\n\n\n\n.mj-custom-select-trigger[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n cursor: pointer;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-custom-select-trigger[_ngcontent-%COMP%]:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-custom-select-value[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mj-custom-select-value--placeholder[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n.mj-custom-select-chevron[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n transition: transform var(--mj-transition-base) ease;\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n.mj-custom-select-chevron--open[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n\n\n\n\n.mj-fk-search[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n}\n\n.mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n padding-right: 28px;\n}\n\n.mj-fk-search-icon[_ngcontent-%COMP%] {\n position: absolute;\n right: 4px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.mj-fk-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 2px;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 11px;\n padding: 4px 6px;\n line-height: 1;\n border-radius: 3px;\n transition: all var(--mj-transition-base);\n}\n\n.mj-fk-clear[_ngcontent-%COMP%]:hover {\n color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n\n\n.mj-fk-search--matched[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n\n\n\n\n.mj-fk-dropdown[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-lg);\n max-height: 240px;\n overflow-y: auto;\n padding: 4px;\n animation: _ngcontent-%COMP%_mj-dropdown-in 150ms ease;\n}\n\n.mj-fk-dropdown--above[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_mj-dropdown-in-above 150ms ease;\n}\n\n.mj-fk-option[_ngcontent-%COMP%] {\n padding: 10px 14px;\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: background var(--mj-transition-base);\n border-radius: 6px;\n}\n\n.mj-fk-option[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.mj-fk-option--selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-option--selected[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n@keyframes _ngcontent-%COMP%_mj-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n@keyframes _ngcontent-%COMP%_mj-dropdown-in-above {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n\n\n\n\n.mj-forms-field-label[_ngcontent-%COMP%] [_ngcontent-%COMP%]:global(.mj-forms-search-highlight) {\n background-color: var(--mj-color-warning-200, #fef08a);\n color: var(--mj-color-warning-800, #854d0e);\n padding: 0;\n border-radius: 2px;\n font-weight: 700;\n box-shadow: 0 0 0 2px var(--mj-color-warning-200, #fef08a);\n}\n\n\n\n\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n border-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-status-error);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n\n\n\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%]:focus {\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%] {\n border-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-forms-field-input--textarea[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 8%, transparent);\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-custom-select-trigger[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning[_ngcontent-%COMP%] .mj-fk-search[_ngcontent-%COMP%] .mj-forms-field-input[_ngcontent-%COMP%] {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n\n\n\n\n.mj-forms-field-validation[_ngcontent-%COMP%] {\n grid-column: 2;\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: -2px;\n overflow: hidden;\n animation: _ngcontent-%COMP%_mj-validation-slide-in 200ms ease-out;\n}\n\n.mj-forms-field-validation-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n font-size: 12px;\n line-height: 1.4;\n padding: 3px 0 1px;\n}\n\n.mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n\n\n.mj-forms-field-validation--error[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.mj-forms-field-validation--error[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.mj-forms-field-validation--warning[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] {\n color: var(--mj-color-warning-700);\n}\n\n.mj-forms-field-validation--warning[_ngcontent-%COMP%] .mj-forms-field-validation-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n\n@keyframes _ngcontent-%COMP%_mj-validation-slide-in {\n from {\n opacity: 0;\n max-height: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n max-height: 100px;\n transform: translateY(0);\n }\n}\n\n\n\n\n\n@media (max-width: 640px) {\n .mj-forms-field[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n gap: 4px;\n }\n\n .mj-forms-field-label[_ngcontent-%COMP%] {\n font-size: 12px;\n }\n\n .mj-forms-field-validation[_ngcontent-%COMP%] {\n grid-column: 1;\n }\n}"], changeDetection: 0 });
1170
1175
  }
1171
1176
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MjFormFieldComponent, [{
1172
1177
  type: Component,
1173
- args: [{ standalone: false, selector: 'mj-form-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (Record && (Record.IsSaved || !IsFieldReadOnly)) {\n <!-- READ-ONLY MODE -->\n @if ((!EditMode || IsFieldReadOnly) && !ShouldHideField) {\n <div class=\"mj-forms-field\" [class.mj-forms-field--readonly]=\"EditMode && IsFieldReadOnly\" [class.mj-forms-field--dirty]=\"IsDirty\">\n @if (ShowLabel) {\n <label class=\"mj-forms-field-label\" [innerHTML]=\"HighlightedDisplayName\"></label>\n }\n <div class=\"mj-forms-field-control\">\n <!-- FK fields with a mapped name field: show the name as a hyperlink -->\n @if (IsFKWithNameField) {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link mj-forms-field-link--fk\" (click)=\"OnRecordLinkClick($event)\" title=\"View related record\">\n {{ FKDisplayName }}\n </a>\n </span>\n }\n @else {\n @switch (LinkType) {\n @case ('Email') {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link\" (click)=\"OnEmailLinkClick($event)\" title=\"Send email\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-envelope mj-forms-field-link-icon\"></i>\n </a>\n </span>\n }\n @case ('URL') {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link\" (click)=\"OnUrlLinkClick($event)\" title=\"Open link\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-arrow-up-right-from-square mj-forms-field-link-icon\"></i>\n </a>\n </span>\n }\n @case ('Record') {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link\" (click)=\"OnRecordLinkClick($event)\" title=\"View related record\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-arrow-up-right-from-square mj-forms-field-link-icon\"></i>\n </a>\n </span>\n }\n @default {\n @if (Type === 'checkbox') {\n <span class=\"mj-forms-field-value\">\n <div class=\"mj-forms-field-checkbox\">\n <input type=\"checkbox\" [checked]=\"!!Value\" disabled>\n </div>\n </span>\n }\n @else if (IsLongText) {\n <span class=\"mj-forms-field-value mj-forms-field-value--long\">{{ FormatValue() }}</span>\n }\n @else {\n <span class=\"mj-forms-field-value\">{{ FormatValue() }}</span>\n }\n }\n }\n }\n </div>\n </div>\n }\n\n <!-- EDIT MODE -->\n @if (EditMode && !IsFieldReadOnly) {\n <div class=\"mj-forms-field mj-forms-field--editing\" [class.mj-forms-field--dirty]=\"IsDirty\" [class.mj-forms-field--required-empty]=\"IsRequiredEmpty\" [class.mj-forms-field--has-error]=\"ShowErrors\" [class.mj-forms-field--has-warning]=\"ShowWarnings\">\n @if (ShowLabel) {\n <label class=\"mj-forms-field-label\" [innerHTML]=\"HighlightedDisplayName\"></label>\n }\n <div class=\"mj-forms-field-control\">\n <!-- Foreign Key fields get custom search autocomplete -->\n @if (HasRelatedEntity) {\n <div class=\"mj-fk-search\" [class.mj-fk-search--matched]=\"FKIsMatched\">\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FKSearchText\"\n (input)=\"OnFKInput($event)\"\n (focus)=\"OnFKFocus($event)\"\n (blur)=\"OnFKBlur()\"\n placeholder=\"Search...\">\n @if (FKSearchText) {\n <button class=\"mj-fk-clear\" (mousedown)=\"OnFKClearClick($event)\" title=\"Clear\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n } @else {\n <i class=\"fa-solid fa-magnifying-glass mj-fk-search-icon\"></i>\n }\n @if (ShowFKDropdown && FKSuggestions.length > 0) {\n <div class=\"mj-fk-dropdown\" [ngStyle]=\"DropdownPositionStyle\" [class.mj-fk-dropdown--above]=\"OpenAbove\">\n @for (suggestion of FKSuggestions; track suggestion.PrimaryKeyValue) {\n <div class=\"mj-fk-option\" (mousedown)=\"OnFKSelectItem(suggestion, $event)\">\n {{ suggestion.DisplayName }}\n </div>\n }\n </div>\n }\n </div>\n }\n @else {\n @switch (Type) {\n @case ('textbox') {\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (input)=\"OnInputChange($event)\">\n }\n @case ('textarea') {\n <textarea\n class=\"mj-forms-field-input mj-forms-field-input--textarea\"\n [value]=\"FormatValue()\"\n (input)=\"OnInputChange($event)\"></textarea>\n }\n @case ('number') {\n <input type=\"number\"\n class=\"mj-forms-field-input mj-forms-field-input--number\"\n [value]=\"Value\"\n (change)=\"OnNumberChange($event)\">\n }\n @case ('datepicker') {\n <input type=\"date\"\n class=\"mj-forms-field-input mj-forms-field-input--date\"\n [value]=\"DateInputValue\"\n (change)=\"OnDateChange($event)\">\n }\n @case ('checkbox') {\n <div class=\"mj-forms-field-checkbox\">\n <input type=\"checkbox\"\n [checked]=\"!!Value\"\n (change)=\"OnCheckboxChange($event)\">\n </div>\n }\n @case ('select') {\n <div class=\"mj-custom-select-trigger\"\n tabindex=\"0\"\n (click)=\"OnSelectTriggerClick($event)\"\n (blur)=\"OnSelectTriggerBlur()\">\n <span class=\"mj-custom-select-value\" [class.mj-custom-select-value--placeholder]=\"!FormatValue()\">\n {{ FormatValue() || '-- Select --' }}\n </span>\n <i class=\"fa-solid fa-chevron-down mj-custom-select-chevron\" [class.mj-custom-select-chevron--open]=\"ShowSelectDropdown\"></i>\n </div>\n @if (ShowSelectDropdown && PossibleValues.length > 0) {\n <div class=\"mj-fk-dropdown\" [ngStyle]=\"DropdownPositionStyle\" [class.mj-fk-dropdown--above]=\"OpenAbove\">\n @for (option of PossibleValues; track option) {\n <div class=\"mj-fk-option\" [class.mj-fk-option--selected]=\"FormatValue() === option\" (mousedown)=\"OnSelectOptionClick(option, $event)\">\n {{ option }}\n </div>\n }\n </div>\n }\n }\n @case ('autocomplete') {\n <div class=\"mj-fk-search\">\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (input)=\"OnValueListInput($event)\"\n (focus)=\"OnValueListFocus($event)\"\n (blur)=\"OnValueListBlur()\"\n placeholder=\"Type to search...\">\n <i class=\"fa-solid fa-magnifying-glass mj-fk-search-icon\"></i>\n @if (ShowValueListDropdown && FilteredPossibleValues.length > 0) {\n <div class=\"mj-fk-dropdown\" [ngStyle]=\"DropdownPositionStyle\" [class.mj-fk-dropdown--above]=\"OpenAbove\">\n @for (option of FilteredPossibleValues; track option) {\n <div class=\"mj-fk-option\" (mousedown)=\"OnValueListSelect(option, $event)\">\n {{ option }}\n </div>\n }\n </div>\n }\n </div>\n }\n @default {\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (change)=\"OnInputChange($event)\">\n }\n }\n }\n </div>\n <!-- Inline validation messages -->\n @if (DisplayErrors.length > 0) {\n <div class=\"mj-forms-field-validation mj-forms-field-validation--error\">\n @for (error of DisplayErrors; track error.Message) {\n <div class=\"mj-forms-field-validation-item\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n <span>{{ error.Message }}</span>\n </div>\n }\n </div>\n }\n @if (DisplayWarnings.length > 0) {\n <div class=\"mj-forms-field-validation mj-forms-field-validation--warning\">\n @for (warning of DisplayWarnings; track warning.Message) {\n <div class=\"mj-forms-field-validation-item\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <span>{{ warning.Message }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n}\n", styles: ["/* ============================================\n FORM FIELD - Shared styles for read and edit\n ============================================ */\n:host {\n --mj-accent: #667eea;\n --mj-accent-light: rgba(102, 126, 234, 0.08);\n --mj-text-primary: #1f2937;\n --mj-text-secondary: #4b5563;\n --mj-text-muted: #9ca3af;\n --mj-border: #e5e7eb;\n --mj-error: #ef4444;\n --mj-warning: #f59e0b;\n --mj-card-bg: #ffffff;\n --mj-forms-field-label-width: 200px;\n --mj-forms-field-gap: 12px;\n --mj-transition: 200ms;\n\n display: contents;\n}\n\n.mj-forms-field {\n display: grid;\n grid-template-columns: var(--mj-forms-field-label-width) 1fr;\n gap: var(--mj-forms-field-gap);\n align-items: baseline;\n padding: 8px 0;\n transition: all var(--mj-transition) ease;\n}\n\n/* Subtle row hover in edit mode */\n.mj-forms-field--editing:hover {\n background: var(--mj-accent-light);\n border-radius: 6px;\n margin: 0 -8px;\n padding: 8px 8px;\n}\n\n/* ============================================\n LABEL\n ============================================ */\n.mj-forms-field-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n padding-top: 2px;\n word-break: break-word;\n}\n\n/* ============================================\n FIELD CONTROL WRAPPER (value + dirty dot)\n ============================================ */\n.mj-forms-field-control {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.mj-forms-field-control > * {\n flex: 1;\n min-width: 0;\n}\n\n/* ============================================\n DIRTY INDICATOR (solid amber dot after label)\n ============================================ */\n.mj-forms-field--dirty .mj-forms-field-label::after {\n content: '';\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--mj-warning);\n margin-left: 6px;\n vertical-align: middle;\n}\n\n/* ============================================\n REQUIRED FIELD - red underline when empty\n ============================================ */\n.mj-forms-field--required-empty .mj-forms-field-input {\n border-bottom-color: var(--mj-error);\n}\n\n.mj-forms-field--required-empty .mj-forms-field-input:focus {\n background: #fef2f2;\n border-bottom-color: var(--mj-error);\n}\n\n.mj-forms-field--required-empty .mj-custom-select-trigger {\n border-bottom-color: var(--mj-error);\n}\n\n.mj-forms-field--required-empty .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-error);\n}\n\n/* ============================================\n READ-ONLY VALUE\n ============================================ */\n.mj-forms-field-value {\n font-size: 14px;\n color: var(--mj-text-primary);\n min-height: 24px;\n display: flex;\n align-items: center;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\n.mj-forms-field-value--long {\n white-space: pre-line;\n max-height: 300px;\n overflow: auto;\n}\n\n/* Read-only fields in edit mode */\n.mj-forms-field--readonly {\n opacity: 0.7;\n}\n\n.mj-forms-field--readonly .mj-forms-field-value {\n color: var(--mj-text-secondary);\n}\n\n/* ============================================\n LINKS (FK, email, URL)\n ============================================ */\n.mj-forms-field-link {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-accent);\n cursor: pointer;\n font-weight: 400;\n font-size: 14px;\n transition: color var(--mj-transition);\n text-decoration: none;\n}\n\n.mj-forms-field-link:hover {\n color: #5a6fd6;\n}\n\n.mj-forms-field-link-icon {\n font-size: 11px;\n opacity: 0;\n transition: opacity var(--mj-transition);\n}\n\n.mj-forms-field-link:hover .mj-forms-field-link-icon {\n opacity: 1;\n}\n\n/* FK fields showing entity name instead of raw ID */\n.mj-forms-field-link--fk {\n font-size: 14px;\n font-weight: 400;\n}\n\n/* ============================================\n EDIT MODE INPUTS - Clean underline style\n ============================================ */\n.mj-forms-field-input {\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border);\n padding: 4px 0;\n width: 100%;\n outline: none;\n transition: border-color var(--mj-transition) ease,\n background var(--mj-transition) ease;\n}\n\n.mj-forms-field-input:focus {\n border-bottom-color: var(--mj-accent);\n background: var(--mj-accent-light);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-forms-field-input::placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n/* Textarea variant */\n.mj-forms-field-input--textarea {\n resize: vertical;\n min-height: 60px;\n border: 1.5px solid var(--mj-border);\n border-radius: 6px;\n padding: 8px 10px;\n background: white;\n font-family: inherit;\n}\n\n.mj-forms-field-input--textarea:focus {\n border-color: var(--mj-accent);\n box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);\n background: white;\n padding: 8px 10px;\n border-radius: 6px;\n}\n\n/* Number input - narrower */\n.mj-forms-field-input--number {\n max-width: 200px;\n}\n\n/* Date input - narrower */\n.mj-forms-field-input--date {\n max-width: 220px;\n}\n\n/* ============================================\n CHECKBOX (custom styled)\n ============================================ */\n.mj-forms-field-checkbox {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"] {\n appearance: none;\n width: 18px;\n height: 18px;\n border: 2px solid var(--mj-border);\n border-radius: 4px;\n cursor: pointer;\n position: relative;\n transition: all var(--mj-transition) ease;\n flex-shrink: 0;\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:checked {\n background: var(--mj-accent);\n border-color: var(--mj-accent);\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:checked::after {\n content: '';\n position: absolute;\n left: 5px;\n top: 1px;\n width: 5px;\n height: 9px;\n border: solid white;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n/* ============================================\n CUSTOM SELECT DROPDOWN (replaces native <select>)\n ============================================ */\n.mj-custom-select-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border);\n padding: 4px 0;\n width: 100%;\n cursor: pointer;\n outline: none;\n transition: border-color var(--mj-transition) ease,\n background var(--mj-transition) ease;\n}\n\n.mj-custom-select-trigger:focus {\n border-bottom-color: var(--mj-accent);\n background: var(--mj-accent-light);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-custom-select-value {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mj-custom-select-value--placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n.mj-custom-select-chevron {\n font-size: 11px;\n color: var(--mj-text-muted);\n transition: transform var(--mj-transition) ease;\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n.mj-custom-select-chevron--open {\n transform: rotate(180deg);\n}\n\n/* ============================================\n FK SEARCH (custom autocomplete)\n ============================================ */\n.mj-fk-search {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n}\n\n.mj-fk-search .mj-forms-field-input {\n padding-right: 28px;\n}\n\n.mj-fk-search-icon {\n position: absolute;\n right: 4px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.mj-fk-clear {\n position: absolute;\n right: 2px;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 11px;\n padding: 4px 6px;\n line-height: 1;\n border-radius: 3px;\n transition: all var(--mj-transition);\n}\n\n.mj-fk-clear:hover {\n color: var(--mj-error);\n background: rgba(239, 68, 68, 0.08);\n}\n\n/* Matched state: solid accent underline */\n.mj-fk-search--matched .mj-forms-field-input {\n border-bottom: 2px solid var(--mj-accent);\n}\n\n/* ============================================\n FLOATING DROPDOWN PANEL (position: fixed via ngStyle)\n ============================================ */\n.mj-fk-dropdown {\n background: var(--mj-card-bg);\n border: 1px solid var(--mj-border);\n border-radius: 8px;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);\n max-height: 240px;\n overflow-y: auto;\n padding: 4px;\n animation: mj-dropdown-in 150ms ease;\n}\n\n.mj-fk-dropdown--above {\n animation: mj-dropdown-in-above 150ms ease;\n}\n\n.mj-fk-option {\n padding: 10px 14px;\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: background var(--mj-transition);\n border-radius: 6px;\n}\n\n.mj-fk-option:hover {\n background: var(--mj-accent-light);\n}\n\n.mj-fk-option--selected {\n background: var(--mj-accent-light);\n font-weight: 600;\n color: var(--mj-accent);\n}\n\n.mj-fk-option--selected:hover {\n background: rgba(102, 126, 234, 0.15);\n}\n\n@keyframes mj-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n@keyframes mj-dropdown-in-above {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* ============================================\n SEARCH HIGHLIGHTING\n ============================================ */\n.mj-forms-field-label :global(.mj-forms-search-highlight) {\n background-color: #fef08a;\n color: #854d0e;\n padding: 0;\n border-radius: 2px;\n font-weight: 700;\n box-shadow: 0 0 0 2px #fef08a;\n}\n\n/* ============================================\n VALIDATION ERROR STATE\n ============================================ */\n.mj-forms-field--has-error .mj-forms-field-input {\n border-bottom-color: var(--mj-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error .mj-forms-field-input:focus {\n background: #fef2f2;\n border-bottom-color: var(--mj-error);\n}\n\n.mj-forms-field--has-error .mj-forms-field-input--textarea {\n border-color: var(--mj-error);\n}\n\n.mj-forms-field--has-error .mj-forms-field-input--textarea:focus {\n border-color: var(--mj-error);\n box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.08);\n}\n\n.mj-forms-field--has-error .mj-custom-select-trigger {\n border-bottom-color: var(--mj-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-error);\n border-bottom-width: 2px;\n}\n\n/* ============================================\n VALIDATION WARNING STATE\n ============================================ */\n.mj-forms-field--has-warning .mj-forms-field-input {\n border-bottom-color: var(--mj-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input:focus {\n background: #fffbeb;\n border-bottom-color: var(--mj-warning);\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input--textarea {\n border-color: var(--mj-warning);\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input--textarea:focus {\n border-color: var(--mj-warning);\n box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.08);\n}\n\n.mj-forms-field--has-warning .mj-custom-select-trigger {\n border-bottom-color: var(--mj-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-warning);\n border-bottom-width: 2px;\n}\n\n/* ============================================\n VALIDATION MESSAGE AREA\n ============================================ */\n.mj-forms-field-validation {\n grid-column: 2;\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: -2px;\n overflow: hidden;\n animation: mj-validation-slide-in 200ms ease-out;\n}\n\n.mj-forms-field-validation-item {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n font-size: 12px;\n line-height: 1.4;\n padding: 3px 0 1px;\n}\n\n.mj-forms-field-validation-item i {\n font-size: 11px;\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n/* Error message colors */\n.mj-forms-field-validation--error .mj-forms-field-validation-item {\n color: var(--mj-error);\n}\n\n.mj-forms-field-validation--error .mj-forms-field-validation-item i {\n color: var(--mj-error);\n}\n\n/* Warning message colors */\n.mj-forms-field-validation--warning .mj-forms-field-validation-item {\n color: #b45309;\n}\n\n.mj-forms-field-validation--warning .mj-forms-field-validation-item i {\n color: var(--mj-warning);\n}\n\n@keyframes mj-validation-slide-in {\n from {\n opacity: 0;\n max-height: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n max-height: 100px;\n transform: translateY(0);\n }\n}\n\n/* ============================================\n RESPONSIVE\n ============================================ */\n@media (max-width: 640px) {\n .mj-forms-field {\n grid-template-columns: 1fr;\n gap: 4px;\n }\n\n .mj-forms-field-label {\n font-size: 12px;\n }\n\n .mj-forms-field-validation {\n grid-column: 1;\n }\n}\n"] }]
1178
+ args: [{ standalone: false, selector: 'mj-form-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (Record && (Record.IsSaved || !IsFieldReadOnly)) {\n <!-- READ-ONLY MODE -->\n @if ((!EditMode || IsFieldReadOnly) && !ShouldHideField) {\n <div class=\"mj-forms-field\" [class.mj-forms-field--readonly]=\"EditMode && IsFieldReadOnly\" [class.mj-forms-field--dirty]=\"IsDirty\">\n @if (ShowLabel) {\n <label class=\"mj-forms-field-label\" [innerHTML]=\"HighlightedDisplayName\"></label>\n }\n <div class=\"mj-forms-field-control\">\n <!-- FK fields with a mapped name field: show the name as a hyperlink -->\n @if (IsFKWithNameField) {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link mj-forms-field-link--fk\" (click)=\"OnRecordLinkClick($event)\" title=\"View related record\">\n {{ FKDisplayName }}\n </a>\n </span>\n }\n @else {\n @switch (LinkType) {\n @case ('Email') {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link\" (click)=\"OnEmailLinkClick($event)\" title=\"Send email\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-envelope mj-forms-field-link-icon\"></i>\n </a>\n </span>\n }\n @case ('URL') {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link\" (click)=\"OnUrlLinkClick($event)\" title=\"Open link\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-arrow-up-right-from-square mj-forms-field-link-icon\"></i>\n </a>\n </span>\n }\n @case ('Record') {\n <span class=\"mj-forms-field-value\">\n <a class=\"mj-forms-field-link\" (click)=\"OnRecordLinkClick($event)\" title=\"View related record\">\n {{ FormatValue() }}\n <i class=\"fa-solid fa-arrow-up-right-from-square mj-forms-field-link-icon\"></i>\n </a>\n </span>\n }\n @default {\n @if (Type === 'checkbox') {\n <span class=\"mj-forms-field-value\">\n <div class=\"mj-forms-field-checkbox\">\n <input type=\"checkbox\" [checked]=\"!!Value\" disabled>\n </div>\n </span>\n }\n @else if (IsLongText) {\n <span class=\"mj-forms-field-value mj-forms-field-value--long\">{{ FormatValue() }}</span>\n }\n @else {\n <span class=\"mj-forms-field-value\">{{ FormatValue() }}</span>\n }\n }\n }\n }\n </div>\n </div>\n }\n\n <!-- EDIT MODE -->\n @if (EditMode && !IsFieldReadOnly) {\n <div class=\"mj-forms-field mj-forms-field--editing\" [class.mj-forms-field--dirty]=\"IsDirty\" [class.mj-forms-field--required-empty]=\"IsRequiredEmpty\" [class.mj-forms-field--has-error]=\"ShowErrors\" [class.mj-forms-field--has-warning]=\"ShowWarnings\">\n @if (ShowLabel) {\n <label class=\"mj-forms-field-label\" [innerHTML]=\"HighlightedDisplayName\"></label>\n }\n <div class=\"mj-forms-field-control\">\n <!-- Foreign Key fields get custom search autocomplete -->\n @if (HasRelatedEntity) {\n <div class=\"mj-fk-search\" [class.mj-fk-search--matched]=\"FKIsMatched\">\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FKSearchText\"\n (input)=\"OnFKInput($event)\"\n (focus)=\"OnFKFocus($event)\"\n (blur)=\"OnFKBlur()\"\n placeholder=\"Search...\">\n @if (FKSearchText) {\n <button class=\"mj-fk-clear\" (mousedown)=\"OnFKClearClick($event)\" title=\"Clear\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n } @else {\n <i class=\"fa-solid fa-magnifying-glass mj-fk-search-icon\"></i>\n }\n @if (ShowFKDropdown && FKSuggestions.length > 0) {\n <div class=\"mj-fk-dropdown\" [ngStyle]=\"DropdownPositionStyle\" [class.mj-fk-dropdown--above]=\"OpenAbove\">\n @for (suggestion of FKSuggestions; track suggestion.PrimaryKeyValue) {\n <div class=\"mj-fk-option\" (mousedown)=\"OnFKSelectItem(suggestion, $event)\">\n {{ suggestion.DisplayName }}\n </div>\n }\n </div>\n }\n </div>\n }\n @else {\n @switch (Type) {\n @case ('textbox') {\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (input)=\"OnInputChange($event)\">\n }\n @case ('textarea') {\n <textarea\n class=\"mj-forms-field-input mj-forms-field-input--textarea\"\n [value]=\"FormatValue()\"\n (input)=\"OnInputChange($event)\"></textarea>\n }\n @case ('number') {\n <input type=\"number\"\n class=\"mj-forms-field-input mj-forms-field-input--number\"\n [value]=\"Value\"\n (change)=\"OnNumberChange($event)\">\n }\n @case ('datepicker') {\n <input type=\"date\"\n class=\"mj-forms-field-input mj-forms-field-input--date\"\n [value]=\"DateInputValue\"\n (change)=\"OnDateChange($event)\">\n }\n @case ('checkbox') {\n <div class=\"mj-forms-field-checkbox\">\n <input type=\"checkbox\"\n [checked]=\"!!Value\"\n (change)=\"OnCheckboxChange($event)\">\n </div>\n }\n @case ('select') {\n <div class=\"mj-custom-select-trigger\"\n tabindex=\"0\"\n (click)=\"OnSelectTriggerClick($event)\"\n (blur)=\"OnSelectTriggerBlur()\">\n <span class=\"mj-custom-select-value\" [class.mj-custom-select-value--placeholder]=\"!FormatValue()\">\n {{ FormatValue() || '-- Select --' }}\n </span>\n <i class=\"fa-solid fa-chevron-down mj-custom-select-chevron\" [class.mj-custom-select-chevron--open]=\"ShowSelectDropdown\"></i>\n </div>\n @if (ShowSelectDropdown && PossibleValues.length > 0) {\n <div class=\"mj-fk-dropdown\" [ngStyle]=\"DropdownPositionStyle\" [class.mj-fk-dropdown--above]=\"OpenAbove\">\n @for (option of PossibleValues; track option) {\n <div class=\"mj-fk-option\" [class.mj-fk-option--selected]=\"FormatValue() === option\" (mousedown)=\"OnSelectOptionClick(option, $event)\">\n {{ option }}\n </div>\n }\n </div>\n }\n }\n @case ('autocomplete') {\n <div class=\"mj-fk-search\">\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (input)=\"OnValueListInput($event)\"\n (focus)=\"OnValueListFocus($event)\"\n (blur)=\"OnValueListBlur()\"\n placeholder=\"Type to search...\">\n <i class=\"fa-solid fa-magnifying-glass mj-fk-search-icon\"></i>\n @if (ShowValueListDropdown && FilteredPossibleValues.length > 0) {\n <div class=\"mj-fk-dropdown\" [ngStyle]=\"DropdownPositionStyle\" [class.mj-fk-dropdown--above]=\"OpenAbove\">\n @for (option of FilteredPossibleValues; track option) {\n <div class=\"mj-fk-option\" (mousedown)=\"OnValueListSelect(option, $event)\">\n {{ option }}\n </div>\n }\n </div>\n }\n </div>\n }\n @default {\n <input type=\"text\"\n class=\"mj-forms-field-input\"\n [value]=\"FormatValue()\"\n (change)=\"OnInputChange($event)\">\n }\n }\n }\n </div>\n <!-- Inline validation messages -->\n @if (DisplayErrors.length > 0) {\n <div class=\"mj-forms-field-validation mj-forms-field-validation--error\">\n @for (error of DisplayErrors; track error.Message) {\n <div class=\"mj-forms-field-validation-item\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n <span>{{ error.Message }}</span>\n </div>\n }\n </div>\n }\n @if (DisplayWarnings.length > 0) {\n <div class=\"mj-forms-field-validation mj-forms-field-validation--warning\">\n @for (warning of DisplayWarnings; track warning.Message) {\n <div class=\"mj-forms-field-validation-item\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <span>{{ warning.Message }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n}\n", styles: ["/* ============================================\n FORM FIELD - Shared styles for read and edit\n ============================================ */\n:host {\n --mj-forms-field-label-width: 200px;\n --mj-forms-field-gap: 12px;\n\n display: contents;\n}\n\n.mj-forms-field {\n display: grid;\n grid-template-columns: var(--mj-forms-field-label-width) 1fr;\n gap: var(--mj-forms-field-gap);\n align-items: baseline;\n padding: 8px 0;\n transition: all var(--mj-transition-base) ease;\n}\n\n/* Subtle row hover in edit mode */\n.mj-forms-field--editing:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 6px;\n margin: 0 -8px;\n padding: 8px 8px;\n}\n\n/* ============================================\n LABEL\n ============================================ */\n.mj-forms-field-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n padding-top: 2px;\n word-break: break-word;\n}\n\n/* ============================================\n FIELD CONTROL WRAPPER (value + dirty dot)\n ============================================ */\n.mj-forms-field-control {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.mj-forms-field-control > * {\n flex: 1;\n min-width: 0;\n}\n\n/* ============================================\n DIRTY INDICATOR (solid amber dot after label)\n ============================================ */\n.mj-forms-field--dirty .mj-forms-field-label::after {\n content: '';\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--mj-status-warning);\n margin-left: 6px;\n vertical-align: middle;\n}\n\n/* ============================================\n REQUIRED FIELD - red underline when empty\n ============================================ */\n.mj-forms-field--required-empty .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty .mj-forms-field-input:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty .mj-custom-select-trigger {\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--required-empty .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n}\n\n/* ============================================\n READ-ONLY VALUE\n ============================================ */\n.mj-forms-field-value {\n font-size: 14px;\n color: var(--mj-text-primary);\n min-height: 24px;\n display: flex;\n align-items: center;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\n.mj-forms-field-value--long {\n white-space: pre-line;\n max-height: 300px;\n overflow: auto;\n}\n\n/* Read-only fields in edit mode */\n.mj-forms-field--readonly {\n opacity: 0.7;\n}\n\n.mj-forms-field--readonly .mj-forms-field-value {\n color: var(--mj-text-secondary);\n}\n\n/* ============================================\n LINKS (FK, email, URL)\n ============================================ */\n.mj-forms-field-link {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-weight: 400;\n font-size: 14px;\n transition: color var(--mj-transition-base);\n text-decoration: none;\n}\n\n.mj-forms-field-link:hover {\n color: var(--mj-brand-primary-hover);\n}\n\n.mj-forms-field-link-icon {\n font-size: 11px;\n opacity: 0;\n transition: opacity var(--mj-transition-base);\n}\n\n.mj-forms-field-link:hover .mj-forms-field-link-icon {\n opacity: 1;\n}\n\n/* FK fields showing entity name instead of raw ID */\n.mj-forms-field-link--fk {\n font-size: 14px;\n font-weight: 400;\n}\n\n/* ============================================\n EDIT MODE INPUTS - Clean underline style\n ============================================ */\n.mj-forms-field-input {\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-forms-field-input:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-forms-field-input::placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n/* Textarea variant */\n.mj-forms-field-input--textarea {\n resize: vertical;\n min-height: 60px;\n border: 1.5px solid var(--mj-border-default);\n border-radius: 6px;\n padding: 8px 10px;\n background: var(--mj-bg-surface);\n font-family: inherit;\n}\n\n.mj-forms-field-input--textarea:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n background: var(--mj-bg-surface);\n padding: 8px 10px;\n border-radius: 6px;\n}\n\n/* Number input - narrower */\n.mj-forms-field-input--number {\n max-width: 200px;\n}\n\n/* Date input - narrower */\n.mj-forms-field-input--date {\n max-width: 220px;\n}\n\n/* ============================================\n CHECKBOX (custom styled)\n ============================================ */\n.mj-forms-field-checkbox {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"] {\n appearance: none;\n width: 18px;\n height: 18px;\n border: 2px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n position: relative;\n transition: all var(--mj-transition-base) ease;\n flex-shrink: 0;\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:checked {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:checked::after {\n content: '';\n position: absolute;\n left: 5px;\n top: 1px;\n width: 5px;\n height: 9px;\n border: solid var(--mj-text-inverse);\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n}\n\n.mj-forms-field-checkbox input[type=\"checkbox\"]:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n/* ============================================\n CUSTOM SELECT DROPDOWN (replaces native <select>)\n ============================================ */\n.mj-custom-select-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 14px;\n font-family: inherit;\n color: var(--mj-text-primary);\n background: transparent;\n border: none;\n border-bottom: 1.5px solid var(--mj-border-default);\n padding: 4px 0;\n width: 100%;\n cursor: pointer;\n outline: none;\n transition: border-color var(--mj-transition-base) ease,\n background var(--mj-transition-base) ease;\n}\n\n.mj-custom-select-trigger:focus {\n border-bottom-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n border-radius: 4px 4px 0 0;\n padding: 4px 6px;\n}\n\n.mj-custom-select-value {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mj-custom-select-value--placeholder {\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n.mj-custom-select-chevron {\n font-size: 11px;\n color: var(--mj-text-muted);\n transition: transform var(--mj-transition-base) ease;\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n.mj-custom-select-chevron--open {\n transform: rotate(180deg);\n}\n\n/* ============================================\n FK SEARCH (custom autocomplete)\n ============================================ */\n.mj-fk-search {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n}\n\n.mj-fk-search .mj-forms-field-input {\n padding-right: 28px;\n}\n\n.mj-fk-search-icon {\n position: absolute;\n right: 4px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.mj-fk-clear {\n position: absolute;\n right: 2px;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 11px;\n padding: 4px 6px;\n line-height: 1;\n border-radius: 3px;\n transition: all var(--mj-transition-base);\n}\n\n.mj-fk-clear:hover {\n color: var(--mj-status-error);\n background: color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n/* Matched state: solid accent underline */\n.mj-fk-search--matched .mj-forms-field-input {\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n/* ============================================\n FLOATING DROPDOWN PANEL (position: fixed via ngStyle)\n ============================================ */\n.mj-fk-dropdown {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-lg);\n max-height: 240px;\n overflow-y: auto;\n padding: 4px;\n animation: mj-dropdown-in 150ms ease;\n}\n\n.mj-fk-dropdown--above {\n animation: mj-dropdown-in-above 150ms ease;\n}\n\n.mj-fk-option {\n padding: 10px 14px;\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: background var(--mj-transition-base);\n border-radius: 6px;\n}\n\n.mj-fk-option:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.mj-fk-option--selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.mj-fk-option--selected:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n@keyframes mj-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n@keyframes mj-dropdown-in-above {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* ============================================\n SEARCH HIGHLIGHTING\n ============================================ */\n.mj-forms-field-label :global(.mj-forms-search-highlight) {\n background-color: var(--mj-color-warning-200, #fef08a);\n color: var(--mj-color-warning-800, #854d0e);\n padding: 0;\n border-radius: 2px;\n font-weight: 700;\n box-shadow: 0 0 0 2px var(--mj-color-warning-200, #fef08a);\n}\n\n/* ============================================\n VALIDATION ERROR STATE\n ============================================ */\n.mj-forms-field--has-error .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error .mj-forms-field-input:focus {\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error .mj-forms-field-input--textarea {\n border-color: var(--mj-status-error);\n}\n\n.mj-forms-field--has-error .mj-forms-field-input--textarea:focus {\n border-color: var(--mj-status-error);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-error) 8%, transparent);\n}\n\n.mj-forms-field--has-error .mj-custom-select-trigger {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-error .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-status-error);\n border-bottom-width: 2px;\n}\n\n/* ============================================\n VALIDATION WARNING STATE\n ============================================ */\n.mj-forms-field--has-warning .mj-forms-field-input {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input:focus {\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n border-bottom-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input--textarea {\n border-color: var(--mj-status-warning);\n}\n\n.mj-forms-field--has-warning .mj-forms-field-input--textarea:focus {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 8%, transparent);\n}\n\n.mj-forms-field--has-warning .mj-custom-select-trigger {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n.mj-forms-field--has-warning .mj-fk-search .mj-forms-field-input {\n border-bottom-color: var(--mj-status-warning);\n border-bottom-width: 2px;\n}\n\n/* ============================================\n VALIDATION MESSAGE AREA\n ============================================ */\n.mj-forms-field-validation {\n grid-column: 2;\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: -2px;\n overflow: hidden;\n animation: mj-validation-slide-in 200ms ease-out;\n}\n\n.mj-forms-field-validation-item {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n font-size: 12px;\n line-height: 1.4;\n padding: 3px 0 1px;\n}\n\n.mj-forms-field-validation-item i {\n font-size: 11px;\n margin-top: 2px;\n flex-shrink: 0;\n}\n\n/* Error message colors */\n.mj-forms-field-validation--error .mj-forms-field-validation-item {\n color: var(--mj-status-error);\n}\n\n.mj-forms-field-validation--error .mj-forms-field-validation-item i {\n color: var(--mj-status-error);\n}\n\n/* Warning message colors */\n.mj-forms-field-validation--warning .mj-forms-field-validation-item {\n color: var(--mj-color-warning-700);\n}\n\n.mj-forms-field-validation--warning .mj-forms-field-validation-item i {\n color: var(--mj-status-warning);\n}\n\n@keyframes mj-validation-slide-in {\n from {\n opacity: 0;\n max-height: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n max-height: 100px;\n transform: translateY(0);\n }\n}\n\n/* ============================================\n RESPONSIVE\n ============================================ */\n@media (max-width: 640px) {\n .mj-forms-field {\n grid-template-columns: 1fr;\n gap: 4px;\n }\n\n .mj-forms-field-label {\n font-size: 12px;\n }\n\n .mj-forms-field-validation {\n grid-column: 1;\n }\n}\n"] }]
1174
1179
  }], null, { Record: [{
1175
1180
  type: Input
1176
1181
  }], EditMode: [{