@masterteam/components 0.0.149 → 0.0.151

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.
@@ -1,9 +1,11 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, model, output, booleanAttribute, effect, Component } from '@angular/core';
2
+ import { input, model, output, booleanAttribute, inject, DestroyRef, viewChild, signal, computed, effect, afterNextRender, Component } from '@angular/core';
3
3
  import * as i1 from '@angular/forms';
4
4
  import { FormsModule } from '@angular/forms';
5
5
  import { Icon } from '@masterteam/icons';
6
6
  import { SelectButton } from 'primeng/selectbutton';
7
+ import { Popover } from 'primeng/popover';
8
+ import { Button } from '@masterteam/components/button';
7
9
 
8
10
  class Tabs {
9
11
  options = input([], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
@@ -11,11 +13,21 @@ class Tabs {
11
13
  optionValue = input('value', ...(ngDevMode ? [{ debugName: "optionValue" }] : /* istanbul ignore next */ []));
12
14
  active = model(null, ...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
13
15
  mode = input('horizontal', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
16
+ moreLabel = input('More', ...(ngDevMode ? [{ debugName: "moreLabel" }] : /* istanbul ignore next */ []));
14
17
  onChange = output();
15
18
  size = input(...(ngDevMode ? [undefined, { debugName: "size" }] : /* istanbul ignore next */ []));
16
19
  fluid = input(false, { ...(ngDevMode ? { debugName: "fluid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
17
20
  disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
18
- // TODO: make a decision about this maybe we should remove it
21
+ destroyRef = inject(DestroyRef);
22
+ tabsContainer = viewChild('tabsContainer', ...(ngDevMode ? [{ debugName: "tabsContainer" }] : /* istanbul ignore next */ []));
23
+ measureRow = viewChild('measureRow', ...(ngDevMode ? [{ debugName: "measureRow" }] : /* istanbul ignore next */ []));
24
+ resizeObserver;
25
+ measureHandle = 0;
26
+ visibleCount = signal(Number.MAX_SAFE_INTEGER, ...(ngDevMode ? [{ debugName: "visibleCount" }] : /* istanbul ignore next */ []));
27
+ visibleOptions = computed(() => this.options().slice(0, this.visibleCount()), ...(ngDevMode ? [{ debugName: "visibleOptions" }] : /* istanbul ignore next */ []));
28
+ overflowOptions = computed(() => this.options().slice(this.visibleCount()), ...(ngDevMode ? [{ debugName: "overflowOptions" }] : /* istanbul ignore next */ []));
29
+ hasOverflow = computed(() => this.overflowOptions().length > 0, ...(ngDevMode ? [{ debugName: "hasOverflow" }] : /* istanbul ignore next */ []));
30
+ isActiveInOverflow = computed(() => this.overflowOptions().some((option) => this.isActiveOption(option)), ...(ngDevMode ? [{ debugName: "isActiveInOverflow" }] : /* istanbul ignore next */ []));
19
31
  constructor() {
20
32
  effect(() => {
21
33
  const options = this.options();
@@ -28,6 +40,87 @@ class Tabs {
28
40
  this.active.set(this.resolveValue(options[0]));
29
41
  }
30
42
  });
43
+ afterNextRender(() => {
44
+ if (this.mode() !== 'underline')
45
+ return;
46
+ this.setupResizeObserver();
47
+ this.scheduleMeasure();
48
+ });
49
+ effect(() => {
50
+ // Re-measure when options or mode change.
51
+ this.options();
52
+ if (this.mode() !== 'underline')
53
+ return;
54
+ this.scheduleMeasure();
55
+ });
56
+ this.destroyRef.onDestroy(() => {
57
+ this.resizeObserver?.disconnect();
58
+ if (this.measureHandle) {
59
+ cancelAnimationFrame(this.measureHandle);
60
+ }
61
+ });
62
+ }
63
+ setupResizeObserver() {
64
+ const container = this.tabsContainer()?.nativeElement;
65
+ if (!container || typeof ResizeObserver === 'undefined')
66
+ return;
67
+ this.resizeObserver = new ResizeObserver(() => this.scheduleMeasure());
68
+ this.resizeObserver.observe(container);
69
+ }
70
+ scheduleMeasure() {
71
+ if (this.measureHandle) {
72
+ cancelAnimationFrame(this.measureHandle);
73
+ }
74
+ this.measureHandle = requestAnimationFrame(() => {
75
+ this.measureHandle = 0;
76
+ this.measureAndUpdate();
77
+ });
78
+ }
79
+ measureAndUpdate() {
80
+ const container = this.tabsContainer()?.nativeElement;
81
+ const measureRow = this.measureRow()?.nativeElement;
82
+ if (!container || !measureRow)
83
+ return;
84
+ const optionsCount = this.options().length;
85
+ if (optionsCount === 0) {
86
+ this.visibleCount.set(0);
87
+ return;
88
+ }
89
+ if (container.clientWidth === 0)
90
+ return;
91
+ // Inner width excludes the container's horizontal padding so we compare
92
+ // against the actual space available to the flex tabs row.
93
+ const style = getComputedStyle(container);
94
+ const paddingX = (parseFloat(style.paddingLeft) || 0) +
95
+ (parseFloat(style.paddingRight) || 0);
96
+ const innerWidth = container.clientWidth - paddingX;
97
+ if (innerWidth <= 0)
98
+ return;
99
+ const tabWidths = Array.from(measureRow.children).map((el) => el.getBoundingClientRect().width);
100
+ if (tabWidths.length === 0)
101
+ return;
102
+ // Approximate gap-0.5 between tabs (2px).
103
+ const gap = 2;
104
+ const totalWidth = tabWidths.reduce((sum, width) => sum + width, 0) +
105
+ Math.max(0, tabWidths.length - 1) * gap;
106
+ // Everything fits — no more button needed.
107
+ if (totalWidth <= innerWidth) {
108
+ this.visibleCount.set(tabWidths.length);
109
+ return;
110
+ }
111
+ // Reserve space for the More button (icon + label ~ 88px).
112
+ const moreButtonReserve = 96;
113
+ const available = innerWidth - moreButtonReserve;
114
+ let cumulative = 0;
115
+ let visibleCount = 0;
116
+ for (let i = 0; i < tabWidths.length; i++) {
117
+ const next = cumulative + tabWidths[i] + (i > 0 ? gap : 0);
118
+ if (next > available)
119
+ break;
120
+ cumulative = next;
121
+ visibleCount++;
122
+ }
123
+ this.visibleCount.set(Math.max(1, visibleCount));
31
124
  }
32
125
  onTabChange(value) {
33
126
  this.onChange.emit(value);
@@ -63,6 +156,14 @@ class Tabs {
63
156
  hasBadge(option) {
64
157
  return option?.badge !== null && option?.badge !== undefined;
65
158
  }
159
+ hasCountBadge(option) {
160
+ const badge = option?.badge;
161
+ if (badge === null || badge === undefined || badge === '') {
162
+ return false;
163
+ }
164
+ const numeric = typeof badge === 'number' ? badge : Number(badge);
165
+ return Number.isNaN(numeric) ? true : numeric > 0;
166
+ }
66
167
  isActiveOption(option) {
67
168
  return Object.is(this.active(), this.resolveValue(option));
68
169
  }
@@ -73,15 +174,15 @@ class Tabs {
73
174
  return this.resolveValue(option) ?? index;
74
175
  }
75
176
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: Tabs, deps: [], target: i0.ɵɵFactoryTarget.Component });
76
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: Tabs, isStandalone: true, selector: "mt-tabs", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: false, transformFunction: null }, optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: false, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, fluid: { classPropertyName: "fluid", publicName: "fluid", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { active: "activeChange", onChange: "onChange" }, host: { properties: { "class.w-full": "fluid()" }, classAttribute: "grid gap-1" }, ngImport: i0, template: "@if (mode() === \"vertical\") {\r\n <div\r\n class=\"flex min-h-0 flex-col gap-1 rounded-2xl border border-surface-200 bg-white p-2\"\r\n role=\"tablist\"\r\n aria-orientation=\"vertical\"\r\n >\r\n @for (option of options(); track trackOption(option, $index)) {\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"group relative flex w-full items-center gap-3 overflow-hidden rounded-lg px-3 py-2.5 text-left text-sm transition-colors duration-150 outline-none focus-visible:ring-2 focus-visible:ring-primary/20\"\r\n [attr.aria-selected]=\"isActiveOption(option)\"\r\n [attr.tabindex]=\"isActiveOption(option) ? 0 : -1\"\r\n [disabled]=\"disabled() || isOptionDisabled(option)\"\r\n [class.bg-primary-50]=\"isActiveOption(option)\"\r\n [class.font-semibold]=\"isActiveOption(option)\"\r\n [class.text-primary-700]=\"isActiveOption(option)\"\r\n [class.text-surface-500]=\"!isActiveOption(option)\"\r\n [class.hover:bg-surface-50]=\"!isActiveOption(option)\"\r\n [class.cursor-not-allowed]=\"disabled() || isOptionDisabled(option)\"\r\n [class.opacity-60]=\"disabled() || isOptionDisabled(option)\"\r\n (click)=\"onOptionSelect(option)\"\r\n >\r\n @if (resolveIcon(option); as icon) {\r\n <mt-icon\r\n [icon]=\"icon\"\r\n class=\"relative z-10 text-base\"\r\n [class.text-primary]=\"isActiveOption(option)\"\r\n [class.text-surface-400]=\"!isActiveOption(option)\"\r\n />\r\n }\r\n\r\n <span class=\"relative z-10 min-w-0 flex-1 truncate\">\r\n {{ resolveLabel(option) }}\r\n </span>\r\n\r\n @if (hasBadge(option)) {\r\n <span\r\n class=\"relative z-10 ms-auto inline-flex min-w-5 items-center justify-center rounded-full px-2 py-0.5 text-[11px] font-bold leading-none\"\r\n [class.bg-primary]=\"isActiveOption(option)\"\r\n [class.text-white]=\"isActiveOption(option)\"\r\n [class.bg-surface-100]=\"!isActiveOption(option)\"\r\n [class.text-surface-600]=\"!isActiveOption(option)\"\r\n >\r\n {{ resolveBadge(option) }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n} @else {\r\n <p-selectbutton\r\n [options]=\"options()\"\r\n [(ngModel)]=\"active\"\r\n (ngModelChange)=\"onTabChange($event)\"\r\n [optionLabel]=\"optionLabel()\"\r\n [optionValue]=\"optionValue()\"\r\n styleClass=\"my-tabs-button\"\r\n [size]=\"size()\"\r\n [fluid]=\"fluid()\"\r\n [disabled]=\"disabled()\"\r\n unselectable\r\n />\r\n}\r\n", styles: [":host{min-width:0}\n"], dependencies: [{ kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: SelectButton, selector: "p-selectButton, p-selectbutton, p-select-button", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "unselectable", "tabindex", "multiple", "allowEmpty", "styleClass", "ariaLabelledBy", "dataKey", "autofocus", "size", "fluid"], outputs: ["onOptionClick", "onChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
177
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: Tabs, isStandalone: true, selector: "mt-tabs", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: false, transformFunction: null }, optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: false, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, moreLabel: { classPropertyName: "moreLabel", publicName: "moreLabel", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, fluid: { classPropertyName: "fluid", publicName: "fluid", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { active: "activeChange", onChange: "onChange" }, host: { properties: { "class.w-full": "fluid()" }, classAttribute: "grid min-w-0 gap-1" }, viewQueries: [{ propertyName: "tabsContainer", first: true, predicate: ["tabsContainer"], descendants: true, isSignal: true }, { propertyName: "measureRow", first: true, predicate: ["measureRow"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (mode() === \"vertical\") {\r\n <div\r\n class=\"flex min-h-0 flex-col gap-1 rounded-2xl border border-surface-200 bg-white p-2\"\r\n role=\"tablist\"\r\n aria-orientation=\"vertical\"\r\n >\r\n @for (option of options(); track trackOption(option, $index)) {\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"group relative flex w-full items-center gap-3 overflow-hidden rounded-lg px-3 py-2.5 text-left text-sm transition-colors duration-150 outline-none focus-visible:ring-2 focus-visible:ring-primary/20\"\r\n [attr.aria-selected]=\"isActiveOption(option)\"\r\n [attr.tabindex]=\"isActiveOption(option) ? 0 : -1\"\r\n [disabled]=\"disabled() || isOptionDisabled(option)\"\r\n [class.bg-primary-50]=\"isActiveOption(option)\"\r\n [class.font-semibold]=\"isActiveOption(option)\"\r\n [class.text-primary-700]=\"isActiveOption(option)\"\r\n [class.text-surface-500]=\"!isActiveOption(option)\"\r\n [class.hover:bg-surface-50]=\"!isActiveOption(option)\"\r\n [class.cursor-not-allowed]=\"disabled() || isOptionDisabled(option)\"\r\n [class.opacity-60]=\"disabled() || isOptionDisabled(option)\"\r\n (click)=\"onOptionSelect(option)\"\r\n >\r\n @if (resolveIcon(option); as icon) {\r\n <mt-icon\r\n [icon]=\"icon\"\r\n class=\"relative z-10 text-base\"\r\n [class.text-primary]=\"isActiveOption(option)\"\r\n [class.text-surface-400]=\"!isActiveOption(option)\"\r\n />\r\n }\r\n\r\n <span class=\"relative z-10 min-w-0 flex-1 truncate\">\r\n {{ resolveLabel(option) }}\r\n </span>\r\n\r\n @if (hasBadge(option)) {\r\n <span\r\n class=\"relative z-10 ms-auto inline-flex min-w-5 items-center justify-center rounded-full px-2 py-0.5 text-[11px] font-bold leading-none\"\r\n [class.bg-primary]=\"isActiveOption(option)\"\r\n [class.text-white]=\"isActiveOption(option)\"\r\n [class.bg-surface-100]=\"!isActiveOption(option)\"\r\n [class.text-surface-600]=\"!isActiveOption(option)\"\r\n >\r\n {{ resolveBadge(option) }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n} @else if (mode() === \"underline\") {\r\n <div\r\n #tabsContainer\r\n class=\"relative flex w-full min-w-0 max-w-full items-center gap-0.5 overflow-hidden\"\r\n role=\"tablist\"\r\n aria-orientation=\"horizontal\"\r\n >\r\n <!-- Invisible measurement ghost row: always renders every option at natural width -->\r\n <div\r\n #measureRow\r\n aria-hidden=\"true\"\r\n class=\"pointer-events-none invisible absolute top-0 left-0 flex flex-nowrap gap-0.5 -z-10\"\r\n >\r\n @for (option of options(); track trackOption(option, $index)) {\r\n <span\r\n class=\"inline-flex items-center gap-1.5 border-b-2 border-transparent px-3.5 py-2.5 text-sm font-semibold whitespace-nowrap\"\r\n >\r\n @if (resolveIcon(option); as icon) {\r\n <mt-icon [icon]=\"icon\" class=\"text-base\" />\r\n }\r\n <span>{{ resolveLabel(option) }}</span>\r\n @if (hasCountBadge(option)) {\r\n <span\r\n class=\"inline-grid min-w-[18px] place-items-center rounded-full px-1.5 text-[10px] leading-4 font-bold tabular-nums\"\r\n >\r\n {{ resolveBadge(option) }}\r\n </span>\r\n }\r\n </span>\r\n }\r\n </div>\r\n\r\n <!-- Visible tabs row -->\r\n <div\r\n class=\"flex min-w-0 flex-1 items-center gap-0.5 overflow-hidden border-b border-surface-200\"\r\n >\r\n @for (option of visibleOptions(); track trackOption(option, $index)) {\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"-mb-px inline-flex shrink-0 items-center gap-1.5 border-b-2 px-3.5 py-2.5 text-sm whitespace-nowrap transition-colors duration-150 outline-none focus-visible:ring-2 focus-visible:ring-primary/20\"\r\n [attr.aria-selected]=\"isActiveOption(option)\"\r\n [attr.tabindex]=\"isActiveOption(option) ? 0 : -1\"\r\n [disabled]=\"disabled() || isOptionDisabled(option)\"\r\n [class.border-primary]=\"isActiveOption(option)\"\r\n [class.text-primary]=\"isActiveOption(option)\"\r\n [class.font-semibold]=\"isActiveOption(option)\"\r\n [class.border-transparent]=\"!isActiveOption(option)\"\r\n [class.text-surface-700]=\"!isActiveOption(option)\"\r\n [class.font-medium]=\"!isActiveOption(option)\"\r\n [class.hover:text-primary-600]=\"\r\n !isActiveOption(option) && !(disabled() || isOptionDisabled(option))\r\n \"\r\n [class.cursor-not-allowed]=\"disabled() || isOptionDisabled(option)\"\r\n [class.opacity-60]=\"disabled() || isOptionDisabled(option)\"\r\n (click)=\"onOptionSelect(option)\"\r\n >\r\n @if (resolveIcon(option); as icon) {\r\n <mt-icon [icon]=\"icon\" class=\"text-base\" />\r\n }\r\n\r\n <span class=\"truncate\">{{ resolveLabel(option) }}</span>\r\n\r\n @if (hasCountBadge(option)) {\r\n <span\r\n class=\"inline-grid min-w-[18px] place-items-center rounded-full px-1.5 text-[10px] leading-4 font-bold tabular-nums\"\r\n [class.bg-primary-50]=\"isActiveOption(option)\"\r\n [class.text-primary-700]=\"isActiveOption(option)\"\r\n [class.bg-surface-100]=\"!isActiveOption(option)\"\r\n [class.text-surface-500]=\"!isActiveOption(option)\"\r\n >\r\n {{ resolveBadge(option) }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n @if (hasOverflow()) {\r\n <div\r\n class=\"flex shrink-0 items-center -mb-px border-b border-surface-200 pb-1\"\r\n >\r\n <mt-button\r\n icon=\"arrow.chevron-down\"\r\n [label]=\"moreLabel()\"\r\n size=\"small\"\r\n severity=\"primary\"\r\n [text]=\"true\"\r\n [rounded]=\"true\"\r\n (onClick)=\"morePopover.toggle($event)\"\r\n />\r\n <p-popover #morePopover appendTo=\"body\">\r\n <div class=\"flex flex-col min-w-40\">\r\n @for (\r\n option of overflowOptions();\r\n track trackOption(option, $index)\r\n ) {\r\n <button\r\n type=\"button\"\r\n class=\"flex cursor-pointer items-center gap-2 rounded px-2 py-2 text-sm transition-colors\"\r\n [class.bg-primary-50]=\"isActiveOption(option)\"\r\n [class.text-primary]=\"isActiveOption(option)\"\r\n [class.font-semibold]=\"isActiveOption(option)\"\r\n [class.text-surface-700]=\"!isActiveOption(option)\"\r\n [class.hover:bg-surface-100]=\"!isActiveOption(option)\"\r\n [class.cursor-not-allowed]=\"\r\n disabled() || isOptionDisabled(option)\r\n \"\r\n [class.opacity-60]=\"disabled() || isOptionDisabled(option)\"\r\n [disabled]=\"disabled() || isOptionDisabled(option)\"\r\n (click)=\"onOptionSelect(option); morePopover.hide()\"\r\n >\r\n @if (resolveIcon(option); as icon) {\r\n <mt-icon [icon]=\"icon\" class=\"text-base\" />\r\n }\r\n <span class=\"flex-1 truncate\">{{ resolveLabel(option) }}</span>\r\n @if (hasCountBadge(option)) {\r\n <span\r\n class=\"inline-grid min-w-[18px] place-items-center rounded-full px-1.5 text-[10px] leading-4 font-bold tabular-nums\"\r\n [class.bg-primary-100]=\"isActiveOption(option)\"\r\n [class.text-primary-700]=\"isActiveOption(option)\"\r\n [class.bg-surface-100]=\"!isActiveOption(option)\"\r\n [class.text-surface-500]=\"!isActiveOption(option)\"\r\n >\r\n {{ resolveBadge(option) }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n </p-popover>\r\n </div>\r\n }\r\n </div>\r\n} @else {\r\n <p-selectbutton\r\n [options]=\"options()\"\r\n [(ngModel)]=\"active\"\r\n (ngModelChange)=\"onTabChange($event)\"\r\n [optionLabel]=\"optionLabel()\"\r\n [optionValue]=\"optionValue()\"\r\n styleClass=\"my-tabs-button\"\r\n [size]=\"size()\"\r\n [fluid]=\"fluid()\"\r\n [disabled]=\"disabled()\"\r\n unselectable\r\n />\r\n}\r\n", styles: [":host{min-width:0}\n"], dependencies: [{ kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: SelectButton, selector: "p-selectButton, p-selectbutton, p-select-button", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "unselectable", "tabindex", "multiple", "allowEmpty", "styleClass", "ariaLabelledBy", "dataKey", "autofocus", "size", "fluid"], outputs: ["onOptionClick", "onChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }] });
77
178
  }
78
179
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: Tabs, decorators: [{
79
180
  type: Component,
80
- args: [{ selector: 'mt-tabs', standalone: true, imports: [Icon, SelectButton, FormsModule], host: {
81
- class: 'grid gap-1',
181
+ args: [{ selector: 'mt-tabs', standalone: true, imports: [Icon, SelectButton, FormsModule, Button, Popover], host: {
182
+ class: 'grid min-w-0 gap-1',
82
183
  '[class.w-full]': 'fluid()',
83
- }, template: "@if (mode() === \"vertical\") {\r\n <div\r\n class=\"flex min-h-0 flex-col gap-1 rounded-2xl border border-surface-200 bg-white p-2\"\r\n role=\"tablist\"\r\n aria-orientation=\"vertical\"\r\n >\r\n @for (option of options(); track trackOption(option, $index)) {\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"group relative flex w-full items-center gap-3 overflow-hidden rounded-lg px-3 py-2.5 text-left text-sm transition-colors duration-150 outline-none focus-visible:ring-2 focus-visible:ring-primary/20\"\r\n [attr.aria-selected]=\"isActiveOption(option)\"\r\n [attr.tabindex]=\"isActiveOption(option) ? 0 : -1\"\r\n [disabled]=\"disabled() || isOptionDisabled(option)\"\r\n [class.bg-primary-50]=\"isActiveOption(option)\"\r\n [class.font-semibold]=\"isActiveOption(option)\"\r\n [class.text-primary-700]=\"isActiveOption(option)\"\r\n [class.text-surface-500]=\"!isActiveOption(option)\"\r\n [class.hover:bg-surface-50]=\"!isActiveOption(option)\"\r\n [class.cursor-not-allowed]=\"disabled() || isOptionDisabled(option)\"\r\n [class.opacity-60]=\"disabled() || isOptionDisabled(option)\"\r\n (click)=\"onOptionSelect(option)\"\r\n >\r\n @if (resolveIcon(option); as icon) {\r\n <mt-icon\r\n [icon]=\"icon\"\r\n class=\"relative z-10 text-base\"\r\n [class.text-primary]=\"isActiveOption(option)\"\r\n [class.text-surface-400]=\"!isActiveOption(option)\"\r\n />\r\n }\r\n\r\n <span class=\"relative z-10 min-w-0 flex-1 truncate\">\r\n {{ resolveLabel(option) }}\r\n </span>\r\n\r\n @if (hasBadge(option)) {\r\n <span\r\n class=\"relative z-10 ms-auto inline-flex min-w-5 items-center justify-center rounded-full px-2 py-0.5 text-[11px] font-bold leading-none\"\r\n [class.bg-primary]=\"isActiveOption(option)\"\r\n [class.text-white]=\"isActiveOption(option)\"\r\n [class.bg-surface-100]=\"!isActiveOption(option)\"\r\n [class.text-surface-600]=\"!isActiveOption(option)\"\r\n >\r\n {{ resolveBadge(option) }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n} @else {\r\n <p-selectbutton\r\n [options]=\"options()\"\r\n [(ngModel)]=\"active\"\r\n (ngModelChange)=\"onTabChange($event)\"\r\n [optionLabel]=\"optionLabel()\"\r\n [optionValue]=\"optionValue()\"\r\n styleClass=\"my-tabs-button\"\r\n [size]=\"size()\"\r\n [fluid]=\"fluid()\"\r\n [disabled]=\"disabled()\"\r\n unselectable\r\n />\r\n}\r\n", styles: [":host{min-width:0}\n"] }]
84
- }], ctorParameters: () => [], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: false }] }], optionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionValue", required: false }] }], active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }, { type: i0.Output, args: ["activeChange"] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], onChange: [{ type: i0.Output, args: ["onChange"] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], fluid: [{ type: i0.Input, args: [{ isSignal: true, alias: "fluid", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
184
+ }, template: "@if (mode() === \"vertical\") {\r\n <div\r\n class=\"flex min-h-0 flex-col gap-1 rounded-2xl border border-surface-200 bg-white p-2\"\r\n role=\"tablist\"\r\n aria-orientation=\"vertical\"\r\n >\r\n @for (option of options(); track trackOption(option, $index)) {\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"group relative flex w-full items-center gap-3 overflow-hidden rounded-lg px-3 py-2.5 text-left text-sm transition-colors duration-150 outline-none focus-visible:ring-2 focus-visible:ring-primary/20\"\r\n [attr.aria-selected]=\"isActiveOption(option)\"\r\n [attr.tabindex]=\"isActiveOption(option) ? 0 : -1\"\r\n [disabled]=\"disabled() || isOptionDisabled(option)\"\r\n [class.bg-primary-50]=\"isActiveOption(option)\"\r\n [class.font-semibold]=\"isActiveOption(option)\"\r\n [class.text-primary-700]=\"isActiveOption(option)\"\r\n [class.text-surface-500]=\"!isActiveOption(option)\"\r\n [class.hover:bg-surface-50]=\"!isActiveOption(option)\"\r\n [class.cursor-not-allowed]=\"disabled() || isOptionDisabled(option)\"\r\n [class.opacity-60]=\"disabled() || isOptionDisabled(option)\"\r\n (click)=\"onOptionSelect(option)\"\r\n >\r\n @if (resolveIcon(option); as icon) {\r\n <mt-icon\r\n [icon]=\"icon\"\r\n class=\"relative z-10 text-base\"\r\n [class.text-primary]=\"isActiveOption(option)\"\r\n [class.text-surface-400]=\"!isActiveOption(option)\"\r\n />\r\n }\r\n\r\n <span class=\"relative z-10 min-w-0 flex-1 truncate\">\r\n {{ resolveLabel(option) }}\r\n </span>\r\n\r\n @if (hasBadge(option)) {\r\n <span\r\n class=\"relative z-10 ms-auto inline-flex min-w-5 items-center justify-center rounded-full px-2 py-0.5 text-[11px] font-bold leading-none\"\r\n [class.bg-primary]=\"isActiveOption(option)\"\r\n [class.text-white]=\"isActiveOption(option)\"\r\n [class.bg-surface-100]=\"!isActiveOption(option)\"\r\n [class.text-surface-600]=\"!isActiveOption(option)\"\r\n >\r\n {{ resolveBadge(option) }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n} @else if (mode() === \"underline\") {\r\n <div\r\n #tabsContainer\r\n class=\"relative flex w-full min-w-0 max-w-full items-center gap-0.5 overflow-hidden\"\r\n role=\"tablist\"\r\n aria-orientation=\"horizontal\"\r\n >\r\n <!-- Invisible measurement ghost row: always renders every option at natural width -->\r\n <div\r\n #measureRow\r\n aria-hidden=\"true\"\r\n class=\"pointer-events-none invisible absolute top-0 left-0 flex flex-nowrap gap-0.5 -z-10\"\r\n >\r\n @for (option of options(); track trackOption(option, $index)) {\r\n <span\r\n class=\"inline-flex items-center gap-1.5 border-b-2 border-transparent px-3.5 py-2.5 text-sm font-semibold whitespace-nowrap\"\r\n >\r\n @if (resolveIcon(option); as icon) {\r\n <mt-icon [icon]=\"icon\" class=\"text-base\" />\r\n }\r\n <span>{{ resolveLabel(option) }}</span>\r\n @if (hasCountBadge(option)) {\r\n <span\r\n class=\"inline-grid min-w-[18px] place-items-center rounded-full px-1.5 text-[10px] leading-4 font-bold tabular-nums\"\r\n >\r\n {{ resolveBadge(option) }}\r\n </span>\r\n }\r\n </span>\r\n }\r\n </div>\r\n\r\n <!-- Visible tabs row -->\r\n <div\r\n class=\"flex min-w-0 flex-1 items-center gap-0.5 overflow-hidden border-b border-surface-200\"\r\n >\r\n @for (option of visibleOptions(); track trackOption(option, $index)) {\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"-mb-px inline-flex shrink-0 items-center gap-1.5 border-b-2 px-3.5 py-2.5 text-sm whitespace-nowrap transition-colors duration-150 outline-none focus-visible:ring-2 focus-visible:ring-primary/20\"\r\n [attr.aria-selected]=\"isActiveOption(option)\"\r\n [attr.tabindex]=\"isActiveOption(option) ? 0 : -1\"\r\n [disabled]=\"disabled() || isOptionDisabled(option)\"\r\n [class.border-primary]=\"isActiveOption(option)\"\r\n [class.text-primary]=\"isActiveOption(option)\"\r\n [class.font-semibold]=\"isActiveOption(option)\"\r\n [class.border-transparent]=\"!isActiveOption(option)\"\r\n [class.text-surface-700]=\"!isActiveOption(option)\"\r\n [class.font-medium]=\"!isActiveOption(option)\"\r\n [class.hover:text-primary-600]=\"\r\n !isActiveOption(option) && !(disabled() || isOptionDisabled(option))\r\n \"\r\n [class.cursor-not-allowed]=\"disabled() || isOptionDisabled(option)\"\r\n [class.opacity-60]=\"disabled() || isOptionDisabled(option)\"\r\n (click)=\"onOptionSelect(option)\"\r\n >\r\n @if (resolveIcon(option); as icon) {\r\n <mt-icon [icon]=\"icon\" class=\"text-base\" />\r\n }\r\n\r\n <span class=\"truncate\">{{ resolveLabel(option) }}</span>\r\n\r\n @if (hasCountBadge(option)) {\r\n <span\r\n class=\"inline-grid min-w-[18px] place-items-center rounded-full px-1.5 text-[10px] leading-4 font-bold tabular-nums\"\r\n [class.bg-primary-50]=\"isActiveOption(option)\"\r\n [class.text-primary-700]=\"isActiveOption(option)\"\r\n [class.bg-surface-100]=\"!isActiveOption(option)\"\r\n [class.text-surface-500]=\"!isActiveOption(option)\"\r\n >\r\n {{ resolveBadge(option) }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n @if (hasOverflow()) {\r\n <div\r\n class=\"flex shrink-0 items-center -mb-px border-b border-surface-200 pb-1\"\r\n >\r\n <mt-button\r\n icon=\"arrow.chevron-down\"\r\n [label]=\"moreLabel()\"\r\n size=\"small\"\r\n severity=\"primary\"\r\n [text]=\"true\"\r\n [rounded]=\"true\"\r\n (onClick)=\"morePopover.toggle($event)\"\r\n />\r\n <p-popover #morePopover appendTo=\"body\">\r\n <div class=\"flex flex-col min-w-40\">\r\n @for (\r\n option of overflowOptions();\r\n track trackOption(option, $index)\r\n ) {\r\n <button\r\n type=\"button\"\r\n class=\"flex cursor-pointer items-center gap-2 rounded px-2 py-2 text-sm transition-colors\"\r\n [class.bg-primary-50]=\"isActiveOption(option)\"\r\n [class.text-primary]=\"isActiveOption(option)\"\r\n [class.font-semibold]=\"isActiveOption(option)\"\r\n [class.text-surface-700]=\"!isActiveOption(option)\"\r\n [class.hover:bg-surface-100]=\"!isActiveOption(option)\"\r\n [class.cursor-not-allowed]=\"\r\n disabled() || isOptionDisabled(option)\r\n \"\r\n [class.opacity-60]=\"disabled() || isOptionDisabled(option)\"\r\n [disabled]=\"disabled() || isOptionDisabled(option)\"\r\n (click)=\"onOptionSelect(option); morePopover.hide()\"\r\n >\r\n @if (resolveIcon(option); as icon) {\r\n <mt-icon [icon]=\"icon\" class=\"text-base\" />\r\n }\r\n <span class=\"flex-1 truncate\">{{ resolveLabel(option) }}</span>\r\n @if (hasCountBadge(option)) {\r\n <span\r\n class=\"inline-grid min-w-[18px] place-items-center rounded-full px-1.5 text-[10px] leading-4 font-bold tabular-nums\"\r\n [class.bg-primary-100]=\"isActiveOption(option)\"\r\n [class.text-primary-700]=\"isActiveOption(option)\"\r\n [class.bg-surface-100]=\"!isActiveOption(option)\"\r\n [class.text-surface-500]=\"!isActiveOption(option)\"\r\n >\r\n {{ resolveBadge(option) }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n </p-popover>\r\n </div>\r\n }\r\n </div>\r\n} @else {\r\n <p-selectbutton\r\n [options]=\"options()\"\r\n [(ngModel)]=\"active\"\r\n (ngModelChange)=\"onTabChange($event)\"\r\n [optionLabel]=\"optionLabel()\"\r\n [optionValue]=\"optionValue()\"\r\n styleClass=\"my-tabs-button\"\r\n [size]=\"size()\"\r\n [fluid]=\"fluid()\"\r\n [disabled]=\"disabled()\"\r\n unselectable\r\n />\r\n}\r\n", styles: [":host{min-width:0}\n"] }]
185
+ }], ctorParameters: () => [], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: false }] }], optionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionValue", required: false }] }], active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }, { type: i0.Output, args: ["activeChange"] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], moreLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "moreLabel", required: false }] }], onChange: [{ type: i0.Output, args: ["onChange"] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], fluid: [{ type: i0.Input, args: [{ isSignal: true, alias: "fluid", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], tabsContainer: [{ type: i0.ViewChild, args: ['tabsContainer', { isSignal: true }] }], measureRow: [{ type: i0.ViewChild, args: ['measureRow', { isSignal: true }] }] } });
85
186
 
86
187
  /**
87
188
  * Generated bundle index. Do not edit.
@@ -1 +1 @@
1
- {"version":3,"file":"masterteam-components-tabs.mjs","sources":["../../../../packages/masterteam/components/tabs/tabs.ts","../../../../packages/masterteam/components/tabs/tabs.html","../../../../packages/masterteam/components/tabs/masterteam-components-tabs.ts"],"sourcesContent":["import {\r\n booleanAttribute,\r\n Component,\r\n effect,\r\n input,\r\n model,\r\n output,\r\n} from '@angular/core';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { MTIcon, Icon } from '@masterteam/icons';\r\nimport { SelectButton } from 'primeng/selectbutton';\r\n\r\nexport interface OptionItem {\r\n label?: string;\r\n value?: any;\r\n icon?: MTIcon | null;\r\n badge?: number | string | null;\r\n disabled?: boolean;\r\n [key: string]: unknown;\r\n}\r\n\r\n@Component({\r\n selector: 'mt-tabs',\r\n standalone: true,\r\n imports: [Icon, SelectButton, FormsModule],\r\n templateUrl: './tabs.html',\r\n styleUrls: ['./tabs.scss'],\r\n host: {\r\n class: 'grid gap-1',\r\n '[class.w-full]': 'fluid()',\r\n },\r\n})\r\nexport class Tabs {\r\n options = input<OptionItem[]>([]);\r\n optionLabel = input<string>('label');\r\n optionValue = input<string>('value');\r\n active = model<any>(null);\r\n readonly mode = input<'horizontal' | 'vertical'>('horizontal');\r\n\r\n onChange = output<any>();\r\n\r\n readonly size = input<'small' | 'large' | undefined>();\r\n readonly fluid = input<boolean, unknown>(false, {\r\n transform: booleanAttribute,\r\n });\r\n disabled = input<boolean, unknown>(false, {\r\n transform: booleanAttribute,\r\n });\r\n\r\n // TODO: make a decision about this maybe we should remove it\r\n constructor() {\r\n effect(() => {\r\n const options = this.options();\r\n const active = this.active();\r\n if (!options.length) {\r\n return;\r\n }\r\n\r\n const hasActiveOption = options.some((option) =>\r\n Object.is(this.resolveValue(option), active),\r\n );\r\n if (!hasActiveOption) {\r\n this.active.set(this.resolveValue(options[0]));\r\n }\r\n });\r\n }\r\n\r\n onTabChange(value: any) {\r\n this.onChange.emit(value);\r\n }\r\n\r\n onOptionSelect(option: OptionItem): void {\r\n if (this.disabled() || this.isOptionDisabled(option)) {\r\n return;\r\n }\r\n\r\n const value = this.resolveValue(option);\r\n this.active.set(value);\r\n this.onTabChange(value);\r\n }\r\n\r\n resolveLabel(option: OptionItem): string {\r\n const labelKey = this.optionLabel();\r\n const label =\r\n option && typeof option === 'object'\r\n ? (option as Record<string, unknown>)[labelKey]\r\n : option;\r\n\r\n return typeof label === 'string' ? label : String(label ?? '');\r\n }\r\n\r\n resolveValue(option: OptionItem): unknown {\r\n const valueKey = this.optionValue();\r\n if (option && typeof option === 'object' && valueKey in option) {\r\n return (option as Record<string, unknown>)[valueKey];\r\n }\r\n\r\n return option;\r\n }\r\n\r\n resolveIcon(option: OptionItem): MTIcon | null {\r\n return typeof option?.icon === 'string' ? option.icon : null;\r\n }\r\n\r\n resolveBadge(option: OptionItem): number | string | null {\r\n return option?.badge ?? null;\r\n }\r\n\r\n hasBadge(option: OptionItem): boolean {\r\n return option?.badge !== null && option?.badge !== undefined;\r\n }\r\n\r\n isActiveOption(option: OptionItem): boolean {\r\n return Object.is(this.active(), this.resolveValue(option));\r\n }\r\n\r\n isOptionDisabled(option: OptionItem): boolean {\r\n return !!option?.disabled;\r\n }\r\n\r\n trackOption(option: OptionItem, index: number): unknown {\r\n return this.resolveValue(option) ?? index;\r\n }\r\n}\r\n","@if (mode() === \"vertical\") {\r\n <div\r\n class=\"flex min-h-0 flex-col gap-1 rounded-2xl border border-surface-200 bg-white p-2\"\r\n role=\"tablist\"\r\n aria-orientation=\"vertical\"\r\n >\r\n @for (option of options(); track trackOption(option, $index)) {\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"group relative flex w-full items-center gap-3 overflow-hidden rounded-lg px-3 py-2.5 text-left text-sm transition-colors duration-150 outline-none focus-visible:ring-2 focus-visible:ring-primary/20\"\r\n [attr.aria-selected]=\"isActiveOption(option)\"\r\n [attr.tabindex]=\"isActiveOption(option) ? 0 : -1\"\r\n [disabled]=\"disabled() || isOptionDisabled(option)\"\r\n [class.bg-primary-50]=\"isActiveOption(option)\"\r\n [class.font-semibold]=\"isActiveOption(option)\"\r\n [class.text-primary-700]=\"isActiveOption(option)\"\r\n [class.text-surface-500]=\"!isActiveOption(option)\"\r\n [class.hover:bg-surface-50]=\"!isActiveOption(option)\"\r\n [class.cursor-not-allowed]=\"disabled() || isOptionDisabled(option)\"\r\n [class.opacity-60]=\"disabled() || isOptionDisabled(option)\"\r\n (click)=\"onOptionSelect(option)\"\r\n >\r\n @if (resolveIcon(option); as icon) {\r\n <mt-icon\r\n [icon]=\"icon\"\r\n class=\"relative z-10 text-base\"\r\n [class.text-primary]=\"isActiveOption(option)\"\r\n [class.text-surface-400]=\"!isActiveOption(option)\"\r\n />\r\n }\r\n\r\n <span class=\"relative z-10 min-w-0 flex-1 truncate\">\r\n {{ resolveLabel(option) }}\r\n </span>\r\n\r\n @if (hasBadge(option)) {\r\n <span\r\n class=\"relative z-10 ms-auto inline-flex min-w-5 items-center justify-center rounded-full px-2 py-0.5 text-[11px] font-bold leading-none\"\r\n [class.bg-primary]=\"isActiveOption(option)\"\r\n [class.text-white]=\"isActiveOption(option)\"\r\n [class.bg-surface-100]=\"!isActiveOption(option)\"\r\n [class.text-surface-600]=\"!isActiveOption(option)\"\r\n >\r\n {{ resolveBadge(option) }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n} @else {\r\n <p-selectbutton\r\n [options]=\"options()\"\r\n [(ngModel)]=\"active\"\r\n (ngModelChange)=\"onTabChange($event)\"\r\n [optionLabel]=\"optionLabel()\"\r\n [optionValue]=\"optionValue()\"\r\n styleClass=\"my-tabs-button\"\r\n [size]=\"size()\"\r\n [fluid]=\"fluid()\"\r\n [disabled]=\"disabled()\"\r\n unselectable\r\n />\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"masterteam-components-tabs.mjs","sources":["../../../../packages/masterteam/components/tabs/tabs.ts","../../../../packages/masterteam/components/tabs/tabs.html","../../../../packages/masterteam/components/tabs/masterteam-components-tabs.ts"],"sourcesContent":["import {\r\n afterNextRender,\r\n booleanAttribute,\r\n Component,\r\n computed,\r\n DestroyRef,\r\n effect,\r\n ElementRef,\r\n inject,\r\n input,\r\n model,\r\n output,\r\n signal,\r\n viewChild,\r\n} from '@angular/core';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { MTIcon, Icon } from '@masterteam/icons';\r\nimport { SelectButton } from 'primeng/selectbutton';\r\nimport { Popover } from 'primeng/popover';\r\nimport { Button } from '@masterteam/components/button';\r\n\r\nexport interface OptionItem {\r\n label?: string;\r\n value?: any;\r\n icon?: MTIcon | null;\r\n badge?: number | string | null;\r\n disabled?: boolean;\r\n [key: string]: unknown;\r\n}\r\n\r\n@Component({\r\n selector: 'mt-tabs',\r\n standalone: true,\r\n imports: [Icon, SelectButton, FormsModule, Button, Popover],\r\n templateUrl: './tabs.html',\r\n styleUrls: ['./tabs.scss'],\r\n host: {\r\n class: 'grid min-w-0 gap-1',\r\n '[class.w-full]': 'fluid()',\r\n },\r\n})\r\nexport class Tabs {\r\n options = input<OptionItem[]>([]);\r\n optionLabel = input<string>('label');\r\n optionValue = input<string>('value');\r\n active = model<any>(null);\r\n readonly mode = input<'horizontal' | 'vertical' | 'underline'>('horizontal');\r\n readonly moreLabel = input<string>('More');\r\n\r\n onChange = output<any>();\r\n\r\n readonly size = input<'small' | 'large' | undefined>();\r\n readonly fluid = input<boolean, unknown>(false, {\r\n transform: booleanAttribute,\r\n });\r\n disabled = input<boolean, unknown>(false, {\r\n transform: booleanAttribute,\r\n });\r\n\r\n private readonly destroyRef = inject(DestroyRef);\r\n private readonly tabsContainer =\r\n viewChild<ElementRef<HTMLElement>>('tabsContainer');\r\n private readonly measureRow =\r\n viewChild<ElementRef<HTMLElement>>('measureRow');\r\n private resizeObserver?: ResizeObserver;\r\n private measureHandle = 0;\r\n\r\n readonly visibleCount = signal<number>(Number.MAX_SAFE_INTEGER);\r\n readonly visibleOptions = computed(() =>\r\n this.options().slice(0, this.visibleCount()),\r\n );\r\n readonly overflowOptions = computed(() =>\r\n this.options().slice(this.visibleCount()),\r\n );\r\n readonly hasOverflow = computed(() => this.overflowOptions().length > 0);\r\n readonly isActiveInOverflow = computed(() =>\r\n this.overflowOptions().some((option) => this.isActiveOption(option)),\r\n );\r\n\r\n constructor() {\r\n effect(() => {\r\n const options = this.options();\r\n const active = this.active();\r\n if (!options.length) {\r\n return;\r\n }\r\n\r\n const hasActiveOption = options.some((option) =>\r\n Object.is(this.resolveValue(option), active),\r\n );\r\n if (!hasActiveOption) {\r\n this.active.set(this.resolveValue(options[0]));\r\n }\r\n });\r\n\r\n afterNextRender(() => {\r\n if (this.mode() !== 'underline') return;\r\n this.setupResizeObserver();\r\n this.scheduleMeasure();\r\n });\r\n\r\n effect(() => {\r\n // Re-measure when options or mode change.\r\n this.options();\r\n if (this.mode() !== 'underline') return;\r\n this.scheduleMeasure();\r\n });\r\n\r\n this.destroyRef.onDestroy(() => {\r\n this.resizeObserver?.disconnect();\r\n if (this.measureHandle) {\r\n cancelAnimationFrame(this.measureHandle);\r\n }\r\n });\r\n }\r\n\r\n private setupResizeObserver(): void {\r\n const container = this.tabsContainer()?.nativeElement;\r\n if (!container || typeof ResizeObserver === 'undefined') return;\r\n\r\n this.resizeObserver = new ResizeObserver(() => this.scheduleMeasure());\r\n this.resizeObserver.observe(container);\r\n }\r\n\r\n private scheduleMeasure(): void {\r\n if (this.measureHandle) {\r\n cancelAnimationFrame(this.measureHandle);\r\n }\r\n this.measureHandle = requestAnimationFrame(() => {\r\n this.measureHandle = 0;\r\n this.measureAndUpdate();\r\n });\r\n }\r\n\r\n private measureAndUpdate(): void {\r\n const container = this.tabsContainer()?.nativeElement;\r\n const measureRow = this.measureRow()?.nativeElement;\r\n if (!container || !measureRow) return;\r\n\r\n const optionsCount = this.options().length;\r\n if (optionsCount === 0) {\r\n this.visibleCount.set(0);\r\n return;\r\n }\r\n\r\n if (container.clientWidth === 0) return;\r\n\r\n // Inner width excludes the container's horizontal padding so we compare\r\n // against the actual space available to the flex tabs row.\r\n const style = getComputedStyle(container);\r\n const paddingX =\r\n (parseFloat(style.paddingLeft) || 0) +\r\n (parseFloat(style.paddingRight) || 0);\r\n const innerWidth = container.clientWidth - paddingX;\r\n if (innerWidth <= 0) return;\r\n\r\n const tabWidths = Array.from(measureRow.children).map(\r\n (el) => (el as HTMLElement).getBoundingClientRect().width,\r\n );\r\n\r\n if (tabWidths.length === 0) return;\r\n\r\n // Approximate gap-0.5 between tabs (2px).\r\n const gap = 2;\r\n const totalWidth =\r\n tabWidths.reduce((sum, width) => sum + width, 0) +\r\n Math.max(0, tabWidths.length - 1) * gap;\r\n\r\n // Everything fits — no more button needed.\r\n if (totalWidth <= innerWidth) {\r\n this.visibleCount.set(tabWidths.length);\r\n return;\r\n }\r\n\r\n // Reserve space for the More button (icon + label ~ 88px).\r\n const moreButtonReserve = 96;\r\n const available = innerWidth - moreButtonReserve;\r\n\r\n let cumulative = 0;\r\n let visibleCount = 0;\r\n for (let i = 0; i < tabWidths.length; i++) {\r\n const next = cumulative + tabWidths[i] + (i > 0 ? gap : 0);\r\n if (next > available) break;\r\n cumulative = next;\r\n visibleCount++;\r\n }\r\n\r\n this.visibleCount.set(Math.max(1, visibleCount));\r\n }\r\n\r\n onTabChange(value: any) {\r\n this.onChange.emit(value);\r\n }\r\n\r\n onOptionSelect(option: OptionItem): void {\r\n if (this.disabled() || this.isOptionDisabled(option)) {\r\n return;\r\n }\r\n\r\n const value = this.resolveValue(option);\r\n this.active.set(value);\r\n this.onTabChange(value);\r\n }\r\n\r\n resolveLabel(option: OptionItem): string {\r\n const labelKey = this.optionLabel();\r\n const label =\r\n option && typeof option === 'object'\r\n ? (option as Record<string, unknown>)[labelKey]\r\n : option;\r\n\r\n return typeof label === 'string' ? label : String(label ?? '');\r\n }\r\n\r\n resolveValue(option: OptionItem): unknown {\r\n const valueKey = this.optionValue();\r\n if (option && typeof option === 'object' && valueKey in option) {\r\n return (option as Record<string, unknown>)[valueKey];\r\n }\r\n\r\n return option;\r\n }\r\n\r\n resolveIcon(option: OptionItem): MTIcon | null {\r\n return typeof option?.icon === 'string' ? option.icon : null;\r\n }\r\n\r\n resolveBadge(option: OptionItem): number | string | null {\r\n return option?.badge ?? null;\r\n }\r\n\r\n hasBadge(option: OptionItem): boolean {\r\n return option?.badge !== null && option?.badge !== undefined;\r\n }\r\n\r\n hasCountBadge(option: OptionItem): boolean {\r\n const badge = option?.badge;\r\n if (badge === null || badge === undefined || badge === '') {\r\n return false;\r\n }\r\n const numeric = typeof badge === 'number' ? badge : Number(badge);\r\n return Number.isNaN(numeric) ? true : numeric > 0;\r\n }\r\n\r\n isActiveOption(option: OptionItem): boolean {\r\n return Object.is(this.active(), this.resolveValue(option));\r\n }\r\n\r\n isOptionDisabled(option: OptionItem): boolean {\r\n return !!option?.disabled;\r\n }\r\n\r\n trackOption(option: OptionItem, index: number): unknown {\r\n return this.resolveValue(option) ?? index;\r\n }\r\n}\r\n","@if (mode() === \"vertical\") {\r\n <div\r\n class=\"flex min-h-0 flex-col gap-1 rounded-2xl border border-surface-200 bg-white p-2\"\r\n role=\"tablist\"\r\n aria-orientation=\"vertical\"\r\n >\r\n @for (option of options(); track trackOption(option, $index)) {\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"group relative flex w-full items-center gap-3 overflow-hidden rounded-lg px-3 py-2.5 text-left text-sm transition-colors duration-150 outline-none focus-visible:ring-2 focus-visible:ring-primary/20\"\r\n [attr.aria-selected]=\"isActiveOption(option)\"\r\n [attr.tabindex]=\"isActiveOption(option) ? 0 : -1\"\r\n [disabled]=\"disabled() || isOptionDisabled(option)\"\r\n [class.bg-primary-50]=\"isActiveOption(option)\"\r\n [class.font-semibold]=\"isActiveOption(option)\"\r\n [class.text-primary-700]=\"isActiveOption(option)\"\r\n [class.text-surface-500]=\"!isActiveOption(option)\"\r\n [class.hover:bg-surface-50]=\"!isActiveOption(option)\"\r\n [class.cursor-not-allowed]=\"disabled() || isOptionDisabled(option)\"\r\n [class.opacity-60]=\"disabled() || isOptionDisabled(option)\"\r\n (click)=\"onOptionSelect(option)\"\r\n >\r\n @if (resolveIcon(option); as icon) {\r\n <mt-icon\r\n [icon]=\"icon\"\r\n class=\"relative z-10 text-base\"\r\n [class.text-primary]=\"isActiveOption(option)\"\r\n [class.text-surface-400]=\"!isActiveOption(option)\"\r\n />\r\n }\r\n\r\n <span class=\"relative z-10 min-w-0 flex-1 truncate\">\r\n {{ resolveLabel(option) }}\r\n </span>\r\n\r\n @if (hasBadge(option)) {\r\n <span\r\n class=\"relative z-10 ms-auto inline-flex min-w-5 items-center justify-center rounded-full px-2 py-0.5 text-[11px] font-bold leading-none\"\r\n [class.bg-primary]=\"isActiveOption(option)\"\r\n [class.text-white]=\"isActiveOption(option)\"\r\n [class.bg-surface-100]=\"!isActiveOption(option)\"\r\n [class.text-surface-600]=\"!isActiveOption(option)\"\r\n >\r\n {{ resolveBadge(option) }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n} @else if (mode() === \"underline\") {\r\n <div\r\n #tabsContainer\r\n class=\"relative flex w-full min-w-0 max-w-full items-center gap-0.5 overflow-hidden\"\r\n role=\"tablist\"\r\n aria-orientation=\"horizontal\"\r\n >\r\n <!-- Invisible measurement ghost row: always renders every option at natural width -->\r\n <div\r\n #measureRow\r\n aria-hidden=\"true\"\r\n class=\"pointer-events-none invisible absolute top-0 left-0 flex flex-nowrap gap-0.5 -z-10\"\r\n >\r\n @for (option of options(); track trackOption(option, $index)) {\r\n <span\r\n class=\"inline-flex items-center gap-1.5 border-b-2 border-transparent px-3.5 py-2.5 text-sm font-semibold whitespace-nowrap\"\r\n >\r\n @if (resolveIcon(option); as icon) {\r\n <mt-icon [icon]=\"icon\" class=\"text-base\" />\r\n }\r\n <span>{{ resolveLabel(option) }}</span>\r\n @if (hasCountBadge(option)) {\r\n <span\r\n class=\"inline-grid min-w-[18px] place-items-center rounded-full px-1.5 text-[10px] leading-4 font-bold tabular-nums\"\r\n >\r\n {{ resolveBadge(option) }}\r\n </span>\r\n }\r\n </span>\r\n }\r\n </div>\r\n\r\n <!-- Visible tabs row -->\r\n <div\r\n class=\"flex min-w-0 flex-1 items-center gap-0.5 overflow-hidden border-b border-surface-200\"\r\n >\r\n @for (option of visibleOptions(); track trackOption(option, $index)) {\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"-mb-px inline-flex shrink-0 items-center gap-1.5 border-b-2 px-3.5 py-2.5 text-sm whitespace-nowrap transition-colors duration-150 outline-none focus-visible:ring-2 focus-visible:ring-primary/20\"\r\n [attr.aria-selected]=\"isActiveOption(option)\"\r\n [attr.tabindex]=\"isActiveOption(option) ? 0 : -1\"\r\n [disabled]=\"disabled() || isOptionDisabled(option)\"\r\n [class.border-primary]=\"isActiveOption(option)\"\r\n [class.text-primary]=\"isActiveOption(option)\"\r\n [class.font-semibold]=\"isActiveOption(option)\"\r\n [class.border-transparent]=\"!isActiveOption(option)\"\r\n [class.text-surface-700]=\"!isActiveOption(option)\"\r\n [class.font-medium]=\"!isActiveOption(option)\"\r\n [class.hover:text-primary-600]=\"\r\n !isActiveOption(option) && !(disabled() || isOptionDisabled(option))\r\n \"\r\n [class.cursor-not-allowed]=\"disabled() || isOptionDisabled(option)\"\r\n [class.opacity-60]=\"disabled() || isOptionDisabled(option)\"\r\n (click)=\"onOptionSelect(option)\"\r\n >\r\n @if (resolveIcon(option); as icon) {\r\n <mt-icon [icon]=\"icon\" class=\"text-base\" />\r\n }\r\n\r\n <span class=\"truncate\">{{ resolveLabel(option) }}</span>\r\n\r\n @if (hasCountBadge(option)) {\r\n <span\r\n class=\"inline-grid min-w-[18px] place-items-center rounded-full px-1.5 text-[10px] leading-4 font-bold tabular-nums\"\r\n [class.bg-primary-50]=\"isActiveOption(option)\"\r\n [class.text-primary-700]=\"isActiveOption(option)\"\r\n [class.bg-surface-100]=\"!isActiveOption(option)\"\r\n [class.text-surface-500]=\"!isActiveOption(option)\"\r\n >\r\n {{ resolveBadge(option) }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n @if (hasOverflow()) {\r\n <div\r\n class=\"flex shrink-0 items-center -mb-px border-b border-surface-200 pb-1\"\r\n >\r\n <mt-button\r\n icon=\"arrow.chevron-down\"\r\n [label]=\"moreLabel()\"\r\n size=\"small\"\r\n severity=\"primary\"\r\n [text]=\"true\"\r\n [rounded]=\"true\"\r\n (onClick)=\"morePopover.toggle($event)\"\r\n />\r\n <p-popover #morePopover appendTo=\"body\">\r\n <div class=\"flex flex-col min-w-40\">\r\n @for (\r\n option of overflowOptions();\r\n track trackOption(option, $index)\r\n ) {\r\n <button\r\n type=\"button\"\r\n class=\"flex cursor-pointer items-center gap-2 rounded px-2 py-2 text-sm transition-colors\"\r\n [class.bg-primary-50]=\"isActiveOption(option)\"\r\n [class.text-primary]=\"isActiveOption(option)\"\r\n [class.font-semibold]=\"isActiveOption(option)\"\r\n [class.text-surface-700]=\"!isActiveOption(option)\"\r\n [class.hover:bg-surface-100]=\"!isActiveOption(option)\"\r\n [class.cursor-not-allowed]=\"\r\n disabled() || isOptionDisabled(option)\r\n \"\r\n [class.opacity-60]=\"disabled() || isOptionDisabled(option)\"\r\n [disabled]=\"disabled() || isOptionDisabled(option)\"\r\n (click)=\"onOptionSelect(option); morePopover.hide()\"\r\n >\r\n @if (resolveIcon(option); as icon) {\r\n <mt-icon [icon]=\"icon\" class=\"text-base\" />\r\n }\r\n <span class=\"flex-1 truncate\">{{ resolveLabel(option) }}</span>\r\n @if (hasCountBadge(option)) {\r\n <span\r\n class=\"inline-grid min-w-[18px] place-items-center rounded-full px-1.5 text-[10px] leading-4 font-bold tabular-nums\"\r\n [class.bg-primary-100]=\"isActiveOption(option)\"\r\n [class.text-primary-700]=\"isActiveOption(option)\"\r\n [class.bg-surface-100]=\"!isActiveOption(option)\"\r\n [class.text-surface-500]=\"!isActiveOption(option)\"\r\n >\r\n {{ resolveBadge(option) }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n </p-popover>\r\n </div>\r\n }\r\n </div>\r\n} @else {\r\n <p-selectbutton\r\n [options]=\"options()\"\r\n [(ngModel)]=\"active\"\r\n (ngModelChange)=\"onTabChange($event)\"\r\n [optionLabel]=\"optionLabel()\"\r\n [optionValue]=\"optionValue()\"\r\n styleClass=\"my-tabs-button\"\r\n [size]=\"size()\"\r\n [fluid]=\"fluid()\"\r\n [disabled]=\"disabled()\"\r\n unselectable\r\n />\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masterteam/components",
3
- "version": "0.0.149",
3
+ "version": "0.0.151",
4
4
  "publishConfig": {
5
5
  "directory": "../../../dist/masterteam/components",
6
6
  "linkDirectory": true,
@@ -5,6 +5,37 @@ import { HttpContext } from '@angular/common/http';
5
5
  import { MTIcon } from '@masterteam/icons';
6
6
  import { CdkDragDrop } from '@angular/cdk/drag-drop';
7
7
 
8
+ interface ComparisonValueSide {
9
+ raw: unknown;
10
+ value: unknown;
11
+ display?: string | null;
12
+ }
13
+ interface ValueComparison {
14
+ kind: 'Value';
15
+ oldValue: ComparisonValueSide;
16
+ newValue: ComparisonValueSide;
17
+ }
18
+ interface EntityComparisonField {
19
+ propertyKey: string;
20
+ label: string;
21
+ value: unknown;
22
+ display?: string | null;
23
+ }
24
+ type EntityComparisonOperation = 'CreateRecord' | 'UpdateRecord' | 'DeleteRecord';
25
+ interface EntityListComparisonRow {
26
+ kind: 'ModuleRecord';
27
+ operation: EntityComparisonOperation;
28
+ entityId: number;
29
+ oldValues: EntityComparisonField[];
30
+ newValues: EntityComparisonField[];
31
+ }
32
+ interface EntityListComparison {
33
+ kind: 'EntityList';
34
+ targetModuleKey: string;
35
+ rows: EntityListComparisonRow[];
36
+ }
37
+ type PropertyValueComparison = ValueComparison | EntityListComparison;
38
+
8
39
  type EntityViewType = 'Text' | 'LongText' | 'Date' | 'DateTime' | 'Percentage' | 'Status' | 'Currency' | 'Checkbox' | 'User' | 'Lookup' | 'Attachment' | 'LookupMatrix' | 'LeafDetails';
9
40
  type EntityLabelPosition = 'top' | 'bottom';
10
41
  /** Entity size – controls column span (1-24) inside a 24-column grid */
@@ -142,6 +173,8 @@ interface EntityData {
142
173
  viewType: EntityViewType;
143
174
  type?: string;
144
175
  configuration?: EntityConfiguration;
176
+ /** Present on submitted ChangeRequest records — frozen old→new snapshot. */
177
+ comparison?: PropertyValueComparison;
145
178
  }
146
179
  /** Emitted when an entity is resized via the drag handle */
147
180
  interface EntityResizeEvent {
@@ -371,24 +404,90 @@ declare function expandLeafDetailsEntity(entity: EntityData): EntityData[];
371
404
  declare function buildDisplayEntities(entities: EntityData[]): EntityData[];
372
405
 
373
406
  declare class EntityPreview {
374
- /** Single entity data to display */
375
407
  readonly data: _angular_core.InputSignal<EntityData>;
376
408
  readonly attachmentShape: _angular_core.InputSignal<"compact" | "default">;
377
- readonly previewType: _angular_core.Signal<"Text" | "LongText" | "Date" | "DateTime" | "Percentage" | "Status" | "Currency" | "Checkbox" | "User" | "Lookup" | "Attachment" | "LeafDetails">;
409
+ readonly comparisonKind: _angular_core.Signal<"Value" | "EntityList" | null>;
378
410
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EntityPreview, never>;
379
411
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<EntityPreview, "mt-entity-preview", never, { "data": { "alias": "data"; "required": true; "isSignal": true; }; "attachmentShape": { "alias": "attachmentShape"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
380
412
  }
381
413
 
414
+ declare class EntityPreviewBody {
415
+ readonly data: _angular_core.InputSignal<EntityData>;
416
+ readonly attachmentShape: _angular_core.InputSignal<"compact" | "default">;
417
+ readonly previewType: _angular_core.Signal<"Text" | "LongText" | "Date" | "DateTime" | "Percentage" | "Status" | "Currency" | "Checkbox" | "User" | "Lookup" | "Attachment" | "LeafDetails">;
418
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<EntityPreviewBody, never>;
419
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EntityPreviewBody, "mt-entity-preview-body", never, { "data": { "alias": "data"; "required": true; "isSignal": true; }; "attachmentShape": { "alias": "attachmentShape"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
420
+ }
421
+
422
+ declare class ComparisonValue {
423
+ readonly data: _angular_core.InputSignal<EntityData>;
424
+ readonly comparison: _angular_core.Signal<ValueComparison | null>;
425
+ readonly oldEntity: _angular_core.Signal<EntityData | null>;
426
+ readonly newEntity: _angular_core.Signal<EntityData | null>;
427
+ private buildSide;
428
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ComparisonValue, never>;
429
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ComparisonValue, "mt-comparison-value", never, { "data": { "alias": "data"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
430
+ }
431
+
432
+ interface OperationBadge {
433
+ label: string;
434
+ classes: string;
435
+ }
436
+ declare class ComparisonEntityList {
437
+ readonly data: _angular_core.InputSignal<EntityData>;
438
+ readonly comparison: _angular_core.Signal<EntityListComparison | null>;
439
+ readonly rows: _angular_core.Signal<EntityListComparisonRow[]>;
440
+ readonly targetModuleKey: _angular_core.Signal<string>;
441
+ readonly label: _angular_core.Signal<string>;
442
+ badgeFor(op: EntityComparisonOperation): OperationBadge;
443
+ displayField(value: unknown, display?: string | null): string;
444
+ rowId(_i: number, row: EntityListComparisonRow): number | string;
445
+ oldField(row: EntityListComparisonRow, propertyKey: string): {
446
+ value: unknown;
447
+ display?: string | null;
448
+ } | undefined;
449
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ComparisonEntityList, never>;
450
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ComparisonEntityList, "mt-comparison-entity-list", never, { "data": { "alias": "data"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
451
+ }
452
+
453
+ interface EntityClickEvent {
454
+ entity: EntityData;
455
+ key: string;
456
+ source: MouseEvent;
457
+ }
382
458
  declare class EntitiesPreview {
383
459
  /** Array of entity data to display */
384
460
  readonly entities: _angular_core.InputSignal<EntityData[]>;
385
461
  readonly attachmentShape: _angular_core.InputSignal<"compact" | "default">;
462
+ /**
463
+ * Set of entity keys that should appear interactive (cursor pointer,
464
+ * clicks emit). Pass `new Set([...])` from a computed signal in the host
465
+ * for reactive enabling — when the host's set changes, Angular re-renders
466
+ * via its normal change detection, no manual subscriptions required.
467
+ */
468
+ readonly clickableKeys: _angular_core.InputSignal<ReadonlySet<string>>;
469
+ /**
470
+ * Set of entity keys that should render with the "active" treatment
471
+ * (e.g. currently the filter source). Same reactive pattern as
472
+ * `clickableKeys` — host owns a computed signal and passes the value.
473
+ */
474
+ readonly activeKeys: _angular_core.InputSignal<ReadonlySet<string>>;
475
+ /**
476
+ * Emits when an individual entity slot is clicked. Only fires when the
477
+ * entity's key is present in `clickableKeys`.
478
+ */
479
+ readonly entityClick: _angular_core.OutputEmitterRef<EntityClickEvent>;
386
480
  /** Entities expanded and sorted by order */
387
481
  readonly displayEntities: _angular_core.Signal<EntityData[]>;
388
482
  /** Returns the grid-column span for a given entity size (1-24) */
389
483
  getColSpan(entity: EntityData): string;
484
+ /** Stable key resolution shared with the host — must agree on order. */
485
+ private resolveKey;
486
+ protected isClickable(entity: EntityData): boolean;
487
+ protected isActive(entity: EntityData): boolean;
488
+ protected onEntityClick(source: MouseEvent, entity: EntityData): void;
390
489
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EntitiesPreview, never>;
391
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EntitiesPreview, "mt-entities-preview", never, { "entities": { "alias": "entities"; "required": true; "isSignal": true; }; "attachmentShape": { "alias": "attachmentShape"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
490
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EntitiesPreview, "mt-entities-preview", never, { "entities": { "alias": "entities"; "required": true; "isSignal": true; }; "attachmentShape": { "alias": "attachmentShape"; "required": false; "isSignal": true; }; "clickableKeys": { "alias": "clickableKeys"; "required": false; "isSignal": true; }; "activeKeys": { "alias": "activeKeys"; "required": false; "isSignal": true; }; }, { "entityClick": "entityClick"; }, never, never, true, never>;
392
491
  }
393
492
 
394
493
  /**
@@ -459,5 +558,5 @@ declare class EntitiesManage extends EntitiesResizeBase {
459
558
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<EntitiesManage, "mt-entities-manage", never, { "entities": { "alias": "entities"; "required": true; "isSignal": true; }; }, { "entities": "entitiesChange"; "entitiesReordered": "entitiesReordered"; "entityClicked": "entityClicked"; }, never, never, true, never>;
460
559
  }
461
560
 
462
- export { EntitiesManage, EntitiesPreview, EntitiesResizeBase, EntityAttachment, EntityCheckbox, EntityCurrency, EntityDate, EntityField, EntityLeafDetails, EntityLongText, EntityLookup, EntityPercentage, EntityPreview, EntityStatus, EntityText, EntityUser, LEAF_DETAILS_KEY_SEPARATOR, buildDisplayEntities, expandLeafDetailsEntity, isLeafDetailsCatalogConfiguration, isLeafDetailsCollectionValue, isLeafDetailsRuntimeValue, isLeafDetailsSyntheticKey, isLeafDetailsValue };
463
- export type { EntityAttachmentItemValue, EntityAttachmentValue, EntityBaseConfig, EntityConfiguration, EntityData, EntityLabelPosition, EntityLeafDetailsConfig, EntityLookupValue, EntityPercentageConfig, EntityPropertyConfiguration, EntityResizeEvent, EntitySize, EntityStatusValue, EntityUserConfig, EntityUserValue, EntityViewType, LeafDetailsCatalogConfiguration, LeafDetailsCatalogLevelValue, LeafDetailsCatalogStatusValue, LeafDetailsEntityCollectionValue, LeafDetailsEntityValue, LeafDetailsRuntimeChildSchema, LeafDetailsRuntimeStatusCount, LeafDetailsRuntimeStatusDetails, LeafDetailsRuntimeValue, LeafDetailsStatusSummary, LeafLevelSavedConfig };
561
+ export { ComparisonEntityList, ComparisonValue, EntitiesManage, EntitiesPreview, EntitiesResizeBase, EntityAttachment, EntityCheckbox, EntityCurrency, EntityDate, EntityField, EntityLeafDetails, EntityLongText, EntityLookup, EntityPercentage, EntityPreview, EntityPreviewBody, EntityStatus, EntityText, EntityUser, LEAF_DETAILS_KEY_SEPARATOR, buildDisplayEntities, expandLeafDetailsEntity, isLeafDetailsCatalogConfiguration, isLeafDetailsCollectionValue, isLeafDetailsRuntimeValue, isLeafDetailsSyntheticKey, isLeafDetailsValue };
562
+ export type { ComparisonValueSide, EntityAttachmentItemValue, EntityAttachmentValue, EntityBaseConfig, EntityClickEvent, EntityComparisonField, EntityComparisonOperation, EntityConfiguration, EntityData, EntityLabelPosition, EntityLeafDetailsConfig, EntityListComparison, EntityListComparisonRow, EntityLookupValue, EntityPercentageConfig, EntityPropertyConfiguration, EntityResizeEvent, EntitySize, EntityStatusValue, EntityUserConfig, EntityUserValue, EntityViewType, LeafDetailsCatalogConfiguration, LeafDetailsCatalogLevelValue, LeafDetailsCatalogStatusValue, LeafDetailsEntityCollectionValue, LeafDetailsEntityValue, LeafDetailsRuntimeChildSchema, LeafDetailsRuntimeStatusCount, LeafDetailsRuntimeStatusDetails, LeafDetailsRuntimeValue, LeafDetailsStatusSummary, LeafLevelSavedConfig, PropertyValueComparison, ValueComparison };