@memberjunction/ng-export-service 5.11.0 → 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.
@@ -388,11 +388,11 @@ export class ExportDialogComponent {
388
388
  i0.ɵɵconditionalCreate(0, ExportDialogComponent_Conditional_0_Template, 48, 15);
389
389
  } if (rf & 2) {
390
390
  i0.ɵɵconditional(ctx.visible ? 0 : -1);
391
- } }, dependencies: [i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.NumberValueAccessor, i2.CheckboxControlValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.MinValidator, i2.MaxValidator, i2.NgModel, i3.DecimalPipe], styles: ["\n\n\n\n\n.mj-export-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(2px);\n z-index: 1000;\n animation: _ngcontent-%COMP%_fadeIn 0.15s ease-out;\n}\n\n\n\n.mj-export-dialog[_ngcontent-%COMP%] {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background: #ffffff;\n border-radius: 12px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n width: 480px;\n max-width: 95vw;\n max-height: 90vh;\n display: flex;\n flex-direction: column;\n z-index: 1001;\n animation: _ngcontent-%COMP%_slideIn 0.2s ease-out;\n}\n\n\n\n.mj-export-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px;\n border-bottom: 1px solid #e5e7eb;\n}\n\n.mj-export-header[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: #111827;\n}\n\n.mj-export-close[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 8px;\n cursor: pointer;\n color: #6b7280;\n border-radius: 6px;\n transition: all 0.15s ease;\n}\n\n.mj-export-close[_ngcontent-%COMP%]:hover {\n background: #f3f4f6;\n color: #374151;\n}\n\n\n\n.mj-export-content[_ngcontent-%COMP%] {\n padding: 24px;\n overflow-y: auto;\n flex: 1;\n}\n\n\n\n.mj-export-section[_ngcontent-%COMP%] {\n margin-bottom: 24px;\n}\n\n.mj-export-section[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.mj-export-label[_ngcontent-%COMP%] {\n display: block;\n font-size: 13px;\n font-weight: 500;\n color: #374151;\n margin-bottom: 8px;\n}\n\n\n\n.mj-export-formats[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n}\n\n.mj-export-format-btn[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 16px 12px;\n border: 2px solid #e5e7eb;\n border-radius: 10px;\n background: #ffffff;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.mj-export-format-btn[_ngcontent-%COMP%]:hover {\n border-color: #3b82f6;\n background: #f0f9ff;\n}\n\n.mj-export-format-btn.selected[_ngcontent-%COMP%] {\n border-color: #3b82f6;\n background: #eff6ff;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);\n}\n\n.mj-export-format-icon[_ngcontent-%COMP%] {\n font-size: 24px;\n margin-bottom: 8px;\n color: #6b7280;\n}\n\n.mj-export-format-btn.selected[_ngcontent-%COMP%] .mj-export-format-icon[_ngcontent-%COMP%] {\n color: #3b82f6;\n}\n\n.mj-export-format-label[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: #111827;\n margin-bottom: 4px;\n}\n\n.mj-export-format-desc[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #6b7280;\n text-align: center;\n}\n\n\n\n.mj-export-input-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n}\n\n.mj-export-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 10px 14px;\n border: 1px solid #d1d5db;\n border-radius: 8px;\n font-size: 14px;\n color: #111827;\n transition: all 0.15s ease;\n box-sizing: border-box;\n}\n\n.mj-export-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);\n}\n\n.mj-export-input-hint[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #9ca3af;\n margin-top: 4px;\n}\n\n\n\n.mj-export-checkbox-section[_ngcontent-%COMP%] {\n padding: 12px 0;\n}\n\n.mj-export-checkbox[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n font-size: 14px;\n color: #374151;\n}\n\n.mj-export-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n width: 18px;\n height: 18px;\n accent-color: #3b82f6;\n cursor: pointer;\n}\n\n\n\n.mj-export-select[_ngcontent-%COMP%] {\n padding: 10px 14px;\n border: 1px solid #d1d5db;\n border-radius: 8px;\n font-size: 14px;\n color: #111827;\n background: #ffffff;\n cursor: pointer;\n min-width: 160px;\n transition: all 0.15s ease;\n}\n\n.mj-export-select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);\n}\n\n\n\n.mj-export-sampling-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.mj-export-number-input[_ngcontent-%COMP%] {\n width: 100px;\n padding: 10px 14px;\n border: 1px solid #d1d5db;\n border-radius: 8px;\n font-size: 14px;\n color: #111827;\n transition: all 0.15s ease;\n}\n\n.mj-export-number-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);\n}\n\n.mj-export-sampling-desc[_ngcontent-%COMP%] {\n font-size: 13px;\n color: #6b7280;\n margin-top: 8px;\n font-style: italic;\n}\n\n\n\n.mj-export-summary[_ngcontent-%COMP%] {\n background: #f9fafb;\n border-radius: 10px;\n padding: 16px;\n}\n\n.mj-export-summary-row[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 0;\n}\n\n.mj-export-summary-label[_ngcontent-%COMP%] {\n font-size: 14px;\n color: #6b7280;\n}\n\n.mj-export-summary-value[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: #111827;\n}\n\n.mj-export-highlight[_ngcontent-%COMP%] {\n color: #3b82f6;\n font-size: 16px;\n}\n\n\n\n.mj-export-error[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 8px;\n color: #dc2626;\n font-size: 14px;\n margin-top: 16px;\n}\n\n\n\n.mj-export-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n padding: 16px 24px;\n border-top: 1px solid #e5e7eb;\n background: #f9fafb;\n border-radius: 0 0 12px 12px;\n}\n\n.mj-export-btn[_ngcontent-%COMP%] {\n padding: 10px 20px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 8px;\n transition: all 0.15s ease;\n border: none;\n}\n\n.mj-export-btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.mj-export-btn-primary[_ngcontent-%COMP%] {\n background: #3b82f6;\n color: #ffffff;\n}\n\n.mj-export-btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #2563eb;\n}\n\n.mj-export-btn-secondary[_ngcontent-%COMP%] {\n background: #ffffff;\n color: #374151;\n border: 1px solid #d1d5db;\n}\n\n.mj-export-btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #f3f4f6;\n}\n\n\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideIn {\n from {\n opacity: 0;\n transform: translate(-50%, -48%);\n }\n to {\n opacity: 1;\n transform: translate(-50%, -50%);\n }\n}\n\n\n\n.fa-spin[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_spin 1s linear infinite;\n}\n\n@keyframes _ngcontent-%COMP%_spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}"] });
391
+ } }, dependencies: [i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.NumberValueAccessor, i2.CheckboxControlValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.MinValidator, i2.MaxValidator, i2.NgModel, i3.DecimalPipe], styles: ["\n\n\n\n\n.mj-export-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n backdrop-filter: blur(2px);\n z-index: 1000;\n animation: _ngcontent-%COMP%_fadeIn 0.15s ease-out;\n}\n\n\n\n.mj-export-dialog[_ngcontent-%COMP%] {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: 0 25px 50px -12px var(--mj-bg-overlay);\n width: 480px;\n max-width: 95vw;\n max-height: 90vh;\n display: flex;\n flex-direction: column;\n z-index: 1001;\n animation: _ngcontent-%COMP%_slideIn 0.2s ease-out;\n}\n\n\n\n.mj-export-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.mj-export-header[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.mj-export-close[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 8px;\n cursor: pointer;\n color: var(--mj-text-muted);\n border-radius: 6px;\n transition: all 0.15s ease;\n}\n\n.mj-export-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n}\n\n\n\n.mj-export-content[_ngcontent-%COMP%] {\n padding: 24px;\n overflow-y: auto;\n flex: 1;\n}\n\n\n\n.mj-export-section[_ngcontent-%COMP%] {\n margin-bottom: 24px;\n}\n\n.mj-export-section[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.mj-export-label[_ngcontent-%COMP%] {\n display: block;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n margin-bottom: 8px;\n}\n\n\n\n.mj-export-formats[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n}\n\n.mj-export-format-btn[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 16px 12px;\n border: 2px solid var(--mj-border-default);\n border-radius: 10px;\n background: var(--mj-bg-surface);\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.mj-export-format-btn[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.mj-export-format-btn.selected[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.mj-export-format-icon[_ngcontent-%COMP%] {\n font-size: 24px;\n margin-bottom: 8px;\n color: var(--mj-text-muted);\n}\n\n.mj-export-format-btn.selected[_ngcontent-%COMP%] .mj-export-format-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.mj-export-format-label[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n}\n\n.mj-export-format-desc[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n text-align: center;\n}\n\n\n\n.mj-export-input-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n}\n\n.mj-export-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 10px 14px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n transition: all 0.15s ease;\n box-sizing: border-box;\n}\n\n.mj-export-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.mj-export-input-hint[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-disabled);\n margin-top: 4px;\n}\n\n\n\n.mj-export-checkbox-section[_ngcontent-%COMP%] {\n padding: 12px 0;\n}\n\n.mj-export-checkbox[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.mj-export-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n width: 18px;\n height: 18px;\n accent-color: var(--mj-brand-primary);\n cursor: pointer;\n}\n\n\n\n.mj-export-select[_ngcontent-%COMP%] {\n padding: 10px 14px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n cursor: pointer;\n min-width: 160px;\n transition: all 0.15s ease;\n}\n\n.mj-export-select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n\n\n.mj-export-sampling-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.mj-export-number-input[_ngcontent-%COMP%] {\n width: 100px;\n padding: 10px 14px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n transition: all 0.15s ease;\n}\n\n.mj-export-number-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.mj-export-sampling-desc[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n margin-top: 8px;\n font-style: italic;\n}\n\n\n\n.mj-export-summary[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border-radius: 10px;\n padding: 16px;\n}\n\n.mj-export-summary-row[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 0;\n}\n\n.mj-export-summary-label[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-muted);\n}\n\n.mj-export-summary-value[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.mj-export-highlight[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n\n\n.mj-export-error[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n background: color-mix(in srgb, var(--mj-status-error) 8%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 20%, var(--mj-bg-surface));\n border-radius: 8px;\n color: var(--mj-status-error);\n font-size: 14px;\n margin-top: 16px;\n}\n\n\n\n.mj-export-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n padding: 16px 24px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n border-radius: 0 0 12px 12px;\n}\n\n.mj-export-btn[_ngcontent-%COMP%] {\n padding: 10px 20px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 8px;\n transition: all 0.15s ease;\n border: none;\n}\n\n.mj-export-btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.mj-export-btn-primary[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.mj-export-btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.mj-export-btn-secondary[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-strong);\n}\n\n.mj-export-btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-card);\n}\n\n\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideIn {\n from {\n opacity: 0;\n transform: translate(-50%, -48%);\n }\n to {\n opacity: 1;\n transform: translate(-50%, -50%);\n }\n}\n\n\n\n.fa-spin[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_spin 1s linear infinite;\n}\n\n@keyframes _ngcontent-%COMP%_spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}"] });
392
392
  }
393
393
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ExportDialogComponent, [{
394
394
  type: Component,
395
- args: [{ standalone: false, selector: 'mj-export-dialog', template: "<!-- Backdrop -->\n@if (visible) {\n <div class=\"mj-export-backdrop\" (click)=\"onCancel()\"></div>\n\n <!-- Dialog -->\n <div class=\"mj-export-dialog\" role=\"dialog\" aria-modal=\"true\" [attr.aria-labelledby]=\"'export-dialog-title'\">\n <!-- Header -->\n <div class=\"mj-export-header\">\n <h2 id=\"export-dialog-title\">{{ dialogTitle }}</h2>\n <button type=\"button\" class=\"mj-export-close\" (click)=\"onCancel()\" aria-label=\"Close\">\n <span class=\"fa-solid fa-times\"></span>\n </button>\n </div>\n\n <!-- Content -->\n <div class=\"mj-export-content\">\n <!-- Format Selection -->\n <div class=\"mj-export-section\">\n <label class=\"mj-export-label\">Export Format</label>\n <div class=\"mj-export-formats\">\n @for (format of availableFormats; track format) {\n <button\n type=\"button\"\n class=\"mj-export-format-btn\"\n [class.selected]=\"selectedFormat === format\"\n (click)=\"selectFormat(format)\">\n <span class=\"fa-solid {{ getFormatInfo(format).icon }} mj-export-format-icon\"></span>\n <span class=\"mj-export-format-label\">{{ getFormatInfo(format).label }}</span>\n <span class=\"mj-export-format-desc\">{{ getFormatInfo(format).description }}</span>\n </button>\n }\n </div>\n </div>\n\n <!-- File Name -->\n <div class=\"mj-export-section\">\n <label class=\"mj-export-label\" for=\"exportFileName\">File Name</label>\n <div class=\"mj-export-input-group\">\n <input\n type=\"text\"\n id=\"exportFileName\"\n class=\"mj-export-input\"\n [(ngModel)]=\"fileName\"\n placeholder=\"Enter file name\" />\n <span class=\"mj-export-input-hint\">Extension added automatically</span>\n </div>\n </div>\n\n <!-- Include Headers -->\n <div class=\"mj-export-section mj-export-checkbox-section\">\n <label class=\"mj-export-checkbox\">\n <input type=\"checkbox\" [(ngModel)]=\"includeHeaders\" />\n <span class=\"mj-export-checkbox-mark\"></span>\n <span>Include column headers</span>\n </label>\n </div>\n\n <!-- Row Selection (Sampling) -->\n @if (showSamplingOptions) {\n <div class=\"mj-export-section\">\n <label class=\"mj-export-label\">Row Selection</label>\n <div class=\"mj-export-sampling-row\">\n <select class=\"mj-export-select\" [(ngModel)]=\"samplingMode\">\n @for (mode of samplingModes; track mode.mode) {\n <option [value]=\"mode.mode\">{{ mode.label }}</option>\n }\n </select>\n\n @if (needsSampleCount) {\n <input\n type=\"number\"\n class=\"mj-export-number-input\"\n [(ngModel)]=\"sampleCount\"\n [min]=\"1\"\n [max]=\"totalRows\"\n placeholder=\"Count\" />\n }\n\n @if (needsSampleInterval) {\n <input\n type=\"number\"\n class=\"mj-export-number-input\"\n [(ngModel)]=\"sampleInterval\"\n [min]=\"2\"\n [max]=\"totalRows\"\n placeholder=\"Interval\" />\n }\n </div>\n <div class=\"mj-export-sampling-desc\">\n {{ samplingDescription }}\n </div>\n </div>\n }\n\n <!-- Summary -->\n <div class=\"mj-export-section mj-export-summary\">\n <div class=\"mj-export-summary-row\">\n <span class=\"mj-export-summary-label\">Total rows available</span>\n <span class=\"mj-export-summary-value\">{{ totalRows | number }}</span>\n </div>\n <div class=\"mj-export-summary-row\">\n <span class=\"mj-export-summary-label\">Rows to export</span>\n <span class=\"mj-export-summary-value mj-export-highlight\">{{ estimatedRows | number }}</span>\n </div>\n </div>\n\n <!-- Error Message -->\n @if (exportError) {\n <div class=\"mj-export-error\">\n <span class=\"fa-solid fa-exclamation-circle\"></span>\n {{ exportError }}\n </div>\n }\n </div>\n\n <!-- Footer Actions -->\n <div class=\"mj-export-actions\">\n <button\n type=\"button\"\n class=\"mj-export-btn mj-export-btn-primary\"\n (click)=\"onExport()\"\n [disabled]=\"isExporting\">\n @if (!isExporting) {\n <span class=\"fa-solid fa-download\"></span>\n Export\n } @else {\n <span class=\"fa-solid fa-spinner fa-spin\"></span>\n Exporting...\n }\n </button>\n <button\n type=\"button\"\n class=\"mj-export-btn mj-export-btn-secondary\"\n (click)=\"onCancel()\"\n [disabled]=\"isExporting\">\n Cancel\n </button>\n </div>\n </div>\n}\n", styles: ["/* MJ Export Dialog - Modern, gorgeous pure Angular styling */\n\n/* Backdrop */\n.mj-export-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(2px);\n z-index: 1000;\n animation: fadeIn 0.15s ease-out;\n}\n\n/* Dialog Container */\n.mj-export-dialog {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background: #ffffff;\n border-radius: 12px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n width: 480px;\n max-width: 95vw;\n max-height: 90vh;\n display: flex;\n flex-direction: column;\n z-index: 1001;\n animation: slideIn 0.2s ease-out;\n}\n\n/* Header */\n.mj-export-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px;\n border-bottom: 1px solid #e5e7eb;\n}\n\n.mj-export-header h2 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: #111827;\n}\n\n.mj-export-close {\n background: none;\n border: none;\n padding: 8px;\n cursor: pointer;\n color: #6b7280;\n border-radius: 6px;\n transition: all 0.15s ease;\n}\n\n.mj-export-close:hover {\n background: #f3f4f6;\n color: #374151;\n}\n\n/* Content */\n.mj-export-content {\n padding: 24px;\n overflow-y: auto;\n flex: 1;\n}\n\n/* Sections */\n.mj-export-section {\n margin-bottom: 24px;\n}\n\n.mj-export-section:last-child {\n margin-bottom: 0;\n}\n\n.mj-export-label {\n display: block;\n font-size: 13px;\n font-weight: 500;\n color: #374151;\n margin-bottom: 8px;\n}\n\n/* Format Selection Buttons */\n.mj-export-formats {\n display: flex;\n gap: 12px;\n}\n\n.mj-export-format-btn {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 16px 12px;\n border: 2px solid #e5e7eb;\n border-radius: 10px;\n background: #ffffff;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.mj-export-format-btn:hover {\n border-color: #3b82f6;\n background: #f0f9ff;\n}\n\n.mj-export-format-btn.selected {\n border-color: #3b82f6;\n background: #eff6ff;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);\n}\n\n.mj-export-format-icon {\n font-size: 24px;\n margin-bottom: 8px;\n color: #6b7280;\n}\n\n.mj-export-format-btn.selected .mj-export-format-icon {\n color: #3b82f6;\n}\n\n.mj-export-format-label {\n font-size: 14px;\n font-weight: 600;\n color: #111827;\n margin-bottom: 4px;\n}\n\n.mj-export-format-desc {\n font-size: 11px;\n color: #6b7280;\n text-align: center;\n}\n\n/* Input Group */\n.mj-export-input-group {\n display: flex;\n flex-direction: column;\n}\n\n.mj-export-input {\n width: 100%;\n padding: 10px 14px;\n border: 1px solid #d1d5db;\n border-radius: 8px;\n font-size: 14px;\n color: #111827;\n transition: all 0.15s ease;\n box-sizing: border-box;\n}\n\n.mj-export-input:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);\n}\n\n.mj-export-input-hint {\n font-size: 12px;\n color: #9ca3af;\n margin-top: 4px;\n}\n\n/* Checkbox */\n.mj-export-checkbox-section {\n padding: 12px 0;\n}\n\n.mj-export-checkbox {\n display: flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n font-size: 14px;\n color: #374151;\n}\n\n.mj-export-checkbox input[type=\"checkbox\"] {\n width: 18px;\n height: 18px;\n accent-color: #3b82f6;\n cursor: pointer;\n}\n\n/* Select Dropdown */\n.mj-export-select {\n padding: 10px 14px;\n border: 1px solid #d1d5db;\n border-radius: 8px;\n font-size: 14px;\n color: #111827;\n background: #ffffff;\n cursor: pointer;\n min-width: 160px;\n transition: all 0.15s ease;\n}\n\n.mj-export-select:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);\n}\n\n/* Sampling Row */\n.mj-export-sampling-row {\n display: flex;\n gap: 12px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.mj-export-number-input {\n width: 100px;\n padding: 10px 14px;\n border: 1px solid #d1d5db;\n border-radius: 8px;\n font-size: 14px;\n color: #111827;\n transition: all 0.15s ease;\n}\n\n.mj-export-number-input:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);\n}\n\n.mj-export-sampling-desc {\n font-size: 13px;\n color: #6b7280;\n margin-top: 8px;\n font-style: italic;\n}\n\n/* Summary Section */\n.mj-export-summary {\n background: #f9fafb;\n border-radius: 10px;\n padding: 16px;\n}\n\n.mj-export-summary-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 0;\n}\n\n.mj-export-summary-label {\n font-size: 14px;\n color: #6b7280;\n}\n\n.mj-export-summary-value {\n font-size: 14px;\n font-weight: 600;\n color: #111827;\n}\n\n.mj-export-highlight {\n color: #3b82f6;\n font-size: 16px;\n}\n\n/* Error Message */\n.mj-export-error {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 8px;\n color: #dc2626;\n font-size: 14px;\n margin-top: 16px;\n}\n\n/* Footer Actions */\n.mj-export-actions {\n display: flex;\n gap: 12px;\n padding: 16px 24px;\n border-top: 1px solid #e5e7eb;\n background: #f9fafb;\n border-radius: 0 0 12px 12px;\n}\n\n.mj-export-btn {\n padding: 10px 20px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 8px;\n transition: all 0.15s ease;\n border: none;\n}\n\n.mj-export-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.mj-export-btn-primary {\n background: #3b82f6;\n color: #ffffff;\n}\n\n.mj-export-btn-primary:hover:not(:disabled) {\n background: #2563eb;\n}\n\n.mj-export-btn-secondary {\n background: #ffffff;\n color: #374151;\n border: 1px solid #d1d5db;\n}\n\n.mj-export-btn-secondary:hover:not(:disabled) {\n background: #f3f4f6;\n}\n\n/* Animations */\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes slideIn {\n from {\n opacity: 0;\n transform: translate(-50%, -48%);\n }\n to {\n opacity: 1;\n transform: translate(-50%, -50%);\n }\n}\n\n/* Spinner animation */\n.fa-spin {\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n"] }]
395
+ args: [{ standalone: false, selector: 'mj-export-dialog', template: "<!-- Backdrop -->\n@if (visible) {\n <div class=\"mj-export-backdrop\" (click)=\"onCancel()\"></div>\n\n <!-- Dialog -->\n <div class=\"mj-export-dialog\" role=\"dialog\" aria-modal=\"true\" [attr.aria-labelledby]=\"'export-dialog-title'\">\n <!-- Header -->\n <div class=\"mj-export-header\">\n <h2 id=\"export-dialog-title\">{{ dialogTitle }}</h2>\n <button type=\"button\" class=\"mj-export-close\" (click)=\"onCancel()\" aria-label=\"Close\">\n <span class=\"fa-solid fa-times\"></span>\n </button>\n </div>\n\n <!-- Content -->\n <div class=\"mj-export-content\">\n <!-- Format Selection -->\n <div class=\"mj-export-section\">\n <label class=\"mj-export-label\">Export Format</label>\n <div class=\"mj-export-formats\">\n @for (format of availableFormats; track format) {\n <button\n type=\"button\"\n class=\"mj-export-format-btn\"\n [class.selected]=\"selectedFormat === format\"\n (click)=\"selectFormat(format)\">\n <span class=\"fa-solid {{ getFormatInfo(format).icon }} mj-export-format-icon\"></span>\n <span class=\"mj-export-format-label\">{{ getFormatInfo(format).label }}</span>\n <span class=\"mj-export-format-desc\">{{ getFormatInfo(format).description }}</span>\n </button>\n }\n </div>\n </div>\n\n <!-- File Name -->\n <div class=\"mj-export-section\">\n <label class=\"mj-export-label\" for=\"exportFileName\">File Name</label>\n <div class=\"mj-export-input-group\">\n <input\n type=\"text\"\n id=\"exportFileName\"\n class=\"mj-export-input\"\n [(ngModel)]=\"fileName\"\n placeholder=\"Enter file name\" />\n <span class=\"mj-export-input-hint\">Extension added automatically</span>\n </div>\n </div>\n\n <!-- Include Headers -->\n <div class=\"mj-export-section mj-export-checkbox-section\">\n <label class=\"mj-export-checkbox\">\n <input type=\"checkbox\" [(ngModel)]=\"includeHeaders\" />\n <span class=\"mj-export-checkbox-mark\"></span>\n <span>Include column headers</span>\n </label>\n </div>\n\n <!-- Row Selection (Sampling) -->\n @if (showSamplingOptions) {\n <div class=\"mj-export-section\">\n <label class=\"mj-export-label\">Row Selection</label>\n <div class=\"mj-export-sampling-row\">\n <select class=\"mj-export-select\" [(ngModel)]=\"samplingMode\">\n @for (mode of samplingModes; track mode.mode) {\n <option [value]=\"mode.mode\">{{ mode.label }}</option>\n }\n </select>\n\n @if (needsSampleCount) {\n <input\n type=\"number\"\n class=\"mj-export-number-input\"\n [(ngModel)]=\"sampleCount\"\n [min]=\"1\"\n [max]=\"totalRows\"\n placeholder=\"Count\" />\n }\n\n @if (needsSampleInterval) {\n <input\n type=\"number\"\n class=\"mj-export-number-input\"\n [(ngModel)]=\"sampleInterval\"\n [min]=\"2\"\n [max]=\"totalRows\"\n placeholder=\"Interval\" />\n }\n </div>\n <div class=\"mj-export-sampling-desc\">\n {{ samplingDescription }}\n </div>\n </div>\n }\n\n <!-- Summary -->\n <div class=\"mj-export-section mj-export-summary\">\n <div class=\"mj-export-summary-row\">\n <span class=\"mj-export-summary-label\">Total rows available</span>\n <span class=\"mj-export-summary-value\">{{ totalRows | number }}</span>\n </div>\n <div class=\"mj-export-summary-row\">\n <span class=\"mj-export-summary-label\">Rows to export</span>\n <span class=\"mj-export-summary-value mj-export-highlight\">{{ estimatedRows | number }}</span>\n </div>\n </div>\n\n <!-- Error Message -->\n @if (exportError) {\n <div class=\"mj-export-error\">\n <span class=\"fa-solid fa-exclamation-circle\"></span>\n {{ exportError }}\n </div>\n }\n </div>\n\n <!-- Footer Actions -->\n <div class=\"mj-export-actions\">\n <button\n type=\"button\"\n class=\"mj-export-btn mj-export-btn-primary\"\n (click)=\"onExport()\"\n [disabled]=\"isExporting\">\n @if (!isExporting) {\n <span class=\"fa-solid fa-download\"></span>\n Export\n } @else {\n <span class=\"fa-solid fa-spinner fa-spin\"></span>\n Exporting...\n }\n </button>\n <button\n type=\"button\"\n class=\"mj-export-btn mj-export-btn-secondary\"\n (click)=\"onCancel()\"\n [disabled]=\"isExporting\">\n Cancel\n </button>\n </div>\n </div>\n}\n", styles: ["/* MJ Export Dialog */\n\n/* Backdrop */\n.mj-export-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n backdrop-filter: blur(2px);\n z-index: 1000;\n animation: fadeIn 0.15s ease-out;\n}\n\n/* Dialog Container */\n.mj-export-dialog {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: 0 25px 50px -12px var(--mj-bg-overlay);\n width: 480px;\n max-width: 95vw;\n max-height: 90vh;\n display: flex;\n flex-direction: column;\n z-index: 1001;\n animation: slideIn 0.2s ease-out;\n}\n\n/* Header */\n.mj-export-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.mj-export-header h2 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.mj-export-close {\n background: none;\n border: none;\n padding: 8px;\n cursor: pointer;\n color: var(--mj-text-muted);\n border-radius: 6px;\n transition: all 0.15s ease;\n}\n\n.mj-export-close:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n}\n\n/* Content */\n.mj-export-content {\n padding: 24px;\n overflow-y: auto;\n flex: 1;\n}\n\n/* Sections */\n.mj-export-section {\n margin-bottom: 24px;\n}\n\n.mj-export-section:last-child {\n margin-bottom: 0;\n}\n\n.mj-export-label {\n display: block;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n margin-bottom: 8px;\n}\n\n/* Format Selection Buttons */\n.mj-export-formats {\n display: flex;\n gap: 12px;\n}\n\n.mj-export-format-btn {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 16px 12px;\n border: 2px solid var(--mj-border-default);\n border-radius: 10px;\n background: var(--mj-bg-surface);\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.mj-export-format-btn:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.mj-export-format-btn.selected {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.mj-export-format-icon {\n font-size: 24px;\n margin-bottom: 8px;\n color: var(--mj-text-muted);\n}\n\n.mj-export-format-btn.selected .mj-export-format-icon {\n color: var(--mj-brand-primary);\n}\n\n.mj-export-format-label {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n}\n\n.mj-export-format-desc {\n font-size: 11px;\n color: var(--mj-text-muted);\n text-align: center;\n}\n\n/* Input Group */\n.mj-export-input-group {\n display: flex;\n flex-direction: column;\n}\n\n.mj-export-input {\n width: 100%;\n padding: 10px 14px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n transition: all 0.15s ease;\n box-sizing: border-box;\n}\n\n.mj-export-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.mj-export-input-hint {\n font-size: 12px;\n color: var(--mj-text-disabled);\n margin-top: 4px;\n}\n\n/* Checkbox */\n.mj-export-checkbox-section {\n padding: 12px 0;\n}\n\n.mj-export-checkbox {\n display: flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.mj-export-checkbox input[type=\"checkbox\"] {\n width: 18px;\n height: 18px;\n accent-color: var(--mj-brand-primary);\n cursor: pointer;\n}\n\n/* Select Dropdown */\n.mj-export-select {\n padding: 10px 14px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n cursor: pointer;\n min-width: 160px;\n transition: all 0.15s ease;\n}\n\n.mj-export-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n/* Sampling Row */\n.mj-export-sampling-row {\n display: flex;\n gap: 12px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.mj-export-number-input {\n width: 100px;\n padding: 10px 14px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n transition: all 0.15s ease;\n}\n\n.mj-export-number-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.mj-export-sampling-desc {\n font-size: 13px;\n color: var(--mj-text-muted);\n margin-top: 8px;\n font-style: italic;\n}\n\n/* Summary Section */\n.mj-export-summary {\n background: var(--mj-bg-surface-card);\n border-radius: 10px;\n padding: 16px;\n}\n\n.mj-export-summary-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 0;\n}\n\n.mj-export-summary-label {\n font-size: 14px;\n color: var(--mj-text-muted);\n}\n\n.mj-export-summary-value {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.mj-export-highlight {\n color: var(--mj-brand-primary);\n font-size: 16px;\n}\n\n/* Error Message */\n.mj-export-error {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n background: color-mix(in srgb, var(--mj-status-error) 8%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 20%, var(--mj-bg-surface));\n border-radius: 8px;\n color: var(--mj-status-error);\n font-size: 14px;\n margin-top: 16px;\n}\n\n/* Footer Actions */\n.mj-export-actions {\n display: flex;\n gap: 12px;\n padding: 16px 24px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n border-radius: 0 0 12px 12px;\n}\n\n.mj-export-btn {\n padding: 10px 20px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 8px;\n transition: all 0.15s ease;\n border: none;\n}\n\n.mj-export-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.mj-export-btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.mj-export-btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.mj-export-btn-secondary {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-strong);\n}\n\n.mj-export-btn-secondary:hover:not(:disabled) {\n background: var(--mj-bg-surface-card);\n}\n\n/* Animations */\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes slideIn {\n from {\n opacity: 0;\n transform: translate(-50%, -48%);\n }\n to {\n opacity: 1;\n transform: translate(-50%, -50%);\n }\n}\n\n/* Spinner animation */\n.fa-spin {\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n"] }]
396
396
  }], () => [{ type: i1.ExportService }, { type: i0.ChangeDetectorRef }], { visible: [{
397
397
  type: Input
398
398
  }], config: [{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-export-service",
3
- "version": "5.11.0",
3
+ "version": "5.12.0",
4
4
  "description": "MemberJunction: Angular export service and dialog for exporting data to Excel, CSV, and JSON",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
@@ -34,7 +34,7 @@
34
34
  "@angular/cdk": "21.1.3"
35
35
  },
36
36
  "dependencies": {
37
- "@memberjunction/export-engine": "5.11.0",
37
+ "@memberjunction/export-engine": "5.12.0",
38
38
  "tslib": "^2.8.1"
39
39
  },
40
40
  "sideEffects": false,