@memberjunction/ng-entity-card 6.2.0-edge.0 → 6.2.0-edge.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -157,16 +157,16 @@ export declare class MJEntityCardComponent extends BaseAngularComponent implemen
157
157
  get ThumbnailIsImage(): boolean;
158
158
  /** Whether the thumbnail is an icon class */
159
159
  get ThumbnailIsIcon(): boolean;
160
- private get ResolvedMaxFields();
160
+ private get resolvedMaxFields();
161
161
  private resolve;
162
162
  private resolveEntity;
163
163
  private resolveTemplate;
164
164
  private resolveTitle;
165
165
  private resolveEntityIcon;
166
166
  private resolveEntityDisplayName;
167
- private FormatValue;
167
+ private formatValue;
168
168
  private isDateOnlyField;
169
- private BuildEventPayload;
169
+ private buildEventPayload;
170
170
  static ɵfac: i0.ɵɵFactoryDeclaration<MJEntityCardComponent, never>;
171
171
  static ɵcmp: i0.ɵɵComponentDeclaration<MJEntityCardComponent, "mj-entity-card", never, { "EntityName": { "alias": "EntityName"; "required": false; }; "Entity": { "alias": "Entity"; "required": false; }; "Record": { "alias": "Record"; "required": false; }; "Variant": { "alias": "Variant"; "required": false; }; "Template": { "alias": "Template"; "required": false; }; "MaxDisplayFields": { "alias": "MaxDisplayFields"; "required": false; }; "ShowAvatar": { "alias": "ShowAvatar"; "required": false; }; "ShowOpenButton": { "alias": "ShowOpenButton"; "required": false; }; "ShowFieldLabels": { "alias": "ShowFieldLabels"; "required": false; }; "CssClass": { "alias": "CssClass"; "required": false; }; }, { "BeforeCardClick": "BeforeCardClick"; "CardClicked": "CardClicked"; "BeforeOpen": "BeforeOpen"; "OpenRequested": "OpenRequested"; }, never, never, true, never>;
172
172
  }
@@ -274,7 +274,7 @@ export class MJEntityCardComponent extends BaseAngularComponent {
274
274
  // ================================================================
275
275
  /** @internal Handle card click with cancelable before/after pattern */
276
276
  OnCardClick() {
277
- const payload = this.BuildEventPayload();
277
+ const payload = this.buildEventPayload();
278
278
  const cancelable = { Data: payload, Cancel: false };
279
279
  this.BeforeCardClick.emit(cancelable);
280
280
  if (!cancelable.Cancel) {
@@ -284,7 +284,7 @@ export class MJEntityCardComponent extends BaseAngularComponent {
284
284
  /** @internal Handle open button click with cancelable before/after pattern */
285
285
  OnOpenClick(event) {
286
286
  event.stopPropagation();
287
- const payload = this.BuildEventPayload();
287
+ const payload = this.buildEventPayload();
288
288
  const cancelable = { Data: payload, Cancel: false };
289
289
  this.BeforeOpen.emit(cancelable);
290
290
  if (!cancelable.Cancel) {
@@ -298,7 +298,7 @@ export class MJEntityCardComponent extends BaseAngularComponent {
298
298
  get DisplayFields() {
299
299
  if (!this.EffectiveTemplate)
300
300
  return [];
301
- const max = this.ResolvedMaxFields;
301
+ const max = this.resolvedMaxFields;
302
302
  return this.EffectiveTemplate.DisplayFields.slice(0, max);
303
303
  }
304
304
  /** Whether to show the avatar based on variant and input */
@@ -318,7 +318,7 @@ export class MJEntityCardComponent extends BaseAngularComponent {
318
318
  const value = this.Record[field.Name];
319
319
  if (value == null || String(value).trim() === '')
320
320
  return '';
321
- return this.FormatValue(value, field);
321
+ return this.formatValue(value, field);
322
322
  }
323
323
  /** Get the label for a field */
324
324
  GetFieldLabel(fieldName) {
@@ -396,7 +396,7 @@ export class MJEntityCardComponent extends BaseAngularComponent {
396
396
  // ================================================================
397
397
  // Private Methods
398
398
  // ================================================================
399
- get ResolvedMaxFields() {
399
+ get resolvedMaxFields() {
400
400
  if (this.MaxDisplayFields != null)
401
401
  return this.MaxDisplayFields;
402
402
  switch (this.Variant) {
@@ -434,7 +434,7 @@ export class MJEntityCardComponent extends BaseAngularComponent {
434
434
  return null;
435
435
  const metadataKeys = Object.keys(this.Record);
436
436
  if (this.ResolvedEntity) {
437
- const full = GenerateCardTemplate(this.ResolvedEntity, this.ResolvedMaxFields);
437
+ const full = GenerateCardTemplate(this.ResolvedEntity, this.resolvedMaxFields);
438
438
  // Filter to fields present in the record
439
439
  const keySet = new Set(metadataKeys);
440
440
  return {
@@ -447,7 +447,7 @@ export class MJEntityCardComponent extends BaseAngularComponent {
447
447
  BadgeField: full.BadgeField && keySet.has(full.BadgeField) ? full.BadgeField : null,
448
448
  };
449
449
  }
450
- return GenerateCardTemplateFromMetadata(entityName, metadataKeys, this.ResolvedMaxFields, this.ProviderToUse);
450
+ return GenerateCardTemplateFromMetadata(entityName, metadataKeys, this.resolvedMaxFields, this.ProviderToUse);
451
451
  }
452
452
  resolveTitle() {
453
453
  if (!this.EffectiveTemplate || this.EffectiveTemplate.TitleFields.length === 0) {
@@ -471,7 +471,7 @@ export class MJEntityCardComponent extends BaseAngularComponent {
471
471
  return metaEntity;
472
472
  return this.ResolvedEntity?.Name ?? this.EntityName ?? '';
473
473
  }
474
- FormatValue(value, field) {
474
+ formatValue(value, field) {
475
475
  switch (field.Type) {
476
476
  case 'number': {
477
477
  const num = Number(value);
@@ -515,7 +515,7 @@ export class MJEntityCardComponent extends BaseAngularComponent {
515
515
  isDateOnlyField(fieldName) {
516
516
  return IsDateOnlySQLType(this.ResolvedEntity?.Fields?.find(f => f.Name === fieldName)?.Type);
517
517
  }
518
- BuildEventPayload() {
518
+ buildEventPayload() {
519
519
  return {
520
520
  EntityName: this.EntityDisplayName,
521
521
  Record: this.Record,
@@ -1 +1 @@
1
- {"version":3,"file":"entity-card.component.js","sourceRoot":"","sources":["../../src/lib/entity-card.component.ts","../../src/lib/entity-card.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component, Input, Output, EventEmitter,\n OnChanges, SimpleChanges, ChangeDetectionStrategy, ChangeDetectorRef, inject\n} from '@angular/core';\nimport { EntityInfo, IsDateOnlySQLType, FormatDateOnly } from '@memberjunction/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport {\n EntityCardVariant, CardTemplate, CardDisplayField,\n CancelableCardEvent, CardRecordEvent,\n GenerateCardTemplate, GenerateCardTemplateFromMetadata,\n CombineTitleFields, FormatKeyAsLabel,\n} from './entity-card.types';\n\n/**\n * `MJEntityCardComponent` — A generic, metadata-driven entity record card.\n *\n * Renders a single entity record as a visual card with automatically prioritized\n * fields based on MemberJunction entity metadata (`IsNameField`, `DefaultInView`,\n * `Sequence`). Designed to work with both full entity records and sparse vector\n * metadata from the Knowledge Hub.\n *\n * ## Variants\n * - `compact` — Tooltip-sized. Title + 2-3 key fields. No avatar.\n * - `card` — Grid card. Avatar + title + subtitle + display fields + badge.\n * - `detail` — Full panel. All available fields with labels.\n *\n * ## Field Resolution\n * 1. **Title**: All `IsNameField` fields combined in Sequence order\n * 2. **Primary fields**: `DefaultInView=true` sorted by Sequence\n * 3. **Fallback**: First 5 non-PK/FK fields when no metadata flags are set\n *\n * ## Events\n * All interactions follow the `BeforeXXX` / `AfterXXX` cancelable event pattern.\n * Set `event.Cancel = true` in a `BeforeXXX` handler to prevent the default action.\n *\n * @example\n * ```html\n * <!-- From entity name + vector metadata -->\n * <mj-entity-card\n * [EntityName]=\"'Members'\"\n * [Record]=\"vectorMetadata\"\n * Variant=\"card\"\n * (CardClicked)=\"onCardClick($event)\">\n * </mj-entity-card>\n *\n * <!-- From EntityInfo + full record -->\n * <mj-entity-card\n * [Entity]=\"entityInfo\"\n * [Record]=\"record.GetAll()\"\n * Variant=\"detail\"\n * [ShowOpenButton]=\"true\"\n * (OpenRequested)=\"onOpen($event)\">\n * </mj-entity-card>\n * ```\n *\n * @selector mj-entity-card\n */\n@Component({\n standalone: true,\n selector: 'mj-entity-card',\n templateUrl: './entity-card.component.html',\n styleUrls: ['./entity-card.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MJEntityCardComponent extends BaseAngularComponent implements OnChanges {\n private cdr = inject(ChangeDetectorRef);\n\n // ================================================================\n // Data Inputs\n // ================================================================\n\n /**\n * The entity name (e.g., \"Members\"). Used to look up `EntityInfo` from\n * the MJ Metadata cache. Mutually exclusive with `Entity` — if both are\n * provided, `Entity` takes precedence.\n */\n @Input() EntityName: string | null = null;\n\n /**\n * Pre-resolved EntityInfo object. Takes precedence over `EntityName`.\n * Use this when you already have the EntityInfo to avoid a redundant lookup.\n */\n @Input() Entity: EntityInfo | null = null;\n\n /**\n * The record data as a plain key-value object. Works with both full entity\n * records (`record.GetAll()`) and sparse vector metadata.\n *\n * Fields not present in the record are gracefully skipped in the display.\n */\n @Input() Record: Record<string, unknown> = {};\n\n /**\n * Visual variant controlling size, layout, and detail level.\n * @default 'card'\n */\n @Input() Variant: EntityCardVariant = 'card';\n\n // ================================================================\n // Customization Inputs\n // ================================================================\n\n /**\n * Custom card template. When provided, overrides the auto-generated template.\n * Use `GenerateCardTemplate()` from the types module to build one programmatically.\n */\n @Input() Template: CardTemplate | null = null;\n\n /**\n * Maximum number of display fields in the card body.\n * Only applies when using the auto-generated template.\n * @default 4 for 'card', 2 for 'compact', unlimited for 'detail'\n */\n @Input() MaxDisplayFields: number | null = null;\n\n /**\n * Whether to show the entity icon/avatar.\n * @default true for 'card', false for 'compact', true for 'detail'\n */\n @Input() ShowAvatar: boolean | null = null;\n\n /**\n * Whether to show the \"Open Record\" button.\n * @default false\n */\n @Input() ShowOpenButton = false;\n\n /**\n * Whether to show field labels alongside values.\n * @default true for 'detail', false for 'compact', true for 'card'\n */\n @Input() ShowFieldLabels: boolean | null = null;\n\n /**\n * CSS class to apply to the outer container for custom styling.\n */\n @Input() CssClass = '';\n\n // ================================================================\n // Events — BeforeXXX / AfterXXX Pattern\n // ================================================================\n\n /**\n * Fires before the card is clicked. Set `Cancel = true` to prevent\n * the `CardClicked` event from firing.\n */\n @Output() BeforeCardClick = new EventEmitter<CancelableCardEvent<CardRecordEvent>>();\n\n /** Fires after the card is clicked (if not canceled). */\n @Output() CardClicked = new EventEmitter<CardRecordEvent>();\n\n /**\n * Fires before the \"Open Record\" button is clicked. Set `Cancel = true`\n * to prevent the `OpenRequested` event from firing.\n */\n @Output() BeforeOpen = new EventEmitter<CancelableCardEvent<CardRecordEvent>>();\n\n /** Fires when the \"Open Record\" button is clicked (if not canceled). */\n @Output() OpenRequested = new EventEmitter<CardRecordEvent>();\n\n // ================================================================\n // Computed State\n // ================================================================\n\n /** The resolved EntityInfo (from Entity input or EntityName lookup) */\n public ResolvedEntity: EntityInfo | null = null;\n\n /** The effective card template (custom or auto-generated) */\n public EffectiveTemplate: CardTemplate | null = null;\n\n /** The combined title string */\n public Title = '';\n\n /** The entity icon class (from vector metadata or entity info) */\n public EntityIcon = '';\n\n /** Resolved entity display name */\n public EntityDisplayName = '';\n\n // ================================================================\n // Lifecycle\n // ================================================================\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['Entity'] || changes['EntityName'] || changes['Record'] || changes['Template'] || changes['Variant']) {\n this.resolve();\n }\n }\n\n // ================================================================\n // Event Handlers\n // ================================================================\n\n /** @internal Handle card click with cancelable before/after pattern */\n public OnCardClick(): void {\n const payload = this.BuildEventPayload();\n const cancelable: CancelableCardEvent<CardRecordEvent> = { Data: payload, Cancel: false };\n this.BeforeCardClick.emit(cancelable);\n if (!cancelable.Cancel) {\n this.CardClicked.emit(payload);\n }\n }\n\n /** @internal Handle open button click with cancelable before/after pattern */\n public OnOpenClick(event: MouseEvent): void {\n event.stopPropagation();\n const payload = this.BuildEventPayload();\n const cancelable: CancelableCardEvent<CardRecordEvent> = { Data: payload, Cancel: false };\n this.BeforeOpen.emit(cancelable);\n if (!cancelable.Cancel) {\n this.OpenRequested.emit(payload);\n }\n }\n\n // ================================================================\n // Display Helpers (used in template)\n // ================================================================\n\n /** Get the resolved display fields, respecting maxFields for variant */\n public get DisplayFields(): CardDisplayField[] {\n if (!this.EffectiveTemplate) return [];\n const max = this.ResolvedMaxFields;\n return this.EffectiveTemplate.DisplayFields.slice(0, max);\n }\n\n /** Whether to show the avatar based on variant and input */\n public get ShouldShowAvatar(): boolean {\n if (this.ShowAvatar != null) return this.ShowAvatar;\n return this.Variant !== 'compact';\n }\n\n /** Whether to show field labels based on variant and input */\n public get ShouldShowLabels(): boolean {\n if (this.ShowFieldLabels != null) return this.ShowFieldLabels;\n return this.Variant !== 'compact';\n }\n\n /** Get formatted value for a display field */\n public GetFieldValue(field: CardDisplayField): string {\n const value = this.Record[field.Name];\n if (value == null || String(value).trim() === '') return '';\n return this.FormatValue(value, field);\n }\n\n /** Get the label for a field */\n public GetFieldLabel(fieldName: string): string {\n return this.EffectiveTemplate?.FieldLabels[fieldName] ?? FormatKeyAsLabel(fieldName);\n }\n\n /** Get initials from the title for avatar fallback */\n public get Initials(): string {\n if (!this.Title || this.Title === 'Unknown') return '?';\n const words = this.Title.split(/\\s+/).filter(w => w.length > 0);\n if (words.length === 1) return words[0].substring(0, 2).toUpperCase();\n return (words[0][0] + words[words.length - 1][0]).toUpperCase();\n }\n\n /** Get a deterministic color for the avatar based on the record */\n public get AvatarColor(): string {\n const colors = [\n 'var(--mj-brand-primary)', 'var(--mj-status-success)',\n 'var(--mj-status-warning)', 'var(--mj-status-info)',\n ];\n let hash = 0;\n const key = this.Title + (this.Record['RecordID'] ?? '');\n for (let i = 0; i < key.length; i++) {\n hash = key.charCodeAt(i) + ((hash << 5) - hash);\n }\n return colors[Math.abs(hash) % colors.length];\n }\n\n /** Get the subtitle value */\n public get Subtitle(): string {\n if (!this.EffectiveTemplate?.SubtitleField) return '';\n const v = this.Record[this.EffectiveTemplate.SubtitleField];\n return v != null ? String(v) : '';\n }\n\n /** Get the description value */\n public get Description(): string {\n if (!this.EffectiveTemplate?.DescriptionField) return '';\n const v = this.Record[this.EffectiveTemplate.DescriptionField];\n if (v == null) return '';\n const s = String(v);\n return s.length > 120 ? s.substring(0, 120) + '...' : s;\n }\n\n /** Check if a thumbnail is available */\n public get HasThumbnail(): boolean {\n if (!this.EffectiveTemplate?.ThumbnailFields) return false;\n return this.EffectiveTemplate.ThumbnailFields.some(f => {\n const v = this.Record[f];\n return v != null && String(v).trim() !== '';\n });\n }\n\n /** Get the thumbnail URL or icon class */\n public get ThumbnailValue(): string {\n if (!this.EffectiveTemplate?.ThumbnailFields) return '';\n for (const f of this.EffectiveTemplate.ThumbnailFields) {\n const v = this.Record[f];\n if (v != null && String(v).trim() !== '') return String(v);\n }\n return '';\n }\n\n /** Whether the thumbnail is an image URL */\n public get ThumbnailIsImage(): boolean {\n const v = this.ThumbnailValue;\n return v.startsWith('http://') || v.startsWith('https://') || v.startsWith('data:image/');\n }\n\n /** Whether the thumbnail is an icon class */\n public get ThumbnailIsIcon(): boolean {\n const v = this.ThumbnailValue.toLowerCase();\n return v.startsWith('fa-') || v.startsWith('fa ') || v.startsWith('fas ') || v.startsWith('far ');\n }\n\n // ================================================================\n // Private Methods\n // ================================================================\n\n private get ResolvedMaxFields(): number {\n if (this.MaxDisplayFields != null) return this.MaxDisplayFields;\n switch (this.Variant) {\n case 'compact': return 3;\n case 'card': return 4;\n case 'detail': return 999;\n }\n }\n\n private resolve(): void {\n this.ResolvedEntity = this.resolveEntity();\n this.EffectiveTemplate = this.resolveTemplate();\n this.Title = this.resolveTitle();\n this.EntityIcon = this.resolveEntityIcon();\n this.EntityDisplayName = this.resolveEntityDisplayName();\n this.cdr.markForCheck();\n }\n\n private resolveEntity(): EntityInfo | null {\n if (this.Entity) return this.Entity;\n if (!this.EntityName) return null;\n try {\n const md = this.ProviderToUse;\n return md.Entities.find(e => e.Name === this.EntityName) ?? null;\n } catch {\n return null;\n }\n }\n\n private resolveTemplate(): CardTemplate | null {\n if (this.Template) return this.Template;\n const entityName = this.Entity?.Name ?? this.EntityName;\n if (!entityName) return null;\n\n const metadataKeys = Object.keys(this.Record);\n if (this.ResolvedEntity) {\n const full = GenerateCardTemplate(this.ResolvedEntity, this.ResolvedMaxFields);\n // Filter to fields present in the record\n const keySet = new Set(metadataKeys);\n return {\n ...full,\n TitleFields: full.TitleFields.filter(f => keySet.has(f)),\n DisplayFields: full.DisplayFields.filter(f => keySet.has(f.Name)),\n SubtitleField: full.SubtitleField && keySet.has(full.SubtitleField) ? full.SubtitleField : null,\n DescriptionField: full.DescriptionField && keySet.has(full.DescriptionField) ? full.DescriptionField : null,\n ThumbnailFields: full.ThumbnailFields.filter(f => keySet.has(f)),\n BadgeField: full.BadgeField && keySet.has(full.BadgeField) ? full.BadgeField : null,\n };\n }\n\n return GenerateCardTemplateFromMetadata(entityName, metadataKeys, this.ResolvedMaxFields, this.ProviderToUse);\n }\n\n private resolveTitle(): string {\n if (!this.EffectiveTemplate || this.EffectiveTemplate.TitleFields.length === 0) {\n return String(this.Record['Name'] ?? this.Record['Title'] ?? 'Unknown');\n }\n return CombineTitleFields(this.Record, this.EffectiveTemplate.TitleFields);\n }\n\n private resolveEntityIcon(): string {\n // From vector metadata first\n const metaIcon = this.Record['EntityIcon'];\n if (metaIcon && typeof metaIcon === 'string') return metaIcon;\n // From entity info\n if (this.ResolvedEntity?.Icon) return this.ResolvedEntity.Icon;\n return 'fa-solid fa-table';\n }\n\n private resolveEntityDisplayName(): string {\n const metaEntity = this.Record['Entity'];\n if (metaEntity && typeof metaEntity === 'string') return metaEntity;\n return this.ResolvedEntity?.Name ?? this.EntityName ?? '';\n }\n\n private FormatValue(value: unknown, field: CardDisplayField): string {\n switch (field.Type) {\n case 'number': {\n const num = Number(value);\n if (isNaN(num)) return String(value);\n if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`;\n if (num >= 1000) return `${(num / 1000).toFixed(1)}K`;\n const nameLower = field.Name.toLowerCase();\n if (['amount', 'price', 'cost', 'value', 'revenue', 'total'].some(k => nameLower.includes(k))) {\n return `$${num.toLocaleString()}`;\n }\n return num.toLocaleString();\n }\n case 'boolean':\n return value ? 'Yes' : 'No';\n case 'date': {\n try {\n const d = value instanceof Date ? value : new Date(value as string | number);\n if (isNaN(d.getTime())) return String(value);\n const options: Intl.DateTimeFormatOptions = { month: 'short', day: 'numeric', year: 'numeric' };\n // A `date` column is a calendar day that arrives as UTC midnight; a local-zone\n // formatter would land on the previous day for every reader west of Greenwich\n // (MJ#4210). A timestamp names an instant and stays in local time.\n if (this.isDateOnlyField(field.Name)) return FormatDateOnly(d, options);\n return d.toLocaleDateString(undefined, options);\n } catch {\n return String(value);\n }\n }\n default: {\n const s = String(value);\n return s.length > 60 ? s.substring(0, 60) + '...' : s;\n }\n }\n }\n\n private isDateOnlyField(fieldName: string): boolean {\n return IsDateOnlySQLType(this.ResolvedEntity?.Fields?.find(f => f.Name === fieldName)?.Type);\n }\n\n private BuildEventPayload(): CardRecordEvent {\n return {\n EntityName: this.EntityDisplayName,\n Record: this.Record,\n RecordID: String(this.Record['RecordID'] ?? this.Record['ID'] ?? ''),\n };\n }\n}\n","<div class=\"mj-entity-card\"\n [class]=\"'mj-entity-card--' + Variant + ' ' + CssClass\"\n (click)=\"OnCardClick()\">\n\n <!-- Avatar / Thumbnail -->\n @if (ShouldShowAvatar) {\n <div class=\"mj-ec-avatar-area\">\n @if (HasThumbnail && ThumbnailIsImage) {\n <div class=\"mj-ec-thumbnail\">\n <img [src]=\"ThumbnailValue\" alt=\"\" />\n </div>\n } @else if (HasThumbnail && ThumbnailIsIcon) {\n <div class=\"mj-ec-avatar\" [style.background]=\"AvatarColor\">\n <i [class]=\"ThumbnailValue\"></i>\n </div>\n } @else if (EntityIcon) {\n <div class=\"mj-ec-avatar\" [style.background]=\"AvatarColor\">\n <i [class]=\"EntityIcon\"></i>\n </div>\n } @else {\n <div class=\"mj-ec-avatar\" [style.background]=\"AvatarColor\">\n {{ Initials }}\n </div>\n }\n </div>\n }\n\n <!-- Content -->\n <div class=\"mj-ec-content\">\n <!-- Header: Title + Entity -->\n <div class=\"mj-ec-header\">\n <div class=\"mj-ec-title\">{{ Title }}</div>\n @if (EntityDisplayName && Variant !== 'compact') {\n <div class=\"mj-ec-entity\">{{ EntityDisplayName }}</div>\n }\n </div>\n\n <!-- Subtitle -->\n @if (Subtitle && Variant !== 'compact') {\n <div class=\"mj-ec-subtitle\">{{ Subtitle }}</div>\n }\n\n <!-- Description (detail variant only) -->\n @if (Description && Variant === 'detail') {\n <div class=\"mj-ec-description\">{{ Description }}</div>\n }\n\n <!-- Display Fields -->\n @if (DisplayFields.length > 0) {\n <div class=\"mj-ec-fields\" [class.mj-ec-fields--labeled]=\"ShouldShowLabels\">\n @for (field of DisplayFields; track field.Name) {\n @if (GetFieldValue(field); as value) {\n <div class=\"mj-ec-field\">\n @if (ShouldShowLabels) {\n <span class=\"mj-ec-field-label\">{{ field.Label }}</span>\n }\n <span class=\"mj-ec-field-value\">{{ value }}</span>\n </div>\n }\n }\n </div>\n }\n </div>\n\n <!-- Open Button -->\n @if (ShowOpenButton) {\n <button class=\"mj-ec-open-btn\" (click)=\"OnOpenClick($event)\" title=\"Open record\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n </button>\n }\n</div>\n"]}
1
+ {"version":3,"file":"entity-card.component.js","sourceRoot":"","sources":["../../src/lib/entity-card.component.ts","../../src/lib/entity-card.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component, Input, Output, EventEmitter,\n OnChanges, SimpleChanges, ChangeDetectionStrategy, ChangeDetectorRef, inject\n} from '@angular/core';\nimport { EntityInfo, IsDateOnlySQLType, FormatDateOnly } from '@memberjunction/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport {\n EntityCardVariant, CardTemplate, CardDisplayField,\n CancelableCardEvent, CardRecordEvent,\n GenerateCardTemplate, GenerateCardTemplateFromMetadata,\n CombineTitleFields, FormatKeyAsLabel,\n} from './entity-card.types';\n\n/**\n * `MJEntityCardComponent` — A generic, metadata-driven entity record card.\n *\n * Renders a single entity record as a visual card with automatically prioritized\n * fields based on MemberJunction entity metadata (`IsNameField`, `DefaultInView`,\n * `Sequence`). Designed to work with both full entity records and sparse vector\n * metadata from the Knowledge Hub.\n *\n * ## Variants\n * - `compact` — Tooltip-sized. Title + 2-3 key fields. No avatar.\n * - `card` — Grid card. Avatar + title + subtitle + display fields + badge.\n * - `detail` — Full panel. All available fields with labels.\n *\n * ## Field Resolution\n * 1. **Title**: All `IsNameField` fields combined in Sequence order\n * 2. **Primary fields**: `DefaultInView=true` sorted by Sequence\n * 3. **Fallback**: First 5 non-PK/FK fields when no metadata flags are set\n *\n * ## Events\n * All interactions follow the `BeforeXXX` / `AfterXXX` cancelable event pattern.\n * Set `event.Cancel = true` in a `BeforeXXX` handler to prevent the default action.\n *\n * @example\n * ```html\n * <!-- From entity name + vector metadata -->\n * <mj-entity-card\n * [EntityName]=\"'Members'\"\n * [Record]=\"vectorMetadata\"\n * Variant=\"card\"\n * (CardClicked)=\"onCardClick($event)\">\n * </mj-entity-card>\n *\n * <!-- From EntityInfo + full record -->\n * <mj-entity-card\n * [Entity]=\"entityInfo\"\n * [Record]=\"record.GetAll()\"\n * Variant=\"detail\"\n * [ShowOpenButton]=\"true\"\n * (OpenRequested)=\"onOpen($event)\">\n * </mj-entity-card>\n * ```\n *\n * @selector mj-entity-card\n */\n@Component({\n standalone: true,\n selector: 'mj-entity-card',\n templateUrl: './entity-card.component.html',\n styleUrls: ['./entity-card.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MJEntityCardComponent extends BaseAngularComponent implements OnChanges {\n private cdr = inject(ChangeDetectorRef);\n\n // ================================================================\n // Data Inputs\n // ================================================================\n\n /**\n * The entity name (e.g., \"Members\"). Used to look up `EntityInfo` from\n * the MJ Metadata cache. Mutually exclusive with `Entity` — if both are\n * provided, `Entity` takes precedence.\n */\n @Input() EntityName: string | null = null;\n\n /**\n * Pre-resolved EntityInfo object. Takes precedence over `EntityName`.\n * Use this when you already have the EntityInfo to avoid a redundant lookup.\n */\n @Input() Entity: EntityInfo | null = null;\n\n /**\n * The record data as a plain key-value object. Works with both full entity\n * records (`record.GetAll()`) and sparse vector metadata.\n *\n * Fields not present in the record are gracefully skipped in the display.\n */\n @Input() Record: Record<string, unknown> = {};\n\n /**\n * Visual variant controlling size, layout, and detail level.\n * @default 'card'\n */\n @Input() Variant: EntityCardVariant = 'card';\n\n // ================================================================\n // Customization Inputs\n // ================================================================\n\n /**\n * Custom card template. When provided, overrides the auto-generated template.\n * Use `GenerateCardTemplate()` from the types module to build one programmatically.\n */\n @Input() Template: CardTemplate | null = null;\n\n /**\n * Maximum number of display fields in the card body.\n * Only applies when using the auto-generated template.\n * @default 4 for 'card', 2 for 'compact', unlimited for 'detail'\n */\n @Input() MaxDisplayFields: number | null = null;\n\n /**\n * Whether to show the entity icon/avatar.\n * @default true for 'card', false for 'compact', true for 'detail'\n */\n @Input() ShowAvatar: boolean | null = null;\n\n /**\n * Whether to show the \"Open Record\" button.\n * @default false\n */\n @Input() ShowOpenButton = false;\n\n /**\n * Whether to show field labels alongside values.\n * @default true for 'detail', false for 'compact', true for 'card'\n */\n @Input() ShowFieldLabels: boolean | null = null;\n\n /**\n * CSS class to apply to the outer container for custom styling.\n */\n @Input() CssClass = '';\n\n // ================================================================\n // Events — BeforeXXX / AfterXXX Pattern\n // ================================================================\n\n /**\n * Fires before the card is clicked. Set `Cancel = true` to prevent\n * the `CardClicked` event from firing.\n */\n @Output() BeforeCardClick = new EventEmitter<CancelableCardEvent<CardRecordEvent>>();\n\n /** Fires after the card is clicked (if not canceled). */\n @Output() CardClicked = new EventEmitter<CardRecordEvent>();\n\n /**\n * Fires before the \"Open Record\" button is clicked. Set `Cancel = true`\n * to prevent the `OpenRequested` event from firing.\n */\n @Output() BeforeOpen = new EventEmitter<CancelableCardEvent<CardRecordEvent>>();\n\n /** Fires when the \"Open Record\" button is clicked (if not canceled). */\n @Output() OpenRequested = new EventEmitter<CardRecordEvent>();\n\n // ================================================================\n // Computed State\n // ================================================================\n\n /** The resolved EntityInfo (from Entity input or EntityName lookup) */\n public ResolvedEntity: EntityInfo | null = null;\n\n /** The effective card template (custom or auto-generated) */\n public EffectiveTemplate: CardTemplate | null = null;\n\n /** The combined title string */\n public Title = '';\n\n /** The entity icon class (from vector metadata or entity info) */\n public EntityIcon = '';\n\n /** Resolved entity display name */\n public EntityDisplayName = '';\n\n // ================================================================\n // Lifecycle\n // ================================================================\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['Entity'] || changes['EntityName'] || changes['Record'] || changes['Template'] || changes['Variant']) {\n this.resolve();\n }\n }\n\n // ================================================================\n // Event Handlers\n // ================================================================\n\n /** @internal Handle card click with cancelable before/after pattern */\n public OnCardClick(): void {\n const payload = this.buildEventPayload();\n const cancelable: CancelableCardEvent<CardRecordEvent> = { Data: payload, Cancel: false };\n this.BeforeCardClick.emit(cancelable);\n if (!cancelable.Cancel) {\n this.CardClicked.emit(payload);\n }\n }\n\n /** @internal Handle open button click with cancelable before/after pattern */\n public OnOpenClick(event: MouseEvent): void {\n event.stopPropagation();\n const payload = this.buildEventPayload();\n const cancelable: CancelableCardEvent<CardRecordEvent> = { Data: payload, Cancel: false };\n this.BeforeOpen.emit(cancelable);\n if (!cancelable.Cancel) {\n this.OpenRequested.emit(payload);\n }\n }\n\n // ================================================================\n // Display Helpers (used in template)\n // ================================================================\n\n /** Get the resolved display fields, respecting maxFields for variant */\n public get DisplayFields(): CardDisplayField[] {\n if (!this.EffectiveTemplate) return [];\n const max = this.resolvedMaxFields;\n return this.EffectiveTemplate.DisplayFields.slice(0, max);\n }\n\n /** Whether to show the avatar based on variant and input */\n public get ShouldShowAvatar(): boolean {\n if (this.ShowAvatar != null) return this.ShowAvatar;\n return this.Variant !== 'compact';\n }\n\n /** Whether to show field labels based on variant and input */\n public get ShouldShowLabels(): boolean {\n if (this.ShowFieldLabels != null) return this.ShowFieldLabels;\n return this.Variant !== 'compact';\n }\n\n /** Get formatted value for a display field */\n public GetFieldValue(field: CardDisplayField): string {\n const value = this.Record[field.Name];\n if (value == null || String(value).trim() === '') return '';\n return this.formatValue(value, field);\n }\n\n /** Get the label for a field */\n public GetFieldLabel(fieldName: string): string {\n return this.EffectiveTemplate?.FieldLabels[fieldName] ?? FormatKeyAsLabel(fieldName);\n }\n\n /** Get initials from the title for avatar fallback */\n public get Initials(): string {\n if (!this.Title || this.Title === 'Unknown') return '?';\n const words = this.Title.split(/\\s+/).filter(w => w.length > 0);\n if (words.length === 1) return words[0].substring(0, 2).toUpperCase();\n return (words[0][0] + words[words.length - 1][0]).toUpperCase();\n }\n\n /** Get a deterministic color for the avatar based on the record */\n public get AvatarColor(): string {\n const colors = [\n 'var(--mj-brand-primary)', 'var(--mj-status-success)',\n 'var(--mj-status-warning)', 'var(--mj-status-info)',\n ];\n let hash = 0;\n const key = this.Title + (this.Record['RecordID'] ?? '');\n for (let i = 0; i < key.length; i++) {\n hash = key.charCodeAt(i) + ((hash << 5) - hash);\n }\n return colors[Math.abs(hash) % colors.length];\n }\n\n /** Get the subtitle value */\n public get Subtitle(): string {\n if (!this.EffectiveTemplate?.SubtitleField) return '';\n const v = this.Record[this.EffectiveTemplate.SubtitleField];\n return v != null ? String(v) : '';\n }\n\n /** Get the description value */\n public get Description(): string {\n if (!this.EffectiveTemplate?.DescriptionField) return '';\n const v = this.Record[this.EffectiveTemplate.DescriptionField];\n if (v == null) return '';\n const s = String(v);\n return s.length > 120 ? s.substring(0, 120) + '...' : s;\n }\n\n /** Check if a thumbnail is available */\n public get HasThumbnail(): boolean {\n if (!this.EffectiveTemplate?.ThumbnailFields) return false;\n return this.EffectiveTemplate.ThumbnailFields.some(f => {\n const v = this.Record[f];\n return v != null && String(v).trim() !== '';\n });\n }\n\n /** Get the thumbnail URL or icon class */\n public get ThumbnailValue(): string {\n if (!this.EffectiveTemplate?.ThumbnailFields) return '';\n for (const f of this.EffectiveTemplate.ThumbnailFields) {\n const v = this.Record[f];\n if (v != null && String(v).trim() !== '') return String(v);\n }\n return '';\n }\n\n /** Whether the thumbnail is an image URL */\n public get ThumbnailIsImage(): boolean {\n const v = this.ThumbnailValue;\n return v.startsWith('http://') || v.startsWith('https://') || v.startsWith('data:image/');\n }\n\n /** Whether the thumbnail is an icon class */\n public get ThumbnailIsIcon(): boolean {\n const v = this.ThumbnailValue.toLowerCase();\n return v.startsWith('fa-') || v.startsWith('fa ') || v.startsWith('fas ') || v.startsWith('far ');\n }\n\n // ================================================================\n // Private Methods\n // ================================================================\n\n private get resolvedMaxFields(): number {\n if (this.MaxDisplayFields != null) return this.MaxDisplayFields;\n switch (this.Variant) {\n case 'compact': return 3;\n case 'card': return 4;\n case 'detail': return 999;\n }\n }\n\n private resolve(): void {\n this.ResolvedEntity = this.resolveEntity();\n this.EffectiveTemplate = this.resolveTemplate();\n this.Title = this.resolveTitle();\n this.EntityIcon = this.resolveEntityIcon();\n this.EntityDisplayName = this.resolveEntityDisplayName();\n this.cdr.markForCheck();\n }\n\n private resolveEntity(): EntityInfo | null {\n if (this.Entity) return this.Entity;\n if (!this.EntityName) return null;\n try {\n const md = this.ProviderToUse;\n return md.Entities.find(e => e.Name === this.EntityName) ?? null;\n } catch {\n return null;\n }\n }\n\n private resolveTemplate(): CardTemplate | null {\n if (this.Template) return this.Template;\n const entityName = this.Entity?.Name ?? this.EntityName;\n if (!entityName) return null;\n\n const metadataKeys = Object.keys(this.Record);\n if (this.ResolvedEntity) {\n const full = GenerateCardTemplate(this.ResolvedEntity, this.resolvedMaxFields);\n // Filter to fields present in the record\n const keySet = new Set(metadataKeys);\n return {\n ...full,\n TitleFields: full.TitleFields.filter(f => keySet.has(f)),\n DisplayFields: full.DisplayFields.filter(f => keySet.has(f.Name)),\n SubtitleField: full.SubtitleField && keySet.has(full.SubtitleField) ? full.SubtitleField : null,\n DescriptionField: full.DescriptionField && keySet.has(full.DescriptionField) ? full.DescriptionField : null,\n ThumbnailFields: full.ThumbnailFields.filter(f => keySet.has(f)),\n BadgeField: full.BadgeField && keySet.has(full.BadgeField) ? full.BadgeField : null,\n };\n }\n\n return GenerateCardTemplateFromMetadata(entityName, metadataKeys, this.resolvedMaxFields, this.ProviderToUse);\n }\n\n private resolveTitle(): string {\n if (!this.EffectiveTemplate || this.EffectiveTemplate.TitleFields.length === 0) {\n return String(this.Record['Name'] ?? this.Record['Title'] ?? 'Unknown');\n }\n return CombineTitleFields(this.Record, this.EffectiveTemplate.TitleFields);\n }\n\n private resolveEntityIcon(): string {\n // From vector metadata first\n const metaIcon = this.Record['EntityIcon'];\n if (metaIcon && typeof metaIcon === 'string') return metaIcon;\n // From entity info\n if (this.ResolvedEntity?.Icon) return this.ResolvedEntity.Icon;\n return 'fa-solid fa-table';\n }\n\n private resolveEntityDisplayName(): string {\n const metaEntity = this.Record['Entity'];\n if (metaEntity && typeof metaEntity === 'string') return metaEntity;\n return this.ResolvedEntity?.Name ?? this.EntityName ?? '';\n }\n\n private formatValue(value: unknown, field: CardDisplayField): string {\n switch (field.Type) {\n case 'number': {\n const num = Number(value);\n if (isNaN(num)) return String(value);\n if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`;\n if (num >= 1000) return `${(num / 1000).toFixed(1)}K`;\n const nameLower = field.Name.toLowerCase();\n if (['amount', 'price', 'cost', 'value', 'revenue', 'total'].some(k => nameLower.includes(k))) {\n return `$${num.toLocaleString()}`;\n }\n return num.toLocaleString();\n }\n case 'boolean':\n return value ? 'Yes' : 'No';\n case 'date': {\n try {\n const d = value instanceof Date ? value : new Date(value as string | number);\n if (isNaN(d.getTime())) return String(value);\n const options: Intl.DateTimeFormatOptions = { month: 'short', day: 'numeric', year: 'numeric' };\n // A `date` column is a calendar day that arrives as UTC midnight; a local-zone\n // formatter would land on the previous day for every reader west of Greenwich\n // (MJ#4210). A timestamp names an instant and stays in local time.\n if (this.isDateOnlyField(field.Name)) return FormatDateOnly(d, options);\n return d.toLocaleDateString(undefined, options);\n } catch {\n return String(value);\n }\n }\n default: {\n const s = String(value);\n return s.length > 60 ? s.substring(0, 60) + '...' : s;\n }\n }\n }\n\n private isDateOnlyField(fieldName: string): boolean {\n return IsDateOnlySQLType(this.ResolvedEntity?.Fields?.find(f => f.Name === fieldName)?.Type);\n }\n\n private buildEventPayload(): CardRecordEvent {\n return {\n EntityName: this.EntityDisplayName,\n Record: this.Record,\n RecordID: String(this.Record['RecordID'] ?? this.Record['ID'] ?? ''),\n };\n }\n}\n","<div class=\"mj-entity-card\"\n [class]=\"'mj-entity-card--' + Variant + ' ' + CssClass\"\n (click)=\"OnCardClick()\">\n\n <!-- Avatar / Thumbnail -->\n @if (ShouldShowAvatar) {\n <div class=\"mj-ec-avatar-area\">\n @if (HasThumbnail && ThumbnailIsImage) {\n <div class=\"mj-ec-thumbnail\">\n <img [src]=\"ThumbnailValue\" alt=\"\" />\n </div>\n } @else if (HasThumbnail && ThumbnailIsIcon) {\n <div class=\"mj-ec-avatar\" [style.background]=\"AvatarColor\">\n <i [class]=\"ThumbnailValue\"></i>\n </div>\n } @else if (EntityIcon) {\n <div class=\"mj-ec-avatar\" [style.background]=\"AvatarColor\">\n <i [class]=\"EntityIcon\"></i>\n </div>\n } @else {\n <div class=\"mj-ec-avatar\" [style.background]=\"AvatarColor\">\n {{ Initials }}\n </div>\n }\n </div>\n }\n\n <!-- Content -->\n <div class=\"mj-ec-content\">\n <!-- Header: Title + Entity -->\n <div class=\"mj-ec-header\">\n <div class=\"mj-ec-title\">{{ Title }}</div>\n @if (EntityDisplayName && Variant !== 'compact') {\n <div class=\"mj-ec-entity\">{{ EntityDisplayName }}</div>\n }\n </div>\n\n <!-- Subtitle -->\n @if (Subtitle && Variant !== 'compact') {\n <div class=\"mj-ec-subtitle\">{{ Subtitle }}</div>\n }\n\n <!-- Description (detail variant only) -->\n @if (Description && Variant === 'detail') {\n <div class=\"mj-ec-description\">{{ Description }}</div>\n }\n\n <!-- Display Fields -->\n @if (DisplayFields.length > 0) {\n <div class=\"mj-ec-fields\" [class.mj-ec-fields--labeled]=\"ShouldShowLabels\">\n @for (field of DisplayFields; track field.Name) {\n @if (GetFieldValue(field); as value) {\n <div class=\"mj-ec-field\">\n @if (ShouldShowLabels) {\n <span class=\"mj-ec-field-label\">{{ field.Label }}</span>\n }\n <span class=\"mj-ec-field-value\">{{ value }}</span>\n </div>\n }\n }\n </div>\n }\n </div>\n\n <!-- Open Button -->\n @if (ShowOpenButton) {\n <button class=\"mj-ec-open-btn\" (click)=\"OnOpenClick($event)\" title=\"Open record\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n </button>\n }\n</div>\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-entity-card",
3
- "version": "6.2.0-edge.0",
3
+ "version": "6.2.0-edge.1",
4
4
  "description": "MemberJunction: Generic entity record card component with metadata-driven field prioritization",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
@@ -13,7 +13,7 @@
13
13
  "devDependencies": {
14
14
  "@angular/compiler": "21.2.22",
15
15
  "@angular/compiler-cli": "21.2.22",
16
- "@memberjunction/ng-test-utils": "6.2.0-edge.0",
16
+ "@memberjunction/ng-test-utils": "6.2.0-edge.1",
17
17
  "vitest": "^4.0.18"
18
18
  },
19
19
  "peerDependencies": {
@@ -21,9 +21,9 @@
21
21
  "@angular/core": "^21.2.22"
22
22
  },
23
23
  "dependencies": {
24
- "@memberjunction/core": "6.2.0-edge.0",
25
- "@memberjunction/ng-base-types": "6.2.0-edge.0",
26
- "@memberjunction/global": "6.2.0-edge.0",
24
+ "@memberjunction/core": "6.2.0-edge.1",
25
+ "@memberjunction/ng-base-types": "6.2.0-edge.1",
26
+ "@memberjunction/global": "6.2.0-edge.1",
27
27
  "tslib": "^2.8.1"
28
28
  },
29
29
  "repository": {