@memberjunction/ng-base-forms 5.38.0 → 5.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +53 -0
  2. package/dist/lib/base-form-component.d.ts +18 -0
  3. package/dist/lib/base-form-component.d.ts.map +1 -1
  4. package/dist/lib/base-form-component.js +31 -2
  5. package/dist/lib/base-form-component.js.map +1 -1
  6. package/dist/lib/container/record-form-container.component.d.ts +14 -0
  7. package/dist/lib/container/record-form-container.component.d.ts.map +1 -1
  8. package/dist/lib/container/record-form-container.component.js +59 -33
  9. package/dist/lib/container/record-form-container.component.js.map +1 -1
  10. package/dist/lib/field/fk-search-utils.d.ts +31 -0
  11. package/dist/lib/field/fk-search-utils.d.ts.map +1 -0
  12. package/dist/lib/field/fk-search-utils.js +47 -0
  13. package/dist/lib/field/fk-search-utils.js.map +1 -0
  14. package/dist/lib/field/form-field.component.d.ts +401 -6
  15. package/dist/lib/field/form-field.component.d.ts.map +1 -1
  16. package/dist/lib/field/form-field.component.js +1646 -214
  17. package/dist/lib/field/form-field.component.js.map +1 -1
  18. package/dist/lib/field/linked-field-options.d.ts +76 -0
  19. package/dist/lib/field/linked-field-options.d.ts.map +1 -0
  20. package/dist/lib/field/linked-field-options.js +80 -0
  21. package/dist/lib/field/linked-field-options.js.map +1 -0
  22. package/dist/lib/host/entity-form-host.component.d.ts +159 -0
  23. package/dist/lib/host/entity-form-host.component.d.ts.map +1 -0
  24. package/dist/lib/host/entity-form-host.component.js +539 -0
  25. package/dist/lib/host/entity-form-host.component.js.map +1 -0
  26. package/dist/lib/isa-related-panel/isa-related-card.component.js +2 -2
  27. package/dist/lib/overlays/base-form-overlay.d.ts +114 -0
  28. package/dist/lib/overlays/base-form-overlay.d.ts.map +1 -0
  29. package/dist/lib/overlays/base-form-overlay.js +227 -0
  30. package/dist/lib/overlays/base-form-overlay.js.map +1 -0
  31. package/dist/lib/overlays/form-dialog.component.d.ts +35 -0
  32. package/dist/lib/overlays/form-dialog.component.d.ts.map +1 -0
  33. package/dist/lib/overlays/form-dialog.component.js +92 -0
  34. package/dist/lib/overlays/form-dialog.component.js.map +1 -0
  35. package/dist/lib/overlays/form-presenter.service.d.ts +37 -0
  36. package/dist/lib/overlays/form-presenter.service.d.ts.map +1 -0
  37. package/dist/lib/overlays/form-presenter.service.js +130 -0
  38. package/dist/lib/overlays/form-presenter.service.js.map +1 -0
  39. package/dist/lib/overlays/form-presenter.types.d.ts +65 -0
  40. package/dist/lib/overlays/form-presenter.types.d.ts.map +1 -0
  41. package/dist/lib/overlays/form-presenter.types.js +25 -0
  42. package/dist/lib/overlays/form-presenter.types.js.map +1 -0
  43. package/dist/lib/overlays/form-slide-in.component.d.ts +38 -0
  44. package/dist/lib/overlays/form-slide-in.component.d.ts.map +1 -0
  45. package/dist/lib/overlays/form-slide-in.component.js +106 -0
  46. package/dist/lib/overlays/form-slide-in.component.js.map +1 -0
  47. package/dist/lib/overlays/form-window.component.d.ts +32 -0
  48. package/dist/lib/overlays/form-window.component.d.ts.map +1 -0
  49. package/dist/lib/overlays/form-window.component.js +93 -0
  50. package/dist/lib/overlays/form-window.component.js.map +1 -0
  51. package/dist/lib/panel/collapsible-panel.component.d.ts +19 -2
  52. package/dist/lib/panel/collapsible-panel.component.d.ts.map +1 -1
  53. package/dist/lib/panel/collapsible-panel.component.js +70 -13
  54. package/dist/lib/panel/collapsible-panel.component.js.map +1 -1
  55. package/dist/lib/resolver/form-resolver.service.d.ts +139 -0
  56. package/dist/lib/resolver/form-resolver.service.d.ts.map +1 -0
  57. package/dist/lib/resolver/form-resolver.service.js +235 -0
  58. package/dist/lib/resolver/form-resolver.service.js.map +1 -0
  59. package/dist/lib/section-manager/section-manager.component.js +2 -2
  60. package/dist/lib/toolbar/form-toolbar.component.js +2 -2
  61. package/dist/lib/types/entity-form-config.d.ts +125 -0
  62. package/dist/lib/types/entity-form-config.d.ts.map +1 -0
  63. package/dist/lib/types/entity-form-config.js +75 -0
  64. package/dist/lib/types/entity-form-config.js.map +1 -0
  65. package/dist/lib/types/form-types.d.ts +24 -0
  66. package/dist/lib/types/form-types.d.ts.map +1 -1
  67. package/dist/lib/types/form-types.js.map +1 -1
  68. package/dist/lib/types/navigation-events.d.ts +46 -2
  69. package/dist/lib/types/navigation-events.d.ts.map +1 -1
  70. package/dist/lib/types/navigation-events.js.map +1 -1
  71. package/dist/module.d.ts +12 -8
  72. package/dist/module.d.ts.map +1 -1
  73. package/dist/module.js +26 -7
  74. package/dist/module.js.map +1 -1
  75. package/dist/public-api.d.ts +11 -0
  76. package/dist/public-api.d.ts.map +1 -1
  77. package/dist/public-api.js +14 -0
  78. package/dist/public-api.js.map +1 -1
  79. package/package.json +17 -13
@@ -323,11 +323,11 @@ export class MjIsaRelatedCardComponent extends BaseAngularComponent {
323
323
  i0.ɵɵconditional(!ctx.IsLoading && !ctx.LoadError && ctx.RelatedRecord ? 11 : -1);
324
324
  i0.ɵɵadvance();
325
325
  i0.ɵɵconditional(ctx.Children.length > 0 && !ctx.IsLoading ? 12 : -1);
326
- } }, dependencies: [MjIsaRelatedCardComponent], styles: ["/* ============================================\n ISA RELATED CARD\n Compact summary card for one sibling/child entity\n ============================================ */\n\n.mj-isa-card {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n/* ---- Header ---- */\n.mj-isa-card__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 14px;\n background: var(--mj-bg-surface-elevated);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.mj-isa-card__header-left {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.mj-isa-card__icon {\n font-size: 14px;\n color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.mj-isa-card__entity-name {\n font-size: 13px;\n font-weight: 700;\n color: var(--mj-text-primary);\n white-space: nowrap;\n}\n\n.mj-isa-card__record-name {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-weight: 400;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mj-isa-card__open-link {\n font-size: 11px;\n color: var(--mj-brand-primary);\n text-decoration: none;\n font-weight: 600;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.mj-isa-card__open-link:hover {\n text-decoration: underline;\n}\n\n/* ---- Body / Fields ---- */\n.mj-isa-card__body {\n padding: 8px 14px 10px;\n}\n\n.mj-isa-card__field {\n display: flex;\n align-items: baseline;\n padding: 3px 0;\n gap: 8px;\n}\n\n.mj-isa-card__field-label {\n font-size: 11px;\n color: var(--mj-text-muted);\n width: 110px;\n flex-shrink: 0;\n}\n\n.mj-isa-card__field-value {\n font-size: 12px;\n color: var(--mj-text-primary);\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-isa-card__field-value--bool-yes {\n color: var(--mj-status-success);\n}\n\n.mj-isa-card__field-value--bool-no {\n color: var(--mj-status-error);\n}\n\n/* ---- Expand/Collapse ---- */\n.mj-isa-card__expand-row {\n padding: 0 14px 8px;\n}\n\n.mj-isa-card__expand-btn {\n font-size: 11px;\n color: var(--mj-brand-primary);\n background: none;\n border: none;\n cursor: pointer;\n font-weight: 600;\n padding: 0;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.mj-isa-card__expand-btn:hover {\n text-decoration: underline;\n}\n\n.mj-isa-card__expand-chevron {\n font-size: 9px;\n}\n\n.mj-isa-card__extra-fields {\n padding: 0 14px 10px;\n border-top: 1px dashed var(--mj-border-default);\n margin-top: 4px;\n padding-top: 8px;\n}\n\n/* ---- Loading State ---- */\n.mj-isa-card__body--loading {\n padding: 12px 14px;\n}\n\n.mj-isa-card__loading-bar {\n height: 10px;\n background: linear-gradient(90deg,\n var(--mj-bg-surface-sunken) 25%,\n var(--mj-border-default) 50%,\n var(--mj-bg-surface-sunken) 75%);\n background-size: 200% 100%;\n animation: mj-isa-shimmer 1.5s infinite;\n border-radius: 4px;\n margin-bottom: 8px;\n width: 80%;\n}\n\n.mj-isa-card__loading-bar--short {\n width: 50%;\n}\n\n@keyframes mj-isa-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* ---- Nested Sub-Cards (grandchild+ rendered inside parent card) ---- */\n.mj-isa-card__children {\n padding: 6px 10px 8px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.mj-isa-card--nested {\n box-shadow: none;\n border: 1px solid var(--mj-border-default);\n border-left: 2px solid color-mix(in srgb, var(--mj-brand-primary) 60%, var(--mj-color-neutral-400));\n border-radius: var(--mj-radius-md);\n}\n\n.mj-isa-card--nested .mj-isa-card__header {\n padding: 6px 10px;\n background: var(--mj-bg-surface-sunken);\n border-bottom-color: var(--mj-border-default);\n}\n\n.mj-isa-card--nested .mj-isa-card__entity-name {\n font-size: 12px;\n}\n\n.mj-isa-card--nested .mj-isa-card__icon {\n font-size: 12px;\n}\n\n.mj-isa-card--nested .mj-isa-card__body {\n padding: 6px 10px 8px;\n}\n\n.mj-isa-card--nested .mj-isa-card__field-label {\n width: 95px;\n font-size: 10px;\n}\n\n.mj-isa-card--nested .mj-isa-card__field-value {\n font-size: 11px;\n}\n\n/* ---- Error State ---- */\n.mj-isa-card__body--error {\n padding: 10px 14px;\n}\n\n.mj-isa-card__error-text {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-style: italic;\n}\n"], encapsulation: 2, changeDetection: 0 });
326
+ } }, dependencies: [MjIsaRelatedCardComponent], styles: ["/* ============================================\n ISA RELATED CARD\n Compact summary card for one sibling/child entity\n ============================================ */\n\n.mj-isa-card {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n/* ---- Header ---- */\n.mj-isa-card__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 14px;\n background: var(--mj-bg-surface-elevated);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.mj-isa-card__header-left {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.mj-isa-card__icon {\n font-size: 14px;\n color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.mj-isa-card__entity-name {\n font-size: 13px;\n font-weight: 700;\n color: var(--mj-text-primary);\n white-space: nowrap;\n}\n\n.mj-isa-card__record-name {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-weight: 400;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mj-isa-card__open-link {\n font-size: 11px;\n color: var(--mj-brand-primary);\n text-decoration: none;\n font-weight: 600;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.mj-isa-card__open-link:hover {\n text-decoration: underline;\n}\n\n/* ---- Body / Fields ---- */\n.mj-isa-card__body {\n padding: 8px 14px 10px;\n}\n\n.mj-isa-card__field {\n display: flex;\n align-items: baseline;\n padding: 3px 0;\n gap: 8px;\n}\n\n.mj-isa-card__field-label {\n font-size: 11px;\n color: var(--mj-text-muted);\n width: 110px;\n flex-shrink: 0;\n}\n\n.mj-isa-card__field-value {\n font-size: 12px;\n color: var(--mj-text-primary);\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-isa-card__field-value--bool-yes {\n color: var(--mj-status-success);\n}\n\n.mj-isa-card__field-value--bool-no {\n color: var(--mj-status-error);\n}\n\n/* ---- Expand/Collapse ---- */\n.mj-isa-card__expand-row {\n padding: 0 14px 8px;\n}\n\n.mj-isa-card__expand-btn {\n font-size: 11px;\n color: var(--mj-brand-primary);\n background: none;\n border: none;\n cursor: pointer;\n font-weight: 600;\n padding: 0;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.mj-isa-card__expand-btn:hover {\n text-decoration: underline;\n}\n\n.mj-isa-card__expand-chevron {\n font-size: 9px;\n}\n\n.mj-isa-card__extra-fields {\n padding: 0 14px 10px;\n border-top: 1px dashed var(--mj-border-default);\n margin-top: 4px;\n padding-top: 8px;\n}\n\n/* ---- Loading State ---- */\n.mj-isa-card__body--loading {\n padding: 12px 14px;\n}\n\n.mj-isa-card__loading-bar {\n height: 10px;\n background: linear-gradient(90deg,\n var(--mj-bg-surface-sunken) 25%,\n var(--mj-border-default) 50%,\n var(--mj-bg-surface-sunken) 75%);\n background-size: 200% 100%;\n animation: mj-isa-shimmer 1.5s infinite;\n border-radius: 4px;\n margin-bottom: 8px;\n width: 80%;\n}\n\n.mj-isa-card__loading-bar--short {\n width: 50%;\n}\n\n@keyframes mj-isa-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* ---- Nested Sub-Cards (grandchild+ rendered inside parent card) ---- */\n.mj-isa-card__children {\n padding: 6px 10px 8px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.mj-isa-card--nested {\n box-shadow: none;\n border: 1px solid var(--mj-border-default);\n border-left: 2px solid color-mix(in srgb, var(--mj-brand-primary) 60%, var(--mj-border-strong));\n border-radius: var(--mj-radius-md);\n}\n\n.mj-isa-card--nested .mj-isa-card__header {\n padding: 6px 10px;\n background: var(--mj-bg-surface-sunken);\n border-bottom-color: var(--mj-border-default);\n}\n\n.mj-isa-card--nested .mj-isa-card__entity-name {\n font-size: 12px;\n}\n\n.mj-isa-card--nested .mj-isa-card__icon {\n font-size: 12px;\n}\n\n.mj-isa-card--nested .mj-isa-card__body {\n padding: 6px 10px 8px;\n}\n\n.mj-isa-card--nested .mj-isa-card__field-label {\n width: 95px;\n font-size: 10px;\n}\n\n.mj-isa-card--nested .mj-isa-card__field-value {\n font-size: 11px;\n}\n\n/* ---- Error State ---- */\n.mj-isa-card__body--error {\n padding: 10px 14px;\n}\n\n.mj-isa-card__error-text {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-style: italic;\n}\n"], encapsulation: 2, changeDetection: 0 });
327
327
  }
328
328
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MjIsaRelatedCardComponent, [{
329
329
  type: Component,
330
- args: [{ standalone: false, selector: 'mj-isa-related-card', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<!-- ISA Related Card: compact summary of one sibling/child entity record -->\n<div class=\"mj-isa-card\"\n [class.mj-isa-card--loading]=\"IsLoading\"\n [class.mj-isa-card--error]=\"LoadError\"\n [class.mj-isa-card--nested]=\"Depth > 0\">\n\n <!-- Card Header -->\n <div class=\"mj-isa-card__header\">\n <div class=\"mj-isa-card__header-left\">\n <i [class]=\"IconClass\" class=\"mj-isa-card__icon\"></i>\n <span class=\"mj-isa-card__entity-name\">{{ DisplayName }}</span>\n @if (RecordName) {\n <span class=\"mj-isa-card__record-name\">{{ RecordName }}</span>\n }\n </div>\n <a href=\"#\" class=\"mj-isa-card__open-link\" (click)=\"OnOpenClick($event)\">Open &rarr;</a>\n </div>\n\n <!-- Loading State -->\n @if (IsLoading) {\n <div class=\"mj-isa-card__body mj-isa-card__body--loading\">\n <div class=\"mj-isa-card__loading-bar\"></div>\n <div class=\"mj-isa-card__loading-bar mj-isa-card__loading-bar--short\"></div>\n </div>\n }\n\n <!-- Error State -->\n @if (LoadError && !IsLoading) {\n <div class=\"mj-isa-card__body mj-isa-card__body--error\">\n <span class=\"mj-isa-card__error-text\">Unable to load record</span>\n </div>\n }\n\n <!-- Field Values -->\n @if (!IsLoading && !LoadError && RelatedRecord) {\n <div class=\"mj-isa-card__body\">\n @for (field of DefaultFields; track field.Label) {\n <div class=\"mj-isa-card__field\">\n <span class=\"mj-isa-card__field-label\">{{ field.Label }}</span>\n <span class=\"mj-isa-card__field-value\"\n [class.mj-isa-card__field-value--bool-yes]=\"field.IsBooleanTrue\"\n [class.mj-isa-card__field-value--bool-no]=\"field.IsBooleanFalse\">\n {{ field.Value }}\n </span>\n </div>\n }\n </div>\n\n <!-- Expand/Collapse for extra fields -->\n @if (ExtraFields.length > 0) {\n <div class=\"mj-isa-card__expand-row\">\n <button class=\"mj-isa-card__expand-btn\" (click)=\"ToggleExpand()\">\n @if (!Expanded) {\n Show {{ ExtraFields.length }} more field{{ ExtraFields.length > 1 ? 's' : '' }}\n <i class=\"fa-solid fa-chevron-down mj-isa-card__expand-chevron\"></i>\n } @else {\n Show fewer fields\n <i class=\"fa-solid fa-chevron-up mj-isa-card__expand-chevron\"></i>\n }\n </button>\n </div>\n\n @if (Expanded) {\n <div class=\"mj-isa-card__extra-fields\">\n @for (field of ExtraFields; track field.Label) {\n <div class=\"mj-isa-card__field\">\n <span class=\"mj-isa-card__field-label\">{{ field.Label }}</span>\n <span class=\"mj-isa-card__field-value\"\n [class.mj-isa-card__field-value--bool-yes]=\"field.IsBooleanTrue\"\n [class.mj-isa-card__field-value--bool-no]=\"field.IsBooleanFalse\">\n {{ field.Value }}\n </span>\n </div>\n }\n </div>\n }\n }\n }\n\n <!-- Nested sub-cards for IS-A children (e.g., Gold Members inside Members) -->\n @if (Children.length > 0 && !IsLoading) {\n <div class=\"mj-isa-card__children\">\n @for (child of Children; track child.EntityName) {\n <mj-isa-related-card\n [EntityName]=\"child.EntityName\"\n [PrimaryKey]=\"PrimaryKey\"\n [CurrentRecordName]=\"CurrentRecordName\"\n [Relationship]=\"'child'\"\n [Depth]=\"Depth + 1\"\n [Children]=\"child.Children\"\n (Navigate)=\"Navigate.emit($event)\">\n </mj-isa-related-card>\n }\n </div>\n }\n</div>\n", styles: ["/* ============================================\n ISA RELATED CARD\n Compact summary card for one sibling/child entity\n ============================================ */\n\n.mj-isa-card {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n/* ---- Header ---- */\n.mj-isa-card__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 14px;\n background: var(--mj-bg-surface-elevated);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.mj-isa-card__header-left {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.mj-isa-card__icon {\n font-size: 14px;\n color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.mj-isa-card__entity-name {\n font-size: 13px;\n font-weight: 700;\n color: var(--mj-text-primary);\n white-space: nowrap;\n}\n\n.mj-isa-card__record-name {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-weight: 400;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mj-isa-card__open-link {\n font-size: 11px;\n color: var(--mj-brand-primary);\n text-decoration: none;\n font-weight: 600;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.mj-isa-card__open-link:hover {\n text-decoration: underline;\n}\n\n/* ---- Body / Fields ---- */\n.mj-isa-card__body {\n padding: 8px 14px 10px;\n}\n\n.mj-isa-card__field {\n display: flex;\n align-items: baseline;\n padding: 3px 0;\n gap: 8px;\n}\n\n.mj-isa-card__field-label {\n font-size: 11px;\n color: var(--mj-text-muted);\n width: 110px;\n flex-shrink: 0;\n}\n\n.mj-isa-card__field-value {\n font-size: 12px;\n color: var(--mj-text-primary);\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-isa-card__field-value--bool-yes {\n color: var(--mj-status-success);\n}\n\n.mj-isa-card__field-value--bool-no {\n color: var(--mj-status-error);\n}\n\n/* ---- Expand/Collapse ---- */\n.mj-isa-card__expand-row {\n padding: 0 14px 8px;\n}\n\n.mj-isa-card__expand-btn {\n font-size: 11px;\n color: var(--mj-brand-primary);\n background: none;\n border: none;\n cursor: pointer;\n font-weight: 600;\n padding: 0;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.mj-isa-card__expand-btn:hover {\n text-decoration: underline;\n}\n\n.mj-isa-card__expand-chevron {\n font-size: 9px;\n}\n\n.mj-isa-card__extra-fields {\n padding: 0 14px 10px;\n border-top: 1px dashed var(--mj-border-default);\n margin-top: 4px;\n padding-top: 8px;\n}\n\n/* ---- Loading State ---- */\n.mj-isa-card__body--loading {\n padding: 12px 14px;\n}\n\n.mj-isa-card__loading-bar {\n height: 10px;\n background: linear-gradient(90deg,\n var(--mj-bg-surface-sunken) 25%,\n var(--mj-border-default) 50%,\n var(--mj-bg-surface-sunken) 75%);\n background-size: 200% 100%;\n animation: mj-isa-shimmer 1.5s infinite;\n border-radius: 4px;\n margin-bottom: 8px;\n width: 80%;\n}\n\n.mj-isa-card__loading-bar--short {\n width: 50%;\n}\n\n@keyframes mj-isa-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* ---- Nested Sub-Cards (grandchild+ rendered inside parent card) ---- */\n.mj-isa-card__children {\n padding: 6px 10px 8px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.mj-isa-card--nested {\n box-shadow: none;\n border: 1px solid var(--mj-border-default);\n border-left: 2px solid color-mix(in srgb, var(--mj-brand-primary) 60%, var(--mj-color-neutral-400));\n border-radius: var(--mj-radius-md);\n}\n\n.mj-isa-card--nested .mj-isa-card__header {\n padding: 6px 10px;\n background: var(--mj-bg-surface-sunken);\n border-bottom-color: var(--mj-border-default);\n}\n\n.mj-isa-card--nested .mj-isa-card__entity-name {\n font-size: 12px;\n}\n\n.mj-isa-card--nested .mj-isa-card__icon {\n font-size: 12px;\n}\n\n.mj-isa-card--nested .mj-isa-card__body {\n padding: 6px 10px 8px;\n}\n\n.mj-isa-card--nested .mj-isa-card__field-label {\n width: 95px;\n font-size: 10px;\n}\n\n.mj-isa-card--nested .mj-isa-card__field-value {\n font-size: 11px;\n}\n\n/* ---- Error State ---- */\n.mj-isa-card__body--error {\n padding: 10px 14px;\n}\n\n.mj-isa-card__error-text {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-style: italic;\n}\n"] }]
330
+ args: [{ standalone: false, selector: 'mj-isa-related-card', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<!-- ISA Related Card: compact summary of one sibling/child entity record -->\n<div class=\"mj-isa-card\"\n [class.mj-isa-card--loading]=\"IsLoading\"\n [class.mj-isa-card--error]=\"LoadError\"\n [class.mj-isa-card--nested]=\"Depth > 0\">\n\n <!-- Card Header -->\n <div class=\"mj-isa-card__header\">\n <div class=\"mj-isa-card__header-left\">\n <i [class]=\"IconClass\" class=\"mj-isa-card__icon\"></i>\n <span class=\"mj-isa-card__entity-name\">{{ DisplayName }}</span>\n @if (RecordName) {\n <span class=\"mj-isa-card__record-name\">{{ RecordName }}</span>\n }\n </div>\n <a href=\"#\" class=\"mj-isa-card__open-link\" (click)=\"OnOpenClick($event)\">Open &rarr;</a>\n </div>\n\n <!-- Loading State -->\n @if (IsLoading) {\n <div class=\"mj-isa-card__body mj-isa-card__body--loading\">\n <div class=\"mj-isa-card__loading-bar\"></div>\n <div class=\"mj-isa-card__loading-bar mj-isa-card__loading-bar--short\"></div>\n </div>\n }\n\n <!-- Error State -->\n @if (LoadError && !IsLoading) {\n <div class=\"mj-isa-card__body mj-isa-card__body--error\">\n <span class=\"mj-isa-card__error-text\">Unable to load record</span>\n </div>\n }\n\n <!-- Field Values -->\n @if (!IsLoading && !LoadError && RelatedRecord) {\n <div class=\"mj-isa-card__body\">\n @for (field of DefaultFields; track field.Label) {\n <div class=\"mj-isa-card__field\">\n <span class=\"mj-isa-card__field-label\">{{ field.Label }}</span>\n <span class=\"mj-isa-card__field-value\"\n [class.mj-isa-card__field-value--bool-yes]=\"field.IsBooleanTrue\"\n [class.mj-isa-card__field-value--bool-no]=\"field.IsBooleanFalse\">\n {{ field.Value }}\n </span>\n </div>\n }\n </div>\n\n <!-- Expand/Collapse for extra fields -->\n @if (ExtraFields.length > 0) {\n <div class=\"mj-isa-card__expand-row\">\n <button class=\"mj-isa-card__expand-btn\" (click)=\"ToggleExpand()\">\n @if (!Expanded) {\n Show {{ ExtraFields.length }} more field{{ ExtraFields.length > 1 ? 's' : '' }}\n <i class=\"fa-solid fa-chevron-down mj-isa-card__expand-chevron\"></i>\n } @else {\n Show fewer fields\n <i class=\"fa-solid fa-chevron-up mj-isa-card__expand-chevron\"></i>\n }\n </button>\n </div>\n\n @if (Expanded) {\n <div class=\"mj-isa-card__extra-fields\">\n @for (field of ExtraFields; track field.Label) {\n <div class=\"mj-isa-card__field\">\n <span class=\"mj-isa-card__field-label\">{{ field.Label }}</span>\n <span class=\"mj-isa-card__field-value\"\n [class.mj-isa-card__field-value--bool-yes]=\"field.IsBooleanTrue\"\n [class.mj-isa-card__field-value--bool-no]=\"field.IsBooleanFalse\">\n {{ field.Value }}\n </span>\n </div>\n }\n </div>\n }\n }\n }\n\n <!-- Nested sub-cards for IS-A children (e.g., Gold Members inside Members) -->\n @if (Children.length > 0 && !IsLoading) {\n <div class=\"mj-isa-card__children\">\n @for (child of Children; track child.EntityName) {\n <mj-isa-related-card\n [EntityName]=\"child.EntityName\"\n [PrimaryKey]=\"PrimaryKey\"\n [CurrentRecordName]=\"CurrentRecordName\"\n [Relationship]=\"'child'\"\n [Depth]=\"Depth + 1\"\n [Children]=\"child.Children\"\n (Navigate)=\"Navigate.emit($event)\">\n </mj-isa-related-card>\n }\n </div>\n }\n</div>\n", styles: ["/* ============================================\n ISA RELATED CARD\n Compact summary card for one sibling/child entity\n ============================================ */\n\n.mj-isa-card {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n/* ---- Header ---- */\n.mj-isa-card__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 14px;\n background: var(--mj-bg-surface-elevated);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.mj-isa-card__header-left {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.mj-isa-card__icon {\n font-size: 14px;\n color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.mj-isa-card__entity-name {\n font-size: 13px;\n font-weight: 700;\n color: var(--mj-text-primary);\n white-space: nowrap;\n}\n\n.mj-isa-card__record-name {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-weight: 400;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mj-isa-card__open-link {\n font-size: 11px;\n color: var(--mj-brand-primary);\n text-decoration: none;\n font-weight: 600;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.mj-isa-card__open-link:hover {\n text-decoration: underline;\n}\n\n/* ---- Body / Fields ---- */\n.mj-isa-card__body {\n padding: 8px 14px 10px;\n}\n\n.mj-isa-card__field {\n display: flex;\n align-items: baseline;\n padding: 3px 0;\n gap: 8px;\n}\n\n.mj-isa-card__field-label {\n font-size: 11px;\n color: var(--mj-text-muted);\n width: 110px;\n flex-shrink: 0;\n}\n\n.mj-isa-card__field-value {\n font-size: 12px;\n color: var(--mj-text-primary);\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mj-isa-card__field-value--bool-yes {\n color: var(--mj-status-success);\n}\n\n.mj-isa-card__field-value--bool-no {\n color: var(--mj-status-error);\n}\n\n/* ---- Expand/Collapse ---- */\n.mj-isa-card__expand-row {\n padding: 0 14px 8px;\n}\n\n.mj-isa-card__expand-btn {\n font-size: 11px;\n color: var(--mj-brand-primary);\n background: none;\n border: none;\n cursor: pointer;\n font-weight: 600;\n padding: 0;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.mj-isa-card__expand-btn:hover {\n text-decoration: underline;\n}\n\n.mj-isa-card__expand-chevron {\n font-size: 9px;\n}\n\n.mj-isa-card__extra-fields {\n padding: 0 14px 10px;\n border-top: 1px dashed var(--mj-border-default);\n margin-top: 4px;\n padding-top: 8px;\n}\n\n/* ---- Loading State ---- */\n.mj-isa-card__body--loading {\n padding: 12px 14px;\n}\n\n.mj-isa-card__loading-bar {\n height: 10px;\n background: linear-gradient(90deg,\n var(--mj-bg-surface-sunken) 25%,\n var(--mj-border-default) 50%,\n var(--mj-bg-surface-sunken) 75%);\n background-size: 200% 100%;\n animation: mj-isa-shimmer 1.5s infinite;\n border-radius: 4px;\n margin-bottom: 8px;\n width: 80%;\n}\n\n.mj-isa-card__loading-bar--short {\n width: 50%;\n}\n\n@keyframes mj-isa-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* ---- Nested Sub-Cards (grandchild+ rendered inside parent card) ---- */\n.mj-isa-card__children {\n padding: 6px 10px 8px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.mj-isa-card--nested {\n box-shadow: none;\n border: 1px solid var(--mj-border-default);\n border-left: 2px solid color-mix(in srgb, var(--mj-brand-primary) 60%, var(--mj-border-strong));\n border-radius: var(--mj-radius-md);\n}\n\n.mj-isa-card--nested .mj-isa-card__header {\n padding: 6px 10px;\n background: var(--mj-bg-surface-sunken);\n border-bottom-color: var(--mj-border-default);\n}\n\n.mj-isa-card--nested .mj-isa-card__entity-name {\n font-size: 12px;\n}\n\n.mj-isa-card--nested .mj-isa-card__icon {\n font-size: 12px;\n}\n\n.mj-isa-card--nested .mj-isa-card__body {\n padding: 6px 10px 8px;\n}\n\n.mj-isa-card--nested .mj-isa-card__field-label {\n width: 95px;\n font-size: 10px;\n}\n\n.mj-isa-card--nested .mj-isa-card__field-value {\n font-size: 11px;\n}\n\n/* ---- Error State ---- */\n.mj-isa-card__body--error {\n padding: 10px 14px;\n}\n\n.mj-isa-card__error-text {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-style: italic;\n}\n"] }]
331
331
  }], null, { EntityName: [{
332
332
  type: Input
333
333
  }], PrimaryKey: [{
@@ -0,0 +1,114 @@
1
+ import { EventEmitter } from '@angular/core';
2
+ import { BaseEntity, CompositeKey } from '@memberjunction/core';
3
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
4
+ import { MjEntityFormHostComponent } from '../host/entity-form-host.component';
5
+ import { EntityFormConfig } from '../types/entity-form-config';
6
+ import { FormNavigationEvent } from '../types/navigation-events';
7
+ import { FormNotificationEvent, RecordDeletedEvent, RecordSaveFailedEvent, ValidationFailedEvent } from '../types/form-types';
8
+ import { BaseFormComponent } from '../base-form-component';
9
+ import * as i0 from "@angular/core";
10
+ /** How an overlay closed. */
11
+ export type FormOverlayCloseReason = 'save' | 'cancel';
12
+ /**
13
+ * Shared logic for the form overlay shells ({@link MjFormDialogComponent} and
14
+ * {@link MjFormSlideInComponent}). Both wrap an {@link MjEntityFormHostComponent}
15
+ * in chrome that owns the title + Save/Cancel, bubble the host's events upward,
16
+ * and proxy the form inputs downward.
17
+ *
18
+ * Subclasses provide only the template; all input/output plumbing lives here.
19
+ */
20
+ export declare abstract class BaseFormOverlay extends BaseAngularComponent {
21
+ /** Reference to the hosted form (template must name the host `#host`). */
22
+ protected host?: MjEntityFormHostComponent;
23
+ /** Entity name to load. Ignored when {@link Record} is supplied. */
24
+ EntityName: string | null;
25
+ /** Primary key of the record to edit. Empty/absent → new record. */
26
+ PrimaryKey?: CompositeKey;
27
+ /** Convenience single-column ('ID') key; used when {@link PrimaryKey} is absent. */
28
+ RecordID?: string;
29
+ /** Pre-loaded record to bind directly (skips load). */
30
+ Record: BaseEntity | null;
31
+ /** New-record default values: URL-segment string or plain object. */
32
+ NewRecordValues: string | Record<string, unknown> | null;
33
+ /**
34
+ * Render a single registered form section (`BaseFormSectionComponent`
35
+ * registered as `'<EntityName>.<SectionName>'`) instead of the full form.
36
+ * See {@link MjEntityFormHostComponent.SectionName}.
37
+ */
38
+ SectionName: string | null;
39
+ /** Force edit mode (default: new → edit, existing → read). */
40
+ EditMode: boolean | null;
41
+ /**
42
+ * Per-instance config OVERRIDE. Treated as a partial set of overrides that is
43
+ * merged **over** the surface's {@link PresetConfig} — so passing
44
+ * `{ StartInEditMode: true }` keeps the preset's `Toolbar: null` etc. instead
45
+ * of replacing the whole preset. Bind the merged result via {@link EffectiveConfig}.
46
+ */
47
+ Config: EntityFormConfig | null;
48
+ /**
49
+ * The surface's default config preset (TAB/DIALOG/SLIDEIN). Subclasses override
50
+ * this getter; the base returns an empty object (no defaults).
51
+ */
52
+ protected get PresetConfig(): EntityFormConfig;
53
+ /**
54
+ * The config actually handed to the form host: the surface {@link PresetConfig}
55
+ * with any consumer {@link Config} overrides merged on top. This is what makes
56
+ * partial configs work — you only specify what differs from the preset.
57
+ */
58
+ get EffectiveConfig(): EntityFormConfig;
59
+ /** Title shown in the chrome. When empty, derived from the record on load. */
60
+ Title: string;
61
+ /** Whether to show the Save/Cancel footer. Default: true. */
62
+ ShowFooter: boolean;
63
+ /** Save button label. */
64
+ SaveButtonText: string;
65
+ /** Cancel button label. */
66
+ CancelButtonText: string;
67
+ private _visible;
68
+ private _closed;
69
+ /** Two-way: whether the overlay is shown. */
70
+ set Visible(value: boolean);
71
+ get Visible(): boolean;
72
+ VisibleChange: EventEmitter<boolean>;
73
+ /** Emitted after a successful save (carries the saved entity). */
74
+ Saved: EventEmitter<BaseEntity<unknown>>;
75
+ /** Emitted when the overlay closes (save or cancel). */
76
+ Closed: EventEmitter<FormOverlayCloseReason>;
77
+ /** Re-emitted host navigation requests (consumer decides; chrome never routes). */
78
+ Navigate: EventEmitter<FormNavigationEvent>;
79
+ /** Re-emitted host notifications. */
80
+ Notification: EventEmitter<FormNotificationEvent>;
81
+ /** Re-emitted host record-deleted. */
82
+ RecordDeleted: EventEmitter<RecordDeletedEvent>;
83
+ /** Re-emitted host save-failed. */
84
+ RecordSaveFailed: EventEmitter<RecordSaveFailedEvent>;
85
+ /** Re-emitted host validation-failed. */
86
+ ValidationFailed: EventEmitter<ValidationFailedEvent>;
87
+ /** Re-emitted host load error. */
88
+ LoadError: EventEmitter<{
89
+ title: string;
90
+ detail: string;
91
+ }>;
92
+ /** The live form instance, for power-user wiring. */
93
+ FormCreated: EventEmitter<BaseFormComponent>;
94
+ /** True while a save is in flight (disables the Save button). */
95
+ saving: boolean;
96
+ /** Title actually rendered (Title input, or derived from the record). */
97
+ effectiveTitle: string;
98
+ /** The live form component instance (for power-user wiring via MJFormRef). */
99
+ get formInstance(): BaseFormComponent | null;
100
+ /** Resolves the primary key to pass to the host (PrimaryKey beats RecordID). */
101
+ protected get effectivePrimaryKey(): CompositeKey | undefined;
102
+ /** Save via the hosted form. Closing happens on the resulting `Saved` event. */
103
+ onSaveClick(): Promise<void>;
104
+ onHostSaved(record: BaseEntity): void;
105
+ onCancel(): void;
106
+ /** Host asked to be dismissed (e.g. Discard on a brand-new record). */
107
+ onHostDismissed(): void;
108
+ onFormCreated(form: BaseFormComponent): void;
109
+ /** Hide the overlay and emit Closed exactly once per open. Idempotent. */
110
+ protected close(reason: FormOverlayCloseReason): void;
111
+ static ɵfac: i0.ɵɵFactoryDeclaration<BaseFormOverlay, never>;
112
+ static ɵdir: i0.ɵɵDirectiveDeclaration<BaseFormOverlay, never, never, { "EntityName": { "alias": "EntityName"; "required": false; }; "PrimaryKey": { "alias": "PrimaryKey"; "required": false; }; "RecordID": { "alias": "RecordID"; "required": false; }; "Record": { "alias": "Record"; "required": false; }; "NewRecordValues": { "alias": "NewRecordValues"; "required": false; }; "SectionName": { "alias": "SectionName"; "required": false; }; "EditMode": { "alias": "EditMode"; "required": false; }; "Config": { "alias": "Config"; "required": false; }; "Title": { "alias": "Title"; "required": false; }; "ShowFooter": { "alias": "ShowFooter"; "required": false; }; "SaveButtonText": { "alias": "SaveButtonText"; "required": false; }; "CancelButtonText": { "alias": "CancelButtonText"; "required": false; }; "Visible": { "alias": "Visible"; "required": false; }; }, { "VisibleChange": "VisibleChange"; "Saved": "Saved"; "Closed": "Closed"; "Navigate": "Navigate"; "Notification": "Notification"; "RecordDeleted": "RecordDeleted"; "RecordSaveFailed": "RecordSaveFailed"; "ValidationFailed": "ValidationFailed"; "LoadError": "LoadError"; "FormCreated": "FormCreated"; }, never, never, true, never>;
113
+ }
114
+ //# sourceMappingURL=base-form-overlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-form-overlay.d.ts","sourceRoot":"","sources":["../../../src/lib/overlays/base-form-overlay.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAa,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EACL,qBAAqB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,qBAAqB,EACxF,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;;AAE3D,6BAA6B;AAC7B,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEvD;;;;;;;GAOG;AACH,8BACsB,eAAgB,SAAQ,oBAAoB;IAChE,0EAA0E;IACvD,SAAS,CAAC,IAAI,CAAC,EAAE,yBAAyB,CAAC;IAI9D,oEAAoE;IAC3D,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC1C,oEAAoE;IAC3D,UAAU,CAAC,EAAE,YAAY,CAAC;IACnC,oFAAoF;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,uDAAuD;IAC9C,MAAM,EAAE,UAAU,GAAG,IAAI,CAAQ;IAC1C,qEAAqE;IAC5D,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAQ;IACzE;;;;OAIG;IACM,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC3C,8DAA8D;IACrD,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAQ;IACzC;;;;;OAKG;IACM,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAQ;IAEhD;;;OAGG;IACH,SAAS,KAAK,YAAY,IAAI,gBAAgB,CAAe;IAE7D;;;;OAIG;IACH,IAAI,eAAe,IAAI,gBAAgB,CAEtC;IAID,8EAA8E;IACrE,KAAK,SAAM;IACpB,6DAA6D;IACpD,UAAU,UAAQ;IAC3B,yBAAyB;IAChB,cAAc,SAAU;IACjC,2BAA2B;IAClB,gBAAgB,SAAY;IAErC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,6CAA6C;IAC7C,IACI,OAAO,CAAC,KAAK,EAAE,OAAO,EASzB;IACD,IAAI,OAAO,IAAI,OAAO,CAA0B;IAItC,aAAa,wBAA+B;IACtD,kEAAkE;IACxD,KAAK,oCAAkC;IACjD,wDAAwD;IAC9C,MAAM,uCAA8C;IAC9D,mFAAmF;IACzE,QAAQ,oCAA2C;IAC7D,qCAAqC;IAC3B,YAAY,sCAA6C;IACnE,sCAAsC;IAC5B,aAAa,mCAA0C;IACjE,mCAAmC;IACzB,gBAAgB,sCAA6C;IACvE,yCAAyC;IAC/B,gBAAgB,sCAA6C;IACvE,kCAAkC;IACxB,SAAS;eAA6B,MAAM;gBAAU,MAAM;OAAM;IAC5E,qDAAqD;IAC3C,WAAW,kCAAyC;IAI9D,iEAAiE;IAC1D,MAAM,UAAS;IACtB,yEAAyE;IAClE,cAAc,SAAM;IAE3B,8EAA8E;IAC9E,IAAI,YAAY,IAAI,iBAAiB,GAAG,IAAI,CAE3C;IAED,gFAAgF;IAChF,SAAS,KAAK,mBAAmB,IAAI,YAAY,GAAG,SAAS,CAI5D;IAID,gFAAgF;IAC1E,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAUlC,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAKrC,QAAQ,IAAI,IAAI;IAMhB,uEAAuE;IACvE,eAAe,IAAI,IAAI;IAIvB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI;IAa5C,0EAA0E;IAC1E,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI;yCA9JjC,eAAe;2CAAf,eAAe;CAuKpC"}
@@ -0,0 +1,227 @@
1
+ import { Directive, Input, Output, EventEmitter, ViewChild } from '@angular/core';
2
+ import { CompositeKey } from '@memberjunction/core';
3
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
4
+ import * as i0 from "@angular/core";
5
+ const _c0 = ["host"];
6
+ /**
7
+ * Shared logic for the form overlay shells ({@link MjFormDialogComponent} and
8
+ * {@link MjFormSlideInComponent}). Both wrap an {@link MjEntityFormHostComponent}
9
+ * in chrome that owns the title + Save/Cancel, bubble the host's events upward,
10
+ * and proxy the form inputs downward.
11
+ *
12
+ * Subclasses provide only the template; all input/output plumbing lives here.
13
+ */
14
+ export class BaseFormOverlay extends BaseAngularComponent {
15
+ /** Reference to the hosted form (template must name the host `#host`). */
16
+ host;
17
+ // ── Record selection (mirror MjEntityFormHostComponent) ──────────────────
18
+ /** Entity name to load. Ignored when {@link Record} is supplied. */
19
+ EntityName = null;
20
+ /** Primary key of the record to edit. Empty/absent → new record. */
21
+ PrimaryKey;
22
+ /** Convenience single-column ('ID') key; used when {@link PrimaryKey} is absent. */
23
+ RecordID;
24
+ /** Pre-loaded record to bind directly (skips load). */
25
+ Record = null;
26
+ /** New-record default values: URL-segment string or plain object. */
27
+ NewRecordValues = null;
28
+ /**
29
+ * Render a single registered form section (`BaseFormSectionComponent`
30
+ * registered as `'<EntityName>.<SectionName>'`) instead of the full form.
31
+ * See {@link MjEntityFormHostComponent.SectionName}.
32
+ */
33
+ SectionName = null;
34
+ /** Force edit mode (default: new → edit, existing → read). */
35
+ EditMode = null;
36
+ /**
37
+ * Per-instance config OVERRIDE. Treated as a partial set of overrides that is
38
+ * merged **over** the surface's {@link PresetConfig} — so passing
39
+ * `{ StartInEditMode: true }` keeps the preset's `Toolbar: null` etc. instead
40
+ * of replacing the whole preset. Bind the merged result via {@link EffectiveConfig}.
41
+ */
42
+ Config = null;
43
+ /**
44
+ * The surface's default config preset (TAB/DIALOG/SLIDEIN). Subclasses override
45
+ * this getter; the base returns an empty object (no defaults).
46
+ */
47
+ get PresetConfig() { return {}; }
48
+ /**
49
+ * The config actually handed to the form host: the surface {@link PresetConfig}
50
+ * with any consumer {@link Config} overrides merged on top. This is what makes
51
+ * partial configs work — you only specify what differs from the preset.
52
+ */
53
+ get EffectiveConfig() {
54
+ return { ...this.PresetConfig, ...(this.Config ?? {}) };
55
+ }
56
+ // ── Chrome ────────────────────────────────────────────────────────────────
57
+ /** Title shown in the chrome. When empty, derived from the record on load. */
58
+ Title = '';
59
+ /** Whether to show the Save/Cancel footer. Default: true. */
60
+ ShowFooter = true;
61
+ /** Save button label. */
62
+ SaveButtonText = 'Save';
63
+ /** Cancel button label. */
64
+ CancelButtonText = 'Cancel';
65
+ _visible = false;
66
+ _closed = false;
67
+ /** Two-way: whether the overlay is shown. */
68
+ set Visible(value) {
69
+ if (value !== this._visible) {
70
+ this._visible = value;
71
+ if (value) {
72
+ this._closed = false; // re-arm for the next close
73
+ this.effectiveTitle = this.Title; // section mode has no FormCreated; full mode refines this
74
+ }
75
+ this.VisibleChange.emit(value);
76
+ }
77
+ }
78
+ get Visible() { return this._visible; }
79
+ // ── Outputs ─────────────────────────────────────────────────────────────
80
+ VisibleChange = new EventEmitter();
81
+ /** Emitted after a successful save (carries the saved entity). */
82
+ Saved = new EventEmitter();
83
+ /** Emitted when the overlay closes (save or cancel). */
84
+ Closed = new EventEmitter();
85
+ /** Re-emitted host navigation requests (consumer decides; chrome never routes). */
86
+ Navigate = new EventEmitter();
87
+ /** Re-emitted host notifications. */
88
+ Notification = new EventEmitter();
89
+ /** Re-emitted host record-deleted. */
90
+ RecordDeleted = new EventEmitter();
91
+ /** Re-emitted host save-failed. */
92
+ RecordSaveFailed = new EventEmitter();
93
+ /** Re-emitted host validation-failed. */
94
+ ValidationFailed = new EventEmitter();
95
+ /** Re-emitted host load error. */
96
+ LoadError = new EventEmitter();
97
+ /** The live form instance, for power-user wiring. */
98
+ FormCreated = new EventEmitter();
99
+ // ── State ─────────────────────────────────────────────────────────────────
100
+ /** True while a save is in flight (disables the Save button). */
101
+ saving = false;
102
+ /** Title actually rendered (Title input, or derived from the record). */
103
+ effectiveTitle = '';
104
+ /** The live form component instance (for power-user wiring via MJFormRef). */
105
+ get formInstance() {
106
+ return this.host?.Form ?? null;
107
+ }
108
+ /** Resolves the primary key to pass to the host (PrimaryKey beats RecordID). */
109
+ get effectivePrimaryKey() {
110
+ if (this.PrimaryKey)
111
+ return this.PrimaryKey;
112
+ if (this.RecordID)
113
+ return CompositeKey.FromID(this.RecordID);
114
+ return undefined;
115
+ }
116
+ // ── Host event handlers (wired in subclass templates) ─────────────────────
117
+ /** Save via the hosted form. Closing happens on the resulting `Saved` event. */
118
+ async onSaveClick() {
119
+ if (!this.host)
120
+ return;
121
+ this.saving = true;
122
+ try {
123
+ await this.host.Save();
124
+ }
125
+ finally {
126
+ this.saving = false;
127
+ }
128
+ }
129
+ onHostSaved(record) {
130
+ this.Saved.emit(record);
131
+ this.close('save');
132
+ }
133
+ onCancel() {
134
+ if (this._closed)
135
+ return;
136
+ this.host?.Cancel();
137
+ this.close('cancel');
138
+ }
139
+ /** Host asked to be dismissed (e.g. Discard on a brand-new record). */
140
+ onHostDismissed() {
141
+ this.close('cancel');
142
+ }
143
+ onFormCreated(form) {
144
+ this.FormCreated.emit(form);
145
+ if (!this.Title) {
146
+ const rec = form.record;
147
+ const entityLabel = rec?.EntityInfo?.DisplayName ?? rec?.EntityInfo?.Name ?? '';
148
+ this.effectiveTitle = rec?.IsSaved
149
+ ? `${entityLabel}`
150
+ : `New ${entityLabel}`;
151
+ }
152
+ else {
153
+ this.effectiveTitle = this.Title;
154
+ }
155
+ }
156
+ /** Hide the overlay and emit Closed exactly once per open. Idempotent. */
157
+ close(reason) {
158
+ if (this._closed)
159
+ return;
160
+ this._closed = true;
161
+ if (this._visible) {
162
+ this._visible = false;
163
+ this.VisibleChange.emit(false);
164
+ }
165
+ this.Closed.emit(reason);
166
+ }
167
+ static ɵfac = /*@__PURE__*/ (() => { let ɵBaseFormOverlay_BaseFactory; return function BaseFormOverlay_Factory(__ngFactoryType__) { return (ɵBaseFormOverlay_BaseFactory || (ɵBaseFormOverlay_BaseFactory = i0.ɵɵgetInheritedFactory(BaseFormOverlay)))(__ngFactoryType__ || BaseFormOverlay); }; })();
168
+ static ɵdir = /*@__PURE__*/ i0.ɵɵdefineDirective({ type: BaseFormOverlay, viewQuery: function BaseFormOverlay_Query(rf, ctx) { if (rf & 1) {
169
+ i0.ɵɵviewQuery(_c0, 5);
170
+ } if (rf & 2) {
171
+ let _t;
172
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.host = _t.first);
173
+ } }, inputs: { EntityName: "EntityName", PrimaryKey: "PrimaryKey", RecordID: "RecordID", Record: "Record", NewRecordValues: "NewRecordValues", SectionName: "SectionName", EditMode: "EditMode", Config: "Config", Title: "Title", ShowFooter: "ShowFooter", SaveButtonText: "SaveButtonText", CancelButtonText: "CancelButtonText", Visible: "Visible" }, outputs: { VisibleChange: "VisibleChange", Saved: "Saved", Closed: "Closed", Navigate: "Navigate", Notification: "Notification", RecordDeleted: "RecordDeleted", RecordSaveFailed: "RecordSaveFailed", ValidationFailed: "ValidationFailed", LoadError: "LoadError", FormCreated: "FormCreated" }, features: [i0.ɵɵInheritDefinitionFeature] });
174
+ }
175
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(BaseFormOverlay, [{
176
+ type: Directive
177
+ }], null, { host: [{
178
+ type: ViewChild,
179
+ args: ['host']
180
+ }], EntityName: [{
181
+ type: Input
182
+ }], PrimaryKey: [{
183
+ type: Input
184
+ }], RecordID: [{
185
+ type: Input
186
+ }], Record: [{
187
+ type: Input
188
+ }], NewRecordValues: [{
189
+ type: Input
190
+ }], SectionName: [{
191
+ type: Input
192
+ }], EditMode: [{
193
+ type: Input
194
+ }], Config: [{
195
+ type: Input
196
+ }], Title: [{
197
+ type: Input
198
+ }], ShowFooter: [{
199
+ type: Input
200
+ }], SaveButtonText: [{
201
+ type: Input
202
+ }], CancelButtonText: [{
203
+ type: Input
204
+ }], Visible: [{
205
+ type: Input
206
+ }], VisibleChange: [{
207
+ type: Output
208
+ }], Saved: [{
209
+ type: Output
210
+ }], Closed: [{
211
+ type: Output
212
+ }], Navigate: [{
213
+ type: Output
214
+ }], Notification: [{
215
+ type: Output
216
+ }], RecordDeleted: [{
217
+ type: Output
218
+ }], RecordSaveFailed: [{
219
+ type: Output
220
+ }], ValidationFailed: [{
221
+ type: Output
222
+ }], LoadError: [{
223
+ type: Output
224
+ }], FormCreated: [{
225
+ type: Output
226
+ }] }); })();
227
+ //# sourceMappingURL=base-form-overlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-form-overlay.js","sourceRoot":"","sources":["../../../src/lib/overlays/base-form-overlay.ts"],"names":[],"mappings":"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","sourcesContent":["import { Directive, Input, Output, EventEmitter, ViewChild } from '@angular/core';\nimport { BaseEntity, CompositeKey } from '@memberjunction/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\nimport { MjEntityFormHostComponent } from '../host/entity-form-host.component';\nimport { EntityFormConfig } from '../types/entity-form-config';\nimport { FormNavigationEvent } from '../types/navigation-events';\nimport {\n FormNotificationEvent, RecordDeletedEvent, RecordSaveFailedEvent, ValidationFailedEvent\n} from '../types/form-types';\nimport { BaseFormComponent } from '../base-form-component';\n\n/** How an overlay closed. */\nexport type FormOverlayCloseReason = 'save' | 'cancel';\n\n/**\n * Shared logic for the form overlay shells ({@link MjFormDialogComponent} and\n * {@link MjFormSlideInComponent}). Both wrap an {@link MjEntityFormHostComponent}\n * in chrome that owns the title + Save/Cancel, bubble the host's events upward,\n * and proxy the form inputs downward.\n *\n * Subclasses provide only the template; all input/output plumbing lives here.\n */\n@Directive()\nexport abstract class BaseFormOverlay extends BaseAngularComponent {\n /** Reference to the hosted form (template must name the host `#host`). */\n @ViewChild('host') protected host?: MjEntityFormHostComponent;\n\n // ── Record selection (mirror MjEntityFormHostComponent) ──────────────────\n\n /** Entity name to load. Ignored when {@link Record} is supplied. */\n @Input() EntityName: string | null = null;\n /** Primary key of the record to edit. Empty/absent → new record. */\n @Input() PrimaryKey?: CompositeKey;\n /** Convenience single-column ('ID') key; used when {@link PrimaryKey} is absent. */\n @Input() RecordID?: string;\n /** Pre-loaded record to bind directly (skips load). */\n @Input() Record: BaseEntity | null = null;\n /** New-record default values: URL-segment string or plain object. */\n @Input() NewRecordValues: string | Record<string, unknown> | null = null;\n /**\n * Render a single registered form section (`BaseFormSectionComponent`\n * registered as `'<EntityName>.<SectionName>'`) instead of the full form.\n * See {@link MjEntityFormHostComponent.SectionName}.\n */\n @Input() SectionName: string | null = null;\n /** Force edit mode (default: new → edit, existing → read). */\n @Input() EditMode: boolean | null = null;\n /**\n * Per-instance config OVERRIDE. Treated as a partial set of overrides that is\n * merged **over** the surface's {@link PresetConfig} — so passing\n * `{ StartInEditMode: true }` keeps the preset's `Toolbar: null` etc. instead\n * of replacing the whole preset. Bind the merged result via {@link EffectiveConfig}.\n */\n @Input() Config: EntityFormConfig | null = null;\n\n /**\n * The surface's default config preset (TAB/DIALOG/SLIDEIN). Subclasses override\n * this getter; the base returns an empty object (no defaults).\n */\n protected get PresetConfig(): EntityFormConfig { return {}; }\n\n /**\n * The config actually handed to the form host: the surface {@link PresetConfig}\n * with any consumer {@link Config} overrides merged on top. This is what makes\n * partial configs work — you only specify what differs from the preset.\n */\n get EffectiveConfig(): EntityFormConfig {\n return { ...this.PresetConfig, ...(this.Config ?? {}) };\n }\n\n // ── Chrome ────────────────────────────────────────────────────────────────\n\n /** Title shown in the chrome. When empty, derived from the record on load. */\n @Input() Title = '';\n /** Whether to show the Save/Cancel footer. Default: true. */\n @Input() ShowFooter = true;\n /** Save button label. */\n @Input() SaveButtonText = 'Save';\n /** Cancel button label. */\n @Input() CancelButtonText = 'Cancel';\n\n private _visible = false;\n private _closed = false;\n /** Two-way: whether the overlay is shown. */\n @Input()\n set Visible(value: boolean) {\n if (value !== this._visible) {\n this._visible = value;\n if (value) {\n this._closed = false; // re-arm for the next close\n this.effectiveTitle = this.Title; // section mode has no FormCreated; full mode refines this\n }\n this.VisibleChange.emit(value);\n }\n }\n get Visible(): boolean { return this._visible; }\n\n // ── Outputs ─────────────────────────────────────────────────────────────\n\n @Output() VisibleChange = new EventEmitter<boolean>();\n /** Emitted after a successful save (carries the saved entity). */\n @Output() Saved = new EventEmitter<BaseEntity>();\n /** Emitted when the overlay closes (save or cancel). */\n @Output() Closed = new EventEmitter<FormOverlayCloseReason>();\n /** Re-emitted host navigation requests (consumer decides; chrome never routes). */\n @Output() Navigate = new EventEmitter<FormNavigationEvent>();\n /** Re-emitted host notifications. */\n @Output() Notification = new EventEmitter<FormNotificationEvent>();\n /** Re-emitted host record-deleted. */\n @Output() RecordDeleted = new EventEmitter<RecordDeletedEvent>();\n /** Re-emitted host save-failed. */\n @Output() RecordSaveFailed = new EventEmitter<RecordSaveFailedEvent>();\n /** Re-emitted host validation-failed. */\n @Output() ValidationFailed = new EventEmitter<ValidationFailedEvent>();\n /** Re-emitted host load error. */\n @Output() LoadError = new EventEmitter<{ title: string; detail: string }>();\n /** The live form instance, for power-user wiring. */\n @Output() FormCreated = new EventEmitter<BaseFormComponent>();\n\n // ── State ─────────────────────────────────────────────────────────────────\n\n /** True while a save is in flight (disables the Save button). */\n public saving = false;\n /** Title actually rendered (Title input, or derived from the record). */\n public effectiveTitle = '';\n\n /** The live form component instance (for power-user wiring via MJFormRef). */\n get formInstance(): BaseFormComponent | null {\n return this.host?.Form ?? null;\n }\n\n /** Resolves the primary key to pass to the host (PrimaryKey beats RecordID). */\n protected get effectivePrimaryKey(): CompositeKey | undefined {\n if (this.PrimaryKey) return this.PrimaryKey;\n if (this.RecordID) return CompositeKey.FromID(this.RecordID);\n return undefined;\n }\n\n // ── Host event handlers (wired in subclass templates) ─────────────────────\n\n /** Save via the hosted form. Closing happens on the resulting `Saved` event. */\n async onSaveClick(): Promise<void> {\n if (!this.host) return;\n this.saving = true;\n try {\n await this.host.Save();\n } finally {\n this.saving = false;\n }\n }\n\n onHostSaved(record: BaseEntity): void {\n this.Saved.emit(record);\n this.close('save');\n }\n\n onCancel(): void {\n if (this._closed) return;\n this.host?.Cancel();\n this.close('cancel');\n }\n\n /** Host asked to be dismissed (e.g. Discard on a brand-new record). */\n onHostDismissed(): void {\n this.close('cancel');\n }\n\n onFormCreated(form: BaseFormComponent): void {\n this.FormCreated.emit(form);\n if (!this.Title) {\n const rec = form.record;\n const entityLabel = rec?.EntityInfo?.DisplayName ?? rec?.EntityInfo?.Name ?? '';\n this.effectiveTitle = rec?.IsSaved\n ? `${entityLabel}`\n : `New ${entityLabel}`;\n } else {\n this.effectiveTitle = this.Title;\n }\n }\n\n /** Hide the overlay and emit Closed exactly once per open. Idempotent. */\n protected close(reason: FormOverlayCloseReason): void {\n if (this._closed) return;\n this._closed = true;\n if (this._visible) {\n this._visible = false;\n this.VisibleChange.emit(false);\n }\n this.Closed.emit(reason);\n }\n}\n"]}
@@ -0,0 +1,35 @@
1
+ import { BaseFormOverlay } from './base-form-overlay';
2
+ import * as i0 from "@angular/core";
3
+ /**
4
+ * Opens any MemberJunction entity form inside a modal dialog.
5
+ *
6
+ * Wraps {@link MjEntityFormHostComponent} in `<mj-dialog>` chrome with a
7
+ * Save/Cancel footer. Defaults to {@link DIALOG_FORM_CONFIG} (no in-form
8
+ * toolbar, related grids hidden, in-form links inert) — override via `Config`.
9
+ *
10
+ * Standalone — import it directly:
11
+ * ```typescript
12
+ * import { MjFormDialogComponent } from '@memberjunction/ng-base-forms';
13
+ * ```
14
+ *
15
+ * @example Declarative
16
+ * ```html
17
+ * <mj-form-dialog [EntityName]="'Users'" [RecordID]="id"
18
+ * [(Visible)]="show" (Saved)="onSaved($event)"></mj-form-dialog>
19
+ * ```
20
+ */
21
+ export declare class MjFormDialogComponent extends BaseFormOverlay {
22
+ /** Dialog width (px or CSS string). */
23
+ Width: number | string | null;
24
+ /** Dialog height (px or CSS string). Default auto. */
25
+ Height: number | string | null;
26
+ /**
27
+ * Form config. Defaults to the dialog preset; consumers can override.
28
+ * (Declared here so the dialog gets the dialog-appropriate default while the
29
+ * shared base stays presentation-neutral.)
30
+ */
31
+ protected get PresetConfig(): import("../types/entity-form-config").EntityFormConfig;
32
+ static ɵfac: i0.ɵɵFactoryDeclaration<MjFormDialogComponent, never>;
33
+ static ɵcmp: i0.ɵɵComponentDeclaration<MjFormDialogComponent, "mj-form-dialog", never, { "Width": { "alias": "Width"; "required": false; }; "Height": { "alias": "Height"; "required": false; }; }, {}, never, never, true, never>;
34
+ }
35
+ //# sourceMappingURL=form-dialog.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form-dialog.component.d.ts","sourceRoot":"","sources":["../../../src/lib/overlays/form-dialog.component.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;;AAGtD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAMa,qBAAsB,SAAQ,eAAe;IACxD,uCAAuC;IAC9B,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAO;IAC7C,sDAAsD;IAC7C,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAQ;IAE/C;;;;OAIG;IACH,cAAuB,YAAY,2DAAiC;yCAXzD,qBAAqB;2CAArB,qBAAqB;CAYjC"}
@@ -0,0 +1,92 @@
1
+ import { Component, Input } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { MJDialogComponent, MJDialogActionsComponent, MJButtonDirective } from '@memberjunction/ng-ui-components';
4
+ import { BaseFormsModule } from '../../module';
5
+ import { BaseFormOverlay } from './base-form-overlay';
6
+ import { DIALOG_FORM_CONFIG } from '../types/entity-form-config';
7
+ import * as i0 from "@angular/core";
8
+ import * as i1 from "../host/entity-form-host.component";
9
+ function MjFormDialogComponent_Conditional_0_Conditional_3_Template(rf, ctx) { if (rf & 1) {
10
+ const _r3 = i0.ɵɵgetCurrentView();
11
+ i0.ɵɵelementStart(0, "mj-dialog-actions")(1, "button", 4);
12
+ i0.ɵɵlistener("click", function MjFormDialogComponent_Conditional_0_Conditional_3_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onSaveClick()); });
13
+ i0.ɵɵtext(2);
14
+ i0.ɵɵelementEnd();
15
+ i0.ɵɵelementStart(3, "button", 5);
16
+ i0.ɵɵlistener("click", function MjFormDialogComponent_Conditional_0_Conditional_3_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onCancel()); });
17
+ i0.ɵɵtext(4);
18
+ i0.ɵɵelementEnd()();
19
+ } if (rf & 2) {
20
+ const ctx_r1 = i0.ɵɵnextContext(2);
21
+ i0.ɵɵadvance();
22
+ i0.ɵɵproperty("disabled", ctx_r1.saving);
23
+ i0.ɵɵadvance();
24
+ i0.ɵɵtextInterpolate(ctx_r1.SaveButtonText);
25
+ i0.ɵɵadvance();
26
+ i0.ɵɵproperty("disabled", ctx_r1.saving);
27
+ i0.ɵɵadvance();
28
+ i0.ɵɵtextInterpolate(ctx_r1.CancelButtonText);
29
+ } }
30
+ function MjFormDialogComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
31
+ const _r1 = i0.ɵɵgetCurrentView();
32
+ i0.ɵɵelementStart(0, "mj-dialog", 2);
33
+ i0.ɵɵlistener("Close", function MjFormDialogComponent_Conditional_0_Template_mj_dialog_Close_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onCancel()); });
34
+ i0.ɵɵelementStart(1, "mj-entity-form-host", 3, 0);
35
+ i0.ɵɵlistener("Saved", function MjFormDialogComponent_Conditional_0_Template_mj_entity_form_host_Saved_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onHostSaved($event)); })("Dismissed", function MjFormDialogComponent_Conditional_0_Template_mj_entity_form_host_Dismissed_1_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onHostDismissed()); })("FormCreated", function MjFormDialogComponent_Conditional_0_Template_mj_entity_form_host_FormCreated_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFormCreated($event)); })("Navigate", function MjFormDialogComponent_Conditional_0_Template_mj_entity_form_host_Navigate_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.Navigate.emit($event)); })("Notification", function MjFormDialogComponent_Conditional_0_Template_mj_entity_form_host_Notification_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.Notification.emit($event)); })("RecordDeleted", function MjFormDialogComponent_Conditional_0_Template_mj_entity_form_host_RecordDeleted_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.RecordDeleted.emit($event)); })("RecordSaveFailed", function MjFormDialogComponent_Conditional_0_Template_mj_entity_form_host_RecordSaveFailed_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.RecordSaveFailed.emit($event)); })("ValidationFailed", function MjFormDialogComponent_Conditional_0_Template_mj_entity_form_host_ValidationFailed_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ValidationFailed.emit($event)); })("LoadError", function MjFormDialogComponent_Conditional_0_Template_mj_entity_form_host_LoadError_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.LoadError.emit($event)); });
36
+ i0.ɵɵelementEnd();
37
+ i0.ɵɵconditionalCreate(3, MjFormDialogComponent_Conditional_0_Conditional_3_Template, 5, 4, "mj-dialog-actions");
38
+ i0.ɵɵelementEnd();
39
+ } if (rf & 2) {
40
+ const ctx_r1 = i0.ɵɵnextContext();
41
+ i0.ɵɵproperty("Visible", true)("Title", ctx_r1.effectiveTitle)("Width", ctx_r1.Width)("Height", ctx_r1.Height);
42
+ i0.ɵɵadvance();
43
+ i0.ɵɵproperty("EntityName", ctx_r1.EntityName)("PrimaryKey", ctx_r1.effectivePrimaryKey)("Record", ctx_r1.Record)("NewRecordValues", ctx_r1.NewRecordValues)("SectionName", ctx_r1.SectionName)("EditMode", ctx_r1.EditMode)("Config", ctx_r1.EffectiveConfig)("Provider", ctx_r1.Provider);
44
+ i0.ɵɵadvance(2);
45
+ i0.ɵɵconditional(ctx_r1.ShowFooter ? 3 : -1);
46
+ } }
47
+ /**
48
+ * Opens any MemberJunction entity form inside a modal dialog.
49
+ *
50
+ * Wraps {@link MjEntityFormHostComponent} in `<mj-dialog>` chrome with a
51
+ * Save/Cancel footer. Defaults to {@link DIALOG_FORM_CONFIG} (no in-form
52
+ * toolbar, related grids hidden, in-form links inert) — override via `Config`.
53
+ *
54
+ * Standalone — import it directly:
55
+ * ```typescript
56
+ * import { MjFormDialogComponent } from '@memberjunction/ng-base-forms';
57
+ * ```
58
+ *
59
+ * @example Declarative
60
+ * ```html
61
+ * <mj-form-dialog [EntityName]="'Users'" [RecordID]="id"
62
+ * [(Visible)]="show" (Saved)="onSaved($event)"></mj-form-dialog>
63
+ * ```
64
+ */
65
+ export class MjFormDialogComponent extends BaseFormOverlay {
66
+ /** Dialog width (px or CSS string). */
67
+ Width = 760;
68
+ /** Dialog height (px or CSS string). Default auto. */
69
+ Height = null;
70
+ /**
71
+ * Form config. Defaults to the dialog preset; consumers can override.
72
+ * (Declared here so the dialog gets the dialog-appropriate default while the
73
+ * shared base stays presentation-neutral.)
74
+ */
75
+ get PresetConfig() { return DIALOG_FORM_CONFIG; }
76
+ static ɵfac = /*@__PURE__*/ (() => { let ɵMjFormDialogComponent_BaseFactory; return function MjFormDialogComponent_Factory(__ngFactoryType__) { return (ɵMjFormDialogComponent_BaseFactory || (ɵMjFormDialogComponent_BaseFactory = i0.ɵɵgetInheritedFactory(MjFormDialogComponent)))(__ngFactoryType__ || MjFormDialogComponent); }; })();
77
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MjFormDialogComponent, selectors: [["mj-form-dialog"]], inputs: { Width: "Width", Height: "Height" }, features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 1, consts: [["host", ""], [3, "Visible", "Title", "Width", "Height"], [3, "Close", "Visible", "Title", "Width", "Height"], [3, "Saved", "Dismissed", "FormCreated", "Navigate", "Notification", "RecordDeleted", "RecordSaveFailed", "ValidationFailed", "LoadError", "EntityName", "PrimaryKey", "Record", "NewRecordValues", "SectionName", "EditMode", "Config", "Provider"], ["mjButton", "", "variant", "primary", 3, "click", "disabled"], ["mjButton", "", 3, "click", "disabled"]], template: function MjFormDialogComponent_Template(rf, ctx) { if (rf & 1) {
78
+ i0.ɵɵconditionalCreate(0, MjFormDialogComponent_Conditional_0_Template, 4, 13, "mj-dialog", 1);
79
+ } if (rf & 2) {
80
+ i0.ɵɵconditional(ctx.Visible ? 0 : -1);
81
+ } }, dependencies: [CommonModule, BaseFormsModule, i1.MjEntityFormHostComponent, MJDialogComponent, MJDialogActionsComponent, MJButtonDirective], encapsulation: 2 });
82
+ }
83
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MjFormDialogComponent, [{
84
+ type: Component,
85
+ args: [{ standalone: true, selector: 'mj-form-dialog', imports: [CommonModule, BaseFormsModule, MJDialogComponent, MJDialogActionsComponent, MJButtonDirective], template: "@if (Visible) {\n <mj-dialog\n [Visible]=\"true\"\n [Title]=\"effectiveTitle\"\n [Width]=\"Width\"\n [Height]=\"Height\"\n (Close)=\"onCancel()\">\n\n <mj-entity-form-host #host\n [EntityName]=\"EntityName\"\n [PrimaryKey]=\"effectivePrimaryKey!\"\n [Record]=\"Record\"\n [NewRecordValues]=\"NewRecordValues\"\n [SectionName]=\"SectionName\"\n [EditMode]=\"EditMode\"\n [Config]=\"EffectiveConfig\"\n [Provider]=\"Provider\"\n (Saved)=\"onHostSaved($event)\"\n (Dismissed)=\"onHostDismissed()\"\n (FormCreated)=\"onFormCreated($event)\"\n (Navigate)=\"Navigate.emit($event)\"\n (Notification)=\"Notification.emit($event)\"\n (RecordDeleted)=\"RecordDeleted.emit($event)\"\n (RecordSaveFailed)=\"RecordSaveFailed.emit($event)\"\n (ValidationFailed)=\"ValidationFailed.emit($event)\"\n (LoadError)=\"LoadError.emit($event)\">\n </mj-entity-form-host>\n\n @if (ShowFooter) {\n <mj-dialog-actions>\n <button mjButton variant=\"primary\" [disabled]=\"saving\" (click)=\"onSaveClick()\">{{ SaveButtonText }}</button>\n <button mjButton [disabled]=\"saving\" (click)=\"onCancel()\">{{ CancelButtonText }}</button>\n </mj-dialog-actions>\n }\n </mj-dialog>\n}\n" }]
86
+ }], null, { Width: [{
87
+ type: Input
88
+ }], Height: [{
89
+ type: Input
90
+ }] }); })();
91
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MjFormDialogComponent, { className: "MjFormDialogComponent", filePath: "src/lib/overlays/form-dialog.component.ts", lineNumber: 35 }); })();
92
+ //# sourceMappingURL=form-dialog.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form-dialog.component.js","sourceRoot":"","sources":["../../../src/lib/overlays/form-dialog.component.ts","../../../src/lib/overlays/form-dialog.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EACL,iBAAiB,EAAE,wBAAwB,EAAE,iBAAiB,EAC/D,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;;;;;ICsBzD,AADF,yCAAmB,gBAC8D;IAAxB,wMAAS,oBAAa,KAAC;IAAC,YAAoB;IAAA,iBAAS;IAC5G,iCAA0D;IAArB,wMAAS,iBAAU,KAAC;IAAC,YAAsB;IAClF,AADkF,iBAAS,EACvE;;;IAFiB,cAAmB;IAAnB,wCAAmB;IAAyB,cAAoB;IAApB,2CAAoB;IAClF,cAAmB;IAAnB,wCAAmB;IAAsB,cAAsB;IAAtB,6CAAsB;;;;IA9BtF,oCAKuB;IAArB,4LAAS,iBAAU,KAAC;IAEpB,iDAiBuC;IAArC,AADA,AADA,AADA,AADA,AADA,AADA,AADA,AADA,4MAAS,0BAAmB,KAAC,iMAChB,wBAAiB,KAAC,2MAChB,4BAAqB,KAAC,qMACzB,4BAAqB,KAAC,6MAClB,gCAAyB,KAAC,+MACzB,iCAA0B,KAAC,qNACxB,oCAA6B,KAAC,qNAC9B,oCAA6B,KAAC,uMACrC,6BAAsB,KAAC;IACtC,iBAAsB;IAEtB,gHAAkB;IAMpB,iBAAY;;;IA7BV,AADA,AADA,AADA,8BAAgB,gCACQ,uBACT,yBACE;IAIf,cAAyB;IAOzB,AADA,AADA,AADA,AADA,AADA,AADA,AADA,8CAAyB,0CACU,yBAClB,2CACkB,mCACR,6BACN,kCACK,6BACL;IAYvB,eAKC;IALD,4CAKC;;ADvBL;;;;;;;;;;;;;;;;;GAiBG;AAOH,MAAM,OAAO,qBAAsB,SAAQ,eAAe;IACxD,uCAAuC;IAC9B,KAAK,GAA2B,GAAG,CAAC;IAC7C,sDAAsD;IAC7C,MAAM,GAA2B,IAAI,CAAC;IAE/C;;;;OAIG;IACH,IAAuB,YAAY,KAAK,OAAO,kBAAkB,CAAC,CAAC,CAAC;iQAXzD,qBAAqB,yBAArB,qBAAqB;6DAArB,qBAAqB;YClClC,8FAAe;;YAAf,sCAmCC;4BDJW,YAAY,EAAE,eAAe,gCAAE,iBAAiB,EAAE,wBAAwB,EAAE,iBAAiB;;iFAG5F,qBAAqB;cANjC,SAAS;6BACI,IAAI,YACN,gBAAgB,WACjB,CAAC,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,iBAAiB,CAAC;;kBAKvG,KAAK;;kBAEL,KAAK;;kFAJK,qBAAqB","sourcesContent":["import { Component, Input } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport {\n MJDialogComponent, MJDialogActionsComponent, MJButtonDirective\n} from '@memberjunction/ng-ui-components';\n\nimport { BaseFormsModule } from '../../module';\nimport { BaseFormOverlay } from './base-form-overlay';\nimport { DIALOG_FORM_CONFIG } from '../types/entity-form-config';\n\n/**\n * Opens any MemberJunction entity form inside a modal dialog.\n *\n * Wraps {@link MjEntityFormHostComponent} in `<mj-dialog>` chrome with a\n * Save/Cancel footer. Defaults to {@link DIALOG_FORM_CONFIG} (no in-form\n * toolbar, related grids hidden, in-form links inert) — override via `Config`.\n *\n * Standalone — import it directly:\n * ```typescript\n * import { MjFormDialogComponent } from '@memberjunction/ng-base-forms';\n * ```\n *\n * @example Declarative\n * ```html\n * <mj-form-dialog [EntityName]=\"'Users'\" [RecordID]=\"id\"\n * [(Visible)]=\"show\" (Saved)=\"onSaved($event)\"></mj-form-dialog>\n * ```\n */\n@Component({\n standalone: true,\n selector: 'mj-form-dialog',\n imports: [CommonModule, BaseFormsModule, MJDialogComponent, MJDialogActionsComponent, MJButtonDirective],\n templateUrl: './form-dialog.component.html',\n})\nexport class MjFormDialogComponent extends BaseFormOverlay {\n /** Dialog width (px or CSS string). */\n @Input() Width: number | string | null = 760;\n /** Dialog height (px or CSS string). Default auto. */\n @Input() Height: number | string | null = null;\n\n /**\n * Form config. Defaults to the dialog preset; consumers can override.\n * (Declared here so the dialog gets the dialog-appropriate default while the\n * shared base stays presentation-neutral.)\n */\n protected override get PresetConfig() { return DIALOG_FORM_CONFIG; }\n}\n","@if (Visible) {\n <mj-dialog\n [Visible]=\"true\"\n [Title]=\"effectiveTitle\"\n [Width]=\"Width\"\n [Height]=\"Height\"\n (Close)=\"onCancel()\">\n\n <mj-entity-form-host #host\n [EntityName]=\"EntityName\"\n [PrimaryKey]=\"effectivePrimaryKey!\"\n [Record]=\"Record\"\n [NewRecordValues]=\"NewRecordValues\"\n [SectionName]=\"SectionName\"\n [EditMode]=\"EditMode\"\n [Config]=\"EffectiveConfig\"\n [Provider]=\"Provider\"\n (Saved)=\"onHostSaved($event)\"\n (Dismissed)=\"onHostDismissed()\"\n (FormCreated)=\"onFormCreated($event)\"\n (Navigate)=\"Navigate.emit($event)\"\n (Notification)=\"Notification.emit($event)\"\n (RecordDeleted)=\"RecordDeleted.emit($event)\"\n (RecordSaveFailed)=\"RecordSaveFailed.emit($event)\"\n (ValidationFailed)=\"ValidationFailed.emit($event)\"\n (LoadError)=\"LoadError.emit($event)\">\n </mj-entity-form-host>\n\n @if (ShowFooter) {\n <mj-dialog-actions>\n <button mjButton variant=\"primary\" [disabled]=\"saving\" (click)=\"onSaveClick()\">{{ SaveButtonText }}</button>\n <button mjButton [disabled]=\"saving\" (click)=\"onCancel()\">{{ CancelButtonText }}</button>\n </mj-dialog-actions>\n }\n </mj-dialog>\n}\n"]}