@elasticias/ui 1.0.22 → 1.0.24
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.
- package/fesm2022/elasticias-ui.mjs +185 -36
- package/fesm2022/elasticias-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/styles/_comptoir.scss +6 -0
- package/styles/_patterns.scss +13 -10
- package/types/elasticias-ui.d.ts +129 -7
|
@@ -145,6 +145,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
145
145
|
}], propDecorators: { amount: [{ type: i0.Input, args: [{ isSignal: true, alias: "amount", required: true }] }] } });
|
|
146
146
|
|
|
147
147
|
class EfQuantitySelectorComponent {
|
|
148
|
+
/**
|
|
149
|
+
* PrimeNG's Button reads `autofocus || buttonProps?.autofocus`, so a bare
|
|
150
|
+
* `false` collapses to `undefined` and its AutoFocus directive writes the
|
|
151
|
+
* attribute anyway. Passing the flag here too makes it resolve to `false`.
|
|
152
|
+
*/
|
|
153
|
+
noAutofocus = { autofocus: false };
|
|
148
154
|
quantity = input(1, ...(ngDevMode ? [{ debugName: "quantity" }] : /* istanbul ignore next */ []));
|
|
149
155
|
quantityChange = output();
|
|
150
156
|
increment() {
|
|
@@ -159,6 +165,8 @@ class EfQuantitySelectorComponent {
|
|
|
159
165
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.11", type: EfQuantitySelectorComponent, isStandalone: true, selector: "ef-quantity-selector", inputs: { quantity: { classPropertyName: "quantity", publicName: "quantity", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { quantityChange: "quantityChange" }, ngImport: i0, template: `
|
|
160
166
|
<div class="flex items-center gap-2">
|
|
161
167
|
<p-button
|
|
168
|
+
[autofocus]="false"
|
|
169
|
+
[buttonProps]="noAutofocus"
|
|
162
170
|
icon="pi pi-minus"
|
|
163
171
|
[rounded]="true"
|
|
164
172
|
[text]="true"
|
|
@@ -168,6 +176,8 @@ class EfQuantitySelectorComponent {
|
|
|
168
176
|
/>
|
|
169
177
|
<span class="w-8 text-center font-medium">{{ quantity() }}</span>
|
|
170
178
|
<p-button
|
|
179
|
+
[autofocus]="false"
|
|
180
|
+
[buttonProps]="noAutofocus"
|
|
171
181
|
icon="pi pi-plus"
|
|
172
182
|
[rounded]="true"
|
|
173
183
|
[text]="true"
|
|
@@ -186,6 +196,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
186
196
|
template: `
|
|
187
197
|
<div class="flex items-center gap-2">
|
|
188
198
|
<p-button
|
|
199
|
+
[autofocus]="false"
|
|
200
|
+
[buttonProps]="noAutofocus"
|
|
189
201
|
icon="pi pi-minus"
|
|
190
202
|
[rounded]="true"
|
|
191
203
|
[text]="true"
|
|
@@ -195,6 +207,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
195
207
|
/>
|
|
196
208
|
<span class="w-8 text-center font-medium">{{ quantity() }}</span>
|
|
197
209
|
<p-button
|
|
210
|
+
[autofocus]="false"
|
|
211
|
+
[buttonProps]="noAutofocus"
|
|
198
212
|
icon="pi pi-plus"
|
|
199
213
|
[rounded]="true"
|
|
200
214
|
[text]="true"
|
|
@@ -863,6 +877,19 @@ class EfSelectComponent extends AbstractEfFormControl {
|
|
|
863
877
|
filterPlaceholderKey;
|
|
864
878
|
/** Auto-focus the filter input when the panel opens (default: true). */
|
|
865
879
|
autofocusFilter = true;
|
|
880
|
+
/**
|
|
881
|
+
* Take focus on load. Off by default, and bound explicitly rather than left
|
|
882
|
+
* unset, which matters more than it looks: PrimeNG's AutoFocus directive
|
|
883
|
+
* decides with `if (this.autofocus === false)`, and `Select` declares
|
|
884
|
+
* `autofocus` with no initialiser. An unbound control therefore arrives as
|
|
885
|
+
* `undefined`, misses that strict check, and gets a real `autofocus="true"`
|
|
886
|
+
* attribute written onto its label. Every select on a page became an
|
|
887
|
+
* autofocus candidate, so on load the browser focused one of them and
|
|
888
|
+
* scrolled its container to it — which is why a dashboard opened partway
|
|
889
|
+
* down the page. Binding `false` puts the directive back on its intended
|
|
890
|
+
* branch and removes the attribute.
|
|
891
|
+
*/
|
|
892
|
+
autofocus = false;
|
|
866
893
|
/* showClear is inherited from AbstractEfFormControl (default true →
|
|
867
894
|
clearable by default; PrimeNG only renders the ✕ when a value is set). */
|
|
868
895
|
editable = false;
|
|
@@ -1050,11 +1077,11 @@ class EfSelectComponent extends AbstractEfFormControl {
|
|
|
1050
1077
|
}
|
|
1051
1078
|
}
|
|
1052
1079
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfSelectComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
1053
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfSelectComponent, isStandalone: true, selector: "ef-select", inputs: { options: "options", optionLabel: "optionLabel", optionValue: "optionValue", optionDisabled: "optionDisabled", dataKey: "dataKey", group: ["group", "group", booleanAttribute], optionGroupLabel: "optionGroupLabel", optionGroupChildren: "optionGroupChildren", size: "size", fluid: ["fluid", "fluid", booleanAttribute], inline: ["inline", "inline", booleanAttribute], appendTo: "appendTo", multiple: ["multiple", "multiple", booleanAttribute], filter: ["filter", "filter", booleanAttribute], filterBy: "filterBy", filterPlaceholder: "filterPlaceholder", filterPlaceholderKey: "filterPlaceholderKey", autofocusFilter: ["autofocusFilter", "autofocusFilter", booleanAttribute], editable: ["editable", "editable", booleanAttribute], loading: ["loading", "loading", booleanAttribute], virtualScroll: ["virtualScroll", "virtualScroll", booleanAttribute], virtualScrollItemSize: "virtualScrollItemSize", scrollHeight: "scrollHeight", multiDisplay: "multiDisplay", showToggleAll: ["showToggleAll", "showToggleAll", booleanAttribute], emptyMessage: "emptyMessage", emptyMessageKey: "emptyMessageKey", emptyFilterMessage: "emptyFilterMessage", emptyFilterMessageKey: "emptyFilterMessageKey", styleClass: "styleClass", panelStyleClass: "panelStyleClass", filterByKeys: "filterByKeys", variant: "variant", value: "value" }, outputs: { selectionChangeEvent: "selectionChangeEvent", filterChangeEvent: "filterChangeEvent", panelShowEvent: "panelShowEvent", panelHideEvent: "panelHideEvent" }, host: { properties: { "class.ef-inline": "this.isInline", "class.ef-select-host": "this.hostClass" } }, providers: [{
|
|
1080
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfSelectComponent, isStandalone: true, selector: "ef-select", inputs: { options: "options", optionLabel: "optionLabel", optionValue: "optionValue", optionDisabled: "optionDisabled", dataKey: "dataKey", group: ["group", "group", booleanAttribute], optionGroupLabel: "optionGroupLabel", optionGroupChildren: "optionGroupChildren", size: "size", fluid: ["fluid", "fluid", booleanAttribute], inline: ["inline", "inline", booleanAttribute], appendTo: "appendTo", multiple: ["multiple", "multiple", booleanAttribute], filter: ["filter", "filter", booleanAttribute], filterBy: "filterBy", filterPlaceholder: "filterPlaceholder", filterPlaceholderKey: "filterPlaceholderKey", autofocusFilter: ["autofocusFilter", "autofocusFilter", booleanAttribute], autofocus: ["autofocus", "autofocus", booleanAttribute], editable: ["editable", "editable", booleanAttribute], loading: ["loading", "loading", booleanAttribute], virtualScroll: ["virtualScroll", "virtualScroll", booleanAttribute], virtualScrollItemSize: "virtualScrollItemSize", scrollHeight: "scrollHeight", multiDisplay: "multiDisplay", showToggleAll: ["showToggleAll", "showToggleAll", booleanAttribute], emptyMessage: "emptyMessage", emptyMessageKey: "emptyMessageKey", emptyFilterMessage: "emptyFilterMessage", emptyFilterMessageKey: "emptyFilterMessageKey", styleClass: "styleClass", panelStyleClass: "panelStyleClass", filterByKeys: "filterByKeys", variant: "variant", value: "value" }, outputs: { selectionChangeEvent: "selectionChangeEvent", filterChangeEvent: "filterChangeEvent", panelShowEvent: "panelShowEvent", panelHideEvent: "panelHideEvent" }, host: { properties: { "class.ef-inline": "this.isInline", "class.ef-select-host": "this.hostClass" } }, providers: [{
|
|
1054
1081
|
provide: NG_VALUE_ACCESSOR,
|
|
1055
1082
|
useExisting: forwardRef(() => EfSelectComponent),
|
|
1056
1083
|
multi: true,
|
|
1057
|
-
}], queries: [{ propertyName: "itemTemplate", first: true, predicate: ["item"], descendants: true }, { propertyName: "selectedItemTemplate", first: true, predicate: ["selectedItem"], descendants: true }, { propertyName: "groupTemplate", first: true, predicate: ["group"], descendants: true }, { propertyName: "headerTemplate", first: true, predicate: ["header"], descendants: true }, { propertyName: "footerTemplate", first: true, predicate: ["footer"], descendants: true }, { propertyName: "emptyTemplate", first: true, predicate: ["empty"], descendants: true }, { propertyName: "emptyFilterTemplate", first: true, predicate: ["emptyFilter"], descendants: true }, { propertyName: "filterTemplate", first: true, predicate: ["filter"], descendants: true }, { propertyName: "loaderTemplate", first: true, predicate: ["loader"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n @if (variant === 'comptoir') {\n <!-- Comptoir variant \u2014 native <select> against the\n .ef-select-native pattern. No filter / virtualization /\n multi / templates; use the PrimeNG variant for those. -->\n <select\n class=\"ef-select-native\"\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [disabled]=\"isDisabled()\"\n [class.is-invalid]=\"isInvalid\"\n [attr.aria-label]=\"effectiveAriaLabel\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-invalid]=\"isInvalid ? 'true' : null\"\n [attr.aria-describedby]=\"(showRequired || serverErrors) ? errorsId : null\"\n (change)=\"handleNativeSelectChange($any($event.target).value)\"\n >\n @if (effectivePlaceholder) {\n <option value=\"\" [selected]=\"value === null || value === undefined\">\u2014 {{ effectivePlaceholder }} \u2014</option>\n }\n @for (opt of filteredOptions; track $index) {\n <option\n [value]=\"optionValue ? opt[optionValue] : opt\"\n [selected]=\"(optionValue ? opt[optionValue] : opt) === value\"\n >\n {{ opt[optionLabel] }}\n </option>\n }\n </select>\n } @else if (multiple) {\n <!-- \u2500\u2500\u2500\u2500\u2500 PrimeNG multi-select branch \u2500\u2500\u2500\u2500\u2500 -->\n <p-multiselect\n [inputId]=\"effectiveId\"\n [name]=\"name()\"\n [ngModel]=\"value\"\n [ngModelOptions]=\"{standalone: true}\"\n (onChange)=\"handleSelectionChange($event)\"\n (onClear)=\"handleClear()\"\n (onFilter)=\"handleFilter($event)\"\n (onPanelShow)=\"handlePanelShow()\"\n (onPanelHide)=\"handlePanelHide()\"\n [options]=\"filteredOptions\"\n [optionLabel]=\"optionLabel\"\n [optionValue]=\"optionValue\"\n [optionDisabled]=\"optionDisabled\"\n [dataKey]=\"dataKey\"\n [group]=\"group\"\n [optionGroupLabel]=\"optionGroupLabel\"\n [optionGroupChildren]=\"optionGroupChildren\"\n [placeholder]=\"effectivePlaceholder\"\n [filter]=\"filter\"\n [filterPlaceHolder]=\"effectiveFilterPlaceholder\"\n [autofocusFilter]=\"autofocusFilter\"\n [filterBy]=\"filterBy ?? optionLabel\"\n [showClear]=\"showClear()\"\n [disabled]=\"isDisabled()\"\n [appendTo]=\"appendTo\"\n [styleClass]=\"effectiveStyleClass\"\n [panelStyleClass]=\"effectivePanelStyleClass\"\n [scrollHeight]=\"scrollHeight\"\n [virtualScroll]=\"virtualScroll\"\n [virtualScrollItemSize]=\"virtualScrollItemSize\"\n [loading]=\"loading\"\n [emptyMessage]=\"effectiveEmptyMessage\"\n [emptyFilterMessage]=\"effectiveEmptyFilterMessage\"\n [display]=\"multiDisplay\"\n [showToggleAll]=\"showToggleAll\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n fluid\n >\n @if (itemTemplate) {\n <ng-template #item let-item>\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\" />\n </ng-template>\n }\n @if (selectedItemTemplate) {\n <ng-template #selectedItems let-items>\n <ng-container *ngTemplateOutlet=\"selectedItemTemplate; context: { $implicit: items }\" />\n </ng-template>\n }\n @if (groupTemplate) {\n <ng-template #group let-group>\n <ng-container *ngTemplateOutlet=\"groupTemplate; context: { $implicit: group }\" />\n </ng-template>\n }\n @if (headerTemplate) {\n <ng-template #header>\n <ng-container *ngTemplateOutlet=\"headerTemplate\" />\n </ng-template>\n }\n @if (footerTemplate) {\n <ng-template #footer>\n <ng-container *ngTemplateOutlet=\"footerTemplate\" />\n </ng-template>\n }\n @if (emptyTemplate) {\n <ng-template #empty>\n <ng-container *ngTemplateOutlet=\"emptyTemplate\" />\n </ng-template>\n }\n @if (emptyFilterTemplate) {\n <ng-template #emptyfilter>\n <ng-container *ngTemplateOutlet=\"emptyFilterTemplate\" />\n </ng-template>\n }\n @if (filterTemplate) {\n <ng-template #filter let-options=\"options\">\n <ng-container *ngTemplateOutlet=\"filterTemplate; context: { $implicit: options }\" />\n </ng-template>\n }\n @if (loaderTemplate) {\n <ng-template #loader>\n <ng-container *ngTemplateOutlet=\"loaderTemplate\" />\n </ng-template>\n }\n <ng-template #clearicon>\n <span class=\"es-clear\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\">\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </span>\n </ng-template>\n <ng-template #dropdownicon>\n <svg class=\"ef-chevron\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </ng-template>\n </p-multiselect>\n } @else {\n <!-- \u2500\u2500\u2500\u2500\u2500 PrimeNG single-select branch \u2500\u2500\u2500\u2500\u2500 -->\n <p-select\n [inputId]=\"effectiveId\"\n [name]=\"name()\"\n [ngModel]=\"value\"\n [ngModelOptions]=\"{standalone: true}\"\n (onChange)=\"handleSelectionChange($event)\"\n (onClear)=\"handleClear()\"\n (onFilter)=\"handleFilter($event)\"\n (onShow)=\"handlePanelShow()\"\n (onHide)=\"handlePanelHide()\"\n [options]=\"filteredOptions\"\n [optionLabel]=\"optionLabel\"\n [optionValue]=\"optionValue\"\n [optionDisabled]=\"optionDisabled\"\n [dataKey]=\"dataKey\"\n [group]=\"group\"\n [optionGroupLabel]=\"optionGroupLabel\"\n [optionGroupChildren]=\"optionGroupChildren\"\n [placeholder]=\"effectivePlaceholder\"\n [size]=\"size\"\n [filter]=\"filter\"\n [filterPlaceholder]=\"effectiveFilterPlaceholder\"\n [filterBy]=\"filterBy ?? optionLabel\"\n [autofocusFilter]=\"autofocusFilter\"\n [showClear]=\"showClear()\"\n [editable]=\"editable\"\n [disabled]=\"isDisabled()\"\n [appendTo]=\"appendTo\"\n [styleClass]=\"effectiveStyleClass\"\n [panelStyleClass]=\"effectivePanelStyleClass\"\n [scrollHeight]=\"scrollHeight\"\n [virtualScroll]=\"virtualScroll\"\n [virtualScrollItemSize]=\"virtualScrollItemSize\"\n [loading]=\"loading\"\n [emptyMessage]=\"effectiveEmptyMessage\"\n [emptyFilterMessage]=\"effectiveEmptyFilterMessage\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n fluid\n >\n @if (itemTemplate) {\n <ng-template #item let-item>\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\" />\n </ng-template>\n }\n @if (selectedItemTemplate) {\n <ng-template #selectedItem let-item>\n <ng-container *ngTemplateOutlet=\"selectedItemTemplate; context: { $implicit: item }\" />\n </ng-template>\n }\n @if (groupTemplate) {\n <ng-template #group let-group>\n <ng-container *ngTemplateOutlet=\"groupTemplate; context: { $implicit: group }\" />\n </ng-template>\n }\n @if (headerTemplate) {\n <ng-template #header>\n <ng-container *ngTemplateOutlet=\"headerTemplate\" />\n </ng-template>\n }\n @if (footerTemplate) {\n <ng-template #footer>\n <ng-container *ngTemplateOutlet=\"footerTemplate\" />\n </ng-template>\n }\n @if (emptyTemplate) {\n <ng-template #empty>\n <ng-container *ngTemplateOutlet=\"emptyTemplate\" />\n </ng-template>\n }\n @if (emptyFilterTemplate) {\n <ng-template #emptyfilter>\n <ng-container *ngTemplateOutlet=\"emptyFilterTemplate\" />\n </ng-template>\n }\n @if (filterTemplate) {\n <ng-template #filter let-options=\"options\">\n <ng-container *ngTemplateOutlet=\"filterTemplate; context: { $implicit: options }\" />\n </ng-template>\n }\n @if (loaderTemplate) {\n <ng-template #loader>\n <ng-container *ngTemplateOutlet=\"loaderTemplate\" />\n </ng-template>\n }\n <ng-template #clearicon>\n <span class=\"es-clear\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\">\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </span>\n </ng-template>\n <ng-template #dropdownicon>\n <svg class=\"ef-chevron\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </ng-template>\n </p-select>\n }\n @if (showRequired || serverErrors) {\n <div [id]=\"errorsId\" role=\"alert\" aria-live=\"polite\">\n @if (showRequired) {\n <small class=\"text-danger\">{{ 'validation.required' | translate }}</small>\n }\n @if (serverErrors; as errors) {\n @for (error of errors; track error) {\n <small class=\"text-danger block\">{{ error }}</small>\n }\n }\n </div>\n }\n</div>\n", styles: [":host{display:block}:host(.ef-inline){display:flex;align-items:baseline;gap:.5rem}:host(.ef-inline)>label{white-space:nowrap;flex-shrink:0}:host(.ef-inline)>.ef-field-control{flex:1;min-width:0}\n"], dependencies: [{ kind: "ngmodule", type: SelectModule }, { kind: "component", type: i1$2.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i2.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfLabelComponent, selector: "ef-label", inputs: ["label", "labelKey", "for", "styleClass", "required"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
1084
|
+
}], queries: [{ propertyName: "itemTemplate", first: true, predicate: ["item"], descendants: true }, { propertyName: "selectedItemTemplate", first: true, predicate: ["selectedItem"], descendants: true }, { propertyName: "groupTemplate", first: true, predicate: ["group"], descendants: true }, { propertyName: "headerTemplate", first: true, predicate: ["header"], descendants: true }, { propertyName: "footerTemplate", first: true, predicate: ["footer"], descendants: true }, { propertyName: "emptyTemplate", first: true, predicate: ["empty"], descendants: true }, { propertyName: "emptyFilterTemplate", first: true, predicate: ["emptyFilter"], descendants: true }, { propertyName: "filterTemplate", first: true, predicate: ["filter"], descendants: true }, { propertyName: "loaderTemplate", first: true, predicate: ["loader"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n @if (variant === 'comptoir') {\n <!-- Comptoir variant \u2014 native <select> against the\n .ef-select-native pattern. No filter / virtualization /\n multi / templates; use the PrimeNG variant for those. -->\n <select\n class=\"ef-select-native\"\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [disabled]=\"isDisabled()\"\n [class.is-invalid]=\"isInvalid\"\n [attr.aria-label]=\"effectiveAriaLabel\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-invalid]=\"isInvalid ? 'true' : null\"\n [attr.aria-describedby]=\"(showRequired || serverErrors) ? errorsId : null\"\n (change)=\"handleNativeSelectChange($any($event.target).value)\"\n >\n @if (effectivePlaceholder) {\n <option value=\"\" [selected]=\"value === null || value === undefined\">\u2014 {{ effectivePlaceholder }} \u2014</option>\n }\n @for (opt of filteredOptions; track $index) {\n <option\n [value]=\"optionValue ? opt[optionValue] : opt\"\n [selected]=\"(optionValue ? opt[optionValue] : opt) === value\"\n >\n {{ opt[optionLabel] }}\n </option>\n }\n </select>\n } @else if (multiple) {\n <!-- \u2500\u2500\u2500\u2500\u2500 PrimeNG multi-select branch \u2500\u2500\u2500\u2500\u2500 -->\n <p-multiselect\n [inputId]=\"effectiveId\"\n [name]=\"name()\"\n [ngModel]=\"value\"\n [ngModelOptions]=\"{standalone: true}\"\n (onChange)=\"handleSelectionChange($event)\"\n (onClear)=\"handleClear()\"\n (onFilter)=\"handleFilter($event)\"\n (onPanelShow)=\"handlePanelShow()\"\n (onPanelHide)=\"handlePanelHide()\"\n [options]=\"filteredOptions\"\n [optionLabel]=\"optionLabel\"\n [optionValue]=\"optionValue\"\n [optionDisabled]=\"optionDisabled\"\n [dataKey]=\"dataKey\"\n [group]=\"group\"\n [optionGroupLabel]=\"optionGroupLabel\"\n [optionGroupChildren]=\"optionGroupChildren\"\n [placeholder]=\"effectivePlaceholder\"\n [filter]=\"filter\"\n [filterPlaceHolder]=\"effectiveFilterPlaceholder\"\n [autofocusFilter]=\"autofocusFilter\"\n [autofocus]=\"autofocus\"\n [filterBy]=\"filterBy ?? optionLabel\"\n [showClear]=\"showClear()\"\n [disabled]=\"isDisabled()\"\n [appendTo]=\"appendTo\"\n [styleClass]=\"effectiveStyleClass\"\n [panelStyleClass]=\"effectivePanelStyleClass\"\n [scrollHeight]=\"scrollHeight\"\n [virtualScroll]=\"virtualScroll\"\n [virtualScrollItemSize]=\"virtualScrollItemSize\"\n [loading]=\"loading\"\n [emptyMessage]=\"effectiveEmptyMessage\"\n [emptyFilterMessage]=\"effectiveEmptyFilterMessage\"\n [display]=\"multiDisplay\"\n [showToggleAll]=\"showToggleAll\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n fluid\n >\n @if (itemTemplate) {\n <ng-template #item let-item>\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\" />\n </ng-template>\n }\n @if (selectedItemTemplate) {\n <ng-template #selectedItems let-items>\n <ng-container *ngTemplateOutlet=\"selectedItemTemplate; context: { $implicit: items }\" />\n </ng-template>\n }\n @if (groupTemplate) {\n <ng-template #group let-group>\n <ng-container *ngTemplateOutlet=\"groupTemplate; context: { $implicit: group }\" />\n </ng-template>\n }\n @if (headerTemplate) {\n <ng-template #header>\n <ng-container *ngTemplateOutlet=\"headerTemplate\" />\n </ng-template>\n }\n @if (footerTemplate) {\n <ng-template #footer>\n <ng-container *ngTemplateOutlet=\"footerTemplate\" />\n </ng-template>\n }\n @if (emptyTemplate) {\n <ng-template #empty>\n <ng-container *ngTemplateOutlet=\"emptyTemplate\" />\n </ng-template>\n }\n @if (emptyFilterTemplate) {\n <ng-template #emptyfilter>\n <ng-container *ngTemplateOutlet=\"emptyFilterTemplate\" />\n </ng-template>\n }\n @if (filterTemplate) {\n <ng-template #filter let-options=\"options\">\n <ng-container *ngTemplateOutlet=\"filterTemplate; context: { $implicit: options }\" />\n </ng-template>\n }\n @if (loaderTemplate) {\n <ng-template #loader>\n <ng-container *ngTemplateOutlet=\"loaderTemplate\" />\n </ng-template>\n }\n <ng-template #clearicon>\n <span class=\"es-clear\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\">\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </span>\n </ng-template>\n <ng-template #dropdownicon>\n <svg class=\"ef-chevron\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </ng-template>\n </p-multiselect>\n } @else {\n <!-- \u2500\u2500\u2500\u2500\u2500 PrimeNG single-select branch \u2500\u2500\u2500\u2500\u2500 -->\n <p-select\n [inputId]=\"effectiveId\"\n [name]=\"name()\"\n [ngModel]=\"value\"\n [ngModelOptions]=\"{standalone: true}\"\n (onChange)=\"handleSelectionChange($event)\"\n (onClear)=\"handleClear()\"\n (onFilter)=\"handleFilter($event)\"\n (onShow)=\"handlePanelShow()\"\n (onHide)=\"handlePanelHide()\"\n [options]=\"filteredOptions\"\n [optionLabel]=\"optionLabel\"\n [optionValue]=\"optionValue\"\n [optionDisabled]=\"optionDisabled\"\n [dataKey]=\"dataKey\"\n [group]=\"group\"\n [optionGroupLabel]=\"optionGroupLabel\"\n [optionGroupChildren]=\"optionGroupChildren\"\n [placeholder]=\"effectivePlaceholder\"\n [size]=\"size\"\n [filter]=\"filter\"\n [filterPlaceholder]=\"effectiveFilterPlaceholder\"\n [filterBy]=\"filterBy ?? optionLabel\"\n [autofocusFilter]=\"autofocusFilter\"\n [autofocus]=\"autofocus\"\n [showClear]=\"showClear()\"\n [editable]=\"editable\"\n [disabled]=\"isDisabled()\"\n [appendTo]=\"appendTo\"\n [styleClass]=\"effectiveStyleClass\"\n [panelStyleClass]=\"effectivePanelStyleClass\"\n [scrollHeight]=\"scrollHeight\"\n [virtualScroll]=\"virtualScroll\"\n [virtualScrollItemSize]=\"virtualScrollItemSize\"\n [loading]=\"loading\"\n [emptyMessage]=\"effectiveEmptyMessage\"\n [emptyFilterMessage]=\"effectiveEmptyFilterMessage\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n fluid\n >\n @if (itemTemplate) {\n <ng-template #item let-item>\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\" />\n </ng-template>\n }\n @if (selectedItemTemplate) {\n <ng-template #selectedItem let-item>\n <ng-container *ngTemplateOutlet=\"selectedItemTemplate; context: { $implicit: item }\" />\n </ng-template>\n }\n @if (groupTemplate) {\n <ng-template #group let-group>\n <ng-container *ngTemplateOutlet=\"groupTemplate; context: { $implicit: group }\" />\n </ng-template>\n }\n @if (headerTemplate) {\n <ng-template #header>\n <ng-container *ngTemplateOutlet=\"headerTemplate\" />\n </ng-template>\n }\n @if (footerTemplate) {\n <ng-template #footer>\n <ng-container *ngTemplateOutlet=\"footerTemplate\" />\n </ng-template>\n }\n @if (emptyTemplate) {\n <ng-template #empty>\n <ng-container *ngTemplateOutlet=\"emptyTemplate\" />\n </ng-template>\n }\n @if (emptyFilterTemplate) {\n <ng-template #emptyfilter>\n <ng-container *ngTemplateOutlet=\"emptyFilterTemplate\" />\n </ng-template>\n }\n @if (filterTemplate) {\n <ng-template #filter let-options=\"options\">\n <ng-container *ngTemplateOutlet=\"filterTemplate; context: { $implicit: options }\" />\n </ng-template>\n }\n @if (loaderTemplate) {\n <ng-template #loader>\n <ng-container *ngTemplateOutlet=\"loaderTemplate\" />\n </ng-template>\n }\n <ng-template #clearicon>\n <span class=\"es-clear\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\">\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </span>\n </ng-template>\n <ng-template #dropdownicon>\n <svg class=\"ef-chevron\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </ng-template>\n </p-select>\n }\n @if (showRequired || serverErrors) {\n <div [id]=\"errorsId\" role=\"alert\" aria-live=\"polite\">\n @if (showRequired) {\n <small class=\"text-danger\">{{ 'validation.required' | translate }}</small>\n }\n @if (serverErrors; as errors) {\n @for (error of errors; track error) {\n <small class=\"text-danger block\">{{ error }}</small>\n }\n }\n </div>\n }\n</div>\n", styles: [":host{display:block}:host(.ef-inline){display:flex;align-items:baseline;gap:.5rem}:host(.ef-inline)>label{white-space:nowrap;flex-shrink:0}:host(.ef-inline)>.ef-field-control{flex:1;min-width:0}\n"], dependencies: [{ kind: "ngmodule", type: SelectModule }, { kind: "component", type: i1$2.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i2.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfLabelComponent, selector: "ef-label", inputs: ["label", "labelKey", "for", "styleClass", "required"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
1058
1085
|
}
|
|
1059
1086
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfSelectComponent, decorators: [{
|
|
1060
1087
|
type: Component,
|
|
@@ -1069,7 +1096,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
1069
1096
|
provide: NG_VALUE_ACCESSOR,
|
|
1070
1097
|
useExisting: forwardRef(() => EfSelectComponent),
|
|
1071
1098
|
multi: true,
|
|
1072
|
-
}], template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n @if (variant === 'comptoir') {\n <!-- Comptoir variant \u2014 native <select> against the\n .ef-select-native pattern. No filter / virtualization /\n multi / templates; use the PrimeNG variant for those. -->\n <select\n class=\"ef-select-native\"\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [disabled]=\"isDisabled()\"\n [class.is-invalid]=\"isInvalid\"\n [attr.aria-label]=\"effectiveAriaLabel\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-invalid]=\"isInvalid ? 'true' : null\"\n [attr.aria-describedby]=\"(showRequired || serverErrors) ? errorsId : null\"\n (change)=\"handleNativeSelectChange($any($event.target).value)\"\n >\n @if (effectivePlaceholder) {\n <option value=\"\" [selected]=\"value === null || value === undefined\">\u2014 {{ effectivePlaceholder }} \u2014</option>\n }\n @for (opt of filteredOptions; track $index) {\n <option\n [value]=\"optionValue ? opt[optionValue] : opt\"\n [selected]=\"(optionValue ? opt[optionValue] : opt) === value\"\n >\n {{ opt[optionLabel] }}\n </option>\n }\n </select>\n } @else if (multiple) {\n <!-- \u2500\u2500\u2500\u2500\u2500 PrimeNG multi-select branch \u2500\u2500\u2500\u2500\u2500 -->\n <p-multiselect\n [inputId]=\"effectiveId\"\n [name]=\"name()\"\n [ngModel]=\"value\"\n [ngModelOptions]=\"{standalone: true}\"\n (onChange)=\"handleSelectionChange($event)\"\n (onClear)=\"handleClear()\"\n (onFilter)=\"handleFilter($event)\"\n (onPanelShow)=\"handlePanelShow()\"\n (onPanelHide)=\"handlePanelHide()\"\n [options]=\"filteredOptions\"\n [optionLabel]=\"optionLabel\"\n [optionValue]=\"optionValue\"\n [optionDisabled]=\"optionDisabled\"\n [dataKey]=\"dataKey\"\n [group]=\"group\"\n [optionGroupLabel]=\"optionGroupLabel\"\n [optionGroupChildren]=\"optionGroupChildren\"\n [placeholder]=\"effectivePlaceholder\"\n [filter]=\"filter\"\n [filterPlaceHolder]=\"effectiveFilterPlaceholder\"\n [autofocusFilter]=\"autofocusFilter\"\n [filterBy]=\"filterBy ?? optionLabel\"\n [showClear]=\"showClear()\"\n [disabled]=\"isDisabled()\"\n [appendTo]=\"appendTo\"\n [styleClass]=\"effectiveStyleClass\"\n [panelStyleClass]=\"effectivePanelStyleClass\"\n [scrollHeight]=\"scrollHeight\"\n [virtualScroll]=\"virtualScroll\"\n [virtualScrollItemSize]=\"virtualScrollItemSize\"\n [loading]=\"loading\"\n [emptyMessage]=\"effectiveEmptyMessage\"\n [emptyFilterMessage]=\"effectiveEmptyFilterMessage\"\n [display]=\"multiDisplay\"\n [showToggleAll]=\"showToggleAll\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n fluid\n >\n @if (itemTemplate) {\n <ng-template #item let-item>\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\" />\n </ng-template>\n }\n @if (selectedItemTemplate) {\n <ng-template #selectedItems let-items>\n <ng-container *ngTemplateOutlet=\"selectedItemTemplate; context: { $implicit: items }\" />\n </ng-template>\n }\n @if (groupTemplate) {\n <ng-template #group let-group>\n <ng-container *ngTemplateOutlet=\"groupTemplate; context: { $implicit: group }\" />\n </ng-template>\n }\n @if (headerTemplate) {\n <ng-template #header>\n <ng-container *ngTemplateOutlet=\"headerTemplate\" />\n </ng-template>\n }\n @if (footerTemplate) {\n <ng-template #footer>\n <ng-container *ngTemplateOutlet=\"footerTemplate\" />\n </ng-template>\n }\n @if (emptyTemplate) {\n <ng-template #empty>\n <ng-container *ngTemplateOutlet=\"emptyTemplate\" />\n </ng-template>\n }\n @if (emptyFilterTemplate) {\n <ng-template #emptyfilter>\n <ng-container *ngTemplateOutlet=\"emptyFilterTemplate\" />\n </ng-template>\n }\n @if (filterTemplate) {\n <ng-template #filter let-options=\"options\">\n <ng-container *ngTemplateOutlet=\"filterTemplate; context: { $implicit: options }\" />\n </ng-template>\n }\n @if (loaderTemplate) {\n <ng-template #loader>\n <ng-container *ngTemplateOutlet=\"loaderTemplate\" />\n </ng-template>\n }\n <ng-template #clearicon>\n <span class=\"es-clear\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\">\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </span>\n </ng-template>\n <ng-template #dropdownicon>\n <svg class=\"ef-chevron\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </ng-template>\n </p-multiselect>\n } @else {\n <!-- \u2500\u2500\u2500\u2500\u2500 PrimeNG single-select branch \u2500\u2500\u2500\u2500\u2500 -->\n <p-select\n [inputId]=\"effectiveId\"\n [name]=\"name()\"\n [ngModel]=\"value\"\n [ngModelOptions]=\"{standalone: true}\"\n (onChange)=\"handleSelectionChange($event)\"\n (onClear)=\"handleClear()\"\n (onFilter)=\"handleFilter($event)\"\n (onShow)=\"handlePanelShow()\"\n (onHide)=\"handlePanelHide()\"\n [options]=\"filteredOptions\"\n [optionLabel]=\"optionLabel\"\n [optionValue]=\"optionValue\"\n [optionDisabled]=\"optionDisabled\"\n [dataKey]=\"dataKey\"\n [group]=\"group\"\n [optionGroupLabel]=\"optionGroupLabel\"\n [optionGroupChildren]=\"optionGroupChildren\"\n [placeholder]=\"effectivePlaceholder\"\n [size]=\"size\"\n [filter]=\"filter\"\n [filterPlaceholder]=\"effectiveFilterPlaceholder\"\n [filterBy]=\"filterBy ?? optionLabel\"\n [autofocusFilter]=\"autofocusFilter\"\n [showClear]=\"showClear()\"\n [editable]=\"editable\"\n [disabled]=\"isDisabled()\"\n [appendTo]=\"appendTo\"\n [styleClass]=\"effectiveStyleClass\"\n [panelStyleClass]=\"effectivePanelStyleClass\"\n [scrollHeight]=\"scrollHeight\"\n [virtualScroll]=\"virtualScroll\"\n [virtualScrollItemSize]=\"virtualScrollItemSize\"\n [loading]=\"loading\"\n [emptyMessage]=\"effectiveEmptyMessage\"\n [emptyFilterMessage]=\"effectiveEmptyFilterMessage\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n fluid\n >\n @if (itemTemplate) {\n <ng-template #item let-item>\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\" />\n </ng-template>\n }\n @if (selectedItemTemplate) {\n <ng-template #selectedItem let-item>\n <ng-container *ngTemplateOutlet=\"selectedItemTemplate; context: { $implicit: item }\" />\n </ng-template>\n }\n @if (groupTemplate) {\n <ng-template #group let-group>\n <ng-container *ngTemplateOutlet=\"groupTemplate; context: { $implicit: group }\" />\n </ng-template>\n }\n @if (headerTemplate) {\n <ng-template #header>\n <ng-container *ngTemplateOutlet=\"headerTemplate\" />\n </ng-template>\n }\n @if (footerTemplate) {\n <ng-template #footer>\n <ng-container *ngTemplateOutlet=\"footerTemplate\" />\n </ng-template>\n }\n @if (emptyTemplate) {\n <ng-template #empty>\n <ng-container *ngTemplateOutlet=\"emptyTemplate\" />\n </ng-template>\n }\n @if (emptyFilterTemplate) {\n <ng-template #emptyfilter>\n <ng-container *ngTemplateOutlet=\"emptyFilterTemplate\" />\n </ng-template>\n }\n @if (filterTemplate) {\n <ng-template #filter let-options=\"options\">\n <ng-container *ngTemplateOutlet=\"filterTemplate; context: { $implicit: options }\" />\n </ng-template>\n }\n @if (loaderTemplate) {\n <ng-template #loader>\n <ng-container *ngTemplateOutlet=\"loaderTemplate\" />\n </ng-template>\n }\n <ng-template #clearicon>\n <span class=\"es-clear\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\">\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </span>\n </ng-template>\n <ng-template #dropdownicon>\n <svg class=\"ef-chevron\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </ng-template>\n </p-select>\n }\n @if (showRequired || serverErrors) {\n <div [id]=\"errorsId\" role=\"alert\" aria-live=\"polite\">\n @if (showRequired) {\n <small class=\"text-danger\">{{ 'validation.required' | translate }}</small>\n }\n @if (serverErrors; as errors) {\n @for (error of errors; track error) {\n <small class=\"text-danger block\">{{ error }}</small>\n }\n }\n </div>\n }\n</div>\n", styles: [":host{display:block}:host(.ef-inline){display:flex;align-items:baseline;gap:.5rem}:host(.ef-inline)>label{white-space:nowrap;flex-shrink:0}:host(.ef-inline)>.ef-field-control{flex:1;min-width:0}\n"] }]
|
|
1099
|
+
}], template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n @if (variant === 'comptoir') {\n <!-- Comptoir variant \u2014 native <select> against the\n .ef-select-native pattern. No filter / virtualization /\n multi / templates; use the PrimeNG variant for those. -->\n <select\n class=\"ef-select-native\"\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [disabled]=\"isDisabled()\"\n [class.is-invalid]=\"isInvalid\"\n [attr.aria-label]=\"effectiveAriaLabel\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-invalid]=\"isInvalid ? 'true' : null\"\n [attr.aria-describedby]=\"(showRequired || serverErrors) ? errorsId : null\"\n (change)=\"handleNativeSelectChange($any($event.target).value)\"\n >\n @if (effectivePlaceholder) {\n <option value=\"\" [selected]=\"value === null || value === undefined\">\u2014 {{ effectivePlaceholder }} \u2014</option>\n }\n @for (opt of filteredOptions; track $index) {\n <option\n [value]=\"optionValue ? opt[optionValue] : opt\"\n [selected]=\"(optionValue ? opt[optionValue] : opt) === value\"\n >\n {{ opt[optionLabel] }}\n </option>\n }\n </select>\n } @else if (multiple) {\n <!-- \u2500\u2500\u2500\u2500\u2500 PrimeNG multi-select branch \u2500\u2500\u2500\u2500\u2500 -->\n <p-multiselect\n [inputId]=\"effectiveId\"\n [name]=\"name()\"\n [ngModel]=\"value\"\n [ngModelOptions]=\"{standalone: true}\"\n (onChange)=\"handleSelectionChange($event)\"\n (onClear)=\"handleClear()\"\n (onFilter)=\"handleFilter($event)\"\n (onPanelShow)=\"handlePanelShow()\"\n (onPanelHide)=\"handlePanelHide()\"\n [options]=\"filteredOptions\"\n [optionLabel]=\"optionLabel\"\n [optionValue]=\"optionValue\"\n [optionDisabled]=\"optionDisabled\"\n [dataKey]=\"dataKey\"\n [group]=\"group\"\n [optionGroupLabel]=\"optionGroupLabel\"\n [optionGroupChildren]=\"optionGroupChildren\"\n [placeholder]=\"effectivePlaceholder\"\n [filter]=\"filter\"\n [filterPlaceHolder]=\"effectiveFilterPlaceholder\"\n [autofocusFilter]=\"autofocusFilter\"\n [autofocus]=\"autofocus\"\n [filterBy]=\"filterBy ?? optionLabel\"\n [showClear]=\"showClear()\"\n [disabled]=\"isDisabled()\"\n [appendTo]=\"appendTo\"\n [styleClass]=\"effectiveStyleClass\"\n [panelStyleClass]=\"effectivePanelStyleClass\"\n [scrollHeight]=\"scrollHeight\"\n [virtualScroll]=\"virtualScroll\"\n [virtualScrollItemSize]=\"virtualScrollItemSize\"\n [loading]=\"loading\"\n [emptyMessage]=\"effectiveEmptyMessage\"\n [emptyFilterMessage]=\"effectiveEmptyFilterMessage\"\n [display]=\"multiDisplay\"\n [showToggleAll]=\"showToggleAll\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n fluid\n >\n @if (itemTemplate) {\n <ng-template #item let-item>\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\" />\n </ng-template>\n }\n @if (selectedItemTemplate) {\n <ng-template #selectedItems let-items>\n <ng-container *ngTemplateOutlet=\"selectedItemTemplate; context: { $implicit: items }\" />\n </ng-template>\n }\n @if (groupTemplate) {\n <ng-template #group let-group>\n <ng-container *ngTemplateOutlet=\"groupTemplate; context: { $implicit: group }\" />\n </ng-template>\n }\n @if (headerTemplate) {\n <ng-template #header>\n <ng-container *ngTemplateOutlet=\"headerTemplate\" />\n </ng-template>\n }\n @if (footerTemplate) {\n <ng-template #footer>\n <ng-container *ngTemplateOutlet=\"footerTemplate\" />\n </ng-template>\n }\n @if (emptyTemplate) {\n <ng-template #empty>\n <ng-container *ngTemplateOutlet=\"emptyTemplate\" />\n </ng-template>\n }\n @if (emptyFilterTemplate) {\n <ng-template #emptyfilter>\n <ng-container *ngTemplateOutlet=\"emptyFilterTemplate\" />\n </ng-template>\n }\n @if (filterTemplate) {\n <ng-template #filter let-options=\"options\">\n <ng-container *ngTemplateOutlet=\"filterTemplate; context: { $implicit: options }\" />\n </ng-template>\n }\n @if (loaderTemplate) {\n <ng-template #loader>\n <ng-container *ngTemplateOutlet=\"loaderTemplate\" />\n </ng-template>\n }\n <ng-template #clearicon>\n <span class=\"es-clear\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\">\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </span>\n </ng-template>\n <ng-template #dropdownicon>\n <svg class=\"ef-chevron\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </ng-template>\n </p-multiselect>\n } @else {\n <!-- \u2500\u2500\u2500\u2500\u2500 PrimeNG single-select branch \u2500\u2500\u2500\u2500\u2500 -->\n <p-select\n [inputId]=\"effectiveId\"\n [name]=\"name()\"\n [ngModel]=\"value\"\n [ngModelOptions]=\"{standalone: true}\"\n (onChange)=\"handleSelectionChange($event)\"\n (onClear)=\"handleClear()\"\n (onFilter)=\"handleFilter($event)\"\n (onShow)=\"handlePanelShow()\"\n (onHide)=\"handlePanelHide()\"\n [options]=\"filteredOptions\"\n [optionLabel]=\"optionLabel\"\n [optionValue]=\"optionValue\"\n [optionDisabled]=\"optionDisabled\"\n [dataKey]=\"dataKey\"\n [group]=\"group\"\n [optionGroupLabel]=\"optionGroupLabel\"\n [optionGroupChildren]=\"optionGroupChildren\"\n [placeholder]=\"effectivePlaceholder\"\n [size]=\"size\"\n [filter]=\"filter\"\n [filterPlaceholder]=\"effectiveFilterPlaceholder\"\n [filterBy]=\"filterBy ?? optionLabel\"\n [autofocusFilter]=\"autofocusFilter\"\n [autofocus]=\"autofocus\"\n [showClear]=\"showClear()\"\n [editable]=\"editable\"\n [disabled]=\"isDisabled()\"\n [appendTo]=\"appendTo\"\n [styleClass]=\"effectiveStyleClass\"\n [panelStyleClass]=\"effectivePanelStyleClass\"\n [scrollHeight]=\"scrollHeight\"\n [virtualScroll]=\"virtualScroll\"\n [virtualScrollItemSize]=\"virtualScrollItemSize\"\n [loading]=\"loading\"\n [emptyMessage]=\"effectiveEmptyMessage\"\n [emptyFilterMessage]=\"effectiveEmptyFilterMessage\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n fluid\n >\n @if (itemTemplate) {\n <ng-template #item let-item>\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item }\" />\n </ng-template>\n }\n @if (selectedItemTemplate) {\n <ng-template #selectedItem let-item>\n <ng-container *ngTemplateOutlet=\"selectedItemTemplate; context: { $implicit: item }\" />\n </ng-template>\n }\n @if (groupTemplate) {\n <ng-template #group let-group>\n <ng-container *ngTemplateOutlet=\"groupTemplate; context: { $implicit: group }\" />\n </ng-template>\n }\n @if (headerTemplate) {\n <ng-template #header>\n <ng-container *ngTemplateOutlet=\"headerTemplate\" />\n </ng-template>\n }\n @if (footerTemplate) {\n <ng-template #footer>\n <ng-container *ngTemplateOutlet=\"footerTemplate\" />\n </ng-template>\n }\n @if (emptyTemplate) {\n <ng-template #empty>\n <ng-container *ngTemplateOutlet=\"emptyTemplate\" />\n </ng-template>\n }\n @if (emptyFilterTemplate) {\n <ng-template #emptyfilter>\n <ng-container *ngTemplateOutlet=\"emptyFilterTemplate\" />\n </ng-template>\n }\n @if (filterTemplate) {\n <ng-template #filter let-options=\"options\">\n <ng-container *ngTemplateOutlet=\"filterTemplate; context: { $implicit: options }\" />\n </ng-template>\n }\n @if (loaderTemplate) {\n <ng-template #loader>\n <ng-container *ngTemplateOutlet=\"loaderTemplate\" />\n </ng-template>\n }\n <ng-template #clearicon>\n <span class=\"es-clear\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\">\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </span>\n </ng-template>\n <ng-template #dropdownicon>\n <svg class=\"ef-chevron\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </ng-template>\n </p-select>\n }\n @if (showRequired || serverErrors) {\n <div [id]=\"errorsId\" role=\"alert\" aria-live=\"polite\">\n @if (showRequired) {\n <small class=\"text-danger\">{{ 'validation.required' | translate }}</small>\n }\n @if (serverErrors; as errors) {\n @for (error of errors; track error) {\n <small class=\"text-danger block\">{{ error }}</small>\n }\n }\n </div>\n }\n</div>\n", styles: [":host{display:block}:host(.ef-inline){display:flex;align-items:baseline;gap:.5rem}:host(.ef-inline)>label{white-space:nowrap;flex-shrink:0}:host(.ef-inline)>.ef-field-control{flex:1;min-width:0}\n"] }]
|
|
1073
1100
|
}], propDecorators: { options: [{
|
|
1074
1101
|
type: Input
|
|
1075
1102
|
}], optionLabel: [{
|
|
@@ -1112,6 +1139,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
1112
1139
|
}], autofocusFilter: [{
|
|
1113
1140
|
type: Input,
|
|
1114
1141
|
args: [{ transform: booleanAttribute }]
|
|
1142
|
+
}], autofocus: [{
|
|
1143
|
+
type: Input,
|
|
1144
|
+
args: [{ transform: booleanAttribute }]
|
|
1115
1145
|
}], editable: [{
|
|
1116
1146
|
type: Input,
|
|
1117
1147
|
args: [{ transform: booleanAttribute }]
|
|
@@ -2705,6 +2735,17 @@ class EfButtonComponent {
|
|
|
2705
2735
|
*/
|
|
2706
2736
|
variant = 'primeng';
|
|
2707
2737
|
severity = 'primary';
|
|
2738
|
+
/**
|
|
2739
|
+
* Control height.
|
|
2740
|
+
*
|
|
2741
|
+
* - `'small'` — `--hit` (32px). Dense rows, toolbars, row actions. Default,
|
|
2742
|
+
* because that is what every call site in the product already renders.
|
|
2743
|
+
* - `'base'` — `--hit-base` (40px). The height a comptoir input, select and
|
|
2744
|
+
* datepicker render at, so this is the one to use for a button sitting in
|
|
2745
|
+
* a form row: at `'small'` it is 8px shorter than the field beside it and
|
|
2746
|
+
* the row reads as misaligned.
|
|
2747
|
+
* - `'large'` — retained alias for `'base'`; nothing in the product uses it.
|
|
2748
|
+
*/
|
|
2708
2749
|
size = 'small';
|
|
2709
2750
|
disabled = false;
|
|
2710
2751
|
rounded = false;
|
|
@@ -2725,6 +2766,34 @@ class EfButtonComponent {
|
|
|
2725
2766
|
* long-press once the label is hidden by responsive CSS. */
|
|
2726
2767
|
tooltipKey;
|
|
2727
2768
|
tooltipPosition = 'top';
|
|
2769
|
+
/**
|
|
2770
|
+
* Take focus on load. Bound explicitly rather than left unset: PrimeNG's
|
|
2771
|
+
* AutoFocus directive tests `autofocus === false`, and the control declares
|
|
2772
|
+
* it with no initialiser, so an unbound instance arrives as `undefined`,
|
|
2773
|
+
* misses that check and has a real `autofocus` attribute written onto it.
|
|
2774
|
+
* Every such control on a page then becomes an autofocus candidate, and the
|
|
2775
|
+
* browser scrolls its container to whichever one it picks on load.
|
|
2776
|
+
*/
|
|
2777
|
+
set autofocus(v) {
|
|
2778
|
+
this._autofocus = v;
|
|
2779
|
+
// Rebuilt rather than an inline object literal in the template: a fresh
|
|
2780
|
+
// object every change-detection pass would re-set the child's input on
|
|
2781
|
+
// every cycle for a value that almost never changes.
|
|
2782
|
+
this.pnButtonProps = { autofocus: v };
|
|
2783
|
+
}
|
|
2784
|
+
get autofocus() {
|
|
2785
|
+
return this._autofocus;
|
|
2786
|
+
}
|
|
2787
|
+
_autofocus = false;
|
|
2788
|
+
/**
|
|
2789
|
+
* PrimeNG's Button resolves its focus flag as
|
|
2790
|
+
* `autofocus || buttonProps?.autofocus`. Passing `false` alone is therefore
|
|
2791
|
+
* not enough: `false || undefined` is `undefined`, which misses the
|
|
2792
|
+
* AutoFocus directive's `=== false` test and writes the attribute anyway.
|
|
2793
|
+
* Supplying the flag through `buttonProps` as well makes the expression
|
|
2794
|
+
* resolve to a real `false`.
|
|
2795
|
+
*/
|
|
2796
|
+
pnButtonProps = { autofocus: false };
|
|
2728
2797
|
/** Resolved tooltip translation key — `tooltipKey` if provided,
|
|
2729
2798
|
* otherwise `labelKey`. Lets responsive icon-only buttons reuse
|
|
2730
2799
|
* their label as the tooltip without restating it at every call
|
|
@@ -2739,12 +2808,21 @@ class EfButtonComponent {
|
|
|
2739
2808
|
return this.tooltip ?? this.label;
|
|
2740
2809
|
}
|
|
2741
2810
|
clickEvent = new EventEmitter();
|
|
2811
|
+
/**
|
|
2812
|
+
* Size as PrimeNG's Button understands it. Its own scale is only
|
|
2813
|
+
* `'small' | 'large'`, with the default (unset) being the normal height, so
|
|
2814
|
+
* `'base'` maps to `null` rather than being forwarded verbatim.
|
|
2815
|
+
*/
|
|
2816
|
+
get pnSize() {
|
|
2817
|
+
return this.size === 'base' ? null : this.size;
|
|
2818
|
+
}
|
|
2742
2819
|
/** Composed class string for the Comptoir variant —
|
|
2743
2820
|
* `btn btn-{severity} btn-sm` plus any caller-supplied `styleClass`. */
|
|
2744
2821
|
get comptoirClass() {
|
|
2745
2822
|
// 'danger' renders as ghost + danger-tint (applied as inline style
|
|
2746
2823
|
// in the template); other severities map directly.
|
|
2747
2824
|
const sevClass = this.severity === 'danger' ? 'btn-ghost' : `btn-${this.severity}`;
|
|
2825
|
+
// 'base' and 'large' both fall through to the bare `.btn`, which is --hit-base.
|
|
2748
2826
|
const sizeClass = this.size === 'small' ? 'btn-sm' : '';
|
|
2749
2827
|
return ['btn', sevClass, sizeClass, this.styleClass ?? '']
|
|
2750
2828
|
.filter(Boolean)
|
|
@@ -2760,11 +2838,11 @@ class EfButtonComponent {
|
|
|
2760
2838
|
this.clickEvent.emit(event);
|
|
2761
2839
|
}
|
|
2762
2840
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2763
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfButtonComponent, isStandalone: true, selector: "ef-button", inputs: { label: "label", labelKey: "labelKey", icon: "icon", variant: "variant", severity: "severity", size: "size", disabled: ["disabled", "disabled", booleanAttribute], rounded: ["rounded", "rounded", booleanAttribute], outlined: ["outlined", "outlined", booleanAttribute], raised: ["raised", "raised", booleanAttribute], text: ["text", "text", booleanAttribute], loading: ["loading", "loading", booleanAttribute], styleClass: "styleClass", type: "type", badge: "badge", badgeSeverity: "badgeSeverity", tooltip: "tooltip", tooltipKey: "tooltipKey", tooltipPosition: "tooltipPosition" }, outputs: { clickEvent: "clickEvent" }, ngImport: i0, template: "@if (variant === 'comptoir') {\n <!-- Comptoir variant \u2014 native button against the `.btn` pattern\n in `@elasticias/ui/styles/patterns`. PrimeNG severities\n (success/info/warn/help/contrast/secondary) fall through to\n this branch only when explicitly passed with variant='comptoir';\n they render as ghost since they have no Comptoir equivalent. -->\n <button\n [type]=\"type\"\n [class]=\"comptoirClass\"\n [disabled]=\"disabled || loading\"\n [style.color]=\"comptoirInlineColor\"\n [pTooltip]=\"effectiveTooltipKey ? (effectiveTooltipKey | translate) : effectiveTooltip\"\n [tooltipPosition]=\"tooltipPosition\"\n (click)=\"handleClick($event)\"\n >\n @if (loading) {\n <i class=\"pi pi-spinner pi-spin\" aria-hidden=\"true\"></i>\n } @else if (icon) {\n <i [class]=\"icon\" aria-hidden=\"true\"></i>\n }\n @if (labelKey || label) {\n <span>{{ labelKey ? (labelKey | translate) : label }}</span>\n }\n </button>\n} @else {\n <!-- PrimeNG variant (default) \u2014 v1 styling via
|
|
2841
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfButtonComponent, isStandalone: true, selector: "ef-button", inputs: { label: "label", labelKey: "labelKey", icon: "icon", variant: "variant", severity: "severity", size: "size", disabled: ["disabled", "disabled", booleanAttribute], rounded: ["rounded", "rounded", booleanAttribute], outlined: ["outlined", "outlined", booleanAttribute], raised: ["raised", "raised", booleanAttribute], text: ["text", "text", booleanAttribute], loading: ["loading", "loading", booleanAttribute], styleClass: "styleClass", type: "type", badge: "badge", badgeSeverity: "badgeSeverity", tooltip: "tooltip", tooltipKey: "tooltipKey", tooltipPosition: "tooltipPosition", autofocus: ["autofocus", "autofocus", booleanAttribute] }, outputs: { clickEvent: "clickEvent" }, ngImport: i0, template: "@if (variant === 'comptoir') {\n <!-- Comptoir variant \u2014 native button against the `.btn` pattern\n in `@elasticias/ui/styles/patterns`. PrimeNG severities\n (success/info/warn/help/contrast/secondary) fall through to\n this branch only when explicitly passed with variant='comptoir';\n they render as ghost since they have no Comptoir equivalent. -->\n <button\n [type]=\"type\"\n [class]=\"comptoirClass\"\n [disabled]=\"disabled || loading\"\n [style.color]=\"comptoirInlineColor\"\n [pTooltip]=\"effectiveTooltipKey ? (effectiveTooltipKey | translate) : effectiveTooltip\"\n [tooltipPosition]=\"tooltipPosition\"\n (click)=\"handleClick($event)\"\n >\n @if (loading) {\n <i class=\"pi pi-spinner pi-spin\" aria-hidden=\"true\"></i>\n } @else if (icon) {\n <i [class]=\"icon\" aria-hidden=\"true\"></i>\n }\n @if (labelKey || label) {\n <span>{{ labelKey ? (labelKey | translate) : label }}</span>\n }\n </button>\n} @else {\n <!-- PrimeNG variant (default) \u2014 v1 styling via p-button. -->\n <p-button\n [autofocus]=\"autofocus\"\n [buttonProps]=\"pnButtonProps\"\n [label]=\"labelKey ? (labelKey | translate) : label\"\n [icon]=\"icon\"\n [severity]=\"$any(severity)\"\n [size]=\"pnSize\"\n [disabled]=\"disabled\"\n [rounded]=\"rounded\"\n [outlined]=\"outlined\"\n [raised]=\"raised\"\n [text]=\"text\"\n [loading]=\"loading\"\n [styleClass]=\"styleClass\"\n [type]=\"type\"\n [badge]=\"badge\"\n [badgeSeverity]=\"badgeSeverity\"\n [pTooltip]=\"effectiveTooltipKey ? (effectiveTooltipKey | translate) : effectiveTooltip\"\n [tooltipPosition]=\"tooltipPosition\"\n (onClick)=\"handleClick($event)\"\n />\n}\n", dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
2764
2842
|
}
|
|
2765
2843
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfButtonComponent, decorators: [{
|
|
2766
2844
|
type: Component,
|
|
2767
|
-
args: [{ selector: 'ef-button', standalone: true, imports: [ButtonModule, TooltipModule, TranslateModule], template: "@if (variant === 'comptoir') {\n <!-- Comptoir variant \u2014 native button against the `.btn` pattern\n in `@elasticias/ui/styles/patterns`. PrimeNG severities\n (success/info/warn/help/contrast/secondary) fall through to\n this branch only when explicitly passed with variant='comptoir';\n they render as ghost since they have no Comptoir equivalent. -->\n <button\n [type]=\"type\"\n [class]=\"comptoirClass\"\n [disabled]=\"disabled || loading\"\n [style.color]=\"comptoirInlineColor\"\n [pTooltip]=\"effectiveTooltipKey ? (effectiveTooltipKey | translate) : effectiveTooltip\"\n [tooltipPosition]=\"tooltipPosition\"\n (click)=\"handleClick($event)\"\n >\n @if (loading) {\n <i class=\"pi pi-spinner pi-spin\" aria-hidden=\"true\"></i>\n } @else if (icon) {\n <i [class]=\"icon\" aria-hidden=\"true\"></i>\n }\n @if (labelKey || label) {\n <span>{{ labelKey ? (labelKey | translate) : label }}</span>\n }\n </button>\n} @else {\n <!-- PrimeNG variant (default) \u2014 v1 styling via
|
|
2845
|
+
args: [{ selector: 'ef-button', standalone: true, imports: [ButtonModule, TooltipModule, TranslateModule], template: "@if (variant === 'comptoir') {\n <!-- Comptoir variant \u2014 native button against the `.btn` pattern\n in `@elasticias/ui/styles/patterns`. PrimeNG severities\n (success/info/warn/help/contrast/secondary) fall through to\n this branch only when explicitly passed with variant='comptoir';\n they render as ghost since they have no Comptoir equivalent. -->\n <button\n [type]=\"type\"\n [class]=\"comptoirClass\"\n [disabled]=\"disabled || loading\"\n [style.color]=\"comptoirInlineColor\"\n [pTooltip]=\"effectiveTooltipKey ? (effectiveTooltipKey | translate) : effectiveTooltip\"\n [tooltipPosition]=\"tooltipPosition\"\n (click)=\"handleClick($event)\"\n >\n @if (loading) {\n <i class=\"pi pi-spinner pi-spin\" aria-hidden=\"true\"></i>\n } @else if (icon) {\n <i [class]=\"icon\" aria-hidden=\"true\"></i>\n }\n @if (labelKey || label) {\n <span>{{ labelKey ? (labelKey | translate) : label }}</span>\n }\n </button>\n} @else {\n <!-- PrimeNG variant (default) \u2014 v1 styling via p-button. -->\n <p-button\n [autofocus]=\"autofocus\"\n [buttonProps]=\"pnButtonProps\"\n [label]=\"labelKey ? (labelKey | translate) : label\"\n [icon]=\"icon\"\n [severity]=\"$any(severity)\"\n [size]=\"pnSize\"\n [disabled]=\"disabled\"\n [rounded]=\"rounded\"\n [outlined]=\"outlined\"\n [raised]=\"raised\"\n [text]=\"text\"\n [loading]=\"loading\"\n [styleClass]=\"styleClass\"\n [type]=\"type\"\n [badge]=\"badge\"\n [badgeSeverity]=\"badgeSeverity\"\n [pTooltip]=\"effectiveTooltipKey ? (effectiveTooltipKey | translate) : effectiveTooltip\"\n [tooltipPosition]=\"tooltipPosition\"\n (onClick)=\"handleClick($event)\"\n />\n}\n" }]
|
|
2768
2846
|
}], propDecorators: { label: [{
|
|
2769
2847
|
type: Input
|
|
2770
2848
|
}], labelKey: [{
|
|
@@ -2809,6 +2887,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
2809
2887
|
type: Input
|
|
2810
2888
|
}], tooltipPosition: [{
|
|
2811
2889
|
type: Input
|
|
2890
|
+
}], autofocus: [{
|
|
2891
|
+
type: Input,
|
|
2892
|
+
args: [{ transform: booleanAttribute }]
|
|
2812
2893
|
}], clickEvent: [{
|
|
2813
2894
|
type: Output
|
|
2814
2895
|
}] } });
|
|
@@ -3335,7 +3416,7 @@ class EfDialogComponent {
|
|
|
3335
3416
|
this.saveAction.emit();
|
|
3336
3417
|
}
|
|
3337
3418
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3338
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfDialogComponent, isStandalone: true, selector: "ef-dialog", inputs: { header: "header", headerKey: "headerKey", subtitle: "subtitle", subtitleKey: "subtitleKey", visible: ["visible", "visible", booleanAttribute], modal: ["modal", "modal", booleanAttribute], closable: ["closable", "closable", booleanAttribute], draggable: ["draggable", "draggable", booleanAttribute], resizable: ["resizable", "resizable", booleanAttribute], dismissableMask: ["dismissableMask", "dismissableMask", booleanAttribute], closeOnEscape: ["closeOnEscape", "closeOnEscape", booleanAttribute], severity: "severity", icon: "icon", size: "size", style: "style", styleClass: "styleClass", position: "position", appendTo: "appendTo", variant: "variant", actions: "actions", defaultActions: ["defaultActions", "defaultActions", booleanAttribute], saveLabelKey: "saveLabelKey", cancelLabelKey: "cancelLabelKey", saveLabel: "saveLabel", cancelLabel: "cancelLabel", saveIcon: "saveIcon", cancelIcon: "cancelIcon", saveDisabled: ["saveDisabled", "saveDisabled", booleanAttribute], saveStyleClass: "saveStyleClass", cancelStyleClass: "cancelStyleClass", saveSeverity: "saveSeverity", cancelSeverity: "cancelSeverity" }, outputs: { visibleChange: "visibleChange", showEvent: "showEvent", hideEvent: "hideEvent", saveAction: "saveAction", cancelAction: "cancelAction", actionClick: "actionClick" }, viewQueries: [{ propertyName: "defaultFooterTpl", first: true, predicate: ["defaultFooter"], descendants: true, static: true }], ngImport: i0, template: "<p-dialog\n [visible]=\"visible\"\n (visibleChange)=\"handleVisibleChange($event)\"\n [modal]=\"modal\"\n [draggable]=\"draggable\"\n [resizable]=\"resizable\"\n [dismissableMask]=\"dismissableMask\"\n [closeOnEscape]=\"closeOnEscape\"\n [style]=\"style\"\n [styleClass]=\"effectiveStyleClass\"\n [position]=\"position\"\n [appendTo]=\"appendTo\"\n [header]=\"variant === 'primeng' ? effectiveTitle : null\"\n [closable]=\"variant === 'primeng' ? closable : false\"\n [footerTemplate]=\"variant === 'primeng' && !useDynamicActions && defaultActions ? defaultFooterTpl : null\"\n (onShow)=\"handleShow()\"\n (onHide)=\"handleHide()\"\n>\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 COMPTOIR HEADER (content-child #header) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Replaces PrimeNG's default header strip with our icon + title\n + subtitle + close X structure. Skipped in 'primeng' variant\n (which uses the [header] string input + native close). -->\n @if (variant === 'comptoir') {\n <ng-template #header>\n @if (effectiveIcon) {\n <span class=\"es-dialog__icon\" aria-hidden=\"true\">\n <i [class]=\"effectiveIcon\"></i>\n </span>\n }\n <div class=\"es-dialog__title-block\">\n <div class=\"es-dialog__title\">{{ effectiveTitle }}</div>\n @if (effectiveSubtitle) {\n <div class=\"es-dialog__sub\">{{ effectiveSubtitle }}</div>\n }\n </div>\n @if (closable) {\n <button\n type=\"button\"\n class=\"es-dialog__close\"\n [attr.aria-label]=\"'common_close' | translate\"\n (click)=\"handleVisibleChange(false)\"\n >\n <i class=\"pi pi-times\"></i>\n </button>\n }\n </ng-template>\n }\n\n <!-- Body \u2014 projected from <ef-dialog>\u2026</ef-dialog> -->\n <ng-content />\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 COMPTOIR FOOTER (content-child #footer) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Dynamic [actions] path takes precedence; falls back to the\n backward-compat save+cancel pair when defaultActions is on. -->\n @if (variant === 'comptoir' && hasFooter) {\n <ng-template #footer>\n @if (useDynamicActions) {\n @for (a of actions; track $index) {\n <button\n type=\"button\"\n [class]=\"actionClass(a)\"\n [disabled]=\"a.disabled || a.loading\"\n (click)=\"handleActionClick(a, $index)\"\n >\n @if (a.icon) {\n <i [class]=\"a.icon\"></i>\n }\n {{ actionLabel(a) }}\n </button>\n }\n } @else {\n <ef-button\n variant=\"comptoir\"\n [severity]=\"cancelSeverity\"\n [labelKey]=\"cancelLabelKey\"\n [label]=\"cancelLabel\"\n [icon]=\"cancelIcon\"\n [styleClass]=\"cancelStyleClass\"\n (clickEvent)=\"onDefaultCancel()\"\n />\n <ef-button\n variant=\"comptoir\"\n [severity]=\"saveSeverity\"\n [labelKey]=\"saveLabelKey\"\n [label]=\"saveLabel\"\n [icon]=\"saveIcon\"\n [styleClass]=\"saveStyleClass\"\n [disabled]=\"saveDisabled\"\n (clickEvent)=\"onDefaultSave()\"\n />\n }\n </ng-template>\n }\n</p-dialog>\n\n<!-- Default-action footer template for the 'primeng' variant (legacy path).\n Declared outside <p-dialog> because the comptoir branch above already\n provides its own content-child footer; this template is only consumed\n when variant === 'primeng' via [footerTemplate] input binding. -->\n<ng-template #defaultFooter>\n <ef-button\n variant=\"primeng\"\n [severity]=\"cancelSeverity\"\n [labelKey]=\"cancelLabelKey\"\n [label]=\"cancelLabel\"\n [icon]=\"cancelIcon\"\n [styleClass]=\"cancelStyleClass\"\n (clickEvent)=\"onDefaultCancel()\"\n />\n <ef-button\n variant=\"primeng\"\n [severity]=\"saveSeverity\"\n [labelKey]=\"saveLabelKey\"\n [label]=\"saveLabel\"\n [icon]=\"saveIcon\"\n [styleClass]=\"saveStyleClass\"\n [disabled]=\"saveDisabled\"\n (clickEvent)=\"onDefaultSave()\"\n />\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i1$6.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfButtonComponent, selector: "ef-button", inputs: ["label", "labelKey", "icon", "variant", "severity", "size", "disabled", "rounded", "outlined", "raised", "text", "loading", "styleClass", "type", "badge", "badgeSeverity", "tooltip", "tooltipKey", "tooltipPosition"], outputs: ["clickEvent"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
3419
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfDialogComponent, isStandalone: true, selector: "ef-dialog", inputs: { header: "header", headerKey: "headerKey", subtitle: "subtitle", subtitleKey: "subtitleKey", visible: ["visible", "visible", booleanAttribute], modal: ["modal", "modal", booleanAttribute], closable: ["closable", "closable", booleanAttribute], draggable: ["draggable", "draggable", booleanAttribute], resizable: ["resizable", "resizable", booleanAttribute], dismissableMask: ["dismissableMask", "dismissableMask", booleanAttribute], closeOnEscape: ["closeOnEscape", "closeOnEscape", booleanAttribute], severity: "severity", icon: "icon", size: "size", style: "style", styleClass: "styleClass", position: "position", appendTo: "appendTo", variant: "variant", actions: "actions", defaultActions: ["defaultActions", "defaultActions", booleanAttribute], saveLabelKey: "saveLabelKey", cancelLabelKey: "cancelLabelKey", saveLabel: "saveLabel", cancelLabel: "cancelLabel", saveIcon: "saveIcon", cancelIcon: "cancelIcon", saveDisabled: ["saveDisabled", "saveDisabled", booleanAttribute], saveStyleClass: "saveStyleClass", cancelStyleClass: "cancelStyleClass", saveSeverity: "saveSeverity", cancelSeverity: "cancelSeverity" }, outputs: { visibleChange: "visibleChange", showEvent: "showEvent", hideEvent: "hideEvent", saveAction: "saveAction", cancelAction: "cancelAction", actionClick: "actionClick" }, viewQueries: [{ propertyName: "defaultFooterTpl", first: true, predicate: ["defaultFooter"], descendants: true, static: true }], ngImport: i0, template: "<p-dialog\n [visible]=\"visible\"\n (visibleChange)=\"handleVisibleChange($event)\"\n [modal]=\"modal\"\n [draggable]=\"draggable\"\n [resizable]=\"resizable\"\n [dismissableMask]=\"dismissableMask\"\n [closeOnEscape]=\"closeOnEscape\"\n [style]=\"style\"\n [styleClass]=\"effectiveStyleClass\"\n [position]=\"position\"\n [appendTo]=\"appendTo\"\n [header]=\"variant === 'primeng' ? effectiveTitle : null\"\n [closable]=\"variant === 'primeng' ? closable : false\"\n [footerTemplate]=\"variant === 'primeng' && !useDynamicActions && defaultActions ? defaultFooterTpl : null\"\n (onShow)=\"handleShow()\"\n (onHide)=\"handleHide()\"\n>\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 COMPTOIR HEADER (content-child #header) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Replaces PrimeNG's default header strip with our icon + title\n + subtitle + close X structure. Skipped in 'primeng' variant\n (which uses the [header] string input + native close). -->\n @if (variant === 'comptoir') {\n <ng-template #header>\n @if (effectiveIcon) {\n <span class=\"es-dialog__icon\" aria-hidden=\"true\">\n <i [class]=\"effectiveIcon\"></i>\n </span>\n }\n <div class=\"es-dialog__title-block\">\n <div class=\"es-dialog__title\">{{ effectiveTitle }}</div>\n @if (effectiveSubtitle) {\n <div class=\"es-dialog__sub\">{{ effectiveSubtitle }}</div>\n }\n </div>\n @if (closable) {\n <button\n type=\"button\"\n class=\"es-dialog__close\"\n [attr.aria-label]=\"'common_close' | translate\"\n (click)=\"handleVisibleChange(false)\"\n >\n <i class=\"pi pi-times\"></i>\n </button>\n }\n </ng-template>\n }\n\n <!-- Body \u2014 projected from <ef-dialog>\u2026</ef-dialog> -->\n <ng-content />\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 COMPTOIR FOOTER (content-child #footer) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Dynamic [actions] path takes precedence; falls back to the\n backward-compat save+cancel pair when defaultActions is on. -->\n @if (variant === 'comptoir' && hasFooter) {\n <ng-template #footer>\n @if (useDynamicActions) {\n @for (a of actions; track $index) {\n <button\n type=\"button\"\n [class]=\"actionClass(a)\"\n [disabled]=\"a.disabled || a.loading\"\n (click)=\"handleActionClick(a, $index)\"\n >\n @if (a.icon) {\n <i [class]=\"a.icon\"></i>\n }\n {{ actionLabel(a) }}\n </button>\n }\n } @else {\n <ef-button\n variant=\"comptoir\"\n [severity]=\"cancelSeverity\"\n [labelKey]=\"cancelLabelKey\"\n [label]=\"cancelLabel\"\n [icon]=\"cancelIcon\"\n [styleClass]=\"cancelStyleClass\"\n (clickEvent)=\"onDefaultCancel()\"\n />\n <ef-button\n variant=\"comptoir\"\n [severity]=\"saveSeverity\"\n [labelKey]=\"saveLabelKey\"\n [label]=\"saveLabel\"\n [icon]=\"saveIcon\"\n [styleClass]=\"saveStyleClass\"\n [disabled]=\"saveDisabled\"\n (clickEvent)=\"onDefaultSave()\"\n />\n }\n </ng-template>\n }\n</p-dialog>\n\n<!-- Default-action footer template for the 'primeng' variant (legacy path).\n Declared outside <p-dialog> because the comptoir branch above already\n provides its own content-child footer; this template is only consumed\n when variant === 'primeng' via [footerTemplate] input binding. -->\n<ng-template #defaultFooter>\n <ef-button\n variant=\"primeng\"\n [severity]=\"cancelSeverity\"\n [labelKey]=\"cancelLabelKey\"\n [label]=\"cancelLabel\"\n [icon]=\"cancelIcon\"\n [styleClass]=\"cancelStyleClass\"\n (clickEvent)=\"onDefaultCancel()\"\n />\n <ef-button\n variant=\"primeng\"\n [severity]=\"saveSeverity\"\n [labelKey]=\"saveLabelKey\"\n [label]=\"saveLabel\"\n [icon]=\"saveIcon\"\n [styleClass]=\"saveStyleClass\"\n [disabled]=\"saveDisabled\"\n (clickEvent)=\"onDefaultSave()\"\n />\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i1$6.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfButtonComponent, selector: "ef-button", inputs: ["label", "labelKey", "icon", "variant", "severity", "size", "disabled", "rounded", "outlined", "raised", "text", "loading", "styleClass", "type", "badge", "badgeSeverity", "tooltip", "tooltipKey", "tooltipPosition", "autofocus"], outputs: ["clickEvent"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
3339
3420
|
}
|
|
3340
3421
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfDialogComponent, decorators: [{
|
|
3341
3422
|
type: Component,
|
|
@@ -3531,7 +3612,7 @@ class EfChangeHistoryComponent {
|
|
|
3531
3612
|
return `${pad(d.getDate())}/${pad(d.getMonth() + 1)}/${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
|
3532
3613
|
}
|
|
3533
3614
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfChangeHistoryComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3534
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfChangeHistoryComponent, isStandalone: true, selector: "ef-change-history", inputs: { entries: { classPropertyName: "entries", publicName: "entries", isSignal: true, isRequired: false, transformFunction: null }, titleKey: { classPropertyName: "titleKey", publicName: "titleKey", isSignal: true, isRequired: false, transformFunction: null }, emptyKey: { classPropertyName: "emptyKey", publicName: "emptyKey", isSignal: true, isRequired: false, transformFunction: null }, limit: { classPropertyName: "limit", publicName: "limit", isSignal: true, isRequired: false, transformFunction: null }, previewLimit: { classPropertyName: "previewLimit", publicName: "previewLimit", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, startCollapsed: { classPropertyName: "startCollapsed", publicName: "startCollapsed", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ef-card\n [titleKey]=\"titleKey()\"\n [collapsible]=\"collapsible()\"\n [collapsed]=\"startCollapsed()\"\n>\n <ng-container head-extra>\n @if (hasMore()) {\n <ef-button\n variant=\"comptoir\"\n severity=\"ghost\"\n size=\"small\"\n icon=\"pi pi-window-maximize\"\n tooltipKey=\"audit_view_all\"\n (clickEvent)=\"openDialog($event)\"\n />\n }\n </ng-container>\n\n <ng-container\n *ngTemplateOutlet=\"timeline; context: { $implicit: previewRows(), compact: true }\"\n ></ng-container>\n\n @if (hasMore()) {\n <button type=\"button\" class=\"ch-more\" (click)=\"openDialog()\">\n {{ 'audit_view_all' | translate }} ({{ rows().length }})\n </button>\n }\n</ef-card>\n\n<!-- \"Show more\" dialog \u2014 full timeline, roomy + scrollable -->\n<ef-dialog\n [visible]=\"dialogVisible()\"\n (visibleChange)=\"dialogVisible.set($event)\"\n [headerKey]=\"titleKey()\"\n [defaultActions]=\"false\"\n size=\"lg\"\n [modal]=\"true\"\n position=\"center\"\n>\n <ng-container\n *ngTemplateOutlet=\"timeline; context: { $implicit: rows(), compact: false }\"\n ></ng-container>\n</ef-dialog>\n\n<ng-template #timeline let-items let-compact=\"compact\">\n @if (items.length === 0) {\n <p class=\"text-mute small\">{{ emptyKey() | translate }}</p>\n } @else {\n <div class=\"timeline\" [class.timeline--compact]=\"compact\">\n @for (row of items; track $index) {\n <div class=\"item\">\n <span class=\"dot\" [class]=\"row.meta.cls\" aria-hidden=\"true\"></span>\n <div class=\"body\">\n <div class=\"label\">{{ row.operationLabel }}</div>\n <div class=\"meta\">\n @if (row.entry.userName) {\n <span class=\"strong\">{{ row.entry.userName }}</span> \u00B7\n }\n {{ formatWhen(row.entry.occurredAt) }}\n </div>\n\n @if (row.entry.operation === 'status_changed' && (row.entry.fromStatus || row.entry.toStatus)) {\n <div class=\"ch-status small\">\n <span class=\"text-mute\">{{ row.entry.fromStatus || '\u2014' }}</span>\n <i class=\"pi pi-arrow-right\"></i>\n <span class=\"strong\">{{ row.entry.toStatus || '\u2014' }}</span>\n </div>\n }\n\n @if (row.entry.changes?.length) {\n <ul class=\"ch-changes small\">\n @for (c of row.entry.changes; track c.field) {\n <li>\n <span class=\"ch-field\">{{ fieldLabel(c.field) }}</span>\n <span class=\"text-mute\">{{ c.oldValue || '\u2014' }}</span>\n <i class=\"pi pi-arrow-right\"></i>\n <span class=\"strong\">{{ c.newValue || '\u2014' }}</span>\n </li>\n }\n </ul>\n }\n\n @if (row.entry.note) {\n <div class=\"ch-note small\">{{ row.entry.note }}</div>\n }\n </div>\n </div>\n }\n </div>\n }\n</ng-template>\n", styles: [":host{display:block}.dot.op-created{background:var(--st-delivered-fg, #16a34a);border-color:var(--st-delivered-fg, #16a34a)}.dot.op-updated{background:#2563eb;border-color:#2563eb}.dot.op-status{background:#f59e0b;border-color:#f59e0b}.dot.op-deleted{background:#dc2626;border-color:#dc2626}.dot.op-note{background:#64748b;border-color:#64748b}.dot.op-default{background:var(--ink-300, #94a3b8);border-color:var(--ink-300, #94a3b8)}.ch-status{display:flex;align-items:center;gap:6px;margin-top:4px}.item .body{min-width:0}.ch-changes{list-style:none;padding:0;margin:4px 0 0}.ch-changes li{display:flex;align-items:center;gap:6px;padding:1px 0;min-width:0}.ch-field{font-weight:600;min-width:120px}.timeline--compact .ch-changes .ch-field{flex:0 0 auto}.timeline--compact .ch-changes .text-mute,.timeline--compact .ch-changes .strong{flex:1 1 0;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.timeline:not(.timeline--compact) .ch-changes li{flex-wrap:wrap}.timeline:not(.timeline--compact) .ch-changes .text-mute,.timeline:not(.timeline--compact) .ch-changes .strong{overflow-wrap:anywhere}.ch-changes .pi,.ch-status .pi{font-size:10px;opacity:.6}.ch-note{margin-top:4px;padding-left:8px;border-left:2px solid var(--rule-soft, #e2e8f0);color:var(--ink-600, #475569)}.ch-more{margin-top:8px;border:0;background:transparent;cursor:pointer;padding:2px 0;font-size:12px;font-weight:600;color:var(--module, #2563eb)}.ch-more:hover{text-decoration:underline}:host-context([dir=rtl]) .ch-changes .pi-arrow-right,:host-context([dir=rtl]) .ch-status .pi-arrow-right{transform:scaleX(-1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfCardComponent, selector: "ef-card", inputs: ["titleKey", "title", "metaKey", "meta", "tone", "forceHead", "hasFoot", "collapsible", "overflowVisible", "loading", "skeleton", "skeletonRows", "skeletonHeight", "collapsed"], outputs: ["collapsedChange"] }, { kind: "component", type: EfDialogComponent, selector: "ef-dialog", inputs: ["header", "headerKey", "subtitle", "subtitleKey", "visible", "modal", "closable", "draggable", "resizable", "dismissableMask", "closeOnEscape", "severity", "icon", "size", "style", "styleClass", "position", "appendTo", "variant", "actions", "defaultActions", "saveLabelKey", "cancelLabelKey", "saveLabel", "cancelLabel", "saveIcon", "cancelIcon", "saveDisabled", "saveStyleClass", "cancelStyleClass", "saveSeverity", "cancelSeverity"], outputs: ["visibleChange", "showEvent", "hideEvent", "saveAction", "cancelAction", "actionClick"] }, { kind: "component", type: EfButtonComponent, selector: "ef-button", inputs: ["label", "labelKey", "icon", "variant", "severity", "size", "disabled", "rounded", "outlined", "raised", "text", "loading", "styleClass", "type", "badge", "badgeSeverity", "tooltip", "tooltipKey", "tooltipPosition"], outputs: ["clickEvent"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3615
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfChangeHistoryComponent, isStandalone: true, selector: "ef-change-history", inputs: { entries: { classPropertyName: "entries", publicName: "entries", isSignal: true, isRequired: false, transformFunction: null }, titleKey: { classPropertyName: "titleKey", publicName: "titleKey", isSignal: true, isRequired: false, transformFunction: null }, emptyKey: { classPropertyName: "emptyKey", publicName: "emptyKey", isSignal: true, isRequired: false, transformFunction: null }, limit: { classPropertyName: "limit", publicName: "limit", isSignal: true, isRequired: false, transformFunction: null }, previewLimit: { classPropertyName: "previewLimit", publicName: "previewLimit", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, startCollapsed: { classPropertyName: "startCollapsed", publicName: "startCollapsed", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ef-card\n [titleKey]=\"titleKey()\"\n [collapsible]=\"collapsible()\"\n [collapsed]=\"startCollapsed()\"\n>\n <ng-container head-extra>\n @if (hasMore()) {\n <ef-button\n variant=\"comptoir\"\n severity=\"ghost\"\n size=\"small\"\n icon=\"pi pi-window-maximize\"\n tooltipKey=\"audit_view_all\"\n (clickEvent)=\"openDialog($event)\"\n />\n }\n </ng-container>\n\n <ng-container\n *ngTemplateOutlet=\"timeline; context: { $implicit: previewRows(), compact: true }\"\n ></ng-container>\n\n @if (hasMore()) {\n <button type=\"button\" class=\"ch-more\" (click)=\"openDialog()\">\n {{ 'audit_view_all' | translate }} ({{ rows().length }})\n </button>\n }\n</ef-card>\n\n<!-- \"Show more\" dialog \u2014 full timeline, roomy + scrollable -->\n<ef-dialog\n [visible]=\"dialogVisible()\"\n (visibleChange)=\"dialogVisible.set($event)\"\n [headerKey]=\"titleKey()\"\n [defaultActions]=\"false\"\n size=\"lg\"\n [modal]=\"true\"\n position=\"center\"\n>\n <ng-container\n *ngTemplateOutlet=\"timeline; context: { $implicit: rows(), compact: false }\"\n ></ng-container>\n</ef-dialog>\n\n<ng-template #timeline let-items let-compact=\"compact\">\n @if (items.length === 0) {\n <p class=\"text-mute small\">{{ emptyKey() | translate }}</p>\n } @else {\n <div class=\"timeline\" [class.timeline--compact]=\"compact\">\n @for (row of items; track $index) {\n <div class=\"item\">\n <span class=\"dot\" [class]=\"row.meta.cls\" aria-hidden=\"true\"></span>\n <div class=\"body\">\n <div class=\"label\">{{ row.operationLabel }}</div>\n <div class=\"meta\">\n @if (row.entry.userName) {\n <span class=\"strong\">{{ row.entry.userName }}</span> \u00B7\n }\n {{ formatWhen(row.entry.occurredAt) }}\n </div>\n\n @if (row.entry.operation === 'status_changed' && (row.entry.fromStatus || row.entry.toStatus)) {\n <div class=\"ch-status small\">\n <span class=\"text-mute\">{{ row.entry.fromStatus || '\u2014' }}</span>\n <i class=\"pi pi-arrow-right\"></i>\n <span class=\"strong\">{{ row.entry.toStatus || '\u2014' }}</span>\n </div>\n }\n\n @if (row.entry.changes?.length) {\n <ul class=\"ch-changes small\">\n @for (c of row.entry.changes; track c.field) {\n <li>\n <span class=\"ch-field\">{{ fieldLabel(c.field) }}</span>\n <span class=\"text-mute\">{{ c.oldValue || '\u2014' }}</span>\n <i class=\"pi pi-arrow-right\"></i>\n <span class=\"strong\">{{ c.newValue || '\u2014' }}</span>\n </li>\n }\n </ul>\n }\n\n @if (row.entry.note) {\n <div class=\"ch-note small\">{{ row.entry.note }}</div>\n }\n </div>\n </div>\n }\n </div>\n }\n</ng-template>\n", styles: [":host{display:block}.dot.op-created{background:var(--st-delivered-fg, #16a34a);border-color:var(--st-delivered-fg, #16a34a)}.dot.op-updated{background:#2563eb;border-color:#2563eb}.dot.op-status{background:#f59e0b;border-color:#f59e0b}.dot.op-deleted{background:#dc2626;border-color:#dc2626}.dot.op-note{background:#64748b;border-color:#64748b}.dot.op-default{background:var(--ink-300, #94a3b8);border-color:var(--ink-300, #94a3b8)}.ch-status{display:flex;align-items:center;gap:6px;margin-top:4px}.item .body{min-width:0}.ch-changes{list-style:none;padding:0;margin:4px 0 0}.ch-changes li{display:flex;align-items:center;gap:6px;padding:1px 0;min-width:0}.ch-field{font-weight:600;min-width:120px}.timeline--compact .ch-changes .ch-field{flex:0 0 auto}.timeline--compact .ch-changes .text-mute,.timeline--compact .ch-changes .strong{flex:1 1 0;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.timeline:not(.timeline--compact) .ch-changes li{flex-wrap:wrap}.timeline:not(.timeline--compact) .ch-changes .text-mute,.timeline:not(.timeline--compact) .ch-changes .strong{overflow-wrap:anywhere}.ch-changes .pi,.ch-status .pi{font-size:10px;opacity:.6}.ch-note{margin-top:4px;padding-left:8px;border-left:2px solid var(--rule-soft, #e2e8f0);color:var(--ink-600, #475569)}.ch-more{margin-top:8px;border:0;background:transparent;cursor:pointer;padding:2px 0;font-size:12px;font-weight:600;color:var(--module, #2563eb)}.ch-more:hover{text-decoration:underline}:host-context([dir=rtl]) .ch-changes .pi-arrow-right,:host-context([dir=rtl]) .ch-status .pi-arrow-right{transform:scaleX(-1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfCardComponent, selector: "ef-card", inputs: ["titleKey", "title", "metaKey", "meta", "tone", "forceHead", "hasFoot", "collapsible", "overflowVisible", "loading", "skeleton", "skeletonRows", "skeletonHeight", "collapsed"], outputs: ["collapsedChange"] }, { kind: "component", type: EfDialogComponent, selector: "ef-dialog", inputs: ["header", "headerKey", "subtitle", "subtitleKey", "visible", "modal", "closable", "draggable", "resizable", "dismissableMask", "closeOnEscape", "severity", "icon", "size", "style", "styleClass", "position", "appendTo", "variant", "actions", "defaultActions", "saveLabelKey", "cancelLabelKey", "saveLabel", "cancelLabel", "saveIcon", "cancelIcon", "saveDisabled", "saveStyleClass", "cancelStyleClass", "saveSeverity", "cancelSeverity"], outputs: ["visibleChange", "showEvent", "hideEvent", "saveAction", "cancelAction", "actionClick"] }, { kind: "component", type: EfButtonComponent, selector: "ef-button", inputs: ["label", "labelKey", "icon", "variant", "severity", "size", "disabled", "rounded", "outlined", "raised", "text", "loading", "styleClass", "type", "badge", "badgeSeverity", "tooltip", "tooltipKey", "tooltipPosition", "autofocus"], outputs: ["clickEvent"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3535
3616
|
}
|
|
3536
3617
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfChangeHistoryComponent, decorators: [{
|
|
3537
3618
|
type: Component,
|
|
@@ -3828,7 +3909,7 @@ class EfPagerComponent {
|
|
|
3828
3909
|
return btn.kind === 'page' ? `p${btn.value}` : `e${index}`;
|
|
3829
3910
|
}
|
|
3830
3911
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfPagerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3831
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfPagerComponent, isStandalone: true, selector: "ef-pager", inputs: { pageNumber: { classPropertyName: "pageNumber", publicName: "pageNumber", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, totalCount: { classPropertyName: "totalCount", publicName: "totalCount", isSignal: true, isRequired: false, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, linesPerPageLabelKey: { classPropertyName: "linesPerPageLabelKey", publicName: "linesPerPageLabelKey", isSignal: true, isRequired: false, transformFunction: null }, ofLabelKey: { classPropertyName: "ofLabelKey", publicName: "ofLabelKey", isSignal: true, isRequired: false, transformFunction: null }, prevLabelKey: { classPropertyName: "prevLabelKey", publicName: "prevLabelKey", isSignal: true, isRequired: false, transformFunction: null }, nextLabelKey: { classPropertyName: "nextLabelKey", publicName: "nextLabelKey", isSignal: true, isRequired: false, transformFunction: null }, hideSize: { classPropertyName: "hideSize", publicName: "hideSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageChange: "pageChange", pageSizeChange: "pageSizeChange" }, ngImport: i0, template: "<div class=\"pager\">\n @if (!hideSize()) {\n <div class=\"size\">\n <span>{{ linesPerPageLabelKey() | translate }}</span>\n <ef-select\n size=\"small\"\n appendTo=\"body\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [options]=\"sizeOptions()\"\n [value]=\"pageSize()\"\n [ariaLabelKey]=\"linesPerPageLabelKey()\"\n [showClear]=\"false\"\n (selectionChangeEvent)=\"onSizeChange($event)\"\n />\n @if (totalCount() > 0) {\n <span>\u00B7 {{ range().start }}\u2013{{ range().end }} {{ ofLabelKey() | translate }} {{ totalCount() }}</span>\n }\n </div>\n } @else {\n <span></span>\n }\n\n <div class=\"pages\">\n <button\n class=\"pg\"\n type=\"button\"\n [disabled]=\"pageNumber() <= 1\"\n [attr.aria-label]=\"prevLabelKey() | translate\"\n (click)=\"goToPage(pageNumber() - 1)\"\n >\u2039</button>\n\n @for (btn of pageButtons(); track trackBtn($index, btn)) {\n @if (btn.kind === 'page') {\n <button\n class=\"pg\"\n type=\"button\"\n [class.active]=\"btn.value === pageNumber()\"\n (click)=\"goToPage(btn.value)\"\n >{{ btn.value }}</button>\n } @else {\n <span class=\"pg\" aria-hidden=\"true\" style=\"cursor: default;\">\u2026</span>\n }\n }\n\n <button\n class=\"pg\"\n type=\"button\"\n [disabled]=\"pageNumber() >= totalPages()\"\n [attr.aria-label]=\"nextLabelKey() | translate\"\n (click)=\"goToPage(pageNumber() + 1)\"\n >\u203A</button>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfSelectComponent, selector: "ef-select", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "dataKey", "group", "optionGroupLabel", "optionGroupChildren", "size", "fluid", "inline", "appendTo", "multiple", "filter", "filterBy", "filterPlaceholder", "filterPlaceholderKey", "autofocusFilter", "editable", "loading", "virtualScroll", "virtualScrollItemSize", "scrollHeight", "multiDisplay", "showToggleAll", "emptyMessage", "emptyMessageKey", "emptyFilterMessage", "emptyFilterMessageKey", "styleClass", "panelStyleClass", "filterByKeys", "variant", "value"], outputs: ["selectionChangeEvent", "filterChangeEvent", "panelShowEvent", "panelHideEvent"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3912
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfPagerComponent, isStandalone: true, selector: "ef-pager", inputs: { pageNumber: { classPropertyName: "pageNumber", publicName: "pageNumber", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, totalCount: { classPropertyName: "totalCount", publicName: "totalCount", isSignal: true, isRequired: false, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, linesPerPageLabelKey: { classPropertyName: "linesPerPageLabelKey", publicName: "linesPerPageLabelKey", isSignal: true, isRequired: false, transformFunction: null }, ofLabelKey: { classPropertyName: "ofLabelKey", publicName: "ofLabelKey", isSignal: true, isRequired: false, transformFunction: null }, prevLabelKey: { classPropertyName: "prevLabelKey", publicName: "prevLabelKey", isSignal: true, isRequired: false, transformFunction: null }, nextLabelKey: { classPropertyName: "nextLabelKey", publicName: "nextLabelKey", isSignal: true, isRequired: false, transformFunction: null }, hideSize: { classPropertyName: "hideSize", publicName: "hideSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageChange: "pageChange", pageSizeChange: "pageSizeChange" }, ngImport: i0, template: "<div class=\"pager\">\n @if (!hideSize()) {\n <div class=\"size\">\n <span>{{ linesPerPageLabelKey() | translate }}</span>\n <ef-select\n size=\"small\"\n appendTo=\"body\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [options]=\"sizeOptions()\"\n [value]=\"pageSize()\"\n [ariaLabelKey]=\"linesPerPageLabelKey()\"\n [showClear]=\"false\"\n (selectionChangeEvent)=\"onSizeChange($event)\"\n />\n @if (totalCount() > 0) {\n <span>\u00B7 {{ range().start }}\u2013{{ range().end }} {{ ofLabelKey() | translate }} {{ totalCount() }}</span>\n }\n </div>\n } @else {\n <span></span>\n }\n\n <div class=\"pages\">\n <button\n class=\"pg\"\n type=\"button\"\n [disabled]=\"pageNumber() <= 1\"\n [attr.aria-label]=\"prevLabelKey() | translate\"\n (click)=\"goToPage(pageNumber() - 1)\"\n >\u2039</button>\n\n @for (btn of pageButtons(); track trackBtn($index, btn)) {\n @if (btn.kind === 'page') {\n <button\n class=\"pg\"\n type=\"button\"\n [class.active]=\"btn.value === pageNumber()\"\n (click)=\"goToPage(btn.value)\"\n >{{ btn.value }}</button>\n } @else {\n <span class=\"pg\" aria-hidden=\"true\" style=\"cursor: default;\">\u2026</span>\n }\n }\n\n <button\n class=\"pg\"\n type=\"button\"\n [disabled]=\"pageNumber() >= totalPages()\"\n [attr.aria-label]=\"nextLabelKey() | translate\"\n (click)=\"goToPage(pageNumber() + 1)\"\n >\u203A</button>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfSelectComponent, selector: "ef-select", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "dataKey", "group", "optionGroupLabel", "optionGroupChildren", "size", "fluid", "inline", "appendTo", "multiple", "filter", "filterBy", "filterPlaceholder", "filterPlaceholderKey", "autofocusFilter", "autofocus", "editable", "loading", "virtualScroll", "virtualScrollItemSize", "scrollHeight", "multiDisplay", "showToggleAll", "emptyMessage", "emptyMessageKey", "emptyFilterMessage", "emptyFilterMessageKey", "styleClass", "panelStyleClass", "filterByKeys", "variant", "value"], outputs: ["selectionChangeEvent", "filterChangeEvent", "panelShowEvent", "panelHideEvent"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3832
3913
|
}
|
|
3833
3914
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfPagerComponent, decorators: [{
|
|
3834
3915
|
type: Component,
|
|
@@ -4876,6 +4957,21 @@ class EfDataCardComponent {
|
|
|
4876
4957
|
ev.preventDefault();
|
|
4877
4958
|
this.rowReorder.emit({ from: index, to });
|
|
4878
4959
|
}
|
|
4960
|
+
/**
|
|
4961
|
+
* Honour the declared column widths exactly instead of treating them as
|
|
4962
|
+
* hints.
|
|
4963
|
+
*
|
|
4964
|
+
* The default `table-layout: auto` sizes a column to its content, so a
|
|
4965
|
+
* cell whose content is wider than the declared width simply wins. On the
|
|
4966
|
+
* order builder that meant clicking into a 116px discount cell swapped in
|
|
4967
|
+
* an editor whose input carries an intrinsic 200px, the column jumped to
|
|
4968
|
+
* 271px, and the article column lost the difference — every row re-flowed
|
|
4969
|
+
* mid-edit. With fixed layout the declared widths hold and the columns
|
|
4970
|
+
* that declare none share what is left.
|
|
4971
|
+
*
|
|
4972
|
+
* Opt-in: a table whose columns are all content-sized still wants `auto`.
|
|
4973
|
+
*/
|
|
4974
|
+
fixedLayout = input(false, { ...(ngDevMode ? { debugName: "fixedLayout" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
4879
4975
|
/** Row density. Applied as a class on `.tbl-wrap`. */
|
|
4880
4976
|
density = signal('default', ...(ngDevMode ? [{ debugName: "density" }] : /* istanbul ignore next */ []));
|
|
4881
4977
|
/** Column ids the viewer has hidden. */
|
|
@@ -5061,7 +5157,7 @@ class EfDataCardComponent {
|
|
|
5061
5157
|
};
|
|
5062
5158
|
trackByColumn = (_, col) => col.id;
|
|
5063
5159
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfDataCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5064
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfDataCardComponent, isStandalone: true, selector: "ef-data-card", inputs: { mobileLayout: { classPropertyName: "mobileLayout", publicName: "mobileLayout", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, trackByField: { classPropertyName: "trackByField", publicName: "trackByField", isSignal: true, isRequired: false, transformFunction: null }, pageNumber: { classPropertyName: "pageNumber", publicName: "pageNumber", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, totalCount: { classPropertyName: "totalCount", publicName: "totalCount", isSignal: true, isRequired: false, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, hidePager: { classPropertyName: "hidePager", publicName: "hidePager", isSignal: true, isRequired: false, transformFunction: null }, sort: { classPropertyName: "sort", publicName: "sort", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, errorMsg: { classPropertyName: "errorMsg", publicName: "errorMsg", isSignal: true, isRequired: false, transformFunction: null }, loadingKey: { classPropertyName: "loadingKey", publicName: "loadingKey", isSignal: true, isRequired: false, transformFunction: null }, rowDoubleClickable: { classPropertyName: "rowDoubleClickable", publicName: "rowDoubleClickable", isSignal: true, isRequired: false, transformFunction: null }, hasActionsColumn: { classPropertyName: "hasActionsColumn", publicName: "hasActionsColumn", isSignal: true, isRequired: false, transformFunction: null }, rowActionsContext: { classPropertyName: "rowActionsContext", publicName: "rowActionsContext", isSignal: true, isRequired: false, transformFunction: null }, showViewAction: { classPropertyName: "showViewAction", publicName: "showViewAction", isSignal: true, isRequired: false, transformFunction: null }, showEditAction: { classPropertyName: "showEditAction", publicName: "showEditAction", isSignal: true, isRequired: false, transformFunction: null }, showDuplicateAction: { classPropertyName: "showDuplicateAction", publicName: "showDuplicateAction", isSignal: true, isRequired: false, transformFunction: null }, showDeleteAction: { classPropertyName: "showDeleteAction", publicName: "showDeleteAction", isSignal: true, isRequired: false, transformFunction: null }, showDensityControl: { classPropertyName: "showDensityControl", publicName: "showDensityControl", isSignal: true, isRequired: false, transformFunction: null }, showColumnPicker: { classPropertyName: "showColumnPicker", publicName: "showColumnPicker", isSignal: true, isRequired: false, transformFunction: null }, showExportControl: { classPropertyName: "showExportControl", publicName: "showExportControl", isSignal: true, isRequired: false, transformFunction: null }, exporting: { classPropertyName: "exporting", publicName: "exporting", isSignal: true, isRequired: false, transformFunction: null }, screenContext: { classPropertyName: "screenContext", publicName: "screenContext", isSignal: true, isRequired: false, transformFunction: null }, searchTerm: { classPropertyName: "searchTerm", publicName: "searchTerm", isSignal: true, isRequired: false, transformFunction: null }, tableKey: { classPropertyName: "tableKey", publicName: "tableKey", isSignal: true, isRequired: false, transformFunction: null }, defaultDensity: { classPropertyName: "defaultDensity", publicName: "defaultDensity", isSignal: true, isRequired: false, transformFunction: null }, reorderable: { classPropertyName: "reorderable", publicName: "reorderable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageChange: "pageChange", pageSizeChange: "pageSizeChange", sortChange: "sortChange", rowDoubleClick: "rowDoubleClick", rowAction: "rowAction", exportRequest: "exportRequest", clearSearch: "clearSearch", rowReorder: "rowReorder" }, host: { listeners: { "document:click": "onDocumentClick($event)", "document:keydown.escape": "onEscape()", "ef-row-actions-toggle": "onRowActionsToggle($event)" } }, queries: [{ propertyName: "bodyTemplates", predicate: EfColumnTemplateDirective }, { propertyName: "headerTemplates", predicate: EfColumnHeaderTemplateDirective }], ngImport: i0, template: "<!-- One cell renderer, shared by the table, the mobile row and the mobile\n detail. A new column type is added here once, not three times. -->\n<ng-template #cellTpl let-row let-col=\"col\" let-index=\"index\">\n @if (bodyTemplate(col.id); as bodyTpl) {\n <ng-container *ngTemplateOutlet=\"bodyTpl; context: { $implicit: row, col: col, index: index }\"></ng-container>\n } @else {\n @switch (col.type) {\n @case ('number') {\n {{ $any(cellValue(row, col)) | number:numberFormat(col):col.locale }}\n }\n @case ('money') {\n {{ $any(cellValue(row, col)) | currency:(col.currencyCode || 'EUR'):(col.currencyDisplay || 'symbol'):numberFormat(col):col.locale }}\n }\n @case ('date') {\n {{ $any(cellValue(row, col)) | date:(col.dateFormat || 'dd/MM/yyyy'):undefined:col.locale }}\n }\n @case ('datetime') {\n {{ $any(cellValue(row, col)) | date:(col.dateFormat || 'dd/MM/yyyy HH:mm'):undefined:col.locale }}\n }\n @case ('boolean') {\n @if (cellValue(row, col)) {\n <span class=\"bool yes\"><span class=\"dot\"></span> \u2713</span>\n } @else {\n <span class=\"bool no\"><span class=\"dot\"></span> \u2014</span>\n }\n }\n @case ('mono') {\n <span class=\"ref\">{{ cellValue(row, col) }}</span>\n }\n @case ('chip') {\n <span [class]=\"'chip ' + (col.chipPrefix || 'chip-') + cellValue(row, col)\">\n \u25CF {{ cellValue(row, col) }}\n </span>\n }\n @case ('status') {\n <ef-status-chip\n [referenceKey]=\"col.referenceKey || ''\"\n [code]=\"$any(cellValue(row, col))\"\n />\n }\n @case ('reference') {\n {{ resolveReference(cellValue(row, col), col) }}\n }\n @default {\n {{ cellValue(row, col) }}\n }\n }\n }\n</ng-template>\n\n<div class=\"tbl-wrap\" [class.has-open-menu]=\"openMenuCount() > 0 || openTool() !== null\" [attr.data-density]=\"density()\">\n <!-- \u2500\u2500 HEAD ROW \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"tbl-head\">\n <div class=\"count small\">\n @if (loading()) {\n <span>{{ loadingKey() | translate }}</span>\n } @else if (errorMsg()) {\n <span style=\"color: var(--st-cancelled-fg); font-weight: 600;\">\u26A0 {{ errorMsg() }}</span>\n } @else {\n <ng-content select=\"[tbl-head-info]\"></ng-content>\n }\n </div>\n <div class=\"tbl-tools\">\n <ng-content select=\"[tbl-head-actions]\"></ng-content>\n\n @if (canExport()) {\n <div class=\"tbl-tool\">\n <button\n class=\"btn btn-ghost btn-sm\"\n type=\"button\"\n [disabled]=\"exporting()\"\n [attr.aria-busy]=\"exporting()\"\n (click)=\"requestExport()\"\n >\n <i\n class=\"pi\"\n [class.pi-download]=\"!exporting()\"\n [class.pi-spinner]=\"exporting()\"\n [class.is-spinning]=\"exporting()\"\n aria-hidden=\"true\"\n ></i>\n {{ (exporting() ? 'common_export_running' : 'common_export') | translate }}\n </button>\n </div>\n }\n\n @if (showDensityControl()) {\n <div class=\"tbl-tool\">\n <button\n class=\"btn btn-ghost btn-sm\"\n type=\"button\"\n [class.open]=\"openTool() === 'density'\"\n [attr.aria-expanded]=\"openTool() === 'density'\"\n aria-haspopup=\"menu\"\n (click)=\"toggleTool('density')\"\n >\n <i class=\"pi pi-bars\" aria-hidden=\"true\"></i>\n {{ 'common_density' | translate }}\n </button>\n @if (openTool() === 'density') {\n <div class=\"tbl-tool__menu\" role=\"menu\">\n @for (opt of densityOptions; track opt.value) {\n <button\n type=\"button\"\n role=\"menuitemradio\"\n [attr.aria-checked]=\"density() === opt.value\"\n [class.is-active]=\"density() === opt.value\"\n (click)=\"setDensity(opt.value)\"\n >\n <i class=\"pi\" [ngClass]=\"opt.icon\" aria-hidden=\"true\"></i>\n <span class=\"tbl-tool__label\">{{ opt.labelKey | translate }}</span>\n @if (density() === opt.value) {\n <i class=\"pi pi-check tbl-tool__check\" aria-hidden=\"true\"></i>\n }\n </button>\n }\n </div>\n }\n </div>\n }\n\n @if (showColumnPicker()) {\n <div class=\"tbl-tool\">\n <button\n class=\"btn btn-ghost btn-sm\"\n type=\"button\"\n [class.open]=\"openTool() === 'columns'\"\n [attr.aria-expanded]=\"openTool() === 'columns'\"\n aria-haspopup=\"menu\"\n (click)=\"toggleTool('columns')\"\n >\n <i class=\"pi pi-th-large\" aria-hidden=\"true\"></i>\n {{ 'common_columns' | translate }}\n </button>\n @if (openTool() === 'columns') {\n <div class=\"tbl-tool__menu tbl-tool__menu--wide\" role=\"menu\">\n @for (col of hideableColumns(); track col.id) {\n <button\n type=\"button\"\n role=\"menuitemcheckbox\"\n [attr.aria-checked]=\"!isColumnHidden(col.id)\"\n [class.is-active]=\"!isColumnHidden(col.id)\"\n (click)=\"toggleColumn(col.id)\"\n >\n <i class=\"pi\" [class.pi-check]=\"!isColumnHidden(col.id)\" aria-hidden=\"true\"></i>\n <span class=\"tbl-tool__label\">{{\n col.headerKey ? (col.headerKey | translate) : (col.header || col.id)\n }}</span>\n </button>\n }\n <div class=\"tbl-tool__sep\"></div>\n <button type=\"button\" role=\"menuitem\" (click)=\"resetColumns()\">\n <i class=\"pi pi-refresh\" aria-hidden=\"true\"></i>\n <span class=\"tbl-tool__label\">{{ 'common_columns_reset' | translate }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- \u2500\u2500 TABLE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (isMobile()) {\n <!-- \u2500\u2500 MOBILE LIST \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n A six-column table on a 390px screen either overflows or\n squeezes every column to nothing, so the rows become a list.\n Same columns, same cell renderers; each column just declares\n (or is given) a role. Both shapes expand to the same detail \u2014\n they differ only in how much they show collapsed. -->\n <ul class=\"mlist\" [attr.data-layout]=\"effectiveMobileLayout()\">\n @for (row of rows(); track trackByRow($index, row); let i = $index) {\n <li class=\"mrow\" [class.is-open]=\"isExpanded(row, i)\">\n <div\n class=\"mrow__head\"\n [class.is-tappable]=\"hasDetail()\"\n [attr.role]=\"hasDetail() ? 'button' : null\"\n [attr.tabindex]=\"hasDetail() ? 0 : null\"\n [attr.aria-expanded]=\"hasDetail() ? isExpanded(row, i) : null\"\n (click)=\"onRowHeadActivate(row, i, $event)\"\n (keydown.enter)=\"onRowHeadActivate(row, i, $event)\"\n (keydown.space)=\"onRowHeadActivate(row, i, $event)\"\n >\n <div class=\"mrow__lead\">\n @if (primaryColumn(); as pc) {\n <span class=\"mrow__primary\" efOverflowTooltip efTooltip efTooltipPosition=\"top\">\n <ng-container *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: pc, index: i }\"></ng-container>\n </span>\n }\n @if (effectiveMobileLayout() === 'row' && secondaryColumns().length) {\n <span class=\"mrow__secondary\">\n @for (sc of secondaryColumns(); track sc.id) {\n <span class=\"mrow__sec-part\">\n <ng-container *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: sc, index: i }\"></ng-container>\n </span>\n }\n </span>\n }\n </div>\n\n <div class=\"mrow__trail\">\n @if (statusColumn(); as st) {\n <ng-container *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: st, index: i }\"></ng-container>\n }\n @if (hasActionsColumn()) {\n <span class=\"mrow__actions\">\n <ef-row-actions [items]=\"defaultRowActions(row)\" [context]=\"rowActionsContext()\" />\n </span>\n }\n @if (hasDetail() && effectiveMobileLayout() === 'row') {\n <!-- Says the row opens, and which way it is now. Decorative:\n the whole head is the control, and it carries the state. -->\n <i\n class=\"pi pi-chevron-down mrow__chevron\"\n [class.is-open]=\"isExpanded(row, i)\"\n aria-hidden=\"true\"\n ></i>\n }\n </div>\n </div>\n\n @if (visibleDetail(row, i).length) {\n <dl class=\"mrow__detail\">\n @for (col of visibleDetail(row, i); track col.id) {\n <div class=\"mrow__field\">\n <dt>{{ $any(col).headerKey ? ($any(col).headerKey | translate) : $any(col).header }}</dt>\n <dd [class]=\"cellAlignClass($any(col))\">\n <ng-container *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: col, index: i }\"></ng-container>\n </dd>\n </div>\n }\n </dl>\n }\n\n @if (hasMoreThanPreview() && effectiveMobileLayout() === 'card') {\n <button class=\"mrow__more\" type=\"button\" (click)=\"toggleExpanded(row, i)\">\n <span>{{ (isExpanded(row, i) ? 'common_view_less' : 'common_view_more') | translate }}</span>\n <i class=\"pi pi-chevron-down mrow__chevron\" [class.is-open]=\"isExpanded(row, i)\" aria-hidden=\"true\"></i>\n </button>\n }\n </li>\n } @empty {\n <li class=\"mrow mrow--empty\">\n <ng-content select=\"[empty-state-mobile]\">\n <ng-container *ngTemplateOutlet=\"defaultEmptyTpl\"></ng-container>\n </ng-content>\n </li>\n }\n </ul>\n } @else {\n <table class=\"tbl\">\n <thead>\n <tr>\n @if (reorderable()) {\n <th class=\"tbl-drag-h\" aria-hidden=\"true\"></th>\n }\n @for (col of effectiveColumns(); track trackByColumn($index, col)) {\n <!-- A sortable header is a real <button> inside the <th>, not a\n click handler on the cell. The cell carries aria-sort so the\n current order is announced; the arrow stays decorative.\n Sorting was previously mouse-only and silent to assistive\n technology, on every list screen in the product. -->\n <th\n [class]=\"headerAlignClass(col)\"\n [class.is-sortable]=\"col.sortable\"\n [style.width]=\"col.width || null\"\n [attr.data-col]=\"col.id\"\n [attr.aria-sort]=\"ariaSort(col)\"\n >\n @if (col.sortable) {\n <button type=\"button\" class=\"tbl-sort\" (click)=\"onHeaderClick(col)\">\n <ng-container *ngTemplateOutlet=\"headerLabelTpl; context: { col: col }\"></ng-container>\n @if (sortIndicator(col)) {\n <span aria-hidden=\"true\" class=\"tbl-sort__arrow\">{{ sortIndicator(col) }}</span>\n }\n </button>\n } @else {\n <ng-container *ngTemplateOutlet=\"headerLabelTpl; context: { col: col }\"></ng-container>\n }\n </th>\n }\n </tr>\n </thead>\n\n <tbody>\n @for (row of rows(); track trackByRow($index, row); let i = $index) {\n <tr\n [class.is-row-clickable]=\"rowDoubleClickable()\"\n [class.is-dragging]=\"dragFrom() === i\"\n [class.is-drop-target]=\"dragFrom() !== null && dragFrom() !== i && dragTo() === i\"\n [attr.tabindex]=\"rowDoubleClickable() ? 0 : null\"\n [attr.role]=\"rowDoubleClickable() ? 'button' : null\"\n (dblclick)=\"onRowDoubleClick(row, $event)\"\n (keydown.enter)=\"onRowKeydown(row, $event)\"\n >\n @if (reorderable()) {\n <td class=\"tbl-drag\">\n <!-- The row is draggable only by this handle, so a drag never\n starts from a cell the operator meant to click or select.\n Arrow keys move the row for anyone not using a pointer. -->\n <button\n type=\"button\"\n class=\"tbl-drag__grip\"\n [attr.aria-label]=\"'common_reorder_row' | translate\"\n (pointerdown)=\"onDragPointerDown(i, $event)\"\n (pointermove)=\"onDragPointerMove($event)\"\n (pointerup)=\"onDragPointerUp()\"\n (pointercancel)=\"onDragPointerUp()\"\n (keydown)=\"onDragKeydown(i, $event)\"\n >\n <i class=\"pi pi-ellipsis-v\" aria-hidden=\"true\"></i>\n </button>\n </td>\n }\n @for (col of effectiveColumns(); track trackByColumn($index, col); let colIdx = $index) {\n <td efOverflowTooltip efTooltip efTooltipPosition=\"top\" [class]=\"cellAlignClass(col)\" [attr.data-col]=\"col.id\">\n @if (col.id === 'actions' && hasActionsColumn()) {\n <!-- Auto row-actions cell: View / Edit / Duplicate / Delete,\n gated by [show*Action] flags + ScreenContext perms. -->\n <ef-row-actions\n [items]=\"defaultRowActions(row)\"\n [context]=\"rowActionsContext()\"\n />\n } @else {\n <ng-container\n *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: col, index: i }\"\n ></ng-container>\n }\n </td>\n }\n </tr>\n } @empty {\n <tr>\n <td [attr.colspan]=\"effectiveColumns().length + (reorderable() ? 1 : 0)\">\n <ng-content select=\"[empty-state]\">\n <ng-container *ngTemplateOutlet=\"defaultEmptyTpl\"></ng-container>\n </ng-content>\n </td>\n </tr>\n }\n </tbody>\n </table>\n }\n\n <!-- \u2500\u2500 PAGER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <!-- Paging controls for an empty result set are chrome with nothing to\n page, so they stay out of the way until there is something to move\n through. -->\n @if (!hidePager() && rows().length > 0) {\n <ef-pager\n [pageNumber]=\"pageNumber()\"\n [pageSize]=\"pageSize()\"\n [totalCount]=\"totalCount()\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n (pageChange)=\"pageChange.emit($event)\"\n (pageSizeChange)=\"pageSizeChange.emit($event)\"\n />\n }\n</div>\n\n<!-- \u2500\u2500 DEFAULT EMPTY STATE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Rendered when a screen projects nothing into [empty-state] /\n [empty-state-mobile]. It words itself from `searchTerm`, because\n \"nothing matched what you typed\" and \"there is nothing here yet\"\n are different situations needing different ways out. -->\n<ng-template #defaultEmptyTpl>\n <div class=\"tbl-empty\">\n <i\n class=\"pi tbl-empty__icon\"\n [class.pi-search]=\"!!searchTerm()\"\n [class.pi-inbox]=\"!searchTerm()\"\n aria-hidden=\"true\"\n ></i>\n\n @if (searchTerm()) {\n <p class=\"tbl-empty__title\">\n {{ 'common_empty_no_results' | translate: { term: searchTerm() } }}\n </p>\n <p class=\"tbl-empty__hint\">{{ 'common_empty_no_results_hint' | translate }}</p>\n <button class=\"btn btn-sm tbl-empty__action\" type=\"button\" (click)=\"clearSearch.emit()\">\n <i class=\"pi pi-times\" aria-hidden=\"true\"></i>\n {{ 'common_empty_clear_filters' | translate }}\n </button>\n } @else {\n <p class=\"tbl-empty__title\">{{ 'common_empty_none_yet' | translate }}</p>\n <p class=\"tbl-empty__hint\">{{ 'common_empty_none_yet_hint' | translate }}</p>\n }\n </div>\n</ng-template>\n\n<!-- Header label, shared by the sortable and plain header cells so the\n projection rules stay in one place. -->\n<ng-template #headerLabelTpl let-col=\"col\">\n @if (headerTemplate(col.id); as headerTpl) {\n <ng-container *ngTemplateOutlet=\"headerTpl; context: { $implicit: col, col: col }\"></ng-container>\n } @else if (col.headerKey) {\n <span>{{ col.headerKey | translate }}</span>\n } @else if (col.header) {\n <span>{{ col.header }}</span>\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";.tbl thead th.is-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;transition:color var(--t-fast, .14s) var(--ease-out, ease-out)}.tbl thead th.is-sortable:hover{color:var(--text)}.tbl tbody tr.is-row-clickable{cursor:pointer}.tbl-tools{display:flex;gap:6px;align-items:center}.tbl-tool{position:relative}.tbl-tool>.btn.open{color:var(--text);background:var(--paper)}.tbl-tool__menu{position:absolute;top:calc(100% + 8px);inset-inline-end:0;z-index:40;min-width:212px;max-height:340px;overflow-y:auto;padding:6px;display:grid;gap:1px;background:var(--paper-alt);border:1px solid var(--rule);border-radius:var(--r-xl);box-shadow:var(--shadow-3);animation:row-actions-menu-in var(--t-base) var(--ease-spring)}.tbl-tool__menu--wide{min-width:248px}.tbl-tool__menu button{appearance:none;background:transparent;border:0;width:100%;text-align:start;font:inherit;font-size:13.5px;font-weight:600;color:var(--text);display:flex;align-items:center;gap:12px;padding:9px 12px;border-radius:var(--r-md);cursor:pointer;transition:background-color var(--t-fast) var(--ease-out)}.tbl-tool__menu button:hover,.tbl-tool__menu button:focus-visible{background:var(--paper);outline:0}.tbl-tool__menu button>.pi{width:16px;flex:none;font-size:14px;color:var(--muted)}.tbl-tool__menu button.is-active>.pi{color:var(--module, var(--text))}.tbl-tool__label{flex:1 1 auto;min-width:0}.tbl-tool__check{color:var(--module, var(--text))}.tbl-tool__sep{margin:5px 2px;border-top:1px solid var(--rule)}.tbl-wrap[data-density=compact] .tbl tbody td{padding-top:4px;padding-bottom:4px}.tbl-wrap[data-density=comfortable] .tbl tbody td{padding-top:16px;padding-bottom:16px}.mlist{list-style:none;margin:0;padding:0;display:grid}.mrow{border-top:1px solid var(--rule)}.mrow:first-child{border-top:0}.mrow__head{display:flex;align-items:flex-start;gap:var(--s-3);padding:12px var(--s-4);min-height:var(--hit-touch)}.mrow__head.is-tappable{cursor:pointer}.mrow__head.is-tappable:active{background:var(--paper)}.mrow__lead{flex:1;min-width:0;display:grid;gap:2px}.mrow__primary{font-weight:700;font-size:14px;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mrow__secondary{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 6px;font-size:12.5px;color:var(--text-mute);min-width:0}.mrow__secondary .mrow__sec-part+.mrow__sec-part:before{content:\"\\b7\";margin-inline-end:6px;color:var(--text-soft)}.mrow__trail{display:flex;align-items:center;justify-content:flex-end;gap:var(--s-2);flex-shrink:0;min-height:20px}.mrow__actions{display:inline-flex}.mrow__detail{margin:0;padding:0 var(--s-4) 12px;display:grid;gap:1px}.mrow__field{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-3);padding:7px 0;border-top:1px solid var(--rule-soft)}.mrow__field dt{font-size:11.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--text-mute);flex-shrink:0}.mrow__field dd{margin:0;font-size:13.5px;color:var(--text);text-align:end;min-width:0;overflow-wrap:anywhere}.mrow__more{appearance:none;width:100%;background:transparent;border:0;border-top:1px solid var(--rule-soft);padding:10px;font:inherit;font-size:13px;font-weight:600;color:var(--tenant-500);cursor:pointer}.mlist[data-layout=card]{gap:var(--s-3);padding:var(--s-3) var(--s-3) 0}.mlist[data-layout=card] .mrow{border:1px solid var(--rule);border-radius:var(--r-lg);background:var(--paper-alt);overflow:hidden}.mlist[data-layout=card] .mrow__head{border-bottom:1px solid var(--rule)}.mrow__chevron{font-size:11px;color:var(--text-soft);transition:transform var(--t-fast) var(--ease-out);flex-shrink:0}.mrow__chevron.is-open{transform:rotate(180deg);color:var(--text-mute)}.mrow__head.is-tappable:focus-visible{outline:2px solid var(--tenant-400);outline-offset:-2px}.mrow__more{display:flex;align-items:center;justify-content:center;gap:6px}.tbl-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--s-2);padding:var(--s-9) var(--s-4);text-align:center}.tbl-empty__icon{font-size:28px;line-height:1;color:var(--ink-400);margin-block-end:var(--s-1)}.tbl-empty__title{margin:0;font-size:15px;font-weight:600;color:var(--text);max-inline-size:46ch;overflow-wrap:break-word}.tbl-empty__hint{margin:0;font-size:13px;color:var(--ink-600);max-inline-size:52ch;text-wrap:pretty}.tbl-empty__action{margin-block-start:var(--s-3);min-block-size:var(--hit-base)}.mrow--empty{padding:0}@media(max-width:767px){.tbl-empty{padding:var(--s-7) var(--s-4)}.tbl-empty__action{min-block-size:var(--hit-touch)}}.pi.is-spinning{animation:ef-export-spin .9s linear infinite}@keyframes ef-export-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.pi.is-spinning{animation:none}}.tbl th.tbl-drag-h,.tbl td.tbl-drag{width:28px;padding-inline:4px 0;text-align:center}.tbl td.tbl-drag{cursor:default}.tbl .tbl-drag__grip{display:inline-flex;align-items:center;justify-content:center;width:22px;height:26px;padding:0;border:0;border-radius:6px;background:transparent;color:var(--text-soft);cursor:grab;touch-action:none;transition:background var(--t-fast, .14s) var(--ease-out, ease-out),color var(--t-fast, .14s) var(--ease-out, ease-out)}.tbl .tbl-drag__grip:hover{background:var(--paper);color:var(--text)}.tbl .tbl-drag__grip:focus-visible{outline:2px solid var(--tenant, var(--rule));outline-offset:1px}.tbl .tbl-drag__grip:active{cursor:grabbing}.tbl .tbl-drag__grip i{font-size:12px}.tbl tbody tr.is-dragging>td{background:var(--paper);opacity:.55}.tbl tbody tr.is-drop-target>td{box-shadow:inset 0 2px 0 var(--tenant, var(--rule))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfPagerComponent, selector: "ef-pager", inputs: ["pageNumber", "pageSize", "totalCount", "pageSizeOptions", "linesPerPageLabelKey", "ofLabelKey", "prevLabelKey", "nextLabelKey", "hideSize"], outputs: ["pageChange", "pageSizeChange"] }, { kind: "component", type: EfStatusChipComponent, selector: "ef-status-chip", inputs: ["referenceKey", "code", "color", "label", "labelKey", "hideDot", "showCode"] }, { kind: "component", type: EfRowActionsComponent, selector: "ef-row-actions", inputs: ["items", "context", "triggerIcon", "triggerAriaKey", "disabled", "menuLeft"], outputs: ["opened", "closed"] }, { kind: "directive", type: EfOverflowTooltipDirective, selector: "[efOverflowTooltip]" }, { kind: "directive", type: EfTooltipDirective, selector: "[efTooltip]" }, { kind: "pipe", type: i1$3.DecimalPipe, name: "number" }, { kind: "pipe", type: i1$3.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i1$3.DatePipe, name: "date" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5160
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfDataCardComponent, isStandalone: true, selector: "ef-data-card", inputs: { mobileLayout: { classPropertyName: "mobileLayout", publicName: "mobileLayout", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, trackByField: { classPropertyName: "trackByField", publicName: "trackByField", isSignal: true, isRequired: false, transformFunction: null }, pageNumber: { classPropertyName: "pageNumber", publicName: "pageNumber", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, totalCount: { classPropertyName: "totalCount", publicName: "totalCount", isSignal: true, isRequired: false, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, hidePager: { classPropertyName: "hidePager", publicName: "hidePager", isSignal: true, isRequired: false, transformFunction: null }, sort: { classPropertyName: "sort", publicName: "sort", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, errorMsg: { classPropertyName: "errorMsg", publicName: "errorMsg", isSignal: true, isRequired: false, transformFunction: null }, loadingKey: { classPropertyName: "loadingKey", publicName: "loadingKey", isSignal: true, isRequired: false, transformFunction: null }, rowDoubleClickable: { classPropertyName: "rowDoubleClickable", publicName: "rowDoubleClickable", isSignal: true, isRequired: false, transformFunction: null }, hasActionsColumn: { classPropertyName: "hasActionsColumn", publicName: "hasActionsColumn", isSignal: true, isRequired: false, transformFunction: null }, rowActionsContext: { classPropertyName: "rowActionsContext", publicName: "rowActionsContext", isSignal: true, isRequired: false, transformFunction: null }, showViewAction: { classPropertyName: "showViewAction", publicName: "showViewAction", isSignal: true, isRequired: false, transformFunction: null }, showEditAction: { classPropertyName: "showEditAction", publicName: "showEditAction", isSignal: true, isRequired: false, transformFunction: null }, showDuplicateAction: { classPropertyName: "showDuplicateAction", publicName: "showDuplicateAction", isSignal: true, isRequired: false, transformFunction: null }, showDeleteAction: { classPropertyName: "showDeleteAction", publicName: "showDeleteAction", isSignal: true, isRequired: false, transformFunction: null }, showDensityControl: { classPropertyName: "showDensityControl", publicName: "showDensityControl", isSignal: true, isRequired: false, transformFunction: null }, showColumnPicker: { classPropertyName: "showColumnPicker", publicName: "showColumnPicker", isSignal: true, isRequired: false, transformFunction: null }, showExportControl: { classPropertyName: "showExportControl", publicName: "showExportControl", isSignal: true, isRequired: false, transformFunction: null }, exporting: { classPropertyName: "exporting", publicName: "exporting", isSignal: true, isRequired: false, transformFunction: null }, screenContext: { classPropertyName: "screenContext", publicName: "screenContext", isSignal: true, isRequired: false, transformFunction: null }, searchTerm: { classPropertyName: "searchTerm", publicName: "searchTerm", isSignal: true, isRequired: false, transformFunction: null }, tableKey: { classPropertyName: "tableKey", publicName: "tableKey", isSignal: true, isRequired: false, transformFunction: null }, defaultDensity: { classPropertyName: "defaultDensity", publicName: "defaultDensity", isSignal: true, isRequired: false, transformFunction: null }, reorderable: { classPropertyName: "reorderable", publicName: "reorderable", isSignal: true, isRequired: false, transformFunction: null }, fixedLayout: { classPropertyName: "fixedLayout", publicName: "fixedLayout", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageChange: "pageChange", pageSizeChange: "pageSizeChange", sortChange: "sortChange", rowDoubleClick: "rowDoubleClick", rowAction: "rowAction", exportRequest: "exportRequest", clearSearch: "clearSearch", rowReorder: "rowReorder" }, host: { listeners: { "document:click": "onDocumentClick($event)", "document:keydown.escape": "onEscape()", "ef-row-actions-toggle": "onRowActionsToggle($event)" } }, queries: [{ propertyName: "bodyTemplates", predicate: EfColumnTemplateDirective }, { propertyName: "headerTemplates", predicate: EfColumnHeaderTemplateDirective }], ngImport: i0, template: "<!-- One cell renderer, shared by the table, the mobile row and the mobile\n detail. A new column type is added here once, not three times. -->\n<ng-template #cellTpl let-row let-col=\"col\" let-index=\"index\">\n @if (bodyTemplate(col.id); as bodyTpl) {\n <ng-container *ngTemplateOutlet=\"bodyTpl; context: { $implicit: row, col: col, index: index }\"></ng-container>\n } @else {\n @switch (col.type) {\n @case ('number') {\n {{ $any(cellValue(row, col)) | number:numberFormat(col):col.locale }}\n }\n @case ('money') {\n {{ $any(cellValue(row, col)) | currency:(col.currencyCode || 'EUR'):(col.currencyDisplay || 'symbol'):numberFormat(col):col.locale }}\n }\n @case ('date') {\n {{ $any(cellValue(row, col)) | date:(col.dateFormat || 'dd/MM/yyyy'):undefined:col.locale }}\n }\n @case ('datetime') {\n {{ $any(cellValue(row, col)) | date:(col.dateFormat || 'dd/MM/yyyy HH:mm'):undefined:col.locale }}\n }\n @case ('boolean') {\n @if (cellValue(row, col)) {\n <span class=\"bool yes\"><span class=\"dot\"></span> \u2713</span>\n } @else {\n <span class=\"bool no\"><span class=\"dot\"></span> \u2014</span>\n }\n }\n @case ('mono') {\n <span class=\"ref\">{{ cellValue(row, col) }}</span>\n }\n @case ('chip') {\n <span [class]=\"'chip ' + (col.chipPrefix || 'chip-') + cellValue(row, col)\">\n \u25CF {{ cellValue(row, col) }}\n </span>\n }\n @case ('status') {\n <ef-status-chip\n [referenceKey]=\"col.referenceKey || ''\"\n [code]=\"$any(cellValue(row, col))\"\n />\n }\n @case ('reference') {\n {{ resolveReference(cellValue(row, col), col) }}\n }\n @default {\n {{ cellValue(row, col) }}\n }\n }\n }\n</ng-template>\n\n<div class=\"tbl-wrap\" [class.has-open-menu]=\"openMenuCount() > 0 || openTool() !== null\" [attr.data-density]=\"density()\">\n <!-- \u2500\u2500 HEAD ROW \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"tbl-head\">\n <div class=\"count small\">\n @if (loading()) {\n <span>{{ loadingKey() | translate }}</span>\n } @else if (errorMsg()) {\n <span style=\"color: var(--st-cancelled-fg); font-weight: 600;\">\u26A0 {{ errorMsg() }}</span>\n } @else {\n <ng-content select=\"[tbl-head-info]\"></ng-content>\n }\n </div>\n <div class=\"tbl-tools\">\n <ng-content select=\"[tbl-head-actions]\"></ng-content>\n\n @if (canExport()) {\n <div class=\"tbl-tool\">\n <button\n class=\"btn btn-ghost btn-sm\"\n type=\"button\"\n [disabled]=\"exporting()\"\n [attr.aria-busy]=\"exporting()\"\n (click)=\"requestExport()\"\n >\n <i\n class=\"pi\"\n [class.pi-download]=\"!exporting()\"\n [class.pi-spinner]=\"exporting()\"\n [class.is-spinning]=\"exporting()\"\n aria-hidden=\"true\"\n ></i>\n {{ (exporting() ? 'common_export_running' : 'common_export') | translate }}\n </button>\n </div>\n }\n\n @if (showDensityControl()) {\n <div class=\"tbl-tool\">\n <button\n class=\"btn btn-ghost btn-sm\"\n type=\"button\"\n [class.open]=\"openTool() === 'density'\"\n [attr.aria-expanded]=\"openTool() === 'density'\"\n aria-haspopup=\"menu\"\n (click)=\"toggleTool('density')\"\n >\n <i class=\"pi pi-bars\" aria-hidden=\"true\"></i>\n {{ 'common_density' | translate }}\n </button>\n @if (openTool() === 'density') {\n <div class=\"tbl-tool__menu\" role=\"menu\">\n @for (opt of densityOptions; track opt.value) {\n <button\n type=\"button\"\n role=\"menuitemradio\"\n [attr.aria-checked]=\"density() === opt.value\"\n [class.is-active]=\"density() === opt.value\"\n (click)=\"setDensity(opt.value)\"\n >\n <i class=\"pi\" [ngClass]=\"opt.icon\" aria-hidden=\"true\"></i>\n <span class=\"tbl-tool__label\">{{ opt.labelKey | translate }}</span>\n @if (density() === opt.value) {\n <i class=\"pi pi-check tbl-tool__check\" aria-hidden=\"true\"></i>\n }\n </button>\n }\n </div>\n }\n </div>\n }\n\n @if (showColumnPicker()) {\n <div class=\"tbl-tool\">\n <button\n class=\"btn btn-ghost btn-sm\"\n type=\"button\"\n [class.open]=\"openTool() === 'columns'\"\n [attr.aria-expanded]=\"openTool() === 'columns'\"\n aria-haspopup=\"menu\"\n (click)=\"toggleTool('columns')\"\n >\n <i class=\"pi pi-th-large\" aria-hidden=\"true\"></i>\n {{ 'common_columns' | translate }}\n </button>\n @if (openTool() === 'columns') {\n <div class=\"tbl-tool__menu tbl-tool__menu--wide\" role=\"menu\">\n @for (col of hideableColumns(); track col.id) {\n <button\n type=\"button\"\n role=\"menuitemcheckbox\"\n [attr.aria-checked]=\"!isColumnHidden(col.id)\"\n [class.is-active]=\"!isColumnHidden(col.id)\"\n (click)=\"toggleColumn(col.id)\"\n >\n <i class=\"pi\" [class.pi-check]=\"!isColumnHidden(col.id)\" aria-hidden=\"true\"></i>\n <span class=\"tbl-tool__label\">{{\n col.headerKey ? (col.headerKey | translate) : (col.header || col.id)\n }}</span>\n </button>\n }\n <div class=\"tbl-tool__sep\"></div>\n <button type=\"button\" role=\"menuitem\" (click)=\"resetColumns()\">\n <i class=\"pi pi-refresh\" aria-hidden=\"true\"></i>\n <span class=\"tbl-tool__label\">{{ 'common_columns_reset' | translate }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- \u2500\u2500 TABLE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (isMobile()) {\n <!-- \u2500\u2500 MOBILE LIST \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n A six-column table on a 390px screen either overflows or\n squeezes every column to nothing, so the rows become a list.\n Same columns, same cell renderers; each column just declares\n (or is given) a role. Both shapes expand to the same detail \u2014\n they differ only in how much they show collapsed. -->\n <ul class=\"mlist\" [attr.data-layout]=\"effectiveMobileLayout()\">\n @for (row of rows(); track trackByRow($index, row); let i = $index) {\n <li class=\"mrow\" [class.is-open]=\"isExpanded(row, i)\">\n <div\n class=\"mrow__head\"\n [class.is-tappable]=\"hasDetail()\"\n [attr.role]=\"hasDetail() ? 'button' : null\"\n [attr.tabindex]=\"hasDetail() ? 0 : null\"\n [attr.aria-expanded]=\"hasDetail() ? isExpanded(row, i) : null\"\n (click)=\"onRowHeadActivate(row, i, $event)\"\n (keydown.enter)=\"onRowHeadActivate(row, i, $event)\"\n (keydown.space)=\"onRowHeadActivate(row, i, $event)\"\n >\n <div class=\"mrow__lead\">\n @if (primaryColumn(); as pc) {\n <span class=\"mrow__primary\" efOverflowTooltip efTooltip efTooltipPosition=\"top\">\n <ng-container *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: pc, index: i }\"></ng-container>\n </span>\n }\n @if (effectiveMobileLayout() === 'row' && secondaryColumns().length) {\n <span class=\"mrow__secondary\">\n @for (sc of secondaryColumns(); track sc.id) {\n <span class=\"mrow__sec-part\">\n <ng-container *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: sc, index: i }\"></ng-container>\n </span>\n }\n </span>\n }\n </div>\n\n <div class=\"mrow__trail\">\n @if (statusColumn(); as st) {\n <ng-container *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: st, index: i }\"></ng-container>\n }\n @if (hasActionsColumn()) {\n <span class=\"mrow__actions\">\n <ef-row-actions [items]=\"defaultRowActions(row)\" [context]=\"rowActionsContext()\" />\n </span>\n }\n @if (hasDetail() && effectiveMobileLayout() === 'row') {\n <!-- Says the row opens, and which way it is now. Decorative:\n the whole head is the control, and it carries the state. -->\n <i\n class=\"pi pi-chevron-down mrow__chevron\"\n [class.is-open]=\"isExpanded(row, i)\"\n aria-hidden=\"true\"\n ></i>\n }\n </div>\n </div>\n\n @if (visibleDetail(row, i).length) {\n <dl class=\"mrow__detail\">\n @for (col of visibleDetail(row, i); track col.id) {\n <div class=\"mrow__field\">\n <dt>{{ $any(col).headerKey ? ($any(col).headerKey | translate) : $any(col).header }}</dt>\n <dd [class]=\"cellAlignClass($any(col))\">\n <ng-container *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: col, index: i }\"></ng-container>\n </dd>\n </div>\n }\n </dl>\n }\n\n @if (hasMoreThanPreview() && effectiveMobileLayout() === 'card') {\n <button class=\"mrow__more\" type=\"button\" (click)=\"toggleExpanded(row, i)\">\n <span>{{ (isExpanded(row, i) ? 'common_view_less' : 'common_view_more') | translate }}</span>\n <i class=\"pi pi-chevron-down mrow__chevron\" [class.is-open]=\"isExpanded(row, i)\" aria-hidden=\"true\"></i>\n </button>\n }\n </li>\n } @empty {\n <li class=\"mrow mrow--empty\">\n <ng-content select=\"[empty-state-mobile]\">\n <ng-container *ngTemplateOutlet=\"defaultEmptyTpl\"></ng-container>\n </ng-content>\n </li>\n }\n </ul>\n } @else {\n <table class=\"tbl\" [class.tbl--fixed]=\"fixedLayout()\">\n <thead>\n <tr>\n @if (reorderable()) {\n <th class=\"tbl-drag-h\" aria-hidden=\"true\"></th>\n }\n @for (col of effectiveColumns(); track trackByColumn($index, col)) {\n <!-- A sortable header is a real <button> inside the <th>, not a\n click handler on the cell. The cell carries aria-sort so the\n current order is announced; the arrow stays decorative.\n Sorting was previously mouse-only and silent to assistive\n technology, on every list screen in the product. -->\n <th\n [class]=\"headerAlignClass(col)\"\n [class.is-sortable]=\"col.sortable\"\n [style.width]=\"col.width || null\"\n [attr.data-col]=\"col.id\"\n [attr.aria-sort]=\"ariaSort(col)\"\n >\n @if (col.sortable) {\n <button type=\"button\" class=\"tbl-sort\" (click)=\"onHeaderClick(col)\">\n <ng-container *ngTemplateOutlet=\"headerLabelTpl; context: { col: col }\"></ng-container>\n @if (sortIndicator(col)) {\n <span aria-hidden=\"true\" class=\"tbl-sort__arrow\">{{ sortIndicator(col) }}</span>\n }\n </button>\n } @else {\n <ng-container *ngTemplateOutlet=\"headerLabelTpl; context: { col: col }\"></ng-container>\n }\n </th>\n }\n </tr>\n </thead>\n\n <tbody>\n @for (row of rows(); track trackByRow($index, row); let i = $index) {\n <tr\n [class.is-row-clickable]=\"rowDoubleClickable()\"\n [class.is-dragging]=\"dragFrom() === i\"\n [class.is-drop-target]=\"dragFrom() !== null && dragFrom() !== i && dragTo() === i\"\n [attr.tabindex]=\"rowDoubleClickable() ? 0 : null\"\n [attr.role]=\"rowDoubleClickable() ? 'button' : null\"\n (dblclick)=\"onRowDoubleClick(row, $event)\"\n (keydown.enter)=\"onRowKeydown(row, $event)\"\n >\n @if (reorderable()) {\n <td class=\"tbl-drag\">\n <!-- The row is draggable only by this handle, so a drag never\n starts from a cell the operator meant to click or select.\n Arrow keys move the row for anyone not using a pointer. -->\n <button\n type=\"button\"\n class=\"tbl-drag__grip\"\n [attr.aria-label]=\"'common_reorder_row' | translate\"\n (pointerdown)=\"onDragPointerDown(i, $event)\"\n (pointermove)=\"onDragPointerMove($event)\"\n (pointerup)=\"onDragPointerUp()\"\n (pointercancel)=\"onDragPointerUp()\"\n (keydown)=\"onDragKeydown(i, $event)\"\n >\n <i class=\"pi pi-ellipsis-v\" aria-hidden=\"true\"></i>\n </button>\n </td>\n }\n @for (col of effectiveColumns(); track trackByColumn($index, col); let colIdx = $index) {\n <td efOverflowTooltip efTooltip efTooltipPosition=\"top\" [class]=\"cellAlignClass(col)\" [attr.data-col]=\"col.id\">\n @if (col.id === 'actions' && hasActionsColumn()) {\n <!-- Auto row-actions cell: View / Edit / Duplicate / Delete,\n gated by [show*Action] flags + ScreenContext perms. -->\n <ef-row-actions\n [items]=\"defaultRowActions(row)\"\n [context]=\"rowActionsContext()\"\n />\n } @else {\n <ng-container\n *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: col, index: i }\"\n ></ng-container>\n }\n </td>\n }\n </tr>\n } @empty {\n <tr>\n <td [attr.colspan]=\"effectiveColumns().length + (reorderable() ? 1 : 0)\">\n <ng-content select=\"[empty-state]\">\n <ng-container *ngTemplateOutlet=\"defaultEmptyTpl\"></ng-container>\n </ng-content>\n </td>\n </tr>\n }\n </tbody>\n </table>\n }\n\n <!-- \u2500\u2500 PAGER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <!-- Paging controls for an empty result set are chrome with nothing to\n page, so they stay out of the way until there is something to move\n through. -->\n @if (!hidePager() && rows().length > 0) {\n <ef-pager\n [pageNumber]=\"pageNumber()\"\n [pageSize]=\"pageSize()\"\n [totalCount]=\"totalCount()\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n (pageChange)=\"pageChange.emit($event)\"\n (pageSizeChange)=\"pageSizeChange.emit($event)\"\n />\n }\n</div>\n\n<!-- \u2500\u2500 DEFAULT EMPTY STATE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Rendered when a screen projects nothing into [empty-state] /\n [empty-state-mobile]. It words itself from `searchTerm`, because\n \"nothing matched what you typed\" and \"there is nothing here yet\"\n are different situations needing different ways out. -->\n<ng-template #defaultEmptyTpl>\n <div class=\"tbl-empty\">\n <i\n class=\"pi tbl-empty__icon\"\n [class.pi-search]=\"!!searchTerm()\"\n [class.pi-inbox]=\"!searchTerm()\"\n aria-hidden=\"true\"\n ></i>\n\n @if (searchTerm()) {\n <p class=\"tbl-empty__title\">\n {{ 'common_empty_no_results' | translate: { term: searchTerm() } }}\n </p>\n <p class=\"tbl-empty__hint\">{{ 'common_empty_no_results_hint' | translate }}</p>\n <button class=\"btn btn-sm tbl-empty__action\" type=\"button\" (click)=\"clearSearch.emit()\">\n <i class=\"pi pi-times\" aria-hidden=\"true\"></i>\n {{ 'common_empty_clear_filters' | translate }}\n </button>\n } @else {\n <p class=\"tbl-empty__title\">{{ 'common_empty_none_yet' | translate }}</p>\n <p class=\"tbl-empty__hint\">{{ 'common_empty_none_yet_hint' | translate }}</p>\n }\n </div>\n</ng-template>\n\n<!-- Header label, shared by the sortable and plain header cells so the\n projection rules stay in one place. -->\n<ng-template #headerLabelTpl let-col=\"col\">\n @if (headerTemplate(col.id); as headerTpl) {\n <ng-container *ngTemplateOutlet=\"headerTpl; context: { $implicit: col, col: col }\"></ng-container>\n } @else if (col.headerKey) {\n <span>{{ col.headerKey | translate }}</span>\n } @else if (col.header) {\n <span>{{ col.header }}</span>\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";.tbl thead th.is-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;transition:color var(--t-fast, .14s) var(--ease-out, ease-out)}.tbl thead th.is-sortable:hover{color:var(--text)}.tbl tbody tr.is-row-clickable{cursor:pointer}.tbl-tools{display:flex;gap:6px;align-items:center}.tbl-tool{position:relative}.tbl-tool>.btn.open{color:var(--text);background:var(--paper)}.tbl-tool__menu{position:absolute;top:calc(100% + 8px);inset-inline-end:0;z-index:40;min-width:212px;max-height:340px;overflow-y:auto;padding:6px;display:grid;gap:1px;background:var(--paper-alt);border:1px solid var(--rule);border-radius:var(--r-xl);box-shadow:var(--shadow-3);animation:row-actions-menu-in var(--t-base) var(--ease-spring)}.tbl-tool__menu--wide{min-width:248px}.tbl-tool__menu button{appearance:none;background:transparent;border:0;width:100%;text-align:start;font:inherit;font-size:13.5px;font-weight:600;color:var(--text);display:flex;align-items:center;gap:12px;padding:9px 12px;border-radius:var(--r-md);cursor:pointer;transition:background-color var(--t-fast) var(--ease-out)}.tbl-tool__menu button:hover,.tbl-tool__menu button:focus-visible{background:var(--paper);outline:0}.tbl-tool__menu button>.pi{width:16px;flex:none;font-size:14px;color:var(--muted)}.tbl-tool__menu button.is-active>.pi{color:var(--module, var(--text))}.tbl-tool__label{flex:1 1 auto;min-width:0}.tbl-tool__check{color:var(--module, var(--text))}.tbl-tool__sep{margin:5px 2px;border-top:1px solid var(--rule)}.tbl-wrap[data-density=compact] .tbl tbody td{padding-top:4px;padding-bottom:4px}.tbl-wrap[data-density=comfortable] .tbl tbody td{padding-top:16px;padding-bottom:16px}.mlist{list-style:none;margin:0;padding:0;display:grid}.mrow{border-top:1px solid var(--rule)}.mrow:first-child{border-top:0}.mrow__head{display:flex;align-items:flex-start;gap:var(--s-3);padding:12px var(--s-4);min-height:var(--hit-touch)}.mrow__head.is-tappable{cursor:pointer}.mrow__head.is-tappable:active{background:var(--paper)}.mrow__lead{flex:1;min-width:0;display:grid;gap:2px}.mrow__primary{font-weight:700;font-size:14px;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mrow__secondary{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 6px;font-size:12.5px;color:var(--text-mute);min-width:0}.mrow__secondary .mrow__sec-part+.mrow__sec-part:before{content:\"\\b7\";margin-inline-end:6px;color:var(--text-soft)}.mrow__trail{display:flex;align-items:center;justify-content:flex-end;gap:var(--s-2);flex-shrink:0;min-height:20px}.mrow__actions{display:inline-flex}.mrow__detail{margin:0;padding:0 var(--s-4) 12px;display:grid;gap:1px}.mrow__field{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-3);padding:7px 0;border-top:1px solid var(--rule-soft)}.mrow__field dt{font-size:11.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--text-mute);flex-shrink:0}.mrow__field dd{margin:0;font-size:13.5px;color:var(--text);text-align:end;min-width:0;overflow-wrap:anywhere}.mrow__more{appearance:none;width:100%;background:transparent;border:0;border-top:1px solid var(--rule-soft);padding:10px;font:inherit;font-size:13px;font-weight:600;color:var(--tenant-500);cursor:pointer}.mlist[data-layout=card]{gap:var(--s-3);padding:var(--s-3) var(--s-3) 0}.mlist[data-layout=card] .mrow{border:1px solid var(--rule);border-radius:var(--r-lg);background:var(--paper-alt);overflow:hidden}.mlist[data-layout=card] .mrow__head{border-bottom:1px solid var(--rule)}.mrow__chevron{font-size:11px;color:var(--text-soft);transition:transform var(--t-fast) var(--ease-out);flex-shrink:0}.mrow__chevron.is-open{transform:rotate(180deg);color:var(--text-mute)}.mrow__head.is-tappable:focus-visible{outline:2px solid var(--tenant-400);outline-offset:-2px}.mrow__more{display:flex;align-items:center;justify-content:center;gap:6px}.tbl-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--s-2);padding:var(--s-9) var(--s-4);text-align:center}.tbl-empty__icon{font-size:28px;line-height:1;color:var(--ink-400);margin-block-end:var(--s-1)}.tbl-empty__title{margin:0;font-size:15px;font-weight:600;color:var(--text);max-inline-size:46ch;overflow-wrap:break-word}.tbl-empty__hint{margin:0;font-size:13px;color:var(--ink-600);max-inline-size:52ch;text-wrap:pretty}.tbl-empty__action{margin-block-start:var(--s-3);min-block-size:var(--hit-base)}.mrow--empty{padding:0}@media(max-width:767px){.tbl-empty{padding:var(--s-7) var(--s-4)}.tbl-empty__action{min-block-size:var(--hit-touch)}}.pi.is-spinning{animation:ef-export-spin .9s linear infinite}@keyframes ef-export-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.pi.is-spinning{animation:none}}.tbl th.tbl-drag-h,.tbl td.tbl-drag{width:28px;padding-inline:4px 0;text-align:center}.tbl td.tbl-drag{cursor:default}.tbl .tbl-drag__grip{display:inline-flex;align-items:center;justify-content:center;width:22px;height:26px;padding:0;border:0;border-radius:6px;background:transparent;color:var(--text-soft);cursor:grab;touch-action:none;transition:background var(--t-fast, .14s) var(--ease-out, ease-out),color var(--t-fast, .14s) var(--ease-out, ease-out)}.tbl .tbl-drag__grip:hover{background:var(--paper);color:var(--text)}.tbl .tbl-drag__grip:focus-visible{outline:2px solid var(--tenant, var(--rule));outline-offset:1px}.tbl .tbl-drag__grip:active{cursor:grabbing}.tbl .tbl-drag__grip i{font-size:12px}.tbl tbody tr.is-dragging>td{background:var(--paper);opacity:.55}.tbl tbody tr.is-drop-target>td{box-shadow:inset 0 2px 0 var(--tenant, var(--rule))}.tbl.tbl--fixed{table-layout:fixed}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfPagerComponent, selector: "ef-pager", inputs: ["pageNumber", "pageSize", "totalCount", "pageSizeOptions", "linesPerPageLabelKey", "ofLabelKey", "prevLabelKey", "nextLabelKey", "hideSize"], outputs: ["pageChange", "pageSizeChange"] }, { kind: "component", type: EfStatusChipComponent, selector: "ef-status-chip", inputs: ["referenceKey", "code", "color", "label", "labelKey", "hideDot", "showCode"] }, { kind: "component", type: EfRowActionsComponent, selector: "ef-row-actions", inputs: ["items", "context", "triggerIcon", "triggerAriaKey", "disabled", "menuLeft"], outputs: ["opened", "closed"] }, { kind: "directive", type: EfOverflowTooltipDirective, selector: "[efOverflowTooltip]" }, { kind: "directive", type: EfTooltipDirective, selector: "[efTooltip]" }, { kind: "pipe", type: i1$3.DecimalPipe, name: "number" }, { kind: "pipe", type: i1$3.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i1$3.DatePipe, name: "date" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5065
5161
|
}
|
|
5066
5162
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfDataCardComponent, decorators: [{
|
|
5067
5163
|
type: Component,
|
|
@@ -5073,14 +5169,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
5073
5169
|
EfRowActionsComponent,
|
|
5074
5170
|
EfOverflowTooltipDirective,
|
|
5075
5171
|
EfTooltipDirective,
|
|
5076
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- One cell renderer, shared by the table, the mobile row and the mobile\n detail. A new column type is added here once, not three times. -->\n<ng-template #cellTpl let-row let-col=\"col\" let-index=\"index\">\n @if (bodyTemplate(col.id); as bodyTpl) {\n <ng-container *ngTemplateOutlet=\"bodyTpl; context: { $implicit: row, col: col, index: index }\"></ng-container>\n } @else {\n @switch (col.type) {\n @case ('number') {\n {{ $any(cellValue(row, col)) | number:numberFormat(col):col.locale }}\n }\n @case ('money') {\n {{ $any(cellValue(row, col)) | currency:(col.currencyCode || 'EUR'):(col.currencyDisplay || 'symbol'):numberFormat(col):col.locale }}\n }\n @case ('date') {\n {{ $any(cellValue(row, col)) | date:(col.dateFormat || 'dd/MM/yyyy'):undefined:col.locale }}\n }\n @case ('datetime') {\n {{ $any(cellValue(row, col)) | date:(col.dateFormat || 'dd/MM/yyyy HH:mm'):undefined:col.locale }}\n }\n @case ('boolean') {\n @if (cellValue(row, col)) {\n <span class=\"bool yes\"><span class=\"dot\"></span> \u2713</span>\n } @else {\n <span class=\"bool no\"><span class=\"dot\"></span> \u2014</span>\n }\n }\n @case ('mono') {\n <span class=\"ref\">{{ cellValue(row, col) }}</span>\n }\n @case ('chip') {\n <span [class]=\"'chip ' + (col.chipPrefix || 'chip-') + cellValue(row, col)\">\n \u25CF {{ cellValue(row, col) }}\n </span>\n }\n @case ('status') {\n <ef-status-chip\n [referenceKey]=\"col.referenceKey || ''\"\n [code]=\"$any(cellValue(row, col))\"\n />\n }\n @case ('reference') {\n {{ resolveReference(cellValue(row, col), col) }}\n }\n @default {\n {{ cellValue(row, col) }}\n }\n }\n }\n</ng-template>\n\n<div class=\"tbl-wrap\" [class.has-open-menu]=\"openMenuCount() > 0 || openTool() !== null\" [attr.data-density]=\"density()\">\n <!-- \u2500\u2500 HEAD ROW \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"tbl-head\">\n <div class=\"count small\">\n @if (loading()) {\n <span>{{ loadingKey() | translate }}</span>\n } @else if (errorMsg()) {\n <span style=\"color: var(--st-cancelled-fg); font-weight: 600;\">\u26A0 {{ errorMsg() }}</span>\n } @else {\n <ng-content select=\"[tbl-head-info]\"></ng-content>\n }\n </div>\n <div class=\"tbl-tools\">\n <ng-content select=\"[tbl-head-actions]\"></ng-content>\n\n @if (canExport()) {\n <div class=\"tbl-tool\">\n <button\n class=\"btn btn-ghost btn-sm\"\n type=\"button\"\n [disabled]=\"exporting()\"\n [attr.aria-busy]=\"exporting()\"\n (click)=\"requestExport()\"\n >\n <i\n class=\"pi\"\n [class.pi-download]=\"!exporting()\"\n [class.pi-spinner]=\"exporting()\"\n [class.is-spinning]=\"exporting()\"\n aria-hidden=\"true\"\n ></i>\n {{ (exporting() ? 'common_export_running' : 'common_export') | translate }}\n </button>\n </div>\n }\n\n @if (showDensityControl()) {\n <div class=\"tbl-tool\">\n <button\n class=\"btn btn-ghost btn-sm\"\n type=\"button\"\n [class.open]=\"openTool() === 'density'\"\n [attr.aria-expanded]=\"openTool() === 'density'\"\n aria-haspopup=\"menu\"\n (click)=\"toggleTool('density')\"\n >\n <i class=\"pi pi-bars\" aria-hidden=\"true\"></i>\n {{ 'common_density' | translate }}\n </button>\n @if (openTool() === 'density') {\n <div class=\"tbl-tool__menu\" role=\"menu\">\n @for (opt of densityOptions; track opt.value) {\n <button\n type=\"button\"\n role=\"menuitemradio\"\n [attr.aria-checked]=\"density() === opt.value\"\n [class.is-active]=\"density() === opt.value\"\n (click)=\"setDensity(opt.value)\"\n >\n <i class=\"pi\" [ngClass]=\"opt.icon\" aria-hidden=\"true\"></i>\n <span class=\"tbl-tool__label\">{{ opt.labelKey | translate }}</span>\n @if (density() === opt.value) {\n <i class=\"pi pi-check tbl-tool__check\" aria-hidden=\"true\"></i>\n }\n </button>\n }\n </div>\n }\n </div>\n }\n\n @if (showColumnPicker()) {\n <div class=\"tbl-tool\">\n <button\n class=\"btn btn-ghost btn-sm\"\n type=\"button\"\n [class.open]=\"openTool() === 'columns'\"\n [attr.aria-expanded]=\"openTool() === 'columns'\"\n aria-haspopup=\"menu\"\n (click)=\"toggleTool('columns')\"\n >\n <i class=\"pi pi-th-large\" aria-hidden=\"true\"></i>\n {{ 'common_columns' | translate }}\n </button>\n @if (openTool() === 'columns') {\n <div class=\"tbl-tool__menu tbl-tool__menu--wide\" role=\"menu\">\n @for (col of hideableColumns(); track col.id) {\n <button\n type=\"button\"\n role=\"menuitemcheckbox\"\n [attr.aria-checked]=\"!isColumnHidden(col.id)\"\n [class.is-active]=\"!isColumnHidden(col.id)\"\n (click)=\"toggleColumn(col.id)\"\n >\n <i class=\"pi\" [class.pi-check]=\"!isColumnHidden(col.id)\" aria-hidden=\"true\"></i>\n <span class=\"tbl-tool__label\">{{\n col.headerKey ? (col.headerKey | translate) : (col.header || col.id)\n }}</span>\n </button>\n }\n <div class=\"tbl-tool__sep\"></div>\n <button type=\"button\" role=\"menuitem\" (click)=\"resetColumns()\">\n <i class=\"pi pi-refresh\" aria-hidden=\"true\"></i>\n <span class=\"tbl-tool__label\">{{ 'common_columns_reset' | translate }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- \u2500\u2500 TABLE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (isMobile()) {\n <!-- \u2500\u2500 MOBILE LIST \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n A six-column table on a 390px screen either overflows or\n squeezes every column to nothing, so the rows become a list.\n Same columns, same cell renderers; each column just declares\n (or is given) a role. Both shapes expand to the same detail \u2014\n they differ only in how much they show collapsed. -->\n <ul class=\"mlist\" [attr.data-layout]=\"effectiveMobileLayout()\">\n @for (row of rows(); track trackByRow($index, row); let i = $index) {\n <li class=\"mrow\" [class.is-open]=\"isExpanded(row, i)\">\n <div\n class=\"mrow__head\"\n [class.is-tappable]=\"hasDetail()\"\n [attr.role]=\"hasDetail() ? 'button' : null\"\n [attr.tabindex]=\"hasDetail() ? 0 : null\"\n [attr.aria-expanded]=\"hasDetail() ? isExpanded(row, i) : null\"\n (click)=\"onRowHeadActivate(row, i, $event)\"\n (keydown.enter)=\"onRowHeadActivate(row, i, $event)\"\n (keydown.space)=\"onRowHeadActivate(row, i, $event)\"\n >\n <div class=\"mrow__lead\">\n @if (primaryColumn(); as pc) {\n <span class=\"mrow__primary\" efOverflowTooltip efTooltip efTooltipPosition=\"top\">\n <ng-container *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: pc, index: i }\"></ng-container>\n </span>\n }\n @if (effectiveMobileLayout() === 'row' && secondaryColumns().length) {\n <span class=\"mrow__secondary\">\n @for (sc of secondaryColumns(); track sc.id) {\n <span class=\"mrow__sec-part\">\n <ng-container *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: sc, index: i }\"></ng-container>\n </span>\n }\n </span>\n }\n </div>\n\n <div class=\"mrow__trail\">\n @if (statusColumn(); as st) {\n <ng-container *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: st, index: i }\"></ng-container>\n }\n @if (hasActionsColumn()) {\n <span class=\"mrow__actions\">\n <ef-row-actions [items]=\"defaultRowActions(row)\" [context]=\"rowActionsContext()\" />\n </span>\n }\n @if (hasDetail() && effectiveMobileLayout() === 'row') {\n <!-- Says the row opens, and which way it is now. Decorative:\n the whole head is the control, and it carries the state. -->\n <i\n class=\"pi pi-chevron-down mrow__chevron\"\n [class.is-open]=\"isExpanded(row, i)\"\n aria-hidden=\"true\"\n ></i>\n }\n </div>\n </div>\n\n @if (visibleDetail(row, i).length) {\n <dl class=\"mrow__detail\">\n @for (col of visibleDetail(row, i); track col.id) {\n <div class=\"mrow__field\">\n <dt>{{ $any(col).headerKey ? ($any(col).headerKey | translate) : $any(col).header }}</dt>\n <dd [class]=\"cellAlignClass($any(col))\">\n <ng-container *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: col, index: i }\"></ng-container>\n </dd>\n </div>\n }\n </dl>\n }\n\n @if (hasMoreThanPreview() && effectiveMobileLayout() === 'card') {\n <button class=\"mrow__more\" type=\"button\" (click)=\"toggleExpanded(row, i)\">\n <span>{{ (isExpanded(row, i) ? 'common_view_less' : 'common_view_more') | translate }}</span>\n <i class=\"pi pi-chevron-down mrow__chevron\" [class.is-open]=\"isExpanded(row, i)\" aria-hidden=\"true\"></i>\n </button>\n }\n </li>\n } @empty {\n <li class=\"mrow mrow--empty\">\n <ng-content select=\"[empty-state-mobile]\">\n <ng-container *ngTemplateOutlet=\"defaultEmptyTpl\"></ng-container>\n </ng-content>\n </li>\n }\n </ul>\n } @else {\n <table class=\"tbl\">\n <thead>\n <tr>\n @if (reorderable()) {\n <th class=\"tbl-drag-h\" aria-hidden=\"true\"></th>\n }\n @for (col of effectiveColumns(); track trackByColumn($index, col)) {\n <!-- A sortable header is a real <button> inside the <th>, not a\n click handler on the cell. The cell carries aria-sort so the\n current order is announced; the arrow stays decorative.\n Sorting was previously mouse-only and silent to assistive\n technology, on every list screen in the product. -->\n <th\n [class]=\"headerAlignClass(col)\"\n [class.is-sortable]=\"col.sortable\"\n [style.width]=\"col.width || null\"\n [attr.data-col]=\"col.id\"\n [attr.aria-sort]=\"ariaSort(col)\"\n >\n @if (col.sortable) {\n <button type=\"button\" class=\"tbl-sort\" (click)=\"onHeaderClick(col)\">\n <ng-container *ngTemplateOutlet=\"headerLabelTpl; context: { col: col }\"></ng-container>\n @if (sortIndicator(col)) {\n <span aria-hidden=\"true\" class=\"tbl-sort__arrow\">{{ sortIndicator(col) }}</span>\n }\n </button>\n } @else {\n <ng-container *ngTemplateOutlet=\"headerLabelTpl; context: { col: col }\"></ng-container>\n }\n </th>\n }\n </tr>\n </thead>\n\n <tbody>\n @for (row of rows(); track trackByRow($index, row); let i = $index) {\n <tr\n [class.is-row-clickable]=\"rowDoubleClickable()\"\n [class.is-dragging]=\"dragFrom() === i\"\n [class.is-drop-target]=\"dragFrom() !== null && dragFrom() !== i && dragTo() === i\"\n [attr.tabindex]=\"rowDoubleClickable() ? 0 : null\"\n [attr.role]=\"rowDoubleClickable() ? 'button' : null\"\n (dblclick)=\"onRowDoubleClick(row, $event)\"\n (keydown.enter)=\"onRowKeydown(row, $event)\"\n >\n @if (reorderable()) {\n <td class=\"tbl-drag\">\n <!-- The row is draggable only by this handle, so a drag never\n starts from a cell the operator meant to click or select.\n Arrow keys move the row for anyone not using a pointer. -->\n <button\n type=\"button\"\n class=\"tbl-drag__grip\"\n [attr.aria-label]=\"'common_reorder_row' | translate\"\n (pointerdown)=\"onDragPointerDown(i, $event)\"\n (pointermove)=\"onDragPointerMove($event)\"\n (pointerup)=\"onDragPointerUp()\"\n (pointercancel)=\"onDragPointerUp()\"\n (keydown)=\"onDragKeydown(i, $event)\"\n >\n <i class=\"pi pi-ellipsis-v\" aria-hidden=\"true\"></i>\n </button>\n </td>\n }\n @for (col of effectiveColumns(); track trackByColumn($index, col); let colIdx = $index) {\n <td efOverflowTooltip efTooltip efTooltipPosition=\"top\" [class]=\"cellAlignClass(col)\" [attr.data-col]=\"col.id\">\n @if (col.id === 'actions' && hasActionsColumn()) {\n <!-- Auto row-actions cell: View / Edit / Duplicate / Delete,\n gated by [show*Action] flags + ScreenContext perms. -->\n <ef-row-actions\n [items]=\"defaultRowActions(row)\"\n [context]=\"rowActionsContext()\"\n />\n } @else {\n <ng-container\n *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: col, index: i }\"\n ></ng-container>\n }\n </td>\n }\n </tr>\n } @empty {\n <tr>\n <td [attr.colspan]=\"effectiveColumns().length + (reorderable() ? 1 : 0)\">\n <ng-content select=\"[empty-state]\">\n <ng-container *ngTemplateOutlet=\"defaultEmptyTpl\"></ng-container>\n </ng-content>\n </td>\n </tr>\n }\n </tbody>\n </table>\n }\n\n <!-- \u2500\u2500 PAGER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <!-- Paging controls for an empty result set are chrome with nothing to\n page, so they stay out of the way until there is something to move\n through. -->\n @if (!hidePager() && rows().length > 0) {\n <ef-pager\n [pageNumber]=\"pageNumber()\"\n [pageSize]=\"pageSize()\"\n [totalCount]=\"totalCount()\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n (pageChange)=\"pageChange.emit($event)\"\n (pageSizeChange)=\"pageSizeChange.emit($event)\"\n />\n }\n</div>\n\n<!-- \u2500\u2500 DEFAULT EMPTY STATE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Rendered when a screen projects nothing into [empty-state] /\n [empty-state-mobile]. It words itself from `searchTerm`, because\n \"nothing matched what you typed\" and \"there is nothing here yet\"\n are different situations needing different ways out. -->\n<ng-template #defaultEmptyTpl>\n <div class=\"tbl-empty\">\n <i\n class=\"pi tbl-empty__icon\"\n [class.pi-search]=\"!!searchTerm()\"\n [class.pi-inbox]=\"!searchTerm()\"\n aria-hidden=\"true\"\n ></i>\n\n @if (searchTerm()) {\n <p class=\"tbl-empty__title\">\n {{ 'common_empty_no_results' | translate: { term: searchTerm() } }}\n </p>\n <p class=\"tbl-empty__hint\">{{ 'common_empty_no_results_hint' | translate }}</p>\n <button class=\"btn btn-sm tbl-empty__action\" type=\"button\" (click)=\"clearSearch.emit()\">\n <i class=\"pi pi-times\" aria-hidden=\"true\"></i>\n {{ 'common_empty_clear_filters' | translate }}\n </button>\n } @else {\n <p class=\"tbl-empty__title\">{{ 'common_empty_none_yet' | translate }}</p>\n <p class=\"tbl-empty__hint\">{{ 'common_empty_none_yet_hint' | translate }}</p>\n }\n </div>\n</ng-template>\n\n<!-- Header label, shared by the sortable and plain header cells so the\n projection rules stay in one place. -->\n<ng-template #headerLabelTpl let-col=\"col\">\n @if (headerTemplate(col.id); as headerTpl) {\n <ng-container *ngTemplateOutlet=\"headerTpl; context: { $implicit: col, col: col }\"></ng-container>\n } @else if (col.headerKey) {\n <span>{{ col.headerKey | translate }}</span>\n } @else if (col.header) {\n <span>{{ col.header }}</span>\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";.tbl thead th.is-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;transition:color var(--t-fast, .14s) var(--ease-out, ease-out)}.tbl thead th.is-sortable:hover{color:var(--text)}.tbl tbody tr.is-row-clickable{cursor:pointer}.tbl-tools{display:flex;gap:6px;align-items:center}.tbl-tool{position:relative}.tbl-tool>.btn.open{color:var(--text);background:var(--paper)}.tbl-tool__menu{position:absolute;top:calc(100% + 8px);inset-inline-end:0;z-index:40;min-width:212px;max-height:340px;overflow-y:auto;padding:6px;display:grid;gap:1px;background:var(--paper-alt);border:1px solid var(--rule);border-radius:var(--r-xl);box-shadow:var(--shadow-3);animation:row-actions-menu-in var(--t-base) var(--ease-spring)}.tbl-tool__menu--wide{min-width:248px}.tbl-tool__menu button{appearance:none;background:transparent;border:0;width:100%;text-align:start;font:inherit;font-size:13.5px;font-weight:600;color:var(--text);display:flex;align-items:center;gap:12px;padding:9px 12px;border-radius:var(--r-md);cursor:pointer;transition:background-color var(--t-fast) var(--ease-out)}.tbl-tool__menu button:hover,.tbl-tool__menu button:focus-visible{background:var(--paper);outline:0}.tbl-tool__menu button>.pi{width:16px;flex:none;font-size:14px;color:var(--muted)}.tbl-tool__menu button.is-active>.pi{color:var(--module, var(--text))}.tbl-tool__label{flex:1 1 auto;min-width:0}.tbl-tool__check{color:var(--module, var(--text))}.tbl-tool__sep{margin:5px 2px;border-top:1px solid var(--rule)}.tbl-wrap[data-density=compact] .tbl tbody td{padding-top:4px;padding-bottom:4px}.tbl-wrap[data-density=comfortable] .tbl tbody td{padding-top:16px;padding-bottom:16px}.mlist{list-style:none;margin:0;padding:0;display:grid}.mrow{border-top:1px solid var(--rule)}.mrow:first-child{border-top:0}.mrow__head{display:flex;align-items:flex-start;gap:var(--s-3);padding:12px var(--s-4);min-height:var(--hit-touch)}.mrow__head.is-tappable{cursor:pointer}.mrow__head.is-tappable:active{background:var(--paper)}.mrow__lead{flex:1;min-width:0;display:grid;gap:2px}.mrow__primary{font-weight:700;font-size:14px;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mrow__secondary{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 6px;font-size:12.5px;color:var(--text-mute);min-width:0}.mrow__secondary .mrow__sec-part+.mrow__sec-part:before{content:\"\\b7\";margin-inline-end:6px;color:var(--text-soft)}.mrow__trail{display:flex;align-items:center;justify-content:flex-end;gap:var(--s-2);flex-shrink:0;min-height:20px}.mrow__actions{display:inline-flex}.mrow__detail{margin:0;padding:0 var(--s-4) 12px;display:grid;gap:1px}.mrow__field{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-3);padding:7px 0;border-top:1px solid var(--rule-soft)}.mrow__field dt{font-size:11.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--text-mute);flex-shrink:0}.mrow__field dd{margin:0;font-size:13.5px;color:var(--text);text-align:end;min-width:0;overflow-wrap:anywhere}.mrow__more{appearance:none;width:100%;background:transparent;border:0;border-top:1px solid var(--rule-soft);padding:10px;font:inherit;font-size:13px;font-weight:600;color:var(--tenant-500);cursor:pointer}.mlist[data-layout=card]{gap:var(--s-3);padding:var(--s-3) var(--s-3) 0}.mlist[data-layout=card] .mrow{border:1px solid var(--rule);border-radius:var(--r-lg);background:var(--paper-alt);overflow:hidden}.mlist[data-layout=card] .mrow__head{border-bottom:1px solid var(--rule)}.mrow__chevron{font-size:11px;color:var(--text-soft);transition:transform var(--t-fast) var(--ease-out);flex-shrink:0}.mrow__chevron.is-open{transform:rotate(180deg);color:var(--text-mute)}.mrow__head.is-tappable:focus-visible{outline:2px solid var(--tenant-400);outline-offset:-2px}.mrow__more{display:flex;align-items:center;justify-content:center;gap:6px}.tbl-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--s-2);padding:var(--s-9) var(--s-4);text-align:center}.tbl-empty__icon{font-size:28px;line-height:1;color:var(--ink-400);margin-block-end:var(--s-1)}.tbl-empty__title{margin:0;font-size:15px;font-weight:600;color:var(--text);max-inline-size:46ch;overflow-wrap:break-word}.tbl-empty__hint{margin:0;font-size:13px;color:var(--ink-600);max-inline-size:52ch;text-wrap:pretty}.tbl-empty__action{margin-block-start:var(--s-3);min-block-size:var(--hit-base)}.mrow--empty{padding:0}@media(max-width:767px){.tbl-empty{padding:var(--s-7) var(--s-4)}.tbl-empty__action{min-block-size:var(--hit-touch)}}.pi.is-spinning{animation:ef-export-spin .9s linear infinite}@keyframes ef-export-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.pi.is-spinning{animation:none}}.tbl th.tbl-drag-h,.tbl td.tbl-drag{width:28px;padding-inline:4px 0;text-align:center}.tbl td.tbl-drag{cursor:default}.tbl .tbl-drag__grip{display:inline-flex;align-items:center;justify-content:center;width:22px;height:26px;padding:0;border:0;border-radius:6px;background:transparent;color:var(--text-soft);cursor:grab;touch-action:none;transition:background var(--t-fast, .14s) var(--ease-out, ease-out),color var(--t-fast, .14s) var(--ease-out, ease-out)}.tbl .tbl-drag__grip:hover{background:var(--paper);color:var(--text)}.tbl .tbl-drag__grip:focus-visible{outline:2px solid var(--tenant, var(--rule));outline-offset:1px}.tbl .tbl-drag__grip:active{cursor:grabbing}.tbl .tbl-drag__grip i{font-size:12px}.tbl tbody tr.is-dragging>td{background:var(--paper);opacity:.55}.tbl tbody tr.is-drop-target>td{box-shadow:inset 0 2px 0 var(--tenant, var(--rule))}\n"] }]
|
|
5172
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- One cell renderer, shared by the table, the mobile row and the mobile\n detail. A new column type is added here once, not three times. -->\n<ng-template #cellTpl let-row let-col=\"col\" let-index=\"index\">\n @if (bodyTemplate(col.id); as bodyTpl) {\n <ng-container *ngTemplateOutlet=\"bodyTpl; context: { $implicit: row, col: col, index: index }\"></ng-container>\n } @else {\n @switch (col.type) {\n @case ('number') {\n {{ $any(cellValue(row, col)) | number:numberFormat(col):col.locale }}\n }\n @case ('money') {\n {{ $any(cellValue(row, col)) | currency:(col.currencyCode || 'EUR'):(col.currencyDisplay || 'symbol'):numberFormat(col):col.locale }}\n }\n @case ('date') {\n {{ $any(cellValue(row, col)) | date:(col.dateFormat || 'dd/MM/yyyy'):undefined:col.locale }}\n }\n @case ('datetime') {\n {{ $any(cellValue(row, col)) | date:(col.dateFormat || 'dd/MM/yyyy HH:mm'):undefined:col.locale }}\n }\n @case ('boolean') {\n @if (cellValue(row, col)) {\n <span class=\"bool yes\"><span class=\"dot\"></span> \u2713</span>\n } @else {\n <span class=\"bool no\"><span class=\"dot\"></span> \u2014</span>\n }\n }\n @case ('mono') {\n <span class=\"ref\">{{ cellValue(row, col) }}</span>\n }\n @case ('chip') {\n <span [class]=\"'chip ' + (col.chipPrefix || 'chip-') + cellValue(row, col)\">\n \u25CF {{ cellValue(row, col) }}\n </span>\n }\n @case ('status') {\n <ef-status-chip\n [referenceKey]=\"col.referenceKey || ''\"\n [code]=\"$any(cellValue(row, col))\"\n />\n }\n @case ('reference') {\n {{ resolveReference(cellValue(row, col), col) }}\n }\n @default {\n {{ cellValue(row, col) }}\n }\n }\n }\n</ng-template>\n\n<div class=\"tbl-wrap\" [class.has-open-menu]=\"openMenuCount() > 0 || openTool() !== null\" [attr.data-density]=\"density()\">\n <!-- \u2500\u2500 HEAD ROW \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"tbl-head\">\n <div class=\"count small\">\n @if (loading()) {\n <span>{{ loadingKey() | translate }}</span>\n } @else if (errorMsg()) {\n <span style=\"color: var(--st-cancelled-fg); font-weight: 600;\">\u26A0 {{ errorMsg() }}</span>\n } @else {\n <ng-content select=\"[tbl-head-info]\"></ng-content>\n }\n </div>\n <div class=\"tbl-tools\">\n <ng-content select=\"[tbl-head-actions]\"></ng-content>\n\n @if (canExport()) {\n <div class=\"tbl-tool\">\n <button\n class=\"btn btn-ghost btn-sm\"\n type=\"button\"\n [disabled]=\"exporting()\"\n [attr.aria-busy]=\"exporting()\"\n (click)=\"requestExport()\"\n >\n <i\n class=\"pi\"\n [class.pi-download]=\"!exporting()\"\n [class.pi-spinner]=\"exporting()\"\n [class.is-spinning]=\"exporting()\"\n aria-hidden=\"true\"\n ></i>\n {{ (exporting() ? 'common_export_running' : 'common_export') | translate }}\n </button>\n </div>\n }\n\n @if (showDensityControl()) {\n <div class=\"tbl-tool\">\n <button\n class=\"btn btn-ghost btn-sm\"\n type=\"button\"\n [class.open]=\"openTool() === 'density'\"\n [attr.aria-expanded]=\"openTool() === 'density'\"\n aria-haspopup=\"menu\"\n (click)=\"toggleTool('density')\"\n >\n <i class=\"pi pi-bars\" aria-hidden=\"true\"></i>\n {{ 'common_density' | translate }}\n </button>\n @if (openTool() === 'density') {\n <div class=\"tbl-tool__menu\" role=\"menu\">\n @for (opt of densityOptions; track opt.value) {\n <button\n type=\"button\"\n role=\"menuitemradio\"\n [attr.aria-checked]=\"density() === opt.value\"\n [class.is-active]=\"density() === opt.value\"\n (click)=\"setDensity(opt.value)\"\n >\n <i class=\"pi\" [ngClass]=\"opt.icon\" aria-hidden=\"true\"></i>\n <span class=\"tbl-tool__label\">{{ opt.labelKey | translate }}</span>\n @if (density() === opt.value) {\n <i class=\"pi pi-check tbl-tool__check\" aria-hidden=\"true\"></i>\n }\n </button>\n }\n </div>\n }\n </div>\n }\n\n @if (showColumnPicker()) {\n <div class=\"tbl-tool\">\n <button\n class=\"btn btn-ghost btn-sm\"\n type=\"button\"\n [class.open]=\"openTool() === 'columns'\"\n [attr.aria-expanded]=\"openTool() === 'columns'\"\n aria-haspopup=\"menu\"\n (click)=\"toggleTool('columns')\"\n >\n <i class=\"pi pi-th-large\" aria-hidden=\"true\"></i>\n {{ 'common_columns' | translate }}\n </button>\n @if (openTool() === 'columns') {\n <div class=\"tbl-tool__menu tbl-tool__menu--wide\" role=\"menu\">\n @for (col of hideableColumns(); track col.id) {\n <button\n type=\"button\"\n role=\"menuitemcheckbox\"\n [attr.aria-checked]=\"!isColumnHidden(col.id)\"\n [class.is-active]=\"!isColumnHidden(col.id)\"\n (click)=\"toggleColumn(col.id)\"\n >\n <i class=\"pi\" [class.pi-check]=\"!isColumnHidden(col.id)\" aria-hidden=\"true\"></i>\n <span class=\"tbl-tool__label\">{{\n col.headerKey ? (col.headerKey | translate) : (col.header || col.id)\n }}</span>\n </button>\n }\n <div class=\"tbl-tool__sep\"></div>\n <button type=\"button\" role=\"menuitem\" (click)=\"resetColumns()\">\n <i class=\"pi pi-refresh\" aria-hidden=\"true\"></i>\n <span class=\"tbl-tool__label\">{{ 'common_columns_reset' | translate }}</span>\n </button>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- \u2500\u2500 TABLE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (isMobile()) {\n <!-- \u2500\u2500 MOBILE LIST \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n A six-column table on a 390px screen either overflows or\n squeezes every column to nothing, so the rows become a list.\n Same columns, same cell renderers; each column just declares\n (or is given) a role. Both shapes expand to the same detail \u2014\n they differ only in how much they show collapsed. -->\n <ul class=\"mlist\" [attr.data-layout]=\"effectiveMobileLayout()\">\n @for (row of rows(); track trackByRow($index, row); let i = $index) {\n <li class=\"mrow\" [class.is-open]=\"isExpanded(row, i)\">\n <div\n class=\"mrow__head\"\n [class.is-tappable]=\"hasDetail()\"\n [attr.role]=\"hasDetail() ? 'button' : null\"\n [attr.tabindex]=\"hasDetail() ? 0 : null\"\n [attr.aria-expanded]=\"hasDetail() ? isExpanded(row, i) : null\"\n (click)=\"onRowHeadActivate(row, i, $event)\"\n (keydown.enter)=\"onRowHeadActivate(row, i, $event)\"\n (keydown.space)=\"onRowHeadActivate(row, i, $event)\"\n >\n <div class=\"mrow__lead\">\n @if (primaryColumn(); as pc) {\n <span class=\"mrow__primary\" efOverflowTooltip efTooltip efTooltipPosition=\"top\">\n <ng-container *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: pc, index: i }\"></ng-container>\n </span>\n }\n @if (effectiveMobileLayout() === 'row' && secondaryColumns().length) {\n <span class=\"mrow__secondary\">\n @for (sc of secondaryColumns(); track sc.id) {\n <span class=\"mrow__sec-part\">\n <ng-container *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: sc, index: i }\"></ng-container>\n </span>\n }\n </span>\n }\n </div>\n\n <div class=\"mrow__trail\">\n @if (statusColumn(); as st) {\n <ng-container *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: st, index: i }\"></ng-container>\n }\n @if (hasActionsColumn()) {\n <span class=\"mrow__actions\">\n <ef-row-actions [items]=\"defaultRowActions(row)\" [context]=\"rowActionsContext()\" />\n </span>\n }\n @if (hasDetail() && effectiveMobileLayout() === 'row') {\n <!-- Says the row opens, and which way it is now. Decorative:\n the whole head is the control, and it carries the state. -->\n <i\n class=\"pi pi-chevron-down mrow__chevron\"\n [class.is-open]=\"isExpanded(row, i)\"\n aria-hidden=\"true\"\n ></i>\n }\n </div>\n </div>\n\n @if (visibleDetail(row, i).length) {\n <dl class=\"mrow__detail\">\n @for (col of visibleDetail(row, i); track col.id) {\n <div class=\"mrow__field\">\n <dt>{{ $any(col).headerKey ? ($any(col).headerKey | translate) : $any(col).header }}</dt>\n <dd [class]=\"cellAlignClass($any(col))\">\n <ng-container *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: col, index: i }\"></ng-container>\n </dd>\n </div>\n }\n </dl>\n }\n\n @if (hasMoreThanPreview() && effectiveMobileLayout() === 'card') {\n <button class=\"mrow__more\" type=\"button\" (click)=\"toggleExpanded(row, i)\">\n <span>{{ (isExpanded(row, i) ? 'common_view_less' : 'common_view_more') | translate }}</span>\n <i class=\"pi pi-chevron-down mrow__chevron\" [class.is-open]=\"isExpanded(row, i)\" aria-hidden=\"true\"></i>\n </button>\n }\n </li>\n } @empty {\n <li class=\"mrow mrow--empty\">\n <ng-content select=\"[empty-state-mobile]\">\n <ng-container *ngTemplateOutlet=\"defaultEmptyTpl\"></ng-container>\n </ng-content>\n </li>\n }\n </ul>\n } @else {\n <table class=\"tbl\" [class.tbl--fixed]=\"fixedLayout()\">\n <thead>\n <tr>\n @if (reorderable()) {\n <th class=\"tbl-drag-h\" aria-hidden=\"true\"></th>\n }\n @for (col of effectiveColumns(); track trackByColumn($index, col)) {\n <!-- A sortable header is a real <button> inside the <th>, not a\n click handler on the cell. The cell carries aria-sort so the\n current order is announced; the arrow stays decorative.\n Sorting was previously mouse-only and silent to assistive\n technology, on every list screen in the product. -->\n <th\n [class]=\"headerAlignClass(col)\"\n [class.is-sortable]=\"col.sortable\"\n [style.width]=\"col.width || null\"\n [attr.data-col]=\"col.id\"\n [attr.aria-sort]=\"ariaSort(col)\"\n >\n @if (col.sortable) {\n <button type=\"button\" class=\"tbl-sort\" (click)=\"onHeaderClick(col)\">\n <ng-container *ngTemplateOutlet=\"headerLabelTpl; context: { col: col }\"></ng-container>\n @if (sortIndicator(col)) {\n <span aria-hidden=\"true\" class=\"tbl-sort__arrow\">{{ sortIndicator(col) }}</span>\n }\n </button>\n } @else {\n <ng-container *ngTemplateOutlet=\"headerLabelTpl; context: { col: col }\"></ng-container>\n }\n </th>\n }\n </tr>\n </thead>\n\n <tbody>\n @for (row of rows(); track trackByRow($index, row); let i = $index) {\n <tr\n [class.is-row-clickable]=\"rowDoubleClickable()\"\n [class.is-dragging]=\"dragFrom() === i\"\n [class.is-drop-target]=\"dragFrom() !== null && dragFrom() !== i && dragTo() === i\"\n [attr.tabindex]=\"rowDoubleClickable() ? 0 : null\"\n [attr.role]=\"rowDoubleClickable() ? 'button' : null\"\n (dblclick)=\"onRowDoubleClick(row, $event)\"\n (keydown.enter)=\"onRowKeydown(row, $event)\"\n >\n @if (reorderable()) {\n <td class=\"tbl-drag\">\n <!-- The row is draggable only by this handle, so a drag never\n starts from a cell the operator meant to click or select.\n Arrow keys move the row for anyone not using a pointer. -->\n <button\n type=\"button\"\n class=\"tbl-drag__grip\"\n [attr.aria-label]=\"'common_reorder_row' | translate\"\n (pointerdown)=\"onDragPointerDown(i, $event)\"\n (pointermove)=\"onDragPointerMove($event)\"\n (pointerup)=\"onDragPointerUp()\"\n (pointercancel)=\"onDragPointerUp()\"\n (keydown)=\"onDragKeydown(i, $event)\"\n >\n <i class=\"pi pi-ellipsis-v\" aria-hidden=\"true\"></i>\n </button>\n </td>\n }\n @for (col of effectiveColumns(); track trackByColumn($index, col); let colIdx = $index) {\n <td efOverflowTooltip efTooltip efTooltipPosition=\"top\" [class]=\"cellAlignClass(col)\" [attr.data-col]=\"col.id\">\n @if (col.id === 'actions' && hasActionsColumn()) {\n <!-- Auto row-actions cell: View / Edit / Duplicate / Delete,\n gated by [show*Action] flags + ScreenContext perms. -->\n <ef-row-actions\n [items]=\"defaultRowActions(row)\"\n [context]=\"rowActionsContext()\"\n />\n } @else {\n <ng-container\n *ngTemplateOutlet=\"cellTpl; context: { $implicit: row, col: col, index: i }\"\n ></ng-container>\n }\n </td>\n }\n </tr>\n } @empty {\n <tr>\n <td [attr.colspan]=\"effectiveColumns().length + (reorderable() ? 1 : 0)\">\n <ng-content select=\"[empty-state]\">\n <ng-container *ngTemplateOutlet=\"defaultEmptyTpl\"></ng-container>\n </ng-content>\n </td>\n </tr>\n }\n </tbody>\n </table>\n }\n\n <!-- \u2500\u2500 PAGER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <!-- Paging controls for an empty result set are chrome with nothing to\n page, so they stay out of the way until there is something to move\n through. -->\n @if (!hidePager() && rows().length > 0) {\n <ef-pager\n [pageNumber]=\"pageNumber()\"\n [pageSize]=\"pageSize()\"\n [totalCount]=\"totalCount()\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n (pageChange)=\"pageChange.emit($event)\"\n (pageSizeChange)=\"pageSizeChange.emit($event)\"\n />\n }\n</div>\n\n<!-- \u2500\u2500 DEFAULT EMPTY STATE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Rendered when a screen projects nothing into [empty-state] /\n [empty-state-mobile]. It words itself from `searchTerm`, because\n \"nothing matched what you typed\" and \"there is nothing here yet\"\n are different situations needing different ways out. -->\n<ng-template #defaultEmptyTpl>\n <div class=\"tbl-empty\">\n <i\n class=\"pi tbl-empty__icon\"\n [class.pi-search]=\"!!searchTerm()\"\n [class.pi-inbox]=\"!searchTerm()\"\n aria-hidden=\"true\"\n ></i>\n\n @if (searchTerm()) {\n <p class=\"tbl-empty__title\">\n {{ 'common_empty_no_results' | translate: { term: searchTerm() } }}\n </p>\n <p class=\"tbl-empty__hint\">{{ 'common_empty_no_results_hint' | translate }}</p>\n <button class=\"btn btn-sm tbl-empty__action\" type=\"button\" (click)=\"clearSearch.emit()\">\n <i class=\"pi pi-times\" aria-hidden=\"true\"></i>\n {{ 'common_empty_clear_filters' | translate }}\n </button>\n } @else {\n <p class=\"tbl-empty__title\">{{ 'common_empty_none_yet' | translate }}</p>\n <p class=\"tbl-empty__hint\">{{ 'common_empty_none_yet_hint' | translate }}</p>\n }\n </div>\n</ng-template>\n\n<!-- Header label, shared by the sortable and plain header cells so the\n projection rules stay in one place. -->\n<ng-template #headerLabelTpl let-col=\"col\">\n @if (headerTemplate(col.id); as headerTpl) {\n <ng-container *ngTemplateOutlet=\"headerTpl; context: { $implicit: col, col: col }\"></ng-container>\n } @else if (col.headerKey) {\n <span>{{ col.headerKey | translate }}</span>\n } @else if (col.header) {\n <span>{{ col.header }}</span>\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";.tbl thead th.is-sortable{cursor:pointer;-webkit-user-select:none;user-select:none;transition:color var(--t-fast, .14s) var(--ease-out, ease-out)}.tbl thead th.is-sortable:hover{color:var(--text)}.tbl tbody tr.is-row-clickable{cursor:pointer}.tbl-tools{display:flex;gap:6px;align-items:center}.tbl-tool{position:relative}.tbl-tool>.btn.open{color:var(--text);background:var(--paper)}.tbl-tool__menu{position:absolute;top:calc(100% + 8px);inset-inline-end:0;z-index:40;min-width:212px;max-height:340px;overflow-y:auto;padding:6px;display:grid;gap:1px;background:var(--paper-alt);border:1px solid var(--rule);border-radius:var(--r-xl);box-shadow:var(--shadow-3);animation:row-actions-menu-in var(--t-base) var(--ease-spring)}.tbl-tool__menu--wide{min-width:248px}.tbl-tool__menu button{appearance:none;background:transparent;border:0;width:100%;text-align:start;font:inherit;font-size:13.5px;font-weight:600;color:var(--text);display:flex;align-items:center;gap:12px;padding:9px 12px;border-radius:var(--r-md);cursor:pointer;transition:background-color var(--t-fast) var(--ease-out)}.tbl-tool__menu button:hover,.tbl-tool__menu button:focus-visible{background:var(--paper);outline:0}.tbl-tool__menu button>.pi{width:16px;flex:none;font-size:14px;color:var(--muted)}.tbl-tool__menu button.is-active>.pi{color:var(--module, var(--text))}.tbl-tool__label{flex:1 1 auto;min-width:0}.tbl-tool__check{color:var(--module, var(--text))}.tbl-tool__sep{margin:5px 2px;border-top:1px solid var(--rule)}.tbl-wrap[data-density=compact] .tbl tbody td{padding-top:4px;padding-bottom:4px}.tbl-wrap[data-density=comfortable] .tbl tbody td{padding-top:16px;padding-bottom:16px}.mlist{list-style:none;margin:0;padding:0;display:grid}.mrow{border-top:1px solid var(--rule)}.mrow:first-child{border-top:0}.mrow__head{display:flex;align-items:flex-start;gap:var(--s-3);padding:12px var(--s-4);min-height:var(--hit-touch)}.mrow__head.is-tappable{cursor:pointer}.mrow__head.is-tappable:active{background:var(--paper)}.mrow__lead{flex:1;min-width:0;display:grid;gap:2px}.mrow__primary{font-weight:700;font-size:14px;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mrow__secondary{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 6px;font-size:12.5px;color:var(--text-mute);min-width:0}.mrow__secondary .mrow__sec-part+.mrow__sec-part:before{content:\"\\b7\";margin-inline-end:6px;color:var(--text-soft)}.mrow__trail{display:flex;align-items:center;justify-content:flex-end;gap:var(--s-2);flex-shrink:0;min-height:20px}.mrow__actions{display:inline-flex}.mrow__detail{margin:0;padding:0 var(--s-4) 12px;display:grid;gap:1px}.mrow__field{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-3);padding:7px 0;border-top:1px solid var(--rule-soft)}.mrow__field dt{font-size:11.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--text-mute);flex-shrink:0}.mrow__field dd{margin:0;font-size:13.5px;color:var(--text);text-align:end;min-width:0;overflow-wrap:anywhere}.mrow__more{appearance:none;width:100%;background:transparent;border:0;border-top:1px solid var(--rule-soft);padding:10px;font:inherit;font-size:13px;font-weight:600;color:var(--tenant-500);cursor:pointer}.mlist[data-layout=card]{gap:var(--s-3);padding:var(--s-3) var(--s-3) 0}.mlist[data-layout=card] .mrow{border:1px solid var(--rule);border-radius:var(--r-lg);background:var(--paper-alt);overflow:hidden}.mlist[data-layout=card] .mrow__head{border-bottom:1px solid var(--rule)}.mrow__chevron{font-size:11px;color:var(--text-soft);transition:transform var(--t-fast) var(--ease-out);flex-shrink:0}.mrow__chevron.is-open{transform:rotate(180deg);color:var(--text-mute)}.mrow__head.is-tappable:focus-visible{outline:2px solid var(--tenant-400);outline-offset:-2px}.mrow__more{display:flex;align-items:center;justify-content:center;gap:6px}.tbl-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--s-2);padding:var(--s-9) var(--s-4);text-align:center}.tbl-empty__icon{font-size:28px;line-height:1;color:var(--ink-400);margin-block-end:var(--s-1)}.tbl-empty__title{margin:0;font-size:15px;font-weight:600;color:var(--text);max-inline-size:46ch;overflow-wrap:break-word}.tbl-empty__hint{margin:0;font-size:13px;color:var(--ink-600);max-inline-size:52ch;text-wrap:pretty}.tbl-empty__action{margin-block-start:var(--s-3);min-block-size:var(--hit-base)}.mrow--empty{padding:0}@media(max-width:767px){.tbl-empty{padding:var(--s-7) var(--s-4)}.tbl-empty__action{min-block-size:var(--hit-touch)}}.pi.is-spinning{animation:ef-export-spin .9s linear infinite}@keyframes ef-export-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.pi.is-spinning{animation:none}}.tbl th.tbl-drag-h,.tbl td.tbl-drag{width:28px;padding-inline:4px 0;text-align:center}.tbl td.tbl-drag{cursor:default}.tbl .tbl-drag__grip{display:inline-flex;align-items:center;justify-content:center;width:22px;height:26px;padding:0;border:0;border-radius:6px;background:transparent;color:var(--text-soft);cursor:grab;touch-action:none;transition:background var(--t-fast, .14s) var(--ease-out, ease-out),color var(--t-fast, .14s) var(--ease-out, ease-out)}.tbl .tbl-drag__grip:hover{background:var(--paper);color:var(--text)}.tbl .tbl-drag__grip:focus-visible{outline:2px solid var(--tenant, var(--rule));outline-offset:1px}.tbl .tbl-drag__grip:active{cursor:grabbing}.tbl .tbl-drag__grip i{font-size:12px}.tbl tbody tr.is-dragging>td{background:var(--paper);opacity:.55}.tbl tbody tr.is-drop-target>td{box-shadow:inset 0 2px 0 var(--tenant, var(--rule))}.tbl.tbl--fixed{table-layout:fixed}\n"] }]
|
|
5077
5173
|
}], propDecorators: { mobileLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "mobileLayout", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], trackByField: [{ type: i0.Input, args: [{ isSignal: true, alias: "trackByField", required: false }] }], pageNumber: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageNumber", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], totalCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalCount", required: false }] }], pageSizeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizeOptions", required: false }] }], hidePager: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidePager", required: false }] }], sort: [{ type: i0.Input, args: [{ isSignal: true, alias: "sort", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], errorMsg: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMsg", required: false }] }], loadingKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingKey", required: false }] }], rowDoubleClickable: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowDoubleClickable", required: false }] }], hasActionsColumn: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasActionsColumn", required: false }] }], rowActionsContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowActionsContext", required: false }] }], showViewAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "showViewAction", required: false }] }], showEditAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "showEditAction", required: false }] }], showDuplicateAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDuplicateAction", required: false }] }], showDeleteAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDeleteAction", required: false }] }], showDensityControl: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDensityControl", required: false }] }], showColumnPicker: [{ type: i0.Input, args: [{ isSignal: true, alias: "showColumnPicker", required: false }] }], showExportControl: [{ type: i0.Input, args: [{ isSignal: true, alias: "showExportControl", required: false }] }], exporting: [{ type: i0.Input, args: [{ isSignal: true, alias: "exporting", required: false }] }], screenContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "screenContext", required: false }] }], searchTerm: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchTerm", required: false }] }], tableKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableKey", required: false }] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], pageSizeChange: [{ type: i0.Output, args: ["pageSizeChange"] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], rowDoubleClick: [{ type: i0.Output, args: ["rowDoubleClick"] }], rowAction: [{ type: i0.Output, args: ["rowAction"] }], exportRequest: [{ type: i0.Output, args: ["exportRequest"] }], clearSearch: [{ type: i0.Output, args: ["clearSearch"] }], bodyTemplates: [{
|
|
5078
5174
|
type: ContentChildren,
|
|
5079
5175
|
args: [EfColumnTemplateDirective]
|
|
5080
5176
|
}], headerTemplates: [{
|
|
5081
5177
|
type: ContentChildren,
|
|
5082
5178
|
args: [EfColumnHeaderTemplateDirective]
|
|
5083
|
-
}], defaultDensity: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultDensity", required: false }] }], reorderable: [{ type: i0.Input, args: [{ isSignal: true, alias: "reorderable", required: false }] }], rowReorder: [{ type: i0.Output, args: ["rowReorder"] }], onDocumentClick: [{
|
|
5179
|
+
}], defaultDensity: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultDensity", required: false }] }], reorderable: [{ type: i0.Input, args: [{ isSignal: true, alias: "reorderable", required: false }] }], rowReorder: [{ type: i0.Output, args: ["rowReorder"] }], fixedLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "fixedLayout", required: false }] }], onDocumentClick: [{
|
|
5084
5180
|
type: HostListener,
|
|
5085
5181
|
args: ['document:click', ['$event']]
|
|
5086
5182
|
}], onEscape: [{
|
|
@@ -5265,7 +5361,7 @@ class EfOrderBuilderComponent {
|
|
|
5265
5361
|
cols.push({
|
|
5266
5362
|
id: 'discount',
|
|
5267
5363
|
headerKey: 'label.discount',
|
|
5268
|
-
width: '
|
|
5364
|
+
width: '116px',
|
|
5269
5365
|
align: 'end',
|
|
5270
5366
|
cellClass: 'num',
|
|
5271
5367
|
mobile: 'detail',
|
|
@@ -5275,7 +5371,7 @@ class EfOrderBuilderComponent {
|
|
|
5275
5371
|
cols.push({
|
|
5276
5372
|
id: 'tax',
|
|
5277
5373
|
headerKey: 'order_builder.tax',
|
|
5278
|
-
width: '
|
|
5374
|
+
width: '116px',
|
|
5279
5375
|
align: 'end',
|
|
5280
5376
|
cellClass: 'num',
|
|
5281
5377
|
mobile: 'detail',
|
|
@@ -5577,7 +5673,7 @@ class EfOrderBuilderComponent {
|
|
|
5577
5673
|
return OrderEntityHelper.calculateTotals(this.order());
|
|
5578
5674
|
}
|
|
5579
5675
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfOrderBuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5580
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfOrderBuilderComponent, isStandalone: true, selector: "ef-order-builder", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, order: { classPropertyName: "order", publicName: "order", isSignal: true, isRequired: true, transformFunction: null }, products: { classPropertyName: "products", publicName: "products", isSignal: true, isRequired: true, transformFunction: null }, customers: { classPropertyName: "customers", publicName: "customers", isSignal: true, isRequired: true, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, countGroupLabels: { classPropertyName: "countGroupLabels", publicName: "countGroupLabels", isSignal: true, isRequired: false, transformFunction: null }, productKeyField: { classPropertyName: "productKeyField", publicName: "productKeyField", isSignal: true, isRequired: false, transformFunction: null }, backendErrors: { classPropertyName: "backendErrors", publicName: "backendErrors", isSignal: true, isRequired: false, transformFunction: null }, auditEntries: { classPropertyName: "auditEntries", publicName: "auditEntries", isSignal: true, isRequired: false, transformFunction: null }, focusMode: { classPropertyName: "focusMode", publicName: "focusMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { order: "orderChange", openCatalogue: "openCatalogue", orderChanged: "orderChanged", orderValidated: "orderValidated", productsAdded: "productsAdded", focusMode: "focusModeChange" }, viewQueries: [{ propertyName: "typeahead", first: true, predicate: EfProductTypeaheadComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"order-builder\"\n [class.ob-collapsed]=\"focusMode()\"\n [class.ob-rail-open]=\"railOpen()\">\n <div class=\"ob-grid\">\n <div class=\"ob-main\">\n <!-- Order header: customer + date + express add (one card) -->\n <ef-card\n titleKey=\"order_builder.section_order\"\n [metaKey]=\"readonly() ? '' : 'order_builder.quick_add_hint'\"\n [overflowVisible]=\"true\">\n <div class=\"ob-order-head\">\n <div class=\"form-grid\">\n <div class=\"field col-6\">\n <ef-label labelKey=\"label.customer\" for=\"ob-cust\" [required]=\"true\" />\n <ef-select\n inputId=\"ob-cust\"\n [options]=\"customers()\"\n optionLabel=\"companyName\"\n optionValue=\"customerId\"\n [ngModel]=\"order().customerId\"\n (ngModelChange)=\"updateCustomer($event)\"\n [disabled]=\"readonly()\"\n [showClear]=\"true\"\n [filter]=\"true\"\n filterBy=\"companyName\"\n filterPlaceholderKey=\"label.search_customer\"\n appendTo=\"body\"\n placeholderKey=\"label.select_customer\" />\n </div>\n <div class=\"field col-3\">\n <ef-label labelKey=\"label.order_date\" for=\"ob-date\" [required]=\"true\" />\n <ef-datepicker-advanced\n mode=\"field\"\n selectionMode=\"single\"\n inputId=\"ob-date\"\n placeholderKey=\"date_select_date\"\n [ngModel]=\"order().orderDate\"\n (ngModelChange)=\"updateOrderDate($event)\"\n [disabled]=\"readonly()\" />\n </div>\n </div>\n\n @if (!readonly()) {\n <div class=\"qa-grid\">\n <div class=\"qa-combo-wrap\">\n <ef-label labelKey=\"label.article\" />\n <ef-product-typeahead\n [products]=\"products()\"\n [productKeyField]=\"productKeyField()\"\n placeholderKey=\"label.search_product\"\n [currency]=\"currency()\"\n [locale]=\"locale()\"\n (productSelect)=\"onTypeaheadSelect($event)\"\n [showVariants]=\"false\" />\n </div>\n <div class=\"qa-price\">\n <ef-label labelKey=\"label.sale_price\" />\n <ef-inputnumber\n variant=\"comptoir\"\n [value]=\"quickAddPrice()\"\n (valueChangeEvent)=\"quickAddPrice.set($event ?? 0)\"\n [minFractionDigits]=\"2\"\n [maxFractionDigits]=\"2\"\n [locale]=\"locale()\"\n [disabled]=\"readonly()\" />\n </div>\n <div class=\"qa-qtyf\">\n <ef-label labelKey=\"label.quantity\" />\n <ef-inputnumber\n variant=\"comptoir\"\n [ngModel]=\"quickAddQuantity()\"\n (ngModelChange)=\"quickAddQuantity.set($event)\"\n [min]=\"0\"\n [maxFractionDigits]=\"4\"\n [locale]=\"locale()\"\n [disabled]=\"readonly()\"\n />\n </div>\n <div class=\"qa-go\">\n <!-- Ghost while the preconditions are unmet, tenant once the\n line is addable. A disabled control painted in a faded\n tenant fill reads as an enabled button that lost its\n colour, which is the greyed-out accent the design brief\n bans; ghost reads as \"not yet\". -->\n <ef-button\n labelKey=\"action.add\"\n icon=\"pi pi-plus\"\n variant=\"comptoir\"\n [severity]=\"quickAddDisabled() ? 'ghost' : 'tenant'\"\n [disabled]=\"quickAddDisabled()\"\n (clickEvent)=\"addQuickProduct()\" />\n </div>\n </div>\n }\n </div>\n </ef-card>\n\n <!-- Lines.\n\n ef-data-card owns the panel here instead of sitting inside an\n ef-card: `.tbl-wrap` already draws a bordered, rounded surface, so\n nesting it in another one would be a card inside a card. The title\n and the card's actions move into the head slots it provides.\n\n The columns are declared in TS (`lineColumns`) so discount and tax\n follow the document config, and so one definition drives both the\n desktop table and the mobile cards. Only the article column is\n elastic; every other column holds a number of known magnitude and\n gets a fixed track, which keeps the decimals aligned down the\n table rather than shifting with the longest description. -->\n <ef-data-card\n [columns]=\"lineColumns()\"\n [rows]=\"orderLines()\"\n trackByField=\"id\"\n [hidePager]=\"true\"\n defaultDensity=\"compact\"\n [reorderable]=\"!readonly()\"\n (rowReorder)=\"reorderLine($event)\"\n mobileLayout=\"card\">\n\n <div tbl-head-info class=\"ob-lines-head\">\n <span class=\"strong\">{{ 'order_builder.lines' | translate }}</span>\n <span class=\"meta\">\u00B7 {{ orderLines().length }}</span>\n </div>\n\n <div tbl-head-actions class=\"head-actions\">\n @if (config().showCatalogue && !readonly()) {\n <ef-button\n labelKey=\"action.open_catalogue\"\n icon=\"pi pi-box\"\n severity=\"secondary\"\n [text]=\"true\"\n (clickEvent)=\"handleOpenCatalogue()\" />\n }\n <ef-button\n [labelKey]=\"focusMode() ? 'order_builder.show_summary' : 'order_builder.fullscreen'\"\n icon=\"pi pi-window-maximize\"\n severity=\"secondary\"\n [text]=\"true\"\n (clickEvent)=\"toggleFocus()\" />\n </div>\n\n <span empty-state>{{ 'order_builder.empty' | translate }}</span>\n <span empty-state-mobile>{{ 'order_builder.empty' | translate }}</span>\n\n <ng-template efColumnTemplate=\"product\" let-item let-i=\"index\">\n <div class=\"p\">\n <span class=\"ln\">{{ i + 1 }}</span>\n <span class=\"pp\">\n <span class=\"nm\">{{ item.productDescription }}</span>\n </span>\n </div>\n </ng-template>\n\n <ng-template efColumnTemplate=\"price\" let-item>\n @if (!readonly() && isEditingCell(item, 'price')) {\n <ef-inputnumber\n [(ngModel)]=\"item.productUnitPrice\"\n (ngModelChange)=\"onFieldChange(item)\"\n [showClear]=\"false\"\n [autofocus]=\"true\"\n (blurEvent)=\"stopEditCell()\"\n (keyDownEvent)=\"onEditCellKeydown($event)\"\n [min]=\"0\"\n [minFractionDigits]=\"2\"\n [maxFractionDigits]=\"2\"\n [locale]=\"locale()\"\n size=\"small\"\n class=\"!text-end\" />\n } @else {\n <button type=\"button\" class=\"ln-val\" [disabled]=\"readonly()\" (click)=\"startEditCell(item, 'price')\">\n {{ item.productUnitPrice | number: '1.2-2' : locale() }}\n </button>\n }\n </ng-template>\n\n <ng-template efColumnTemplate=\"qty\" let-item>\n @if (!readonly() && isEditingCell(item, 'qty')) {\n <ef-inputnumber\n [(ngModel)]=\"item.quantity\"\n (ngModelChange)=\"onFieldChange(item)\"\n [showClear]=\"false\"\n [autofocus]=\"true\"\n (blurEvent)=\"stopEditCell()\"\n (keyDownEvent)=\"onEditCellKeydown($event)\"\n [min]=\"0\"\n [maxFractionDigits]=\"4\"\n [locale]=\"locale()\"\n size=\"small\"\n class=\"!text-end\" />\n } @else {\n <button type=\"button\" class=\"ln-val\" [disabled]=\"readonly()\" (click)=\"startEditCell(item, 'qty')\">\n {{ item.quantity | number: '1.0-4' : locale() }}\n </button>\n }\n </ng-template>\n\n <ng-template efColumnTemplate=\"discount\" let-item>\n @if (!readonly() && isEditingCell(item, 'discount')) {\n <ef-inputnumber\n [(ngModel)]=\"item.discount\"\n (ngModelChange)=\"onFieldChange(item)\"\n [showClear]=\"false\"\n [autofocus]=\"true\"\n (blurEvent)=\"stopEditCell()\"\n (keyDownEvent)=\"onEditCellKeydown($event)\"\n [min]=\"0\"\n [max]=\"100\"\n [maxFractionDigits]=\"2\"\n suffix=\" %\"\n [locale]=\"locale()\"\n size=\"small\"\n class=\"!text-end\" />\n } @else {\n <button type=\"button\" class=\"ln-val\" [disabled]=\"readonly()\" (click)=\"startEditCell(item, 'discount')\">\n {{ item.discount | number: '1.0-2' : locale() }} %\n </button>\n }\n </ng-template>\n\n <ng-template efColumnTemplate=\"tax\" let-item>\n @if (!readonly() && isEditingCell(item, 'tva')) {\n <ef-inputnumber\n [(ngModel)]=\"item.taxRate\"\n (ngModelChange)=\"onFieldChange(item)\"\n [showClear]=\"false\"\n [autofocus]=\"true\"\n (blurEvent)=\"stopEditCell()\"\n (keyDownEvent)=\"onEditCellKeydown($event)\"\n [min]=\"0\"\n [max]=\"100\"\n [maxFractionDigits]=\"2\"\n suffix=\" %\"\n [locale]=\"locale()\"\n size=\"small\"\n class=\"!text-end\" />\n } @else {\n <button type=\"button\" class=\"ln-val\" [disabled]=\"readonly()\" (click)=\"startEditCell(item, 'tva')\">\n {{ (item.taxRate ?? 0) | number: '1.0-2' : locale() }} %\n </button>\n }\n </ng-template>\n\n <ng-template efColumnTemplate=\"subtotal\" let-item>\n {{ calculateSubtotal(item) | number: '1.2-2' : locale() }}\n </ng-template>\n\n <ng-template efColumnTemplate=\"remove\" let-item>\n <ef-button\n icon=\"pi pi-trash\"\n severity=\"danger\"\n [text]=\"true\"\n styleClass=\"ob-del\"\n (clickEvent)=\"removeOrderLine(item.id)\" />\n </ng-template>\n </ef-data-card>\n\n </div>\n\n <!-- CONTEXT RAIL (1/3) -->\n <aside class=\"ob-rail\">\n <!-- Totaux (top) -->\n <ef-card titleKey=\"order_builder.totals\" [meta]=\"currency()\">\n <div class=\"ob-totals\">\n <div class=\"row\">\n <span class=\"lbl\">{{ 'order_builder.gross' | translate }}</span>\n <span class=\"v\">{{ grossTotal() | number: '1.2-2' : locale() }}</span>\n </div>\n <div class=\"row discount\">\n <span class=\"lbl\">{{ 'order_builder.discount' | translate }}</span>\n <span class=\"v\">\u2212{{ discountTotal() | number: '1.2-2' : locale() }}</span>\n </div>\n <div class=\"row\">\n <span class=\"lbl\">{{ 'order_builder.tax' | translate }}</span>\n <span class=\"v\">{{ tvaTotal() | number: '1.2-2' : locale() }}</span>\n </div>\n <hr />\n <div class=\"row grand\">\n <span class=\"lbl\">{{ 'order_builder.grand_total' | translate }}</span>\n <span class=\"v\">{{ finalTotal() | number: '1.2-2' : locale() }}<span class=\"cur\">{{ currency() }}</span></span>\n </div>\n </div>\n </ef-card>\n\n <!-- R\u00E9capitulatif par format -->\n @if (productsSummary().items.length > 0) {\n <ef-card titleKey=\"order_builder.recap\" metaKey=\"order_builder.auto\">\n <div class=\"ob-recap\">\n <div class=\"cols\">\n @for (col of recapColumns(); track $index) {\n <div class=\"grp\">\n @for (seg of col; track seg.code) {\n <div class=\"seg\">\n <span class=\"fmt\">{{ seg.label }}</span>\n <span class=\"n\">{{ seg.count | number: '1.0-0' : locale() }}</span>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"tot\">\n <span class=\"l\">{{ 'order_builder.total_units' | translate }}</span>\n <span class=\"n\">{{ productsSummary().totalCount | number: '1.0-0' : locale() }}</span>\n </div>\n </div>\n </ef-card>\n }\n\n <!-- Historique (optional, component-owned) -->\n @if (hasAudit()) {\n <ef-change-history [entries]=\"auditEntries()\" />\n }\n </aside>\n </div>\n\n <!-- Floating summary FAB + backdrop -->\n <button type=\"button\" class=\"ob-backdrop\" aria-hidden=\"true\" tabindex=\"-1\" (click)=\"toggleRail(false)\"></button>\n <div class=\"ob-fab\" role=\"status\">\n <div class=\"ft\">\n <span class=\"k\">{{ 'order_builder.total_units' | translate }} \u00B7 {{ productsSummary().totalCount }}</span>\n <span class=\"vv\">{{ finalTotal() | number: '1.2-2' : locale() }}<span class=\"cur\">{{ currency() }}</span></span>\n </div>\n <button type=\"button\" class=\"open\" (click)=\"toggleRail(true)\">\n {{ 'order_builder.summary' | translate }}\n </button>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}:host .order-builder{display:grid;gap:var(--s-3)}:host .order-builder .head-actions{display:flex;align-items:center;gap:6px}:host .order-builder .ob-empty{padding:28px 16px;text-align:center;color:var(--text-mute);font-size:13px}:host .order-builder .text-mute{color:var(--text-mute);font-weight:600}:host .order-builder .form-grid{display:grid;gap:var(--s-3);grid-template-columns:repeat(12,minmax(0,1fr))}:host .order-builder .form-grid>.col-3{grid-column:span 3}:host .order-builder .form-grid>.col-4{grid-column:span 4}:host .order-builder .form-grid>.col-5{grid-column:span 5}:host .order-builder .form-grid>.col-6{grid-column:span 6}@media(max-width:767px){:host .order-builder .form-grid>[class*=col-]{grid-column:span 12}}:host .order-builder .field{display:grid;gap:4px}:host .order-builder .field>label{font-size:11px;font-weight:700;color:var(--text-mute);text-transform:uppercase;letter-spacing:.06em}:host .order-builder .field .req{color:var(--st-cancelled-fg);margin-inline-start:2px}:host .order-builder .ob-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-3);align-items:start}@media(min-width:1280px){:host .order-builder .ob-grid{grid-template-columns:minmax(0,2fr) minmax(0,1fr)}}:host .order-builder .ob-main{display:grid;gap:var(--s-3);min-width:0}:host .order-builder .ob-rail{display:grid;gap:var(--s-3);align-content:start}@media(min-width:1280px){:host .order-builder .ob-rail{position:sticky;top:44px}}:host .order-builder .ob-order-head{display:grid;gap:var(--s-4)}:host .order-builder .qa-grid{display:flex;flex-wrap:wrap;gap:10px;align-items:end;padding-top:var(--s-3);border-top:1px solid var(--rule-soft)}:host .order-builder .qa-combo-wrap{flex:1 1 260px;min-width:0}:host .order-builder .qa-price{flex:0 1 132px}:host .order-builder .qa-qtyf{flex:0 0 132px}:host .order-builder .qa-go{flex:0 0 auto}@media(max-width:560px){:host .order-builder .qa-combo-wrap,:host .order-builder .qa-price,:host .order-builder .qa-qtyf,:host .order-builder .qa-go{flex:1 1 100%}}:host .order-builder .qin{width:58px;text-align:end;font:inherit;font-family:var(--font-mono);font-weight:700;padding:6px 8px;min-height:34px;border:1px solid var(--rule);border-radius:var(--r-sm);background:var(--paper-alt);color:var(--text);outline:0;-moz-appearance:textfield}:host .order-builder .qin::-webkit-outer-spin-button,:host .order-builder .qin::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}:host .order-builder .qin:focus{border-color:var(--tenant-400);box-shadow:0 0 0 3px var(--tenant-100)}:host .order-builder ef-data-card{font-size:13px}:host .order-builder ef-data-card .p{display:flex;align-items:baseline;gap:9px;line-height:1.25}:host .order-builder ef-data-card .p .ln{flex:0 0 auto;min-width:15px;text-align:end;font-family:var(--font-mono);font-size:10.5px;font-weight:700;color:var(--text-soft)}:host .order-builder ef-data-card .p .pp{display:grid;gap:1px;min-width:0}:host .order-builder ef-data-card .p .nm{font-weight:600;letter-spacing:-.005em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host .order-builder ef-data-card .p .nm em{font-style:normal;color:var(--text-mute);font-weight:600}:host .order-builder ef-data-card .p .ref{font-family:var(--font-mono);font-size:10.5px;color:var(--text-soft);font-weight:600}:host .order-builder ef-data-card .num,:host .order-builder ef-data-card .total{font-family:var(--font-mono);font-feature-settings:\"tnum\";font-variant-numeric:tabular-nums}:host .order-builder ef-data-card .ln-val{appearance:none;width:100%;margin:0;padding:5px 8px;border:1px solid transparent;border-radius:7px;background:transparent;font:inherit;font-family:var(--font-mono);font-feature-settings:\"tnum\";font-variant-numeric:tabular-nums;color:inherit;text-align:end;cursor:text;transition:background .12s ease,border-color .12s ease}:host .order-builder ef-data-card .ln-val:hover:not(:disabled){background:var(--paper);border-color:var(--rule)}:host .order-builder ef-data-card .ln-val:focus-visible{outline:none;background:var(--paper);border-color:var(--tenant, var(--rule))}:host .order-builder ef-data-card .ln-val:disabled{cursor:default;background:transparent;border-color:transparent}:host .order-builder ef-data-card .total{font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 85;font-size:13.5px}:host .order-builder ef-data-card .cur{font-size:9.5px;color:var(--text-soft);margin-inline-start:3px}:host .order-builder ef-data-card .free{color:var(--st-delivered-fg)}:host .order-builder .ob-lines-head{display:flex;align-items:baseline;gap:6px;min-width:0}:host .order-builder .ob-lines-head .strong{font-weight:700;color:var(--text)}:host .order-builder .ob-lines-head .meta{color:var(--text-soft)}:host .order-builder .ob-del{color:var(--text-soft)}:host .order-builder .ob-del:hover{color:var(--st-cancelled-fg);border-color:var(--st-cancelled-bg)}:host .order-builder .ob-totals{display:grid;gap:6px}:host .order-builder .ob-totals .row{display:flex;justify-content:space-between;align-items:baseline;gap:14px}:host .order-builder .ob-totals .row .lbl{font-size:12px;font-weight:600;color:var(--text-mute)}:host .order-builder .ob-totals .row .v{font-family:var(--font-mono);font-feature-settings:\"tnum\";font-variant-numeric:tabular-nums;font-weight:700;font-size:12.5px}:host .order-builder .ob-totals .row.discount .v{color:var(--st-pending-fg)}:host .order-builder .ob-totals hr{border:0;border-top:1px solid var(--rule);margin:5px 0}:host .order-builder .ob-totals .grand .lbl{font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 85;font-size:13.5px;color:var(--text)}:host .order-builder .ob-totals .grand .v{font-family:var(--font-display);font-variation-settings:\"opsz\" 96,\"wght\" 700,\"wdth\" 80;font-size:26px;letter-spacing:-.03em;color:var(--text)}:host .order-builder .ob-totals .grand .cur{font-family:var(--font-mono);font-size:.4em;color:var(--text-mute);margin-inline-start:4px}:host .order-builder .ob-recap .cols{display:grid;grid-template-columns:1fr 1fr}:host .order-builder .ob-recap .grp{display:flex;flex-direction:column;gap:3px;min-width:0}:host .order-builder .ob-recap .grp:first-child{padding-inline-end:14px}:host .order-builder .ob-recap .grp+.grp{padding-inline-start:14px;border-inline-start:1px solid var(--rule)}:host .order-builder .ob-recap .seg{display:flex;justify-content:space-between;align-items:baseline;gap:8px}:host .order-builder .ob-recap .seg .fmt{font-size:11.5px;font-weight:700;color:var(--text);letter-spacing:-.005em;min-width:0}:host .order-builder .ob-recap .seg .fmt:after{content:\":\";color:var(--text-soft)}:host .order-builder .ob-recap .seg .n{font-family:var(--font-mono);font-weight:700;font-size:12px;color:var(--text);font-variant-numeric:tabular-nums;flex-shrink:0}:host .order-builder .ob-recap .tot{display:flex;justify-content:space-between;align-items:baseline;margin-top:12px;padding-top:10px;border-top:1px solid var(--rule)}:host .order-builder .ob-recap .tot .l{font-weight:700;font-size:12px}:host .order-builder .ob-recap .tot .n{font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 85;font-size:18px;font-variant-numeric:tabular-nums}:host .order-builder .ob-rail-close{display:none}:host .order-builder .ob-fab{display:none;position:fixed;inset-inline-end:20px;bottom:calc(var(--app-bottom-bar, 0px) + env(safe-area-inset-bottom,0px) + 20px);z-index:30;align-items:center;gap:10px;background:var(--ink-active);color:var(--paper);border-radius:var(--r-pill);padding:8px 10px 8px 16px;box-shadow:var(--shadow-3)}:host .order-builder .ob-fab .ft{display:grid;line-height:1.1}:host .order-builder .ob-fab .ft .k{font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;opacity:.65}:host .order-builder .ob-fab .ft .vv{font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 82;font-size:16px}:host .order-builder .ob-fab .ft .vv .cur{font-family:var(--font-mono);font-size:.6em;opacity:.7;margin-inline-start:3px}:host .order-builder .ob-fab .open{appearance:none;cursor:pointer;border:0;background:#ffffff24;color:#fff;font:inherit;font-size:12px;font-weight:700;border-radius:var(--r-pill);padding:8px 14px;display:inline-flex;align-items:center;gap:6px}:host .order-builder .ob-fab .open:hover{background:#ffffff3d}:host .order-builder .ob-backdrop{display:none;position:fixed;inset:0;z-index:38;background:#0f11156b;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px)}:host .order-builder.ob-collapsed .ob-grid{grid-template-columns:minmax(0,1fr)}:host .order-builder.ob-collapsed .ob-fab{display:flex}:host .order-builder.ob-collapsed .ob-rail{position:fixed;top:0;inset-inline-end:0;height:100dvh;width:min(360px,92vw);z-index:40;background:var(--paper);border-inline-start:1px solid var(--rule);box-shadow:var(--shadow-3);padding:14px;overflow:auto;gap:var(--s-3);transform:translate(101%);transition:transform var(--t-base) var(--ease-out)}[dir=rtl] :host .order-builder.ob-collapsed .ob-rail{transform:translate(-101%)}:host .order-builder.ob-collapsed .ob-rail-close{display:inline-flex}:host .order-builder.ob-collapsed.ob-rail-open .ob-rail{transform:none}:host .order-builder.ob-collapsed.ob-rail-open .ob-backdrop{display:block}@media(max-width:1279px){:host .order-builder .ob-grid{grid-template-columns:minmax(0,1fr)}:host .order-builder .ob-fab{display:flex}:host .order-builder .ob-rail{position:fixed;top:0;inset-inline-end:0;height:100dvh;width:min(360px,92vw);z-index:40;background:var(--paper);border-inline-start:1px solid var(--rule);box-shadow:var(--shadow-3);padding:14px;overflow:auto;gap:var(--s-3);transform:translate(101%);transition:transform var(--t-base) var(--ease-out)}[dir=rtl] :host .order-builder .ob-rail{transform:translate(-101%)}:host .order-builder .ob-rail-close{display:inline-flex!important}:host .order-builder.ob-rail-open .ob-rail{transform:none}:host .order-builder.ob-rail-open .ob-backdrop{display:block}}:host ef-data-card .nm,:host ef-data-card .num,:host ef-data-card .ln-val,:host .ob-totals .v,:host .ob-sum-val{unicode-bidi:plaintext}@media(max-width:767px){:host .order-builder{padding-bottom:calc(var(--app-bottom-bar, 0px) + env(safe-area-inset-bottom,0px) + 20px + 56px + var(--s-4))}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfSelectComponent, selector: "ef-select", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "dataKey", "group", "optionGroupLabel", "optionGroupChildren", "size", "fluid", "inline", "appendTo", "multiple", "filter", "filterBy", "filterPlaceholder", "filterPlaceholderKey", "autofocusFilter", "editable", "loading", "virtualScroll", "virtualScrollItemSize", "scrollHeight", "multiDisplay", "showToggleAll", "emptyMessage", "emptyMessageKey", "emptyFilterMessage", "emptyFilterMessageKey", "styleClass", "panelStyleClass", "filterByKeys", "variant", "value"], outputs: ["selectionChangeEvent", "filterChangeEvent", "panelShowEvent", "panelHideEvent"] }, { kind: "component", type: EfDatepickerAdvancedComponent, selector: "ef-datepicker-advanced", inputs: ["triggerLabelKey", "triggerLabel", "presets", "activePreset", "start", "end", "allowCustomRange", "mode", "selectionMode", "variant", "showTime"], outputs: ["rangeChange", "opened", "closed"] }, { kind: "component", type: EfInputNumberComponent, selector: "ef-inputnumber", inputs: ["value", "invalid", "format", "showButtons", "buttonLayout", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "prefix", "suffix", "currency", "currencyDisplay", "locale", "localeMatcher", "mode", "useGrouping", "minFractionDigits", "maxFractionDigits", "min", "max", "step", "allowEmpty", "inputSize", "size", "maxlength", "minlength", "pattern", "tabindex", "title", "ariaLabelledBy", "inputStyle", "inputStyleClass", "style", "styleClass", "primeNgVariant", "autofocus", "autocomplete", "fluid", "inline", "variant", "pt", "ptOptions", "dt", "unstyled"], outputs: ["inputEvent", "valueChangeEvent", "focusEvent", "blurEvent", "keyDownEvent", "clearEvent"] }, { kind: "component", type: EfLabelComponent, selector: "ef-label", inputs: ["label", "labelKey", "for", "styleClass", "required"] }, { kind: "component", type: EfButtonComponent, selector: "ef-button", inputs: ["label", "labelKey", "icon", "variant", "severity", "size", "disabled", "rounded", "outlined", "raised", "text", "loading", "styleClass", "type", "badge", "badgeSeverity", "tooltip", "tooltipKey", "tooltipPosition"], outputs: ["clickEvent"] }, { kind: "component", type: EfCardComponent, selector: "ef-card", inputs: ["titleKey", "title", "metaKey", "meta", "tone", "forceHead", "hasFoot", "collapsible", "overflowVisible", "loading", "skeleton", "skeletonRows", "skeletonHeight", "collapsed"], outputs: ["collapsedChange"] }, { kind: "component", type: EfChangeHistoryComponent, selector: "ef-change-history", inputs: ["entries", "titleKey", "emptyKey", "limit", "previewLimit", "collapsible", "startCollapsed"] }, { kind: "component", type: EfProductTypeaheadComponent, selector: "ef-product-typeahead", inputs: ["products", "productKeyField", "placeholderKey", "disabled", "currency", "locale", "showVariants"], outputs: ["productSelect"] }, { kind: "component", type: EfDataCardComponent, selector: "ef-data-card", inputs: ["mobileLayout", "columns", "rows", "trackByField", "pageNumber", "pageSize", "totalCount", "pageSizeOptions", "hidePager", "sort", "loading", "errorMsg", "loadingKey", "rowDoubleClickable", "hasActionsColumn", "rowActionsContext", "showViewAction", "showEditAction", "showDuplicateAction", "showDeleteAction", "showDensityControl", "showColumnPicker", "showExportControl", "exporting", "screenContext", "searchTerm", "tableKey", "defaultDensity", "reorderable"], outputs: ["pageChange", "pageSizeChange", "sortChange", "rowDoubleClick", "rowAction", "exportRequest", "clearSearch", "rowReorder"] }, { kind: "directive", type: EfColumnTemplateDirective, selector: "[efColumnTemplate]", inputs: ["efColumnTemplate"] }, { kind: "pipe", type: i1$3.DecimalPipe, name: "number" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
5676
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfOrderBuilderComponent, isStandalone: true, selector: "ef-order-builder", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, order: { classPropertyName: "order", publicName: "order", isSignal: true, isRequired: true, transformFunction: null }, products: { classPropertyName: "products", publicName: "products", isSignal: true, isRequired: true, transformFunction: null }, customers: { classPropertyName: "customers", publicName: "customers", isSignal: true, isRequired: true, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, countGroupLabels: { classPropertyName: "countGroupLabels", publicName: "countGroupLabels", isSignal: true, isRequired: false, transformFunction: null }, productKeyField: { classPropertyName: "productKeyField", publicName: "productKeyField", isSignal: true, isRequired: false, transformFunction: null }, backendErrors: { classPropertyName: "backendErrors", publicName: "backendErrors", isSignal: true, isRequired: false, transformFunction: null }, auditEntries: { classPropertyName: "auditEntries", publicName: "auditEntries", isSignal: true, isRequired: false, transformFunction: null }, focusMode: { classPropertyName: "focusMode", publicName: "focusMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { order: "orderChange", openCatalogue: "openCatalogue", orderChanged: "orderChanged", orderValidated: "orderValidated", productsAdded: "productsAdded", focusMode: "focusModeChange" }, viewQueries: [{ propertyName: "typeahead", first: true, predicate: EfProductTypeaheadComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"order-builder\"\n [class.ob-collapsed]=\"focusMode()\"\n [class.ob-rail-open]=\"railOpen()\">\n <div class=\"ob-grid\">\n <div class=\"ob-main\">\n <!-- Order header: customer + date + express add (one card) -->\n <ef-card\n titleKey=\"order_builder.section_order\"\n [metaKey]=\"readonly() ? '' : 'order_builder.quick_add_hint'\"\n [overflowVisible]=\"true\">\n <div class=\"ob-order-head\">\n <div class=\"form-grid\">\n <div class=\"field col-6\">\n <ef-label labelKey=\"label.customer\" for=\"ob-cust\" [required]=\"true\" />\n <ef-select\n inputId=\"ob-cust\"\n [options]=\"customers()\"\n optionLabel=\"companyName\"\n optionValue=\"customerId\"\n [ngModel]=\"order().customerId\"\n (ngModelChange)=\"updateCustomer($event)\"\n [disabled]=\"readonly()\"\n [showClear]=\"true\"\n [filter]=\"true\"\n filterBy=\"companyName\"\n filterPlaceholderKey=\"label.search_customer\"\n appendTo=\"body\"\n placeholderKey=\"label.select_customer\" />\n </div>\n <div class=\"field col-3\">\n <ef-label labelKey=\"label.order_date\" for=\"ob-date\" [required]=\"true\" />\n <ef-datepicker-advanced\n mode=\"field\"\n selectionMode=\"single\"\n inputId=\"ob-date\"\n placeholderKey=\"date_select_date\"\n [ngModel]=\"order().orderDate\"\n (ngModelChange)=\"updateOrderDate($event)\"\n [disabled]=\"readonly()\" />\n </div>\n </div>\n\n @if (!readonly()) {\n <div class=\"qa-grid\">\n <div class=\"qa-combo-wrap\">\n <ef-label labelKey=\"label.article\" />\n <ef-product-typeahead\n [products]=\"products()\"\n [productKeyField]=\"productKeyField()\"\n placeholderKey=\"label.search_product\"\n [currency]=\"currency()\"\n [locale]=\"locale()\"\n (productSelect)=\"onTypeaheadSelect($event)\"\n [showVariants]=\"false\" />\n </div>\n <div class=\"qa-price\">\n <ef-label labelKey=\"label.sale_price\" />\n <ef-inputnumber\n variant=\"comptoir\"\n [value]=\"quickAddPrice()\"\n (valueChangeEvent)=\"quickAddPrice.set($event ?? 0)\"\n [minFractionDigits]=\"2\"\n [maxFractionDigits]=\"2\"\n [locale]=\"locale()\"\n [disabled]=\"readonly()\" />\n </div>\n <div class=\"qa-qtyf\">\n <ef-label labelKey=\"label.quantity\" />\n <ef-inputnumber\n variant=\"comptoir\"\n [ngModel]=\"quickAddQuantity()\"\n (ngModelChange)=\"quickAddQuantity.set($event)\"\n [min]=\"0\"\n [maxFractionDigits]=\"4\"\n [locale]=\"locale()\"\n [disabled]=\"readonly()\"\n />\n </div>\n <div class=\"qa-go\">\n <!-- Ghost while the preconditions are unmet, tenant once the\n line is addable. A disabled control painted in a faded\n tenant fill reads as an enabled button that lost its\n colour, which is the greyed-out accent the design brief\n bans; ghost reads as \"not yet\". -->\n <ef-button\n labelKey=\"action.add\"\n icon=\"pi pi-plus\"\n variant=\"comptoir\"\n size=\"base\"\n [severity]=\"quickAddDisabled() ? 'ghost' : 'tenant'\"\n [disabled]=\"quickAddDisabled()\"\n (clickEvent)=\"addQuickProduct()\" />\n </div>\n </div>\n }\n </div>\n </ef-card>\n\n <!-- Lines.\n\n ef-data-card owns the panel here instead of sitting inside an\n ef-card: `.tbl-wrap` already draws a bordered, rounded surface, so\n nesting it in another one would be a card inside a card. The title\n and the card's actions move into the head slots it provides.\n\n The columns are declared in TS (`lineColumns`) so discount and tax\n follow the document config, and so one definition drives both the\n desktop table and the mobile cards. Only the article column is\n elastic; every other column holds a number of known magnitude and\n gets a fixed track, which keeps the decimals aligned down the\n table rather than shifting with the longest description. -->\n <ef-data-card\n [columns]=\"lineColumns()\"\n [rows]=\"orderLines()\"\n trackByField=\"id\"\n [hidePager]=\"true\"\n defaultDensity=\"compact\"\n [reorderable]=\"!readonly()\"\n [fixedLayout]=\"true\"\n (rowReorder)=\"reorderLine($event)\"\n mobileLayout=\"card\">\n\n <div tbl-head-info class=\"ob-lines-head\">\n <span class=\"strong\">{{ 'order_builder.lines' | translate }}</span>\n <span class=\"meta\">\u00B7 {{ orderLines().length }}</span>\n </div>\n\n <div tbl-head-actions class=\"head-actions\">\n @if (config().showCatalogue && !readonly()) {\n <ef-button\n labelKey=\"action.open_catalogue\"\n icon=\"pi pi-box\"\n severity=\"secondary\"\n [text]=\"true\"\n (clickEvent)=\"handleOpenCatalogue()\" />\n }\n <ef-button\n [labelKey]=\"focusMode() ? 'order_builder.show_summary' : 'order_builder.fullscreen'\"\n icon=\"pi pi-window-maximize\"\n severity=\"secondary\"\n [text]=\"true\"\n (clickEvent)=\"toggleFocus()\" />\n </div>\n\n <span empty-state>{{ 'order_builder.empty' | translate }}</span>\n <span empty-state-mobile>{{ 'order_builder.empty' | translate }}</span>\n\n <ng-template efColumnTemplate=\"product\" let-item let-i=\"index\">\n <div class=\"p\">\n <span class=\"ln\">{{ i + 1 }}</span>\n <span class=\"pp\">\n <span class=\"nm\">{{ item.productDescription }}</span>\n </span>\n </div>\n </ng-template>\n\n <ng-template efColumnTemplate=\"price\" let-item>\n @if (!readonly() && isEditingCell(item, 'price')) {\n <ef-inputnumber\n [(ngModel)]=\"item.productUnitPrice\"\n (ngModelChange)=\"onFieldChange(item)\"\n [showClear]=\"false\"\n [autofocus]=\"true\"\n (blurEvent)=\"stopEditCell()\"\n (keyDownEvent)=\"onEditCellKeydown($event)\"\n [min]=\"0\"\n [minFractionDigits]=\"2\"\n [maxFractionDigits]=\"2\"\n [locale]=\"locale()\"\n size=\"small\"\n class=\"!text-end\" />\n } @else {\n <button type=\"button\" class=\"ln-val\" [disabled]=\"readonly()\" (click)=\"startEditCell(item, 'price')\">\n {{ item.productUnitPrice | number: '1.2-2' : locale() }}\n </button>\n }\n </ng-template>\n\n <ng-template efColumnTemplate=\"qty\" let-item>\n @if (!readonly() && isEditingCell(item, 'qty')) {\n <ef-inputnumber\n [(ngModel)]=\"item.quantity\"\n (ngModelChange)=\"onFieldChange(item)\"\n [showClear]=\"false\"\n [autofocus]=\"true\"\n (blurEvent)=\"stopEditCell()\"\n (keyDownEvent)=\"onEditCellKeydown($event)\"\n [min]=\"0\"\n [maxFractionDigits]=\"4\"\n [locale]=\"locale()\"\n size=\"small\"\n class=\"!text-end\" />\n } @else {\n <button type=\"button\" class=\"ln-val\" [disabled]=\"readonly()\" (click)=\"startEditCell(item, 'qty')\">\n {{ item.quantity | number: '1.0-4' : locale() }}\n </button>\n }\n </ng-template>\n\n <ng-template efColumnTemplate=\"discount\" let-item>\n @if (!readonly() && isEditingCell(item, 'discount')) {\n <ef-inputnumber\n [(ngModel)]=\"item.discount\"\n (ngModelChange)=\"onFieldChange(item)\"\n [showClear]=\"false\"\n [autofocus]=\"true\"\n (blurEvent)=\"stopEditCell()\"\n (keyDownEvent)=\"onEditCellKeydown($event)\"\n [min]=\"0\"\n [max]=\"100\"\n [maxFractionDigits]=\"2\"\n suffix=\" %\"\n [locale]=\"locale()\"\n size=\"small\"\n class=\"!text-end\" />\n } @else {\n <button type=\"button\" class=\"ln-val\" [disabled]=\"readonly()\" (click)=\"startEditCell(item, 'discount')\">\n {{ item.discount | number: '1.0-2' : locale() }} %\n </button>\n }\n </ng-template>\n\n <ng-template efColumnTemplate=\"tax\" let-item>\n @if (!readonly() && isEditingCell(item, 'tva')) {\n <ef-inputnumber\n [(ngModel)]=\"item.taxRate\"\n (ngModelChange)=\"onFieldChange(item)\"\n [showClear]=\"false\"\n [autofocus]=\"true\"\n (blurEvent)=\"stopEditCell()\"\n (keyDownEvent)=\"onEditCellKeydown($event)\"\n [min]=\"0\"\n [max]=\"100\"\n [maxFractionDigits]=\"2\"\n suffix=\" %\"\n [locale]=\"locale()\"\n size=\"small\"\n class=\"!text-end\" />\n } @else {\n <button type=\"button\" class=\"ln-val\" [disabled]=\"readonly()\" (click)=\"startEditCell(item, 'tva')\">\n {{ (item.taxRate ?? 0) | number: '1.0-2' : locale() }} %\n </button>\n }\n </ng-template>\n\n <ng-template efColumnTemplate=\"subtotal\" let-item>\n {{ calculateSubtotal(item) | number: '1.2-2' : locale() }}\n </ng-template>\n\n <ng-template efColumnTemplate=\"remove\" let-item>\n <ef-button\n icon=\"pi pi-trash\"\n severity=\"danger\"\n [text]=\"true\"\n styleClass=\"ob-del\"\n (clickEvent)=\"removeOrderLine(item.id)\" />\n </ng-template>\n </ef-data-card>\n\n </div>\n\n <!-- CONTEXT RAIL (1/3) -->\n <aside class=\"ob-rail\">\n <!-- Totaux (top) -->\n <ef-card titleKey=\"order_builder.totals\" [meta]=\"currency()\">\n <div class=\"ob-totals\">\n <div class=\"row\">\n <span class=\"lbl\">{{ 'order_builder.gross' | translate }}</span>\n <span class=\"v\">{{ grossTotal() | number: '1.2-2' : locale() }}</span>\n </div>\n <div class=\"row discount\">\n <span class=\"lbl\">{{ 'order_builder.discount' | translate }}</span>\n <span class=\"v\">\u2212{{ discountTotal() | number: '1.2-2' : locale() }}</span>\n </div>\n <div class=\"row\">\n <span class=\"lbl\">{{ 'order_builder.tax' | translate }}</span>\n <span class=\"v\">{{ tvaTotal() | number: '1.2-2' : locale() }}</span>\n </div>\n <hr />\n <div class=\"row grand\">\n <span class=\"lbl\">{{ 'order_builder.grand_total' | translate }}</span>\n <span class=\"v\">{{ finalTotal() | number: '1.2-2' : locale() }}<span class=\"cur\">{{ currency() }}</span></span>\n </div>\n </div>\n </ef-card>\n\n <!-- R\u00E9capitulatif par format -->\n @if (productsSummary().items.length > 0) {\n <ef-card titleKey=\"order_builder.recap\" metaKey=\"order_builder.auto\">\n <div class=\"ob-recap\">\n <div class=\"cols\">\n @for (col of recapColumns(); track $index) {\n <div class=\"grp\">\n @for (seg of col; track seg.code) {\n <div class=\"seg\">\n <span class=\"fmt\">{{ seg.label }}</span>\n <span class=\"n\">{{ seg.count | number: '1.0-0' : locale() }}</span>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"tot\">\n <span class=\"l\">{{ 'order_builder.total_units' | translate }}</span>\n <span class=\"n\">{{ productsSummary().totalCount | number: '1.0-0' : locale() }}</span>\n </div>\n </div>\n </ef-card>\n }\n\n <!-- Historique (optional, component-owned) -->\n @if (hasAudit()) {\n <ef-change-history [entries]=\"auditEntries()\" />\n }\n </aside>\n </div>\n\n <!-- Floating summary FAB + backdrop -->\n <button type=\"button\" class=\"ob-backdrop\" aria-hidden=\"true\" tabindex=\"-1\" (click)=\"toggleRail(false)\"></button>\n <div class=\"ob-fab\" role=\"status\">\n <div class=\"ft\">\n <span class=\"k\">{{ 'order_builder.total_units' | translate }} \u00B7 {{ productsSummary().totalCount }}</span>\n <span class=\"vv\">{{ finalTotal() | number: '1.2-2' : locale() }}<span class=\"cur\">{{ currency() }}</span></span>\n </div>\n <button type=\"button\" class=\"open\" (click)=\"toggleRail(true)\">\n {{ 'order_builder.summary' | translate }}\n </button>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}:host .order-builder{display:grid;gap:var(--s-3)}:host .order-builder .head-actions{display:flex;align-items:center;gap:6px}:host .order-builder .ob-empty{padding:28px 16px;text-align:center;color:var(--text-mute);font-size:13px}:host .order-builder .text-mute{color:var(--text-mute);font-weight:600}:host .order-builder .form-grid{display:grid;gap:var(--s-3);grid-template-columns:repeat(12,minmax(0,1fr))}:host .order-builder .form-grid>.col-3{grid-column:span 3}:host .order-builder .form-grid>.col-4{grid-column:span 4}:host .order-builder .form-grid>.col-5{grid-column:span 5}:host .order-builder .form-grid>.col-6{grid-column:span 6}@media(max-width:767px){:host .order-builder .form-grid>[class*=col-]{grid-column:span 12}}:host .order-builder .field{display:grid;gap:4px}:host .order-builder .field>label{font-size:11px;font-weight:700;color:var(--text-mute);text-transform:uppercase;letter-spacing:.06em}:host .order-builder .field .req{color:var(--st-cancelled-fg);margin-inline-start:2px}:host .order-builder .ob-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-3);align-items:start}@media(min-width:1280px){:host .order-builder .ob-grid{grid-template-columns:minmax(0,2fr) minmax(0,1fr)}}:host .order-builder .ob-main{display:grid;gap:var(--s-3);min-width:0}:host .order-builder .ob-rail{display:grid;gap:var(--s-3);align-content:start}@media(min-width:1280px){:host .order-builder .ob-rail{position:sticky;top:44px}}:host .order-builder .ob-order-head{display:grid;gap:var(--s-4)}:host .order-builder .qa-grid{display:flex;flex-wrap:wrap;gap:10px;align-items:end;padding-top:var(--s-3);border-top:1px solid var(--rule-soft)}:host .order-builder .qa-combo-wrap{flex:1 1 260px;min-width:0}:host .order-builder .qa-price{flex:0 1 132px}:host .order-builder .qa-qtyf{flex:0 0 132px}:host .order-builder .qa-go{flex:0 0 auto}@media(max-width:560px){:host .order-builder .qa-combo-wrap,:host .order-builder .qa-price,:host .order-builder .qa-qtyf,:host .order-builder .qa-go{flex:1 1 100%}}:host .order-builder .qin{width:58px;text-align:end;font:inherit;font-family:var(--font-mono);font-weight:700;padding:6px 8px;min-height:34px;border:1px solid var(--rule);border-radius:var(--r-sm);background:var(--paper-alt);color:var(--text);outline:0;-moz-appearance:textfield}:host .order-builder .qin::-webkit-outer-spin-button,:host .order-builder .qin::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}:host .order-builder .qin:focus{border-color:var(--tenant-400);box-shadow:0 0 0 3px var(--tenant-100)}:host .order-builder ef-data-card{font-size:13px}:host .order-builder ef-data-card .p{display:flex;align-items:baseline;gap:9px;line-height:1.25}:host .order-builder ef-data-card .p .ln{flex:0 0 auto;min-width:15px;text-align:end;font-family:var(--font-mono);font-size:10.5px;font-weight:700;color:var(--text-soft)}:host .order-builder ef-data-card .p .pp{display:grid;gap:1px;min-width:0}:host .order-builder ef-data-card .p .nm{font-weight:600;letter-spacing:-.005em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host .order-builder ef-data-card .p .nm em{font-style:normal;color:var(--text-mute);font-weight:600}:host .order-builder ef-data-card .p .ref{font-family:var(--font-mono);font-size:10.5px;color:var(--text-soft);font-weight:600}:host .order-builder ef-data-card ef-inputnumber,:host .order-builder ef-data-card ef-inputnumber .ef-field-control,:host .order-builder ef-data-card ef-inputnumber input{width:100%;min-width:0}:host .order-builder ef-data-card .num,:host .order-builder ef-data-card .total{font-family:var(--font-mono);font-feature-settings:\"tnum\";font-variant-numeric:tabular-nums}:host .order-builder ef-data-card .ln-val{appearance:none;width:100%;margin:0;padding:5px 8px;border:1px solid transparent;border-radius:7px;background:transparent;font:inherit;font-family:var(--font-mono);font-feature-settings:\"tnum\";font-variant-numeric:tabular-nums;color:inherit;text-align:end;cursor:text;transition:background .12s ease,border-color .12s ease}:host .order-builder ef-data-card .ln-val:hover:not(:disabled){background:var(--paper);border-color:var(--rule)}:host .order-builder ef-data-card .ln-val:focus-visible{outline:none;background:var(--paper);border-color:var(--tenant, var(--rule))}:host .order-builder ef-data-card .ln-val:disabled{cursor:default;background:transparent;border-color:transparent}:host .order-builder ef-data-card .total{font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 85;font-size:13.5px}:host .order-builder ef-data-card .cur{font-size:9.5px;color:var(--text-soft);margin-inline-start:3px}:host .order-builder ef-data-card .free{color:var(--st-delivered-fg)}:host .order-builder .ob-lines-head{display:flex;align-items:baseline;gap:6px;min-width:0}:host .order-builder .ob-lines-head .strong{font-weight:700;color:var(--text)}:host .order-builder .ob-lines-head .meta{color:var(--text-soft)}:host .order-builder .ob-del{color:var(--text-soft)}:host .order-builder .ob-del:hover{color:var(--st-cancelled-fg);border-color:var(--st-cancelled-bg)}:host .order-builder .ob-totals{display:grid;gap:6px}:host .order-builder .ob-totals .row{display:flex;justify-content:space-between;align-items:baseline;gap:14px}:host .order-builder .ob-totals .row .lbl{font-size:12px;font-weight:600;color:var(--text-mute)}:host .order-builder .ob-totals .row .v{font-family:var(--font-mono);font-feature-settings:\"tnum\";font-variant-numeric:tabular-nums;font-weight:700;font-size:12.5px}:host .order-builder .ob-totals .row.discount .v{color:var(--st-pending-fg)}:host .order-builder .ob-totals hr{border:0;border-top:1px solid var(--rule);margin:5px 0}:host .order-builder .ob-totals .grand .lbl{font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 85;font-size:13.5px;color:var(--text)}:host .order-builder .ob-totals .grand .v{font-family:var(--font-display);font-variation-settings:\"opsz\" 96,\"wght\" 700,\"wdth\" 80;font-size:26px;letter-spacing:-.03em;color:var(--text)}:host .order-builder .ob-totals .grand .cur{font-family:var(--font-mono);font-size:.4em;color:var(--text-mute);margin-inline-start:4px}:host .order-builder .ob-recap .cols{display:grid;grid-template-columns:1fr 1fr}:host .order-builder .ob-recap .grp{display:flex;flex-direction:column;gap:3px;min-width:0}:host .order-builder .ob-recap .grp:first-child{padding-inline-end:14px}:host .order-builder .ob-recap .grp+.grp{padding-inline-start:14px;border-inline-start:1px solid var(--rule)}:host .order-builder .ob-recap .seg{display:flex;justify-content:space-between;align-items:baseline;gap:8px}:host .order-builder .ob-recap .seg .fmt{font-size:11.5px;font-weight:700;color:var(--text);letter-spacing:-.005em;min-width:0}:host .order-builder .ob-recap .seg .fmt:after{content:\":\";color:var(--text-soft)}:host .order-builder .ob-recap .seg .n{font-family:var(--font-mono);font-weight:700;font-size:12px;color:var(--text);font-variant-numeric:tabular-nums;flex-shrink:0}:host .order-builder .ob-recap .tot{display:flex;justify-content:space-between;align-items:baseline;margin-top:12px;padding-top:10px;border-top:1px solid var(--rule)}:host .order-builder .ob-recap .tot .l{font-weight:700;font-size:12px}:host .order-builder .ob-recap .tot .n{font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 85;font-size:18px;font-variant-numeric:tabular-nums}:host .order-builder .ob-rail-close{display:none}:host .order-builder .ob-fab{display:none;position:fixed;inset-inline-end:20px;bottom:calc(var(--app-bottom-bar, 0px) + env(safe-area-inset-bottom,0px) + 20px);z-index:30;align-items:center;gap:10px;background:var(--ink-active);color:var(--paper);border-radius:var(--r-pill);padding:8px 10px 8px 16px;box-shadow:var(--shadow-3)}:host .order-builder .ob-fab .ft{display:grid;line-height:1.1}:host .order-builder .ob-fab .ft .k{font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;opacity:.65}:host .order-builder .ob-fab .ft .vv{font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 82;font-size:16px}:host .order-builder .ob-fab .ft .vv .cur{font-family:var(--font-mono);font-size:.6em;opacity:.7;margin-inline-start:3px}:host .order-builder .ob-fab .open{appearance:none;cursor:pointer;border:0;background:#ffffff24;color:#fff;font:inherit;font-size:12px;font-weight:700;border-radius:var(--r-pill);padding:8px 14px;display:inline-flex;align-items:center;gap:6px}:host .order-builder .ob-fab .open:hover{background:#ffffff3d}:host .order-builder .ob-backdrop{display:none;position:fixed;inset:0;z-index:38;background:#0f11156b;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px)}:host .order-builder.ob-collapsed .ob-grid{grid-template-columns:minmax(0,1fr)}:host .order-builder.ob-collapsed .ob-fab{display:flex}:host .order-builder.ob-collapsed .ob-rail{position:fixed;top:0;inset-inline-end:0;height:100dvh;width:min(360px,92vw);z-index:40;background:var(--paper);border-inline-start:1px solid var(--rule);box-shadow:var(--shadow-3);padding:14px;overflow:auto;gap:var(--s-3);transform:translate(101%);transition:transform var(--t-base) var(--ease-out)}[dir=rtl] :host .order-builder.ob-collapsed .ob-rail{transform:translate(-101%)}:host .order-builder.ob-collapsed .ob-rail-close{display:inline-flex}:host .order-builder.ob-collapsed.ob-rail-open .ob-rail{transform:none}:host .order-builder.ob-collapsed.ob-rail-open .ob-backdrop{display:block}@media(max-width:1279px){:host .order-builder .ob-grid{grid-template-columns:minmax(0,1fr)}:host .order-builder .ob-fab{display:flex}:host .order-builder .ob-rail{position:fixed;top:0;inset-inline-end:0;height:100dvh;width:min(360px,92vw);z-index:40;background:var(--paper);border-inline-start:1px solid var(--rule);box-shadow:var(--shadow-3);padding:14px;overflow:auto;gap:var(--s-3);transform:translate(101%);transition:transform var(--t-base) var(--ease-out)}[dir=rtl] :host .order-builder .ob-rail{transform:translate(-101%)}:host .order-builder .ob-rail-close{display:inline-flex!important}:host .order-builder.ob-rail-open .ob-rail{transform:none}:host .order-builder.ob-rail-open .ob-backdrop{display:block}}:host ef-data-card .nm,:host ef-data-card .num,:host ef-data-card .ln-val,:host .ob-totals .v,:host .ob-sum-val{unicode-bidi:plaintext}@media(max-width:767px){:host .order-builder{padding-bottom:calc(var(--app-bottom-bar, 0px) + env(safe-area-inset-bottom,0px) + 20px + 56px + var(--s-4))}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfSelectComponent, selector: "ef-select", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "dataKey", "group", "optionGroupLabel", "optionGroupChildren", "size", "fluid", "inline", "appendTo", "multiple", "filter", "filterBy", "filterPlaceholder", "filterPlaceholderKey", "autofocusFilter", "autofocus", "editable", "loading", "virtualScroll", "virtualScrollItemSize", "scrollHeight", "multiDisplay", "showToggleAll", "emptyMessage", "emptyMessageKey", "emptyFilterMessage", "emptyFilterMessageKey", "styleClass", "panelStyleClass", "filterByKeys", "variant", "value"], outputs: ["selectionChangeEvent", "filterChangeEvent", "panelShowEvent", "panelHideEvent"] }, { kind: "component", type: EfDatepickerAdvancedComponent, selector: "ef-datepicker-advanced", inputs: ["triggerLabelKey", "triggerLabel", "presets", "activePreset", "start", "end", "allowCustomRange", "mode", "selectionMode", "variant", "showTime"], outputs: ["rangeChange", "opened", "closed"] }, { kind: "component", type: EfInputNumberComponent, selector: "ef-inputnumber", inputs: ["value", "invalid", "format", "showButtons", "buttonLayout", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "prefix", "suffix", "currency", "currencyDisplay", "locale", "localeMatcher", "mode", "useGrouping", "minFractionDigits", "maxFractionDigits", "min", "max", "step", "allowEmpty", "inputSize", "size", "maxlength", "minlength", "pattern", "tabindex", "title", "ariaLabelledBy", "inputStyle", "inputStyleClass", "style", "styleClass", "primeNgVariant", "autofocus", "autocomplete", "fluid", "inline", "variant", "pt", "ptOptions", "dt", "unstyled"], outputs: ["inputEvent", "valueChangeEvent", "focusEvent", "blurEvent", "keyDownEvent", "clearEvent"] }, { kind: "component", type: EfLabelComponent, selector: "ef-label", inputs: ["label", "labelKey", "for", "styleClass", "required"] }, { kind: "component", type: EfButtonComponent, selector: "ef-button", inputs: ["label", "labelKey", "icon", "variant", "severity", "size", "disabled", "rounded", "outlined", "raised", "text", "loading", "styleClass", "type", "badge", "badgeSeverity", "tooltip", "tooltipKey", "tooltipPosition", "autofocus"], outputs: ["clickEvent"] }, { kind: "component", type: EfCardComponent, selector: "ef-card", inputs: ["titleKey", "title", "metaKey", "meta", "tone", "forceHead", "hasFoot", "collapsible", "overflowVisible", "loading", "skeleton", "skeletonRows", "skeletonHeight", "collapsed"], outputs: ["collapsedChange"] }, { kind: "component", type: EfChangeHistoryComponent, selector: "ef-change-history", inputs: ["entries", "titleKey", "emptyKey", "limit", "previewLimit", "collapsible", "startCollapsed"] }, { kind: "component", type: EfProductTypeaheadComponent, selector: "ef-product-typeahead", inputs: ["products", "productKeyField", "placeholderKey", "disabled", "currency", "locale", "showVariants"], outputs: ["productSelect"] }, { kind: "component", type: EfDataCardComponent, selector: "ef-data-card", inputs: ["mobileLayout", "columns", "rows", "trackByField", "pageNumber", "pageSize", "totalCount", "pageSizeOptions", "hidePager", "sort", "loading", "errorMsg", "loadingKey", "rowDoubleClickable", "hasActionsColumn", "rowActionsContext", "showViewAction", "showEditAction", "showDuplicateAction", "showDeleteAction", "showDensityControl", "showColumnPicker", "showExportControl", "exporting", "screenContext", "searchTerm", "tableKey", "defaultDensity", "reorderable", "fixedLayout"], outputs: ["pageChange", "pageSizeChange", "sortChange", "rowDoubleClick", "rowAction", "exportRequest", "clearSearch", "rowReorder"] }, { kind: "directive", type: EfColumnTemplateDirective, selector: "[efColumnTemplate]", inputs: ["efColumnTemplate"] }, { kind: "pipe", type: i1$3.DecimalPipe, name: "number" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
5581
5677
|
}
|
|
5582
5678
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfOrderBuilderComponent, decorators: [{
|
|
5583
5679
|
type: Component,
|
|
@@ -5596,7 +5692,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
5596
5692
|
EfProductTypeaheadComponent,
|
|
5597
5693
|
EfDataCardComponent,
|
|
5598
5694
|
EfColumnTemplateDirective,
|
|
5599
|
-
], template: "<div\n class=\"order-builder\"\n [class.ob-collapsed]=\"focusMode()\"\n [class.ob-rail-open]=\"railOpen()\">\n <div class=\"ob-grid\">\n <div class=\"ob-main\">\n <!-- Order header: customer + date + express add (one card) -->\n <ef-card\n titleKey=\"order_builder.section_order\"\n [metaKey]=\"readonly() ? '' : 'order_builder.quick_add_hint'\"\n [overflowVisible]=\"true\">\n <div class=\"ob-order-head\">\n <div class=\"form-grid\">\n <div class=\"field col-6\">\n <ef-label labelKey=\"label.customer\" for=\"ob-cust\" [required]=\"true\" />\n <ef-select\n inputId=\"ob-cust\"\n [options]=\"customers()\"\n optionLabel=\"companyName\"\n optionValue=\"customerId\"\n [ngModel]=\"order().customerId\"\n (ngModelChange)=\"updateCustomer($event)\"\n [disabled]=\"readonly()\"\n [showClear]=\"true\"\n [filter]=\"true\"\n filterBy=\"companyName\"\n filterPlaceholderKey=\"label.search_customer\"\n appendTo=\"body\"\n placeholderKey=\"label.select_customer\" />\n </div>\n <div class=\"field col-3\">\n <ef-label labelKey=\"label.order_date\" for=\"ob-date\" [required]=\"true\" />\n <ef-datepicker-advanced\n mode=\"field\"\n selectionMode=\"single\"\n inputId=\"ob-date\"\n placeholderKey=\"date_select_date\"\n [ngModel]=\"order().orderDate\"\n (ngModelChange)=\"updateOrderDate($event)\"\n [disabled]=\"readonly()\" />\n </div>\n </div>\n\n @if (!readonly()) {\n <div class=\"qa-grid\">\n <div class=\"qa-combo-wrap\">\n <ef-label labelKey=\"label.article\" />\n <ef-product-typeahead\n [products]=\"products()\"\n [productKeyField]=\"productKeyField()\"\n placeholderKey=\"label.search_product\"\n [currency]=\"currency()\"\n [locale]=\"locale()\"\n (productSelect)=\"onTypeaheadSelect($event)\"\n [showVariants]=\"false\" />\n </div>\n <div class=\"qa-price\">\n <ef-label labelKey=\"label.sale_price\" />\n <ef-inputnumber\n variant=\"comptoir\"\n [value]=\"quickAddPrice()\"\n (valueChangeEvent)=\"quickAddPrice.set($event ?? 0)\"\n [minFractionDigits]=\"2\"\n [maxFractionDigits]=\"2\"\n [locale]=\"locale()\"\n [disabled]=\"readonly()\" />\n </div>\n <div class=\"qa-qtyf\">\n <ef-label labelKey=\"label.quantity\" />\n <ef-inputnumber\n variant=\"comptoir\"\n [ngModel]=\"quickAddQuantity()\"\n (ngModelChange)=\"quickAddQuantity.set($event)\"\n [min]=\"0\"\n [maxFractionDigits]=\"4\"\n [locale]=\"locale()\"\n [disabled]=\"readonly()\"\n />\n </div>\n <div class=\"qa-go\">\n <!-- Ghost while the preconditions are unmet, tenant once the\n line is addable. A disabled control painted in a faded\n tenant fill reads as an enabled button that lost its\n colour, which is the greyed-out accent the design brief\n bans; ghost reads as \"not yet\". -->\n <ef-button\n labelKey=\"action.add\"\n icon=\"pi pi-plus\"\n variant=\"comptoir\"\n [severity]=\"quickAddDisabled() ? 'ghost' : 'tenant'\"\n [disabled]=\"quickAddDisabled()\"\n (clickEvent)=\"addQuickProduct()\" />\n </div>\n </div>\n }\n </div>\n </ef-card>\n\n <!-- Lines.\n\n ef-data-card owns the panel here instead of sitting inside an\n ef-card: `.tbl-wrap` already draws a bordered, rounded surface, so\n nesting it in another one would be a card inside a card. The title\n and the card's actions move into the head slots it provides.\n\n The columns are declared in TS (`lineColumns`) so discount and tax\n follow the document config, and so one definition drives both the\n desktop table and the mobile cards. Only the article column is\n elastic; every other column holds a number of known magnitude and\n gets a fixed track, which keeps the decimals aligned down the\n table rather than shifting with the longest description. -->\n <ef-data-card\n [columns]=\"lineColumns()\"\n [rows]=\"orderLines()\"\n trackByField=\"id\"\n [hidePager]=\"true\"\n defaultDensity=\"compact\"\n [reorderable]=\"!readonly()\"\n (rowReorder)=\"reorderLine($event)\"\n mobileLayout=\"card\">\n\n <div tbl-head-info class=\"ob-lines-head\">\n <span class=\"strong\">{{ 'order_builder.lines' | translate }}</span>\n <span class=\"meta\">\u00B7 {{ orderLines().length }}</span>\n </div>\n\n <div tbl-head-actions class=\"head-actions\">\n @if (config().showCatalogue && !readonly()) {\n <ef-button\n labelKey=\"action.open_catalogue\"\n icon=\"pi pi-box\"\n severity=\"secondary\"\n [text]=\"true\"\n (clickEvent)=\"handleOpenCatalogue()\" />\n }\n <ef-button\n [labelKey]=\"focusMode() ? 'order_builder.show_summary' : 'order_builder.fullscreen'\"\n icon=\"pi pi-window-maximize\"\n severity=\"secondary\"\n [text]=\"true\"\n (clickEvent)=\"toggleFocus()\" />\n </div>\n\n <span empty-state>{{ 'order_builder.empty' | translate }}</span>\n <span empty-state-mobile>{{ 'order_builder.empty' | translate }}</span>\n\n <ng-template efColumnTemplate=\"product\" let-item let-i=\"index\">\n <div class=\"p\">\n <span class=\"ln\">{{ i + 1 }}</span>\n <span class=\"pp\">\n <span class=\"nm\">{{ item.productDescription }}</span>\n </span>\n </div>\n </ng-template>\n\n <ng-template efColumnTemplate=\"price\" let-item>\n @if (!readonly() && isEditingCell(item, 'price')) {\n <ef-inputnumber\n [(ngModel)]=\"item.productUnitPrice\"\n (ngModelChange)=\"onFieldChange(item)\"\n [showClear]=\"false\"\n [autofocus]=\"true\"\n (blurEvent)=\"stopEditCell()\"\n (keyDownEvent)=\"onEditCellKeydown($event)\"\n [min]=\"0\"\n [minFractionDigits]=\"2\"\n [maxFractionDigits]=\"2\"\n [locale]=\"locale()\"\n size=\"small\"\n class=\"!text-end\" />\n } @else {\n <button type=\"button\" class=\"ln-val\" [disabled]=\"readonly()\" (click)=\"startEditCell(item, 'price')\">\n {{ item.productUnitPrice | number: '1.2-2' : locale() }}\n </button>\n }\n </ng-template>\n\n <ng-template efColumnTemplate=\"qty\" let-item>\n @if (!readonly() && isEditingCell(item, 'qty')) {\n <ef-inputnumber\n [(ngModel)]=\"item.quantity\"\n (ngModelChange)=\"onFieldChange(item)\"\n [showClear]=\"false\"\n [autofocus]=\"true\"\n (blurEvent)=\"stopEditCell()\"\n (keyDownEvent)=\"onEditCellKeydown($event)\"\n [min]=\"0\"\n [maxFractionDigits]=\"4\"\n [locale]=\"locale()\"\n size=\"small\"\n class=\"!text-end\" />\n } @else {\n <button type=\"button\" class=\"ln-val\" [disabled]=\"readonly()\" (click)=\"startEditCell(item, 'qty')\">\n {{ item.quantity | number: '1.0-4' : locale() }}\n </button>\n }\n </ng-template>\n\n <ng-template efColumnTemplate=\"discount\" let-item>\n @if (!readonly() && isEditingCell(item, 'discount')) {\n <ef-inputnumber\n [(ngModel)]=\"item.discount\"\n (ngModelChange)=\"onFieldChange(item)\"\n [showClear]=\"false\"\n [autofocus]=\"true\"\n (blurEvent)=\"stopEditCell()\"\n (keyDownEvent)=\"onEditCellKeydown($event)\"\n [min]=\"0\"\n [max]=\"100\"\n [maxFractionDigits]=\"2\"\n suffix=\" %\"\n [locale]=\"locale()\"\n size=\"small\"\n class=\"!text-end\" />\n } @else {\n <button type=\"button\" class=\"ln-val\" [disabled]=\"readonly()\" (click)=\"startEditCell(item, 'discount')\">\n {{ item.discount | number: '1.0-2' : locale() }} %\n </button>\n }\n </ng-template>\n\n <ng-template efColumnTemplate=\"tax\" let-item>\n @if (!readonly() && isEditingCell(item, 'tva')) {\n <ef-inputnumber\n [(ngModel)]=\"item.taxRate\"\n (ngModelChange)=\"onFieldChange(item)\"\n [showClear]=\"false\"\n [autofocus]=\"true\"\n (blurEvent)=\"stopEditCell()\"\n (keyDownEvent)=\"onEditCellKeydown($event)\"\n [min]=\"0\"\n [max]=\"100\"\n [maxFractionDigits]=\"2\"\n suffix=\" %\"\n [locale]=\"locale()\"\n size=\"small\"\n class=\"!text-end\" />\n } @else {\n <button type=\"button\" class=\"ln-val\" [disabled]=\"readonly()\" (click)=\"startEditCell(item, 'tva')\">\n {{ (item.taxRate ?? 0) | number: '1.0-2' : locale() }} %\n </button>\n }\n </ng-template>\n\n <ng-template efColumnTemplate=\"subtotal\" let-item>\n {{ calculateSubtotal(item) | number: '1.2-2' : locale() }}\n </ng-template>\n\n <ng-template efColumnTemplate=\"remove\" let-item>\n <ef-button\n icon=\"pi pi-trash\"\n severity=\"danger\"\n [text]=\"true\"\n styleClass=\"ob-del\"\n (clickEvent)=\"removeOrderLine(item.id)\" />\n </ng-template>\n </ef-data-card>\n\n </div>\n\n <!-- CONTEXT RAIL (1/3) -->\n <aside class=\"ob-rail\">\n <!-- Totaux (top) -->\n <ef-card titleKey=\"order_builder.totals\" [meta]=\"currency()\">\n <div class=\"ob-totals\">\n <div class=\"row\">\n <span class=\"lbl\">{{ 'order_builder.gross' | translate }}</span>\n <span class=\"v\">{{ grossTotal() | number: '1.2-2' : locale() }}</span>\n </div>\n <div class=\"row discount\">\n <span class=\"lbl\">{{ 'order_builder.discount' | translate }}</span>\n <span class=\"v\">\u2212{{ discountTotal() | number: '1.2-2' : locale() }}</span>\n </div>\n <div class=\"row\">\n <span class=\"lbl\">{{ 'order_builder.tax' | translate }}</span>\n <span class=\"v\">{{ tvaTotal() | number: '1.2-2' : locale() }}</span>\n </div>\n <hr />\n <div class=\"row grand\">\n <span class=\"lbl\">{{ 'order_builder.grand_total' | translate }}</span>\n <span class=\"v\">{{ finalTotal() | number: '1.2-2' : locale() }}<span class=\"cur\">{{ currency() }}</span></span>\n </div>\n </div>\n </ef-card>\n\n <!-- R\u00E9capitulatif par format -->\n @if (productsSummary().items.length > 0) {\n <ef-card titleKey=\"order_builder.recap\" metaKey=\"order_builder.auto\">\n <div class=\"ob-recap\">\n <div class=\"cols\">\n @for (col of recapColumns(); track $index) {\n <div class=\"grp\">\n @for (seg of col; track seg.code) {\n <div class=\"seg\">\n <span class=\"fmt\">{{ seg.label }}</span>\n <span class=\"n\">{{ seg.count | number: '1.0-0' : locale() }}</span>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"tot\">\n <span class=\"l\">{{ 'order_builder.total_units' | translate }}</span>\n <span class=\"n\">{{ productsSummary().totalCount | number: '1.0-0' : locale() }}</span>\n </div>\n </div>\n </ef-card>\n }\n\n <!-- Historique (optional, component-owned) -->\n @if (hasAudit()) {\n <ef-change-history [entries]=\"auditEntries()\" />\n }\n </aside>\n </div>\n\n <!-- Floating summary FAB + backdrop -->\n <button type=\"button\" class=\"ob-backdrop\" aria-hidden=\"true\" tabindex=\"-1\" (click)=\"toggleRail(false)\"></button>\n <div class=\"ob-fab\" role=\"status\">\n <div class=\"ft\">\n <span class=\"k\">{{ 'order_builder.total_units' | translate }} \u00B7 {{ productsSummary().totalCount }}</span>\n <span class=\"vv\">{{ finalTotal() | number: '1.2-2' : locale() }}<span class=\"cur\">{{ currency() }}</span></span>\n </div>\n <button type=\"button\" class=\"open\" (click)=\"toggleRail(true)\">\n {{ 'order_builder.summary' | translate }}\n </button>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}:host .order-builder{display:grid;gap:var(--s-3)}:host .order-builder .head-actions{display:flex;align-items:center;gap:6px}:host .order-builder .ob-empty{padding:28px 16px;text-align:center;color:var(--text-mute);font-size:13px}:host .order-builder .text-mute{color:var(--text-mute);font-weight:600}:host .order-builder .form-grid{display:grid;gap:var(--s-3);grid-template-columns:repeat(12,minmax(0,1fr))}:host .order-builder .form-grid>.col-3{grid-column:span 3}:host .order-builder .form-grid>.col-4{grid-column:span 4}:host .order-builder .form-grid>.col-5{grid-column:span 5}:host .order-builder .form-grid>.col-6{grid-column:span 6}@media(max-width:767px){:host .order-builder .form-grid>[class*=col-]{grid-column:span 12}}:host .order-builder .field{display:grid;gap:4px}:host .order-builder .field>label{font-size:11px;font-weight:700;color:var(--text-mute);text-transform:uppercase;letter-spacing:.06em}:host .order-builder .field .req{color:var(--st-cancelled-fg);margin-inline-start:2px}:host .order-builder .ob-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-3);align-items:start}@media(min-width:1280px){:host .order-builder .ob-grid{grid-template-columns:minmax(0,2fr) minmax(0,1fr)}}:host .order-builder .ob-main{display:grid;gap:var(--s-3);min-width:0}:host .order-builder .ob-rail{display:grid;gap:var(--s-3);align-content:start}@media(min-width:1280px){:host .order-builder .ob-rail{position:sticky;top:44px}}:host .order-builder .ob-order-head{display:grid;gap:var(--s-4)}:host .order-builder .qa-grid{display:flex;flex-wrap:wrap;gap:10px;align-items:end;padding-top:var(--s-3);border-top:1px solid var(--rule-soft)}:host .order-builder .qa-combo-wrap{flex:1 1 260px;min-width:0}:host .order-builder .qa-price{flex:0 1 132px}:host .order-builder .qa-qtyf{flex:0 0 132px}:host .order-builder .qa-go{flex:0 0 auto}@media(max-width:560px){:host .order-builder .qa-combo-wrap,:host .order-builder .qa-price,:host .order-builder .qa-qtyf,:host .order-builder .qa-go{flex:1 1 100%}}:host .order-builder .qin{width:58px;text-align:end;font:inherit;font-family:var(--font-mono);font-weight:700;padding:6px 8px;min-height:34px;border:1px solid var(--rule);border-radius:var(--r-sm);background:var(--paper-alt);color:var(--text);outline:0;-moz-appearance:textfield}:host .order-builder .qin::-webkit-outer-spin-button,:host .order-builder .qin::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}:host .order-builder .qin:focus{border-color:var(--tenant-400);box-shadow:0 0 0 3px var(--tenant-100)}:host .order-builder ef-data-card{font-size:13px}:host .order-builder ef-data-card .p{display:flex;align-items:baseline;gap:9px;line-height:1.25}:host .order-builder ef-data-card .p .ln{flex:0 0 auto;min-width:15px;text-align:end;font-family:var(--font-mono);font-size:10.5px;font-weight:700;color:var(--text-soft)}:host .order-builder ef-data-card .p .pp{display:grid;gap:1px;min-width:0}:host .order-builder ef-data-card .p .nm{font-weight:600;letter-spacing:-.005em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host .order-builder ef-data-card .p .nm em{font-style:normal;color:var(--text-mute);font-weight:600}:host .order-builder ef-data-card .p .ref{font-family:var(--font-mono);font-size:10.5px;color:var(--text-soft);font-weight:600}:host .order-builder ef-data-card .num,:host .order-builder ef-data-card .total{font-family:var(--font-mono);font-feature-settings:\"tnum\";font-variant-numeric:tabular-nums}:host .order-builder ef-data-card .ln-val{appearance:none;width:100%;margin:0;padding:5px 8px;border:1px solid transparent;border-radius:7px;background:transparent;font:inherit;font-family:var(--font-mono);font-feature-settings:\"tnum\";font-variant-numeric:tabular-nums;color:inherit;text-align:end;cursor:text;transition:background .12s ease,border-color .12s ease}:host .order-builder ef-data-card .ln-val:hover:not(:disabled){background:var(--paper);border-color:var(--rule)}:host .order-builder ef-data-card .ln-val:focus-visible{outline:none;background:var(--paper);border-color:var(--tenant, var(--rule))}:host .order-builder ef-data-card .ln-val:disabled{cursor:default;background:transparent;border-color:transparent}:host .order-builder ef-data-card .total{font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 85;font-size:13.5px}:host .order-builder ef-data-card .cur{font-size:9.5px;color:var(--text-soft);margin-inline-start:3px}:host .order-builder ef-data-card .free{color:var(--st-delivered-fg)}:host .order-builder .ob-lines-head{display:flex;align-items:baseline;gap:6px;min-width:0}:host .order-builder .ob-lines-head .strong{font-weight:700;color:var(--text)}:host .order-builder .ob-lines-head .meta{color:var(--text-soft)}:host .order-builder .ob-del{color:var(--text-soft)}:host .order-builder .ob-del:hover{color:var(--st-cancelled-fg);border-color:var(--st-cancelled-bg)}:host .order-builder .ob-totals{display:grid;gap:6px}:host .order-builder .ob-totals .row{display:flex;justify-content:space-between;align-items:baseline;gap:14px}:host .order-builder .ob-totals .row .lbl{font-size:12px;font-weight:600;color:var(--text-mute)}:host .order-builder .ob-totals .row .v{font-family:var(--font-mono);font-feature-settings:\"tnum\";font-variant-numeric:tabular-nums;font-weight:700;font-size:12.5px}:host .order-builder .ob-totals .row.discount .v{color:var(--st-pending-fg)}:host .order-builder .ob-totals hr{border:0;border-top:1px solid var(--rule);margin:5px 0}:host .order-builder .ob-totals .grand .lbl{font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 85;font-size:13.5px;color:var(--text)}:host .order-builder .ob-totals .grand .v{font-family:var(--font-display);font-variation-settings:\"opsz\" 96,\"wght\" 700,\"wdth\" 80;font-size:26px;letter-spacing:-.03em;color:var(--text)}:host .order-builder .ob-totals .grand .cur{font-family:var(--font-mono);font-size:.4em;color:var(--text-mute);margin-inline-start:4px}:host .order-builder .ob-recap .cols{display:grid;grid-template-columns:1fr 1fr}:host .order-builder .ob-recap .grp{display:flex;flex-direction:column;gap:3px;min-width:0}:host .order-builder .ob-recap .grp:first-child{padding-inline-end:14px}:host .order-builder .ob-recap .grp+.grp{padding-inline-start:14px;border-inline-start:1px solid var(--rule)}:host .order-builder .ob-recap .seg{display:flex;justify-content:space-between;align-items:baseline;gap:8px}:host .order-builder .ob-recap .seg .fmt{font-size:11.5px;font-weight:700;color:var(--text);letter-spacing:-.005em;min-width:0}:host .order-builder .ob-recap .seg .fmt:after{content:\":\";color:var(--text-soft)}:host .order-builder .ob-recap .seg .n{font-family:var(--font-mono);font-weight:700;font-size:12px;color:var(--text);font-variant-numeric:tabular-nums;flex-shrink:0}:host .order-builder .ob-recap .tot{display:flex;justify-content:space-between;align-items:baseline;margin-top:12px;padding-top:10px;border-top:1px solid var(--rule)}:host .order-builder .ob-recap .tot .l{font-weight:700;font-size:12px}:host .order-builder .ob-recap .tot .n{font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 85;font-size:18px;font-variant-numeric:tabular-nums}:host .order-builder .ob-rail-close{display:none}:host .order-builder .ob-fab{display:none;position:fixed;inset-inline-end:20px;bottom:calc(var(--app-bottom-bar, 0px) + env(safe-area-inset-bottom,0px) + 20px);z-index:30;align-items:center;gap:10px;background:var(--ink-active);color:var(--paper);border-radius:var(--r-pill);padding:8px 10px 8px 16px;box-shadow:var(--shadow-3)}:host .order-builder .ob-fab .ft{display:grid;line-height:1.1}:host .order-builder .ob-fab .ft .k{font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;opacity:.65}:host .order-builder .ob-fab .ft .vv{font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 82;font-size:16px}:host .order-builder .ob-fab .ft .vv .cur{font-family:var(--font-mono);font-size:.6em;opacity:.7;margin-inline-start:3px}:host .order-builder .ob-fab .open{appearance:none;cursor:pointer;border:0;background:#ffffff24;color:#fff;font:inherit;font-size:12px;font-weight:700;border-radius:var(--r-pill);padding:8px 14px;display:inline-flex;align-items:center;gap:6px}:host .order-builder .ob-fab .open:hover{background:#ffffff3d}:host .order-builder .ob-backdrop{display:none;position:fixed;inset:0;z-index:38;background:#0f11156b;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px)}:host .order-builder.ob-collapsed .ob-grid{grid-template-columns:minmax(0,1fr)}:host .order-builder.ob-collapsed .ob-fab{display:flex}:host .order-builder.ob-collapsed .ob-rail{position:fixed;top:0;inset-inline-end:0;height:100dvh;width:min(360px,92vw);z-index:40;background:var(--paper);border-inline-start:1px solid var(--rule);box-shadow:var(--shadow-3);padding:14px;overflow:auto;gap:var(--s-3);transform:translate(101%);transition:transform var(--t-base) var(--ease-out)}[dir=rtl] :host .order-builder.ob-collapsed .ob-rail{transform:translate(-101%)}:host .order-builder.ob-collapsed .ob-rail-close{display:inline-flex}:host .order-builder.ob-collapsed.ob-rail-open .ob-rail{transform:none}:host .order-builder.ob-collapsed.ob-rail-open .ob-backdrop{display:block}@media(max-width:1279px){:host .order-builder .ob-grid{grid-template-columns:minmax(0,1fr)}:host .order-builder .ob-fab{display:flex}:host .order-builder .ob-rail{position:fixed;top:0;inset-inline-end:0;height:100dvh;width:min(360px,92vw);z-index:40;background:var(--paper);border-inline-start:1px solid var(--rule);box-shadow:var(--shadow-3);padding:14px;overflow:auto;gap:var(--s-3);transform:translate(101%);transition:transform var(--t-base) var(--ease-out)}[dir=rtl] :host .order-builder .ob-rail{transform:translate(-101%)}:host .order-builder .ob-rail-close{display:inline-flex!important}:host .order-builder.ob-rail-open .ob-rail{transform:none}:host .order-builder.ob-rail-open .ob-backdrop{display:block}}:host ef-data-card .nm,:host ef-data-card .num,:host ef-data-card .ln-val,:host .ob-totals .v,:host .ob-sum-val{unicode-bidi:plaintext}@media(max-width:767px){:host .order-builder{padding-bottom:calc(var(--app-bottom-bar, 0px) + env(safe-area-inset-bottom,0px) + 20px + 56px + var(--s-4))}}\n"] }]
|
|
5695
|
+
], template: "<div\n class=\"order-builder\"\n [class.ob-collapsed]=\"focusMode()\"\n [class.ob-rail-open]=\"railOpen()\">\n <div class=\"ob-grid\">\n <div class=\"ob-main\">\n <!-- Order header: customer + date + express add (one card) -->\n <ef-card\n titleKey=\"order_builder.section_order\"\n [metaKey]=\"readonly() ? '' : 'order_builder.quick_add_hint'\"\n [overflowVisible]=\"true\">\n <div class=\"ob-order-head\">\n <div class=\"form-grid\">\n <div class=\"field col-6\">\n <ef-label labelKey=\"label.customer\" for=\"ob-cust\" [required]=\"true\" />\n <ef-select\n inputId=\"ob-cust\"\n [options]=\"customers()\"\n optionLabel=\"companyName\"\n optionValue=\"customerId\"\n [ngModel]=\"order().customerId\"\n (ngModelChange)=\"updateCustomer($event)\"\n [disabled]=\"readonly()\"\n [showClear]=\"true\"\n [filter]=\"true\"\n filterBy=\"companyName\"\n filterPlaceholderKey=\"label.search_customer\"\n appendTo=\"body\"\n placeholderKey=\"label.select_customer\" />\n </div>\n <div class=\"field col-3\">\n <ef-label labelKey=\"label.order_date\" for=\"ob-date\" [required]=\"true\" />\n <ef-datepicker-advanced\n mode=\"field\"\n selectionMode=\"single\"\n inputId=\"ob-date\"\n placeholderKey=\"date_select_date\"\n [ngModel]=\"order().orderDate\"\n (ngModelChange)=\"updateOrderDate($event)\"\n [disabled]=\"readonly()\" />\n </div>\n </div>\n\n @if (!readonly()) {\n <div class=\"qa-grid\">\n <div class=\"qa-combo-wrap\">\n <ef-label labelKey=\"label.article\" />\n <ef-product-typeahead\n [products]=\"products()\"\n [productKeyField]=\"productKeyField()\"\n placeholderKey=\"label.search_product\"\n [currency]=\"currency()\"\n [locale]=\"locale()\"\n (productSelect)=\"onTypeaheadSelect($event)\"\n [showVariants]=\"false\" />\n </div>\n <div class=\"qa-price\">\n <ef-label labelKey=\"label.sale_price\" />\n <ef-inputnumber\n variant=\"comptoir\"\n [value]=\"quickAddPrice()\"\n (valueChangeEvent)=\"quickAddPrice.set($event ?? 0)\"\n [minFractionDigits]=\"2\"\n [maxFractionDigits]=\"2\"\n [locale]=\"locale()\"\n [disabled]=\"readonly()\" />\n </div>\n <div class=\"qa-qtyf\">\n <ef-label labelKey=\"label.quantity\" />\n <ef-inputnumber\n variant=\"comptoir\"\n [ngModel]=\"quickAddQuantity()\"\n (ngModelChange)=\"quickAddQuantity.set($event)\"\n [min]=\"0\"\n [maxFractionDigits]=\"4\"\n [locale]=\"locale()\"\n [disabled]=\"readonly()\"\n />\n </div>\n <div class=\"qa-go\">\n <!-- Ghost while the preconditions are unmet, tenant once the\n line is addable. A disabled control painted in a faded\n tenant fill reads as an enabled button that lost its\n colour, which is the greyed-out accent the design brief\n bans; ghost reads as \"not yet\". -->\n <ef-button\n labelKey=\"action.add\"\n icon=\"pi pi-plus\"\n variant=\"comptoir\"\n size=\"base\"\n [severity]=\"quickAddDisabled() ? 'ghost' : 'tenant'\"\n [disabled]=\"quickAddDisabled()\"\n (clickEvent)=\"addQuickProduct()\" />\n </div>\n </div>\n }\n </div>\n </ef-card>\n\n <!-- Lines.\n\n ef-data-card owns the panel here instead of sitting inside an\n ef-card: `.tbl-wrap` already draws a bordered, rounded surface, so\n nesting it in another one would be a card inside a card. The title\n and the card's actions move into the head slots it provides.\n\n The columns are declared in TS (`lineColumns`) so discount and tax\n follow the document config, and so one definition drives both the\n desktop table and the mobile cards. Only the article column is\n elastic; every other column holds a number of known magnitude and\n gets a fixed track, which keeps the decimals aligned down the\n table rather than shifting with the longest description. -->\n <ef-data-card\n [columns]=\"lineColumns()\"\n [rows]=\"orderLines()\"\n trackByField=\"id\"\n [hidePager]=\"true\"\n defaultDensity=\"compact\"\n [reorderable]=\"!readonly()\"\n [fixedLayout]=\"true\"\n (rowReorder)=\"reorderLine($event)\"\n mobileLayout=\"card\">\n\n <div tbl-head-info class=\"ob-lines-head\">\n <span class=\"strong\">{{ 'order_builder.lines' | translate }}</span>\n <span class=\"meta\">\u00B7 {{ orderLines().length }}</span>\n </div>\n\n <div tbl-head-actions class=\"head-actions\">\n @if (config().showCatalogue && !readonly()) {\n <ef-button\n labelKey=\"action.open_catalogue\"\n icon=\"pi pi-box\"\n severity=\"secondary\"\n [text]=\"true\"\n (clickEvent)=\"handleOpenCatalogue()\" />\n }\n <ef-button\n [labelKey]=\"focusMode() ? 'order_builder.show_summary' : 'order_builder.fullscreen'\"\n icon=\"pi pi-window-maximize\"\n severity=\"secondary\"\n [text]=\"true\"\n (clickEvent)=\"toggleFocus()\" />\n </div>\n\n <span empty-state>{{ 'order_builder.empty' | translate }}</span>\n <span empty-state-mobile>{{ 'order_builder.empty' | translate }}</span>\n\n <ng-template efColumnTemplate=\"product\" let-item let-i=\"index\">\n <div class=\"p\">\n <span class=\"ln\">{{ i + 1 }}</span>\n <span class=\"pp\">\n <span class=\"nm\">{{ item.productDescription }}</span>\n </span>\n </div>\n </ng-template>\n\n <ng-template efColumnTemplate=\"price\" let-item>\n @if (!readonly() && isEditingCell(item, 'price')) {\n <ef-inputnumber\n [(ngModel)]=\"item.productUnitPrice\"\n (ngModelChange)=\"onFieldChange(item)\"\n [showClear]=\"false\"\n [autofocus]=\"true\"\n (blurEvent)=\"stopEditCell()\"\n (keyDownEvent)=\"onEditCellKeydown($event)\"\n [min]=\"0\"\n [minFractionDigits]=\"2\"\n [maxFractionDigits]=\"2\"\n [locale]=\"locale()\"\n size=\"small\"\n class=\"!text-end\" />\n } @else {\n <button type=\"button\" class=\"ln-val\" [disabled]=\"readonly()\" (click)=\"startEditCell(item, 'price')\">\n {{ item.productUnitPrice | number: '1.2-2' : locale() }}\n </button>\n }\n </ng-template>\n\n <ng-template efColumnTemplate=\"qty\" let-item>\n @if (!readonly() && isEditingCell(item, 'qty')) {\n <ef-inputnumber\n [(ngModel)]=\"item.quantity\"\n (ngModelChange)=\"onFieldChange(item)\"\n [showClear]=\"false\"\n [autofocus]=\"true\"\n (blurEvent)=\"stopEditCell()\"\n (keyDownEvent)=\"onEditCellKeydown($event)\"\n [min]=\"0\"\n [maxFractionDigits]=\"4\"\n [locale]=\"locale()\"\n size=\"small\"\n class=\"!text-end\" />\n } @else {\n <button type=\"button\" class=\"ln-val\" [disabled]=\"readonly()\" (click)=\"startEditCell(item, 'qty')\">\n {{ item.quantity | number: '1.0-4' : locale() }}\n </button>\n }\n </ng-template>\n\n <ng-template efColumnTemplate=\"discount\" let-item>\n @if (!readonly() && isEditingCell(item, 'discount')) {\n <ef-inputnumber\n [(ngModel)]=\"item.discount\"\n (ngModelChange)=\"onFieldChange(item)\"\n [showClear]=\"false\"\n [autofocus]=\"true\"\n (blurEvent)=\"stopEditCell()\"\n (keyDownEvent)=\"onEditCellKeydown($event)\"\n [min]=\"0\"\n [max]=\"100\"\n [maxFractionDigits]=\"2\"\n suffix=\" %\"\n [locale]=\"locale()\"\n size=\"small\"\n class=\"!text-end\" />\n } @else {\n <button type=\"button\" class=\"ln-val\" [disabled]=\"readonly()\" (click)=\"startEditCell(item, 'discount')\">\n {{ item.discount | number: '1.0-2' : locale() }} %\n </button>\n }\n </ng-template>\n\n <ng-template efColumnTemplate=\"tax\" let-item>\n @if (!readonly() && isEditingCell(item, 'tva')) {\n <ef-inputnumber\n [(ngModel)]=\"item.taxRate\"\n (ngModelChange)=\"onFieldChange(item)\"\n [showClear]=\"false\"\n [autofocus]=\"true\"\n (blurEvent)=\"stopEditCell()\"\n (keyDownEvent)=\"onEditCellKeydown($event)\"\n [min]=\"0\"\n [max]=\"100\"\n [maxFractionDigits]=\"2\"\n suffix=\" %\"\n [locale]=\"locale()\"\n size=\"small\"\n class=\"!text-end\" />\n } @else {\n <button type=\"button\" class=\"ln-val\" [disabled]=\"readonly()\" (click)=\"startEditCell(item, 'tva')\">\n {{ (item.taxRate ?? 0) | number: '1.0-2' : locale() }} %\n </button>\n }\n </ng-template>\n\n <ng-template efColumnTemplate=\"subtotal\" let-item>\n {{ calculateSubtotal(item) | number: '1.2-2' : locale() }}\n </ng-template>\n\n <ng-template efColumnTemplate=\"remove\" let-item>\n <ef-button\n icon=\"pi pi-trash\"\n severity=\"danger\"\n [text]=\"true\"\n styleClass=\"ob-del\"\n (clickEvent)=\"removeOrderLine(item.id)\" />\n </ng-template>\n </ef-data-card>\n\n </div>\n\n <!-- CONTEXT RAIL (1/3) -->\n <aside class=\"ob-rail\">\n <!-- Totaux (top) -->\n <ef-card titleKey=\"order_builder.totals\" [meta]=\"currency()\">\n <div class=\"ob-totals\">\n <div class=\"row\">\n <span class=\"lbl\">{{ 'order_builder.gross' | translate }}</span>\n <span class=\"v\">{{ grossTotal() | number: '1.2-2' : locale() }}</span>\n </div>\n <div class=\"row discount\">\n <span class=\"lbl\">{{ 'order_builder.discount' | translate }}</span>\n <span class=\"v\">\u2212{{ discountTotal() | number: '1.2-2' : locale() }}</span>\n </div>\n <div class=\"row\">\n <span class=\"lbl\">{{ 'order_builder.tax' | translate }}</span>\n <span class=\"v\">{{ tvaTotal() | number: '1.2-2' : locale() }}</span>\n </div>\n <hr />\n <div class=\"row grand\">\n <span class=\"lbl\">{{ 'order_builder.grand_total' | translate }}</span>\n <span class=\"v\">{{ finalTotal() | number: '1.2-2' : locale() }}<span class=\"cur\">{{ currency() }}</span></span>\n </div>\n </div>\n </ef-card>\n\n <!-- R\u00E9capitulatif par format -->\n @if (productsSummary().items.length > 0) {\n <ef-card titleKey=\"order_builder.recap\" metaKey=\"order_builder.auto\">\n <div class=\"ob-recap\">\n <div class=\"cols\">\n @for (col of recapColumns(); track $index) {\n <div class=\"grp\">\n @for (seg of col; track seg.code) {\n <div class=\"seg\">\n <span class=\"fmt\">{{ seg.label }}</span>\n <span class=\"n\">{{ seg.count | number: '1.0-0' : locale() }}</span>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"tot\">\n <span class=\"l\">{{ 'order_builder.total_units' | translate }}</span>\n <span class=\"n\">{{ productsSummary().totalCount | number: '1.0-0' : locale() }}</span>\n </div>\n </div>\n </ef-card>\n }\n\n <!-- Historique (optional, component-owned) -->\n @if (hasAudit()) {\n <ef-change-history [entries]=\"auditEntries()\" />\n }\n </aside>\n </div>\n\n <!-- Floating summary FAB + backdrop -->\n <button type=\"button\" class=\"ob-backdrop\" aria-hidden=\"true\" tabindex=\"-1\" (click)=\"toggleRail(false)\"></button>\n <div class=\"ob-fab\" role=\"status\">\n <div class=\"ft\">\n <span class=\"k\">{{ 'order_builder.total_units' | translate }} \u00B7 {{ productsSummary().totalCount }}</span>\n <span class=\"vv\">{{ finalTotal() | number: '1.2-2' : locale() }}<span class=\"cur\">{{ currency() }}</span></span>\n </div>\n <button type=\"button\" class=\"open\" (click)=\"toggleRail(true)\">\n {{ 'order_builder.summary' | translate }}\n </button>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}:host .order-builder{display:grid;gap:var(--s-3)}:host .order-builder .head-actions{display:flex;align-items:center;gap:6px}:host .order-builder .ob-empty{padding:28px 16px;text-align:center;color:var(--text-mute);font-size:13px}:host .order-builder .text-mute{color:var(--text-mute);font-weight:600}:host .order-builder .form-grid{display:grid;gap:var(--s-3);grid-template-columns:repeat(12,minmax(0,1fr))}:host .order-builder .form-grid>.col-3{grid-column:span 3}:host .order-builder .form-grid>.col-4{grid-column:span 4}:host .order-builder .form-grid>.col-5{grid-column:span 5}:host .order-builder .form-grid>.col-6{grid-column:span 6}@media(max-width:767px){:host .order-builder .form-grid>[class*=col-]{grid-column:span 12}}:host .order-builder .field{display:grid;gap:4px}:host .order-builder .field>label{font-size:11px;font-weight:700;color:var(--text-mute);text-transform:uppercase;letter-spacing:.06em}:host .order-builder .field .req{color:var(--st-cancelled-fg);margin-inline-start:2px}:host .order-builder .ob-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-3);align-items:start}@media(min-width:1280px){:host .order-builder .ob-grid{grid-template-columns:minmax(0,2fr) minmax(0,1fr)}}:host .order-builder .ob-main{display:grid;gap:var(--s-3);min-width:0}:host .order-builder .ob-rail{display:grid;gap:var(--s-3);align-content:start}@media(min-width:1280px){:host .order-builder .ob-rail{position:sticky;top:44px}}:host .order-builder .ob-order-head{display:grid;gap:var(--s-4)}:host .order-builder .qa-grid{display:flex;flex-wrap:wrap;gap:10px;align-items:end;padding-top:var(--s-3);border-top:1px solid var(--rule-soft)}:host .order-builder .qa-combo-wrap{flex:1 1 260px;min-width:0}:host .order-builder .qa-price{flex:0 1 132px}:host .order-builder .qa-qtyf{flex:0 0 132px}:host .order-builder .qa-go{flex:0 0 auto}@media(max-width:560px){:host .order-builder .qa-combo-wrap,:host .order-builder .qa-price,:host .order-builder .qa-qtyf,:host .order-builder .qa-go{flex:1 1 100%}}:host .order-builder .qin{width:58px;text-align:end;font:inherit;font-family:var(--font-mono);font-weight:700;padding:6px 8px;min-height:34px;border:1px solid var(--rule);border-radius:var(--r-sm);background:var(--paper-alt);color:var(--text);outline:0;-moz-appearance:textfield}:host .order-builder .qin::-webkit-outer-spin-button,:host .order-builder .qin::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}:host .order-builder .qin:focus{border-color:var(--tenant-400);box-shadow:0 0 0 3px var(--tenant-100)}:host .order-builder ef-data-card{font-size:13px}:host .order-builder ef-data-card .p{display:flex;align-items:baseline;gap:9px;line-height:1.25}:host .order-builder ef-data-card .p .ln{flex:0 0 auto;min-width:15px;text-align:end;font-family:var(--font-mono);font-size:10.5px;font-weight:700;color:var(--text-soft)}:host .order-builder ef-data-card .p .pp{display:grid;gap:1px;min-width:0}:host .order-builder ef-data-card .p .nm{font-weight:600;letter-spacing:-.005em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host .order-builder ef-data-card .p .nm em{font-style:normal;color:var(--text-mute);font-weight:600}:host .order-builder ef-data-card .p .ref{font-family:var(--font-mono);font-size:10.5px;color:var(--text-soft);font-weight:600}:host .order-builder ef-data-card ef-inputnumber,:host .order-builder ef-data-card ef-inputnumber .ef-field-control,:host .order-builder ef-data-card ef-inputnumber input{width:100%;min-width:0}:host .order-builder ef-data-card .num,:host .order-builder ef-data-card .total{font-family:var(--font-mono);font-feature-settings:\"tnum\";font-variant-numeric:tabular-nums}:host .order-builder ef-data-card .ln-val{appearance:none;width:100%;margin:0;padding:5px 8px;border:1px solid transparent;border-radius:7px;background:transparent;font:inherit;font-family:var(--font-mono);font-feature-settings:\"tnum\";font-variant-numeric:tabular-nums;color:inherit;text-align:end;cursor:text;transition:background .12s ease,border-color .12s ease}:host .order-builder ef-data-card .ln-val:hover:not(:disabled){background:var(--paper);border-color:var(--rule)}:host .order-builder ef-data-card .ln-val:focus-visible{outline:none;background:var(--paper);border-color:var(--tenant, var(--rule))}:host .order-builder ef-data-card .ln-val:disabled{cursor:default;background:transparent;border-color:transparent}:host .order-builder ef-data-card .total{font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 85;font-size:13.5px}:host .order-builder ef-data-card .cur{font-size:9.5px;color:var(--text-soft);margin-inline-start:3px}:host .order-builder ef-data-card .free{color:var(--st-delivered-fg)}:host .order-builder .ob-lines-head{display:flex;align-items:baseline;gap:6px;min-width:0}:host .order-builder .ob-lines-head .strong{font-weight:700;color:var(--text)}:host .order-builder .ob-lines-head .meta{color:var(--text-soft)}:host .order-builder .ob-del{color:var(--text-soft)}:host .order-builder .ob-del:hover{color:var(--st-cancelled-fg);border-color:var(--st-cancelled-bg)}:host .order-builder .ob-totals{display:grid;gap:6px}:host .order-builder .ob-totals .row{display:flex;justify-content:space-between;align-items:baseline;gap:14px}:host .order-builder .ob-totals .row .lbl{font-size:12px;font-weight:600;color:var(--text-mute)}:host .order-builder .ob-totals .row .v{font-family:var(--font-mono);font-feature-settings:\"tnum\";font-variant-numeric:tabular-nums;font-weight:700;font-size:12.5px}:host .order-builder .ob-totals .row.discount .v{color:var(--st-pending-fg)}:host .order-builder .ob-totals hr{border:0;border-top:1px solid var(--rule);margin:5px 0}:host .order-builder .ob-totals .grand .lbl{font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 85;font-size:13.5px;color:var(--text)}:host .order-builder .ob-totals .grand .v{font-family:var(--font-display);font-variation-settings:\"opsz\" 96,\"wght\" 700,\"wdth\" 80;font-size:26px;letter-spacing:-.03em;color:var(--text)}:host .order-builder .ob-totals .grand .cur{font-family:var(--font-mono);font-size:.4em;color:var(--text-mute);margin-inline-start:4px}:host .order-builder .ob-recap .cols{display:grid;grid-template-columns:1fr 1fr}:host .order-builder .ob-recap .grp{display:flex;flex-direction:column;gap:3px;min-width:0}:host .order-builder .ob-recap .grp:first-child{padding-inline-end:14px}:host .order-builder .ob-recap .grp+.grp{padding-inline-start:14px;border-inline-start:1px solid var(--rule)}:host .order-builder .ob-recap .seg{display:flex;justify-content:space-between;align-items:baseline;gap:8px}:host .order-builder .ob-recap .seg .fmt{font-size:11.5px;font-weight:700;color:var(--text);letter-spacing:-.005em;min-width:0}:host .order-builder .ob-recap .seg .fmt:after{content:\":\";color:var(--text-soft)}:host .order-builder .ob-recap .seg .n{font-family:var(--font-mono);font-weight:700;font-size:12px;color:var(--text);font-variant-numeric:tabular-nums;flex-shrink:0}:host .order-builder .ob-recap .tot{display:flex;justify-content:space-between;align-items:baseline;margin-top:12px;padding-top:10px;border-top:1px solid var(--rule)}:host .order-builder .ob-recap .tot .l{font-weight:700;font-size:12px}:host .order-builder .ob-recap .tot .n{font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 85;font-size:18px;font-variant-numeric:tabular-nums}:host .order-builder .ob-rail-close{display:none}:host .order-builder .ob-fab{display:none;position:fixed;inset-inline-end:20px;bottom:calc(var(--app-bottom-bar, 0px) + env(safe-area-inset-bottom,0px) + 20px);z-index:30;align-items:center;gap:10px;background:var(--ink-active);color:var(--paper);border-radius:var(--r-pill);padding:8px 10px 8px 16px;box-shadow:var(--shadow-3)}:host .order-builder .ob-fab .ft{display:grid;line-height:1.1}:host .order-builder .ob-fab .ft .k{font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;opacity:.65}:host .order-builder .ob-fab .ft .vv{font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 82;font-size:16px}:host .order-builder .ob-fab .ft .vv .cur{font-family:var(--font-mono);font-size:.6em;opacity:.7;margin-inline-start:3px}:host .order-builder .ob-fab .open{appearance:none;cursor:pointer;border:0;background:#ffffff24;color:#fff;font:inherit;font-size:12px;font-weight:700;border-radius:var(--r-pill);padding:8px 14px;display:inline-flex;align-items:center;gap:6px}:host .order-builder .ob-fab .open:hover{background:#ffffff3d}:host .order-builder .ob-backdrop{display:none;position:fixed;inset:0;z-index:38;background:#0f11156b;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px)}:host .order-builder.ob-collapsed .ob-grid{grid-template-columns:minmax(0,1fr)}:host .order-builder.ob-collapsed .ob-fab{display:flex}:host .order-builder.ob-collapsed .ob-rail{position:fixed;top:0;inset-inline-end:0;height:100dvh;width:min(360px,92vw);z-index:40;background:var(--paper);border-inline-start:1px solid var(--rule);box-shadow:var(--shadow-3);padding:14px;overflow:auto;gap:var(--s-3);transform:translate(101%);transition:transform var(--t-base) var(--ease-out)}[dir=rtl] :host .order-builder.ob-collapsed .ob-rail{transform:translate(-101%)}:host .order-builder.ob-collapsed .ob-rail-close{display:inline-flex}:host .order-builder.ob-collapsed.ob-rail-open .ob-rail{transform:none}:host .order-builder.ob-collapsed.ob-rail-open .ob-backdrop{display:block}@media(max-width:1279px){:host .order-builder .ob-grid{grid-template-columns:minmax(0,1fr)}:host .order-builder .ob-fab{display:flex}:host .order-builder .ob-rail{position:fixed;top:0;inset-inline-end:0;height:100dvh;width:min(360px,92vw);z-index:40;background:var(--paper);border-inline-start:1px solid var(--rule);box-shadow:var(--shadow-3);padding:14px;overflow:auto;gap:var(--s-3);transform:translate(101%);transition:transform var(--t-base) var(--ease-out)}[dir=rtl] :host .order-builder .ob-rail{transform:translate(-101%)}:host .order-builder .ob-rail-close{display:inline-flex!important}:host .order-builder.ob-rail-open .ob-rail{transform:none}:host .order-builder.ob-rail-open .ob-backdrop{display:block}}:host ef-data-card .nm,:host ef-data-card .num,:host ef-data-card .ln-val,:host .ob-totals .v,:host .ob-sum-val{unicode-bidi:plaintext}@media(max-width:767px){:host .order-builder{padding-bottom:calc(var(--app-bottom-bar, 0px) + env(safe-area-inset-bottom,0px) + 20px + 56px + var(--s-4))}}\n"] }]
|
|
5600
5696
|
}], ctorParameters: () => [], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], order: [{ type: i0.Input, args: [{ isSignal: true, alias: "order", required: true }] }, { type: i0.Output, args: ["orderChange"] }], products: [{ type: i0.Input, args: [{ isSignal: true, alias: "products", required: true }] }], customers: [{ type: i0.Input, args: [{ isSignal: true, alias: "customers", required: true }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], countGroupLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "countGroupLabels", required: false }] }], productKeyField: [{ type: i0.Input, args: [{ isSignal: true, alias: "productKeyField", required: false }] }], backendErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "backendErrors", required: false }] }], auditEntries: [{ type: i0.Input, args: [{ isSignal: true, alias: "auditEntries", required: false }] }], openCatalogue: [{ type: i0.Output, args: ["openCatalogue"] }], orderChanged: [{ type: i0.Output, args: ["orderChanged"] }], orderValidated: [{ type: i0.Output, args: ["orderValidated"] }], productsAdded: [{ type: i0.Output, args: ["productsAdded"] }], focusMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "focusMode", required: false }] }, { type: i0.Output, args: ["focusModeChange"] }], typeahead: [{ type: i0.ViewChild, args: [i0.forwardRef(() => EfProductTypeaheadComponent), { isSignal: true }] }] } });
|
|
5601
5697
|
|
|
5602
5698
|
/**
|
|
@@ -5715,6 +5811,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
5715
5811
|
}], propDecorators: { orderLines: [{ type: i0.Input, args: [{ isSignal: true, alias: "orderLines", required: true }] }], countGroupLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "countGroupLabels", required: false }] }], legend: [{ type: i0.Input, args: [{ isSignal: true, alias: "legend", required: false }] }], legendKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "legendKey", required: false }] }], totalLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalLabelKey", required: false }] }] } });
|
|
5716
5812
|
|
|
5717
5813
|
class EfProductCatalogueFilterComponent {
|
|
5814
|
+
/**
|
|
5815
|
+
* PrimeNG's Button reads `autofocus || buttonProps?.autofocus`, so a bare
|
|
5816
|
+
* `false` collapses to `undefined` and its AutoFocus directive writes the
|
|
5817
|
+
* attribute anyway. Passing the flag here too makes it resolve to `false`.
|
|
5818
|
+
*/
|
|
5819
|
+
noAutofocus = { autofocus: false };
|
|
5718
5820
|
/** Category groups from reference_data (product_categories items with children) */
|
|
5719
5821
|
categoryGroups = input.required(...(ngDevMode ? [{ debugName: "categoryGroups" }] : /* istanbul ignore next */ []));
|
|
5720
5822
|
/** Products to calculate counts */
|
|
@@ -5791,7 +5893,7 @@ class EfProductCatalogueFilterComponent {
|
|
|
5791
5893
|
return (group.children?.length || 0) > 5;
|
|
5792
5894
|
}
|
|
5793
5895
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfProductCatalogueFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5794
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfProductCatalogueFilterComponent, isStandalone: true, selector: "ef-product-catalogue-filter", inputs: { categoryGroups: { classPropertyName: "categoryGroups", publicName: "categoryGroups", isSignal: true, isRequired: true, transformFunction: null }, products: { classPropertyName: "products", publicName: "products", isSignal: true, isRequired: true, transformFunction: null }, selectedFilters: { classPropertyName: "selectedFilters", publicName: "selectedFilters", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedFilters: "selectedFiltersChange", filtersChanged: "filtersChanged" }, ngImport: i0, template: "<div class=\"flex w-80 shrink-0 flex-col items-start justify-start sticky top-4 max-h-[calc(100vh-2rem)] overflow-y-auto\">\n <div\n class=\"mb-4 flex flex-col items-start justify-center gap-2 self-stretch border-b border-surface-200 px-2 pb-4 dark:border-surface-700\"\n >\n <div class=\"flex items-center justify-between gap-2 self-stretch\">\n <div\n class=\"text-base font-semibold leading-tight text-surface-900 dark:text-surface-0\"\n >\n Filters\n </div>\n <p-button\n size=\"small\"\n severity=\"secondary\"\n [text]=\"true\"\n class=\"py-1! px-2! text-base! font-normal!\"\n (clickEvent)=\"clearAllFilters()\"\n >\n <span pButtonLabel>\n <i class=\"pi pi-eraser\"></i>\n Clear\n </span>\n </p-button>\n </div>\n @if (selectedFilters().length > 0) {\n <div\n class=\"flex flex-wrap items-start justify-start gap-2 self-stretch\"\n >\n @for (filter of selectedFilters(); track filter.type + filter.code) {\n <p-chip\n [label]=\"filter.label\"\n [removable]=\"true\"\n size=\"small\"\n class=\"h-auto rounded-full px-6\"\n removeIcon=\"pi pi-times\"\n (onRemove)=\"removeFilter(filter)\"\n ></p-chip>\n }\n </div>\n }\n </div>\n\n <p-accordion\n [multiple]=\"true\"\n [value]=\"expandedPanels()\"\n class=\"w-full\"\n >\n @for (group of categoryGroups(); track group.code) {\n @if (group.children && group.children.length > 0) {\n <p-accordion-panel [value]=\"group.code\">\n <p-accordion-header>\n <span\n class=\"text-base font-semibold leading-tight text-surface-900 dark:text-surface-0\"\n >{{ group.label }}</span>\n </p-accordion-header>\n <p-accordion-content>\n <div class=\"flex flex-col gap-4\">\n @if (shouldShowSearch(group)) {\n <p-iconfield iconPosition=\"left\" class=\"w-full\">\n <p-inputicon class=\"pi pi-search\"></p-inputicon>\n <input\n pInputText\n size=\"small\"\n [ngModel]=\"searchTerms()[group.code] || ''\"\n (ngModelChange)=\"updateSearchTerm(group.code, $event)\"\n [placeholder]=\"'Rechercher ' + group.label.toLowerCase()\"\n class=\"w-full\"\n />\n </p-iconfield>\n }\n\n @for (item of getFilteredChildren(group); track item.code) {\n <div class=\"flex items-center justify-between gap-2\">\n <div class=\"flex flex-1 items-center gap-2\">\n <p-checkbox\n size=\"small\"\n [inputId]=\"group.code + '_' + item.code\"\n [binary]=\"true\"\n [ngModel]=\"isFilterSelected(group.code, item.code)\"\n (ngModelChange)=\"toggleFilter(group, item)\"\n ></p-checkbox>\n @if (getColorClass(item)) {\n <div\n class=\"h-5 w-5 rounded-full\"\n [class]=\"getColorClass(item)\"\n ></div>\n }\n <ef-label\n [label]=\"item.label\"\n [for]=\"group.code + '_' + item.code\"\n styleClass=\"cursor-pointer text-base font-normal leading-tight text-surface-700 dark:text-surface-300\"\n />\n </div>\n @if (getItemCount(group.code, item.code) > 0) {\n <p-badge\n [value]=\"getItemCount(group.code, item.code)\"\n size=\"small\"\n class=\"rounded-xl! h-6! min-w-6!\"\n severity=\"secondary\"\n ></p-badge>\n }\n </div>\n }\n </div>\n </p-accordion-content>\n </p-accordion-panel>\n }\n }\n </p-accordion>\n</div>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AccordionModule }, { kind: "component", type: i2$2.Accordion, selector: "p-accordion", inputs: ["value", "multiple", "styleClass", "expandIcon", "collapseIcon", "selectOnFocus", "transitionOptions", "motionOptions"], outputs: ["valueChange", "onClose", "onOpen"] }, { kind: "component", type: i2$2.AccordionPanel, selector: "p-accordion-panel, p-accordionpanel", inputs: ["value", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: i2$2.AccordionHeader, selector: "p-accordion-header, p-accordionheader" }, { kind: "component", type: i2$2.AccordionContent, selector: "p-accordion-content, p-accordioncontent" }, { kind: "ngmodule", type: BadgeModule }, { kind: "component", type: i3.Badge, selector: "p-badge", inputs: ["styleClass", "badgeSize", "size", "severity", "value", "badgeDisabled"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i1.ButtonLabel, selector: "[pButtonLabel]", inputs: ["ptButtonLabel", "pButtonLabelPT", "pButtonLabelUnstyled"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i5.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: ChipModule }, { kind: "component", type: i6.Chip, selector: "p-chip", inputs: ["label", "icon", "image", "alt", "styleClass", "disabled", "removable", "removeIcon", "chipProps"], outputs: ["onRemove", "onImageError"] }, { kind: "ngmodule", type: IconFieldModule }, { kind: "component", type: i7.IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["hostName", "iconPosition", "styleClass"] }, { kind: "ngmodule", type: InputIconModule }, { kind: "component", type: i8.InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["hostName", "styleClass"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i9.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: EfLabelComponent, selector: "ef-label", inputs: ["label", "labelKey", "for", "styleClass", "required"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5896
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfProductCatalogueFilterComponent, isStandalone: true, selector: "ef-product-catalogue-filter", inputs: { categoryGroups: { classPropertyName: "categoryGroups", publicName: "categoryGroups", isSignal: true, isRequired: true, transformFunction: null }, products: { classPropertyName: "products", publicName: "products", isSignal: true, isRequired: true, transformFunction: null }, selectedFilters: { classPropertyName: "selectedFilters", publicName: "selectedFilters", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedFilters: "selectedFiltersChange", filtersChanged: "filtersChanged" }, ngImport: i0, template: "<div class=\"flex w-80 shrink-0 flex-col items-start justify-start sticky top-4 max-h-[calc(100vh-2rem)] overflow-y-auto\">\n <div\n class=\"mb-4 flex flex-col items-start justify-center gap-2 self-stretch border-b border-surface-200 px-2 pb-4 dark:border-surface-700\"\n >\n <div class=\"flex items-center justify-between gap-2 self-stretch\">\n <div\n class=\"text-base font-semibold leading-tight text-surface-900 dark:text-surface-0\"\n >\n Filters\n </div>\n <p-button\n [autofocus]=\"false\"\n [buttonProps]=\"noAutofocus\"\n size=\"small\"\n severity=\"secondary\"\n [text]=\"true\"\n class=\"py-1! px-2! text-base! font-normal!\"\n (clickEvent)=\"clearAllFilters()\"\n >\n <span pButtonLabel>\n <i class=\"pi pi-eraser\"></i>\n Clear\n </span>\n </p-button>\n </div>\n @if (selectedFilters().length > 0) {\n <div\n class=\"flex flex-wrap items-start justify-start gap-2 self-stretch\"\n >\n @for (filter of selectedFilters(); track filter.type + filter.code) {\n <p-chip\n [label]=\"filter.label\"\n [removable]=\"true\"\n size=\"small\"\n class=\"h-auto rounded-full px-6\"\n removeIcon=\"pi pi-times\"\n (onRemove)=\"removeFilter(filter)\"\n ></p-chip>\n }\n </div>\n }\n </div>\n\n <p-accordion\n [multiple]=\"true\"\n [value]=\"expandedPanels()\"\n class=\"w-full\"\n >\n @for (group of categoryGroups(); track group.code) {\n @if (group.children && group.children.length > 0) {\n <p-accordion-panel [value]=\"group.code\">\n <p-accordion-header>\n <span\n class=\"text-base font-semibold leading-tight text-surface-900 dark:text-surface-0\"\n >{{ group.label }}</span>\n </p-accordion-header>\n <p-accordion-content>\n <div class=\"flex flex-col gap-4\">\n @if (shouldShowSearch(group)) {\n <p-iconfield iconPosition=\"left\" class=\"w-full\">\n <p-inputicon class=\"pi pi-search\"></p-inputicon>\n <input\n pInputText\n size=\"small\"\n [ngModel]=\"searchTerms()[group.code] || ''\"\n (ngModelChange)=\"updateSearchTerm(group.code, $event)\"\n [placeholder]=\"'Rechercher ' + group.label.toLowerCase()\"\n class=\"w-full\"\n />\n </p-iconfield>\n }\n\n @for (item of getFilteredChildren(group); track item.code) {\n <div class=\"flex items-center justify-between gap-2\">\n <div class=\"flex flex-1 items-center gap-2\">\n <p-checkbox\n size=\"small\"\n [inputId]=\"group.code + '_' + item.code\"\n [binary]=\"true\"\n [ngModel]=\"isFilterSelected(group.code, item.code)\"\n (ngModelChange)=\"toggleFilter(group, item)\"\n ></p-checkbox>\n @if (getColorClass(item)) {\n <div\n class=\"h-5 w-5 rounded-full\"\n [class]=\"getColorClass(item)\"\n ></div>\n }\n <ef-label\n [label]=\"item.label\"\n [for]=\"group.code + '_' + item.code\"\n styleClass=\"cursor-pointer text-base font-normal leading-tight text-surface-700 dark:text-surface-300\"\n />\n </div>\n @if (getItemCount(group.code, item.code) > 0) {\n <p-badge\n [value]=\"getItemCount(group.code, item.code)\"\n size=\"small\"\n class=\"rounded-xl! h-6! min-w-6!\"\n severity=\"secondary\"\n ></p-badge>\n }\n </div>\n }\n </div>\n </p-accordion-content>\n </p-accordion-panel>\n }\n }\n </p-accordion>\n</div>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AccordionModule }, { kind: "component", type: i2$2.Accordion, selector: "p-accordion", inputs: ["value", "multiple", "styleClass", "expandIcon", "collapseIcon", "selectOnFocus", "transitionOptions", "motionOptions"], outputs: ["valueChange", "onClose", "onOpen"] }, { kind: "component", type: i2$2.AccordionPanel, selector: "p-accordion-panel, p-accordionpanel", inputs: ["value", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: i2$2.AccordionHeader, selector: "p-accordion-header, p-accordionheader" }, { kind: "component", type: i2$2.AccordionContent, selector: "p-accordion-content, p-accordioncontent" }, { kind: "ngmodule", type: BadgeModule }, { kind: "component", type: i3.Badge, selector: "p-badge", inputs: ["styleClass", "badgeSize", "size", "severity", "value", "badgeDisabled"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i1.ButtonLabel, selector: "[pButtonLabel]", inputs: ["ptButtonLabel", "pButtonLabelPT", "pButtonLabelUnstyled"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i5.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: ChipModule }, { kind: "component", type: i6.Chip, selector: "p-chip", inputs: ["label", "icon", "image", "alt", "styleClass", "disabled", "removable", "removeIcon", "chipProps"], outputs: ["onRemove", "onImageError"] }, { kind: "ngmodule", type: IconFieldModule }, { kind: "component", type: i7.IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["hostName", "iconPosition", "styleClass"] }, { kind: "ngmodule", type: InputIconModule }, { kind: "component", type: i8.InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["hostName", "styleClass"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i9.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: EfLabelComponent, selector: "ef-label", inputs: ["label", "labelKey", "for", "styleClass", "required"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5795
5897
|
}
|
|
5796
5898
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfProductCatalogueFilterComponent, decorators: [{
|
|
5797
5899
|
type: Component,
|
|
@@ -5806,7 +5908,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
5806
5908
|
InputIconModule,
|
|
5807
5909
|
InputTextModule,
|
|
5808
5910
|
EfLabelComponent,
|
|
5809
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex w-80 shrink-0 flex-col items-start justify-start sticky top-4 max-h-[calc(100vh-2rem)] overflow-y-auto\">\n <div\n class=\"mb-4 flex flex-col items-start justify-center gap-2 self-stretch border-b border-surface-200 px-2 pb-4 dark:border-surface-700\"\n >\n <div class=\"flex items-center justify-between gap-2 self-stretch\">\n <div\n class=\"text-base font-semibold leading-tight text-surface-900 dark:text-surface-0\"\n >\n Filters\n </div>\n <p-button\n size=\"small\"\n severity=\"secondary\"\n [text]=\"true\"\n class=\"py-1! px-2! text-base! font-normal!\"\n (clickEvent)=\"clearAllFilters()\"\n >\n <span pButtonLabel>\n <i class=\"pi pi-eraser\"></i>\n Clear\n </span>\n </p-button>\n </div>\n @if (selectedFilters().length > 0) {\n <div\n class=\"flex flex-wrap items-start justify-start gap-2 self-stretch\"\n >\n @for (filter of selectedFilters(); track filter.type + filter.code) {\n <p-chip\n [label]=\"filter.label\"\n [removable]=\"true\"\n size=\"small\"\n class=\"h-auto rounded-full px-6\"\n removeIcon=\"pi pi-times\"\n (onRemove)=\"removeFilter(filter)\"\n ></p-chip>\n }\n </div>\n }\n </div>\n\n <p-accordion\n [multiple]=\"true\"\n [value]=\"expandedPanels()\"\n class=\"w-full\"\n >\n @for (group of categoryGroups(); track group.code) {\n @if (group.children && group.children.length > 0) {\n <p-accordion-panel [value]=\"group.code\">\n <p-accordion-header>\n <span\n class=\"text-base font-semibold leading-tight text-surface-900 dark:text-surface-0\"\n >{{ group.label }}</span>\n </p-accordion-header>\n <p-accordion-content>\n <div class=\"flex flex-col gap-4\">\n @if (shouldShowSearch(group)) {\n <p-iconfield iconPosition=\"left\" class=\"w-full\">\n <p-inputicon class=\"pi pi-search\"></p-inputicon>\n <input\n pInputText\n size=\"small\"\n [ngModel]=\"searchTerms()[group.code] || ''\"\n (ngModelChange)=\"updateSearchTerm(group.code, $event)\"\n [placeholder]=\"'Rechercher ' + group.label.toLowerCase()\"\n class=\"w-full\"\n />\n </p-iconfield>\n }\n\n @for (item of getFilteredChildren(group); track item.code) {\n <div class=\"flex items-center justify-between gap-2\">\n <div class=\"flex flex-1 items-center gap-2\">\n <p-checkbox\n size=\"small\"\n [inputId]=\"group.code + '_' + item.code\"\n [binary]=\"true\"\n [ngModel]=\"isFilterSelected(group.code, item.code)\"\n (ngModelChange)=\"toggleFilter(group, item)\"\n ></p-checkbox>\n @if (getColorClass(item)) {\n <div\n class=\"h-5 w-5 rounded-full\"\n [class]=\"getColorClass(item)\"\n ></div>\n }\n <ef-label\n [label]=\"item.label\"\n [for]=\"group.code + '_' + item.code\"\n styleClass=\"cursor-pointer text-base font-normal leading-tight text-surface-700 dark:text-surface-300\"\n />\n </div>\n @if (getItemCount(group.code, item.code) > 0) {\n <p-badge\n [value]=\"getItemCount(group.code, item.code)\"\n size=\"small\"\n class=\"rounded-xl! h-6! min-w-6!\"\n severity=\"secondary\"\n ></p-badge>\n }\n </div>\n }\n </div>\n </p-accordion-content>\n </p-accordion-panel>\n }\n }\n </p-accordion>\n</div>\n" }]
|
|
5911
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex w-80 shrink-0 flex-col items-start justify-start sticky top-4 max-h-[calc(100vh-2rem)] overflow-y-auto\">\n <div\n class=\"mb-4 flex flex-col items-start justify-center gap-2 self-stretch border-b border-surface-200 px-2 pb-4 dark:border-surface-700\"\n >\n <div class=\"flex items-center justify-between gap-2 self-stretch\">\n <div\n class=\"text-base font-semibold leading-tight text-surface-900 dark:text-surface-0\"\n >\n Filters\n </div>\n <p-button\n [autofocus]=\"false\"\n [buttonProps]=\"noAutofocus\"\n size=\"small\"\n severity=\"secondary\"\n [text]=\"true\"\n class=\"py-1! px-2! text-base! font-normal!\"\n (clickEvent)=\"clearAllFilters()\"\n >\n <span pButtonLabel>\n <i class=\"pi pi-eraser\"></i>\n Clear\n </span>\n </p-button>\n </div>\n @if (selectedFilters().length > 0) {\n <div\n class=\"flex flex-wrap items-start justify-start gap-2 self-stretch\"\n >\n @for (filter of selectedFilters(); track filter.type + filter.code) {\n <p-chip\n [label]=\"filter.label\"\n [removable]=\"true\"\n size=\"small\"\n class=\"h-auto rounded-full px-6\"\n removeIcon=\"pi pi-times\"\n (onRemove)=\"removeFilter(filter)\"\n ></p-chip>\n }\n </div>\n }\n </div>\n\n <p-accordion\n [multiple]=\"true\"\n [value]=\"expandedPanels()\"\n class=\"w-full\"\n >\n @for (group of categoryGroups(); track group.code) {\n @if (group.children && group.children.length > 0) {\n <p-accordion-panel [value]=\"group.code\">\n <p-accordion-header>\n <span\n class=\"text-base font-semibold leading-tight text-surface-900 dark:text-surface-0\"\n >{{ group.label }}</span>\n </p-accordion-header>\n <p-accordion-content>\n <div class=\"flex flex-col gap-4\">\n @if (shouldShowSearch(group)) {\n <p-iconfield iconPosition=\"left\" class=\"w-full\">\n <p-inputicon class=\"pi pi-search\"></p-inputicon>\n <input\n pInputText\n size=\"small\"\n [ngModel]=\"searchTerms()[group.code] || ''\"\n (ngModelChange)=\"updateSearchTerm(group.code, $event)\"\n [placeholder]=\"'Rechercher ' + group.label.toLowerCase()\"\n class=\"w-full\"\n />\n </p-iconfield>\n }\n\n @for (item of getFilteredChildren(group); track item.code) {\n <div class=\"flex items-center justify-between gap-2\">\n <div class=\"flex flex-1 items-center gap-2\">\n <p-checkbox\n size=\"small\"\n [inputId]=\"group.code + '_' + item.code\"\n [binary]=\"true\"\n [ngModel]=\"isFilterSelected(group.code, item.code)\"\n (ngModelChange)=\"toggleFilter(group, item)\"\n ></p-checkbox>\n @if (getColorClass(item)) {\n <div\n class=\"h-5 w-5 rounded-full\"\n [class]=\"getColorClass(item)\"\n ></div>\n }\n <ef-label\n [label]=\"item.label\"\n [for]=\"group.code + '_' + item.code\"\n styleClass=\"cursor-pointer text-base font-normal leading-tight text-surface-700 dark:text-surface-300\"\n />\n </div>\n @if (getItemCount(group.code, item.code) > 0) {\n <p-badge\n [value]=\"getItemCount(group.code, item.code)\"\n size=\"small\"\n class=\"rounded-xl! h-6! min-w-6!\"\n severity=\"secondary\"\n ></p-badge>\n }\n </div>\n }\n </div>\n </p-accordion-content>\n </p-accordion-panel>\n }\n }\n </p-accordion>\n</div>\n" }]
|
|
5810
5912
|
}], propDecorators: { categoryGroups: [{ type: i0.Input, args: [{ isSignal: true, alias: "categoryGroups", required: true }] }], products: [{ type: i0.Input, args: [{ isSignal: true, alias: "products", required: true }] }], selectedFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedFilters", required: false }] }, { type: i0.Output, args: ["selectedFiltersChange"] }], filtersChanged: [{ type: i0.Output, args: ["filtersChanged"] }] } });
|
|
5811
5913
|
|
|
5812
5914
|
class EfProductCatalogueComponent {
|
|
@@ -6108,7 +6210,7 @@ class EfProductCatalogueComponent {
|
|
|
6108
6210
|
return (this.currencyPipe.transform(value, this.currencyCode(), 'symbol-narrow', '1.2-2') || '');
|
|
6109
6211
|
}
|
|
6110
6212
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfProductCatalogueComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6111
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfProductCatalogueComponent, isStandalone: true, selector: "ef-product-catalogue", inputs: { products: { classPropertyName: "products", publicName: "products", isSignal: true, isRequired: false, transformFunction: null }, categoryGroups: { classPropertyName: "categoryGroups", publicName: "categoryGroups", isSignal: true, isRequired: false, transformFunction: null }, initialSelectedItems: { classPropertyName: "initialSelectedItems", publicName: "initialSelectedItems", isSignal: true, isRequired: false, transformFunction: null }, defaultFilters: { classPropertyName: "defaultFilters", publicName: "defaultFilters", isSignal: true, isRequired: false, transformFunction: null }, trackByField: { classPropertyName: "trackByField", publicName: "trackByField", isSignal: true, isRequired: false, transformFunction: null }, currencyCode: { classPropertyName: "currencyCode", publicName: "currencyCode", isSignal: true, isRequired: false, transformFunction: null }, localeCode: { classPropertyName: "localeCode", publicName: "localeCode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { productsValidated: "productsValidated" }, queries: [{ propertyName: "productThumbnailTpl", first: true, predicate: ["productThumbnail"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "sortMenu", first: true, predicate: ["sortMenu"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"bg-surface-0 dark:bg-surface-950\">\n <div class=\"flex flex-row gap-4\">\n <!-- Filter Sidebar -->\n <ef-product-catalogue-filter\n [categoryGroups]=\"categoryGroups()\"\n [products]=\"products()\"\n [(selectedFilters)]=\"selectedFilters\"\n (filtersChanged)=\"onFiltersChanged($event)\"\n />\n\n <!-- Product Grid -->\n <div\n class=\"min-h-96 flex-1 rounded-md border-2 border-dotted border-surface-200 bg-surface-50 p-4 dark:border-surface-700 dark:bg-surface-800\"\n >\n <div class=\"sticky top-0 z-10 w-full mb-4 bg-surface-50 dark:bg-surface-800 pb-2 -mt-4 pt-4 -mx-4 px-4\">\n <p-iconfield iconPosition=\"left\" class=\"w-full\">\n <p-inputicon class=\"pi pi-search\"></p-inputicon>\n <input\n pInputText\n size=\"small\"\n [(ngModel)]=\"productSearch\"\n [placeholder]=\"'placeholder.search_products' | translate\"\n class=\"w-full\"\n />\n </p-iconfield>\n </div>\n <div class=\"grid grid-cols-2 gap-4 lg:grid-cols-3 xl:grid-cols-4\">\n @for (product of filteredProducts(); track trackKey(product)) {\n <p-card\n [header]=\"''\"\n [class.border-2]=\"true\"\n [class.border-blue-100]=\"getProductQuantity(product) > 0\"\n [class.!bg-blue-100]=\"getProductQuantity(product) > 0\"\n [class.dark:!border-blue-900]=\"getProductQuantity(product) > 0\"\n [class.dark:!bg-blue-900]=\"getProductQuantity(product) > 0\"\n [class.border-transparent]=\"getProductQuantity(product) === 0\"\n class=\"cursor-pointer hover:shadow-md dark:hover:shadow-md dark:hover:shadow-gray-300/50\"\n >\n <ng-template pTemplate=\"header\">\n <div class=\"w-full\">\n @if (productThumbnailTpl()) {\n <ng-container *ngTemplateOutlet=\"productThumbnailTpl(); context: { $implicit: product }\"></ng-container>\n } @else {\n <!-- Default fallback thumbnail -->\n <div class=\"flex h-[13rem] items-center justify-center bg-surface-100 text-3xl text-surface-400 dark:bg-surface-800\">\n <i class=\"pi pi-box\"></i>\n </div>\n }\n </div>\n </ng-template>\n <ng-template pTemplate=\"content\">\n <div [innerHTML]=\"product.displayName\" class=\"h-14 font-semibold\"></div>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n @if (isVariableProduct(product)) {\n <!-- Variable product: variant selector + per-variant quantities -->\n <div class=\"flex items-center justify-between mb-2\">\n <p-badge\n severity=\"secondary\"\n [value]=\"getActiveVariants(product).length + ' ' + ('catalogue.variants' | translate)\"\n badgeSize=\"small\"\n />\n <div class=\"text-lg font-bold\">\n {{ formatPrice(product) }}\n </div>\n </div>\n\n <!-- Variant selector -->\n <p-select\n [options]=\"getActiveVariants(product)\"\n optionLabel=\"title\"\n optionValue=\"variantId\"\n [ngModel]=\"getSelectedVariantId(product)\"\n (ngModelChange)=\"setSelectedVariant(product, $event)\"\n size=\"small\"\n styleClass=\"w-full mb-3\"\n [placeholder]=\"'placeholder.select_variant' | translate\"\n />\n\n <!-- Add button or quantity stepper for selected variant -->\n <div class=\"mt-2\">\n @if (getProductQuantity(product) > 0) {\n <!-- Show per-variant breakdown -->\n @for (entry of selectedProducts(); track $index) {\n @if (productKey(entry.product) === productKey(product) && entry.variantId) {\n <div class=\"flex items-center justify-center gap-2 mb-2\">\n <span class=\"text-xs font-medium text-surface-600 dark:text-surface-400 min-w-12 text-center\">\n {{ getVariantTitle(product, entry.variantId) }}\n </span>\n <ef-quantity-stepper\n [ngModel]=\"entry.quantity\"\n (ngModelChange)=\"updateVariantQuantity(product, entry.variantId!, $event)\"\n [min]=\"0\"\n [max]=\"1000\"\n [maxFractionDigits]=\"4\"\n [locale]=\"localeCode()\"\n />\n <ef-button\n icon=\"pi pi-times\"\n severity=\"danger\"\n styleClass=\"!rounded-full !w-7 !h-7 !p-0\"\n size=\"small\"\n (clickEvent)=\"removeVariantSelection(product, entry.variantId!)\"\n />\n </div>\n }\n }\n <!-- Add another variant button -->\n <ef-button\n icon=\"pi pi-plus\"\n [label]=\"'button.add_variant' | translate\"\n severity=\"primary\"\n styleClass=\"w-full !rounded-full !h-10 mt-1\"\n size=\"small\"\n (clickEvent)=\"addProduct(product)\"\n />\n } @else {\n <ef-button\n [label]=\"'button.add' | translate\"\n icon=\"pi pi-shopping-cart\"\n severity=\"primary\"\n styleClass=\"w-full !rounded-full !h-12\"\n (clickEvent)=\"addProduct(product)\"\n />\n }\n </div>\n } @else {\n <!-- Simple product: original behavior -->\n <div class=\"flex items-center justify-between\">\n <p-badge\n severity=\"secondary\"\n [value]=\"getPackagingLabel(product)\"\n badgeSize=\"small\"\n />\n <div class=\"text-lg font-bold\">\n {{ formatPrice(product) }}\n </div>\n </div>\n <div class=\"mt-4\">\n @if (getProductQuantity(product) > 0) {\n <div class=\"flex items-center justify-between\">\n <ef-button\n icon=\"pi pi-trash\"\n severity=\"primary\"\n styleClass=\"!rounded-full\"\n (clickEvent)=\"removeProduct(product)\"\n />\n <ef-quantity-stepper\n [ngModel]=\"getProductQuantity(product)\"\n (ngModelChange)=\"updateProductQuantity(product, $event)\"\n [min]=\"0\"\n [max]=\"1000\"\n [maxFractionDigits]=\"4\"\n [locale]=\"localeCode()\"\n />\n </div>\n } @else {\n <ef-button\n [label]=\"'button.add' | translate\"\n icon=\"pi pi-shopping-cart\"\n severity=\"primary\"\n styleClass=\"w-full !rounded-full !h-12\"\n (clickEvent)=\"addProduct(product)\"\n />\n }\n </div>\n }\n </ng-template>\n </p-card>\n } @empty {\n <div class=\"p-2\">{{ 'message.no_products_found' | translate }}</div>\n }\n </div>\n </div>\n </div>\n</div>\n", styles: [".p-accordion-header-link{border:0!important;padding:.25rem 0!important;box-shadow:none!important}.p-accordion-panel{border:0!important;border-bottom:1px solid var(--surface-200)!important}:host-context(.dark) .p-accordion-panel{border-bottom-color:var(--surface-700)!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: BadgeModule }, { kind: "component", type: i3.Badge, selector: "p-badge", inputs: ["styleClass", "badgeSize", "size", "severity", "value", "badgeDisabled"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: EfButtonComponent, selector: "ef-button", inputs: ["label", "labelKey", "icon", "variant", "severity", "size", "disabled", "rounded", "outlined", "raised", "text", "loading", "styleClass", "type", "badge", "badgeSeverity", "tooltip", "tooltipKey", "tooltipPosition"], outputs: ["clickEvent"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i5$1.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "ngmodule", type: IconFieldModule }, { kind: "component", type: i7.IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["hostName", "iconPosition", "styleClass"] }, { kind: "ngmodule", type: InputIconModule }, { kind: "component", type: i8.InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["hostName", "styleClass"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i9.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: MenuModule }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i1$2.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: EfQuantityStepperComponent, selector: "ef-quantity-stepper", inputs: ["value", "min", "max", "step", "minFractionDigits", "maxFractionDigits", "locale", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: EfProductCatalogueFilterComponent, selector: "ef-product-catalogue-filter", inputs: ["categoryGroups", "products", "selectedFilters"], outputs: ["selectedFiltersChange", "filtersChanged"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
6213
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfProductCatalogueComponent, isStandalone: true, selector: "ef-product-catalogue", inputs: { products: { classPropertyName: "products", publicName: "products", isSignal: true, isRequired: false, transformFunction: null }, categoryGroups: { classPropertyName: "categoryGroups", publicName: "categoryGroups", isSignal: true, isRequired: false, transformFunction: null }, initialSelectedItems: { classPropertyName: "initialSelectedItems", publicName: "initialSelectedItems", isSignal: true, isRequired: false, transformFunction: null }, defaultFilters: { classPropertyName: "defaultFilters", publicName: "defaultFilters", isSignal: true, isRequired: false, transformFunction: null }, trackByField: { classPropertyName: "trackByField", publicName: "trackByField", isSignal: true, isRequired: false, transformFunction: null }, currencyCode: { classPropertyName: "currencyCode", publicName: "currencyCode", isSignal: true, isRequired: false, transformFunction: null }, localeCode: { classPropertyName: "localeCode", publicName: "localeCode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { productsValidated: "productsValidated" }, queries: [{ propertyName: "productThumbnailTpl", first: true, predicate: ["productThumbnail"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "sortMenu", first: true, predicate: ["sortMenu"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"bg-surface-0 dark:bg-surface-950\">\n <div class=\"flex flex-row gap-4\">\n <!-- Filter Sidebar -->\n <ef-product-catalogue-filter\n [categoryGroups]=\"categoryGroups()\"\n [products]=\"products()\"\n [(selectedFilters)]=\"selectedFilters\"\n (filtersChanged)=\"onFiltersChanged($event)\"\n />\n\n <!-- Product Grid -->\n <div\n class=\"min-h-96 flex-1 rounded-md border-2 border-dotted border-surface-200 bg-surface-50 p-4 dark:border-surface-700 dark:bg-surface-800\"\n >\n <div class=\"sticky top-0 z-10 w-full mb-4 bg-surface-50 dark:bg-surface-800 pb-2 -mt-4 pt-4 -mx-4 px-4\">\n <p-iconfield iconPosition=\"left\" class=\"w-full\">\n <p-inputicon class=\"pi pi-search\"></p-inputicon>\n <input\n pInputText\n size=\"small\"\n [(ngModel)]=\"productSearch\"\n [placeholder]=\"'placeholder.search_products' | translate\"\n class=\"w-full\"\n />\n </p-iconfield>\n </div>\n <div class=\"grid grid-cols-2 gap-4 lg:grid-cols-3 xl:grid-cols-4\">\n @for (product of filteredProducts(); track trackKey(product)) {\n <p-card\n [header]=\"''\"\n [class.border-2]=\"true\"\n [class.border-blue-100]=\"getProductQuantity(product) > 0\"\n [class.!bg-blue-100]=\"getProductQuantity(product) > 0\"\n [class.dark:!border-blue-900]=\"getProductQuantity(product) > 0\"\n [class.dark:!bg-blue-900]=\"getProductQuantity(product) > 0\"\n [class.border-transparent]=\"getProductQuantity(product) === 0\"\n class=\"cursor-pointer hover:shadow-md dark:hover:shadow-md dark:hover:shadow-gray-300/50\"\n >\n <ng-template pTemplate=\"header\">\n <div class=\"w-full\">\n @if (productThumbnailTpl()) {\n <ng-container *ngTemplateOutlet=\"productThumbnailTpl(); context: { $implicit: product }\"></ng-container>\n } @else {\n <!-- Default fallback thumbnail -->\n <div class=\"flex h-[13rem] items-center justify-center bg-surface-100 text-3xl text-surface-400 dark:bg-surface-800\">\n <i class=\"pi pi-box\"></i>\n </div>\n }\n </div>\n </ng-template>\n <ng-template pTemplate=\"content\">\n <div [innerHTML]=\"product.displayName\" class=\"h-14 font-semibold\"></div>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n @if (isVariableProduct(product)) {\n <!-- Variable product: variant selector + per-variant quantities -->\n <div class=\"flex items-center justify-between mb-2\">\n <p-badge\n severity=\"secondary\"\n [value]=\"getActiveVariants(product).length + ' ' + ('catalogue.variants' | translate)\"\n badgeSize=\"small\"\n />\n <div class=\"text-lg font-bold\">\n {{ formatPrice(product) }}\n </div>\n </div>\n\n <!-- Variant selector -->\n <p-select\n [autofocus]=\"false\"\n [options]=\"getActiveVariants(product)\"\n optionLabel=\"title\"\n optionValue=\"variantId\"\n [ngModel]=\"getSelectedVariantId(product)\"\n (ngModelChange)=\"setSelectedVariant(product, $event)\"\n size=\"small\"\n styleClass=\"w-full mb-3\"\n [placeholder]=\"'placeholder.select_variant' | translate\"\n />\n\n <!-- Add button or quantity stepper for selected variant -->\n <div class=\"mt-2\">\n @if (getProductQuantity(product) > 0) {\n <!-- Show per-variant breakdown -->\n @for (entry of selectedProducts(); track $index) {\n @if (productKey(entry.product) === productKey(product) && entry.variantId) {\n <div class=\"flex items-center justify-center gap-2 mb-2\">\n <span class=\"text-xs font-medium text-surface-600 dark:text-surface-400 min-w-12 text-center\">\n {{ getVariantTitle(product, entry.variantId) }}\n </span>\n <ef-quantity-stepper\n [ngModel]=\"entry.quantity\"\n (ngModelChange)=\"updateVariantQuantity(product, entry.variantId!, $event)\"\n [min]=\"0\"\n [max]=\"1000\"\n [maxFractionDigits]=\"4\"\n [locale]=\"localeCode()\"\n />\n <ef-button\n icon=\"pi pi-times\"\n severity=\"danger\"\n styleClass=\"!rounded-full !w-7 !h-7 !p-0\"\n size=\"small\"\n (clickEvent)=\"removeVariantSelection(product, entry.variantId!)\"\n />\n </div>\n }\n }\n <!-- Add another variant button -->\n <ef-button\n icon=\"pi pi-plus\"\n [label]=\"'button.add_variant' | translate\"\n severity=\"primary\"\n styleClass=\"w-full !rounded-full !h-10 mt-1\"\n size=\"small\"\n (clickEvent)=\"addProduct(product)\"\n />\n } @else {\n <ef-button\n [label]=\"'button.add' | translate\"\n icon=\"pi pi-shopping-cart\"\n severity=\"primary\"\n styleClass=\"w-full !rounded-full !h-12\"\n (clickEvent)=\"addProduct(product)\"\n />\n }\n </div>\n } @else {\n <!-- Simple product: original behavior -->\n <div class=\"flex items-center justify-between\">\n <p-badge\n severity=\"secondary\"\n [value]=\"getPackagingLabel(product)\"\n badgeSize=\"small\"\n />\n <div class=\"text-lg font-bold\">\n {{ formatPrice(product) }}\n </div>\n </div>\n <div class=\"mt-4\">\n @if (getProductQuantity(product) > 0) {\n <div class=\"flex items-center justify-between\">\n <ef-button\n icon=\"pi pi-trash\"\n severity=\"primary\"\n styleClass=\"!rounded-full\"\n (clickEvent)=\"removeProduct(product)\"\n />\n <ef-quantity-stepper\n [ngModel]=\"getProductQuantity(product)\"\n (ngModelChange)=\"updateProductQuantity(product, $event)\"\n [min]=\"0\"\n [max]=\"1000\"\n [maxFractionDigits]=\"4\"\n [locale]=\"localeCode()\"\n />\n </div>\n } @else {\n <ef-button\n [label]=\"'button.add' | translate\"\n icon=\"pi pi-shopping-cart\"\n severity=\"primary\"\n styleClass=\"w-full !rounded-full !h-12\"\n (clickEvent)=\"addProduct(product)\"\n />\n }\n </div>\n }\n </ng-template>\n </p-card>\n } @empty {\n <div class=\"p-2\">{{ 'message.no_products_found' | translate }}</div>\n }\n </div>\n </div>\n </div>\n</div>\n", styles: [".p-accordion-header-link{border:0!important;padding:.25rem 0!important;box-shadow:none!important}.p-accordion-panel{border:0!important;border-bottom:1px solid var(--surface-200)!important}:host-context(.dark) .p-accordion-panel{border-bottom-color:var(--surface-700)!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: BadgeModule }, { kind: "component", type: i3.Badge, selector: "p-badge", inputs: ["styleClass", "badgeSize", "size", "severity", "value", "badgeDisabled"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: EfButtonComponent, selector: "ef-button", inputs: ["label", "labelKey", "icon", "variant", "severity", "size", "disabled", "rounded", "outlined", "raised", "text", "loading", "styleClass", "type", "badge", "badgeSeverity", "tooltip", "tooltipKey", "tooltipPosition", "autofocus"], outputs: ["clickEvent"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i5$1.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "ngmodule", type: IconFieldModule }, { kind: "component", type: i7.IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["hostName", "iconPosition", "styleClass"] }, { kind: "ngmodule", type: InputIconModule }, { kind: "component", type: i8.InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["hostName", "styleClass"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i9.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: MenuModule }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i1$2.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: EfQuantityStepperComponent, selector: "ef-quantity-stepper", inputs: ["value", "min", "max", "step", "minFractionDigits", "maxFractionDigits", "locale", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: EfProductCatalogueFilterComponent, selector: "ef-product-catalogue-filter", inputs: ["categoryGroups", "products", "selectedFilters"], outputs: ["selectedFiltersChange", "filtersChanged"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
6112
6214
|
}
|
|
6113
6215
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfProductCatalogueComponent, decorators: [{
|
|
6114
6216
|
type: Component,
|
|
@@ -6126,7 +6228,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
6126
6228
|
EfQuantityStepperComponent,
|
|
6127
6229
|
EfProductCatalogueFilterComponent,
|
|
6128
6230
|
TranslateModule,
|
|
6129
|
-
], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"bg-surface-0 dark:bg-surface-950\">\n <div class=\"flex flex-row gap-4\">\n <!-- Filter Sidebar -->\n <ef-product-catalogue-filter\n [categoryGroups]=\"categoryGroups()\"\n [products]=\"products()\"\n [(selectedFilters)]=\"selectedFilters\"\n (filtersChanged)=\"onFiltersChanged($event)\"\n />\n\n <!-- Product Grid -->\n <div\n class=\"min-h-96 flex-1 rounded-md border-2 border-dotted border-surface-200 bg-surface-50 p-4 dark:border-surface-700 dark:bg-surface-800\"\n >\n <div class=\"sticky top-0 z-10 w-full mb-4 bg-surface-50 dark:bg-surface-800 pb-2 -mt-4 pt-4 -mx-4 px-4\">\n <p-iconfield iconPosition=\"left\" class=\"w-full\">\n <p-inputicon class=\"pi pi-search\"></p-inputicon>\n <input\n pInputText\n size=\"small\"\n [(ngModel)]=\"productSearch\"\n [placeholder]=\"'placeholder.search_products' | translate\"\n class=\"w-full\"\n />\n </p-iconfield>\n </div>\n <div class=\"grid grid-cols-2 gap-4 lg:grid-cols-3 xl:grid-cols-4\">\n @for (product of filteredProducts(); track trackKey(product)) {\n <p-card\n [header]=\"''\"\n [class.border-2]=\"true\"\n [class.border-blue-100]=\"getProductQuantity(product) > 0\"\n [class.!bg-blue-100]=\"getProductQuantity(product) > 0\"\n [class.dark:!border-blue-900]=\"getProductQuantity(product) > 0\"\n [class.dark:!bg-blue-900]=\"getProductQuantity(product) > 0\"\n [class.border-transparent]=\"getProductQuantity(product) === 0\"\n class=\"cursor-pointer hover:shadow-md dark:hover:shadow-md dark:hover:shadow-gray-300/50\"\n >\n <ng-template pTemplate=\"header\">\n <div class=\"w-full\">\n @if (productThumbnailTpl()) {\n <ng-container *ngTemplateOutlet=\"productThumbnailTpl(); context: { $implicit: product }\"></ng-container>\n } @else {\n <!-- Default fallback thumbnail -->\n <div class=\"flex h-[13rem] items-center justify-center bg-surface-100 text-3xl text-surface-400 dark:bg-surface-800\">\n <i class=\"pi pi-box\"></i>\n </div>\n }\n </div>\n </ng-template>\n <ng-template pTemplate=\"content\">\n <div [innerHTML]=\"product.displayName\" class=\"h-14 font-semibold\"></div>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n @if (isVariableProduct(product)) {\n <!-- Variable product: variant selector + per-variant quantities -->\n <div class=\"flex items-center justify-between mb-2\">\n <p-badge\n severity=\"secondary\"\n [value]=\"getActiveVariants(product).length + ' ' + ('catalogue.variants' | translate)\"\n badgeSize=\"small\"\n />\n <div class=\"text-lg font-bold\">\n {{ formatPrice(product) }}\n </div>\n </div>\n\n <!-- Variant selector -->\n <p-select\n [options]=\"getActiveVariants(product)\"\n optionLabel=\"title\"\n optionValue=\"variantId\"\n [ngModel]=\"getSelectedVariantId(product)\"\n (ngModelChange)=\"setSelectedVariant(product, $event)\"\n size=\"small\"\n styleClass=\"w-full mb-3\"\n [placeholder]=\"'placeholder.select_variant' | translate\"\n />\n\n <!-- Add button or quantity stepper for selected variant -->\n <div class=\"mt-2\">\n @if (getProductQuantity(product) > 0) {\n <!-- Show per-variant breakdown -->\n @for (entry of selectedProducts(); track $index) {\n @if (productKey(entry.product) === productKey(product) && entry.variantId) {\n <div class=\"flex items-center justify-center gap-2 mb-2\">\n <span class=\"text-xs font-medium text-surface-600 dark:text-surface-400 min-w-12 text-center\">\n {{ getVariantTitle(product, entry.variantId) }}\n </span>\n <ef-quantity-stepper\n [ngModel]=\"entry.quantity\"\n (ngModelChange)=\"updateVariantQuantity(product, entry.variantId!, $event)\"\n [min]=\"0\"\n [max]=\"1000\"\n [maxFractionDigits]=\"4\"\n [locale]=\"localeCode()\"\n />\n <ef-button\n icon=\"pi pi-times\"\n severity=\"danger\"\n styleClass=\"!rounded-full !w-7 !h-7 !p-0\"\n size=\"small\"\n (clickEvent)=\"removeVariantSelection(product, entry.variantId!)\"\n />\n </div>\n }\n }\n <!-- Add another variant button -->\n <ef-button\n icon=\"pi pi-plus\"\n [label]=\"'button.add_variant' | translate\"\n severity=\"primary\"\n styleClass=\"w-full !rounded-full !h-10 mt-1\"\n size=\"small\"\n (clickEvent)=\"addProduct(product)\"\n />\n } @else {\n <ef-button\n [label]=\"'button.add' | translate\"\n icon=\"pi pi-shopping-cart\"\n severity=\"primary\"\n styleClass=\"w-full !rounded-full !h-12\"\n (clickEvent)=\"addProduct(product)\"\n />\n }\n </div>\n } @else {\n <!-- Simple product: original behavior -->\n <div class=\"flex items-center justify-between\">\n <p-badge\n severity=\"secondary\"\n [value]=\"getPackagingLabel(product)\"\n badgeSize=\"small\"\n />\n <div class=\"text-lg font-bold\">\n {{ formatPrice(product) }}\n </div>\n </div>\n <div class=\"mt-4\">\n @if (getProductQuantity(product) > 0) {\n <div class=\"flex items-center justify-between\">\n <ef-button\n icon=\"pi pi-trash\"\n severity=\"primary\"\n styleClass=\"!rounded-full\"\n (clickEvent)=\"removeProduct(product)\"\n />\n <ef-quantity-stepper\n [ngModel]=\"getProductQuantity(product)\"\n (ngModelChange)=\"updateProductQuantity(product, $event)\"\n [min]=\"0\"\n [max]=\"1000\"\n [maxFractionDigits]=\"4\"\n [locale]=\"localeCode()\"\n />\n </div>\n } @else {\n <ef-button\n [label]=\"'button.add' | translate\"\n icon=\"pi pi-shopping-cart\"\n severity=\"primary\"\n styleClass=\"w-full !rounded-full !h-12\"\n (clickEvent)=\"addProduct(product)\"\n />\n }\n </div>\n }\n </ng-template>\n </p-card>\n } @empty {\n <div class=\"p-2\">{{ 'message.no_products_found' | translate }}</div>\n }\n </div>\n </div>\n </div>\n</div>\n", styles: [".p-accordion-header-link{border:0!important;padding:.25rem 0!important;box-shadow:none!important}.p-accordion-panel{border:0!important;border-bottom:1px solid var(--surface-200)!important}:host-context(.dark) .p-accordion-panel{border-bottom-color:var(--surface-700)!important}\n"] }]
|
|
6231
|
+
], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"bg-surface-0 dark:bg-surface-950\">\n <div class=\"flex flex-row gap-4\">\n <!-- Filter Sidebar -->\n <ef-product-catalogue-filter\n [categoryGroups]=\"categoryGroups()\"\n [products]=\"products()\"\n [(selectedFilters)]=\"selectedFilters\"\n (filtersChanged)=\"onFiltersChanged($event)\"\n />\n\n <!-- Product Grid -->\n <div\n class=\"min-h-96 flex-1 rounded-md border-2 border-dotted border-surface-200 bg-surface-50 p-4 dark:border-surface-700 dark:bg-surface-800\"\n >\n <div class=\"sticky top-0 z-10 w-full mb-4 bg-surface-50 dark:bg-surface-800 pb-2 -mt-4 pt-4 -mx-4 px-4\">\n <p-iconfield iconPosition=\"left\" class=\"w-full\">\n <p-inputicon class=\"pi pi-search\"></p-inputicon>\n <input\n pInputText\n size=\"small\"\n [(ngModel)]=\"productSearch\"\n [placeholder]=\"'placeholder.search_products' | translate\"\n class=\"w-full\"\n />\n </p-iconfield>\n </div>\n <div class=\"grid grid-cols-2 gap-4 lg:grid-cols-3 xl:grid-cols-4\">\n @for (product of filteredProducts(); track trackKey(product)) {\n <p-card\n [header]=\"''\"\n [class.border-2]=\"true\"\n [class.border-blue-100]=\"getProductQuantity(product) > 0\"\n [class.!bg-blue-100]=\"getProductQuantity(product) > 0\"\n [class.dark:!border-blue-900]=\"getProductQuantity(product) > 0\"\n [class.dark:!bg-blue-900]=\"getProductQuantity(product) > 0\"\n [class.border-transparent]=\"getProductQuantity(product) === 0\"\n class=\"cursor-pointer hover:shadow-md dark:hover:shadow-md dark:hover:shadow-gray-300/50\"\n >\n <ng-template pTemplate=\"header\">\n <div class=\"w-full\">\n @if (productThumbnailTpl()) {\n <ng-container *ngTemplateOutlet=\"productThumbnailTpl(); context: { $implicit: product }\"></ng-container>\n } @else {\n <!-- Default fallback thumbnail -->\n <div class=\"flex h-[13rem] items-center justify-center bg-surface-100 text-3xl text-surface-400 dark:bg-surface-800\">\n <i class=\"pi pi-box\"></i>\n </div>\n }\n </div>\n </ng-template>\n <ng-template pTemplate=\"content\">\n <div [innerHTML]=\"product.displayName\" class=\"h-14 font-semibold\"></div>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n @if (isVariableProduct(product)) {\n <!-- Variable product: variant selector + per-variant quantities -->\n <div class=\"flex items-center justify-between mb-2\">\n <p-badge\n severity=\"secondary\"\n [value]=\"getActiveVariants(product).length + ' ' + ('catalogue.variants' | translate)\"\n badgeSize=\"small\"\n />\n <div class=\"text-lg font-bold\">\n {{ formatPrice(product) }}\n </div>\n </div>\n\n <!-- Variant selector -->\n <p-select\n [autofocus]=\"false\"\n [options]=\"getActiveVariants(product)\"\n optionLabel=\"title\"\n optionValue=\"variantId\"\n [ngModel]=\"getSelectedVariantId(product)\"\n (ngModelChange)=\"setSelectedVariant(product, $event)\"\n size=\"small\"\n styleClass=\"w-full mb-3\"\n [placeholder]=\"'placeholder.select_variant' | translate\"\n />\n\n <!-- Add button or quantity stepper for selected variant -->\n <div class=\"mt-2\">\n @if (getProductQuantity(product) > 0) {\n <!-- Show per-variant breakdown -->\n @for (entry of selectedProducts(); track $index) {\n @if (productKey(entry.product) === productKey(product) && entry.variantId) {\n <div class=\"flex items-center justify-center gap-2 mb-2\">\n <span class=\"text-xs font-medium text-surface-600 dark:text-surface-400 min-w-12 text-center\">\n {{ getVariantTitle(product, entry.variantId) }}\n </span>\n <ef-quantity-stepper\n [ngModel]=\"entry.quantity\"\n (ngModelChange)=\"updateVariantQuantity(product, entry.variantId!, $event)\"\n [min]=\"0\"\n [max]=\"1000\"\n [maxFractionDigits]=\"4\"\n [locale]=\"localeCode()\"\n />\n <ef-button\n icon=\"pi pi-times\"\n severity=\"danger\"\n styleClass=\"!rounded-full !w-7 !h-7 !p-0\"\n size=\"small\"\n (clickEvent)=\"removeVariantSelection(product, entry.variantId!)\"\n />\n </div>\n }\n }\n <!-- Add another variant button -->\n <ef-button\n icon=\"pi pi-plus\"\n [label]=\"'button.add_variant' | translate\"\n severity=\"primary\"\n styleClass=\"w-full !rounded-full !h-10 mt-1\"\n size=\"small\"\n (clickEvent)=\"addProduct(product)\"\n />\n } @else {\n <ef-button\n [label]=\"'button.add' | translate\"\n icon=\"pi pi-shopping-cart\"\n severity=\"primary\"\n styleClass=\"w-full !rounded-full !h-12\"\n (clickEvent)=\"addProduct(product)\"\n />\n }\n </div>\n } @else {\n <!-- Simple product: original behavior -->\n <div class=\"flex items-center justify-between\">\n <p-badge\n severity=\"secondary\"\n [value]=\"getPackagingLabel(product)\"\n badgeSize=\"small\"\n />\n <div class=\"text-lg font-bold\">\n {{ formatPrice(product) }}\n </div>\n </div>\n <div class=\"mt-4\">\n @if (getProductQuantity(product) > 0) {\n <div class=\"flex items-center justify-between\">\n <ef-button\n icon=\"pi pi-trash\"\n severity=\"primary\"\n styleClass=\"!rounded-full\"\n (clickEvent)=\"removeProduct(product)\"\n />\n <ef-quantity-stepper\n [ngModel]=\"getProductQuantity(product)\"\n (ngModelChange)=\"updateProductQuantity(product, $event)\"\n [min]=\"0\"\n [max]=\"1000\"\n [maxFractionDigits]=\"4\"\n [locale]=\"localeCode()\"\n />\n </div>\n } @else {\n <ef-button\n [label]=\"'button.add' | translate\"\n icon=\"pi pi-shopping-cart\"\n severity=\"primary\"\n styleClass=\"w-full !rounded-full !h-12\"\n (clickEvent)=\"addProduct(product)\"\n />\n }\n </div>\n }\n </ng-template>\n </p-card>\n } @empty {\n <div class=\"p-2\">{{ 'message.no_products_found' | translate }}</div>\n }\n </div>\n </div>\n </div>\n</div>\n", styles: [".p-accordion-header-link{border:0!important;padding:.25rem 0!important;box-shadow:none!important}.p-accordion-panel{border:0!important;border-bottom:1px solid var(--surface-200)!important}:host-context(.dark) .p-accordion-panel{border-bottom-color:var(--surface-700)!important}\n"] }]
|
|
6130
6232
|
}], propDecorators: { products: [{ type: i0.Input, args: [{ isSignal: true, alias: "products", required: false }] }], categoryGroups: [{ type: i0.Input, args: [{ isSignal: true, alias: "categoryGroups", required: false }] }], initialSelectedItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialSelectedItems", required: false }] }], defaultFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultFilters", required: false }] }], trackByField: [{ type: i0.Input, args: [{ isSignal: true, alias: "trackByField", required: false }] }], currencyCode: [{ type: i0.Input, args: [{ isSignal: true, alias: "currencyCode", required: false }] }], localeCode: [{ type: i0.Input, args: [{ isSignal: true, alias: "localeCode", required: false }] }], productThumbnailTpl: [{ type: i0.ContentChild, args: ['productThumbnail', { isSignal: true }] }], sortMenu: [{
|
|
6131
6233
|
type: ViewChild,
|
|
6132
6234
|
args: ['sortMenu']
|
|
@@ -6896,7 +6998,7 @@ class EfToolbarComponent {
|
|
|
6896
6998
|
this.router.navigate([baseUrl]);
|
|
6897
6999
|
}
|
|
6898
7000
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6899
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfToolbarComponent, isStandalone: true, selector: "ef-toolbar", inputs: { context: "context", state: "state", disabled: "disabled", backButton: "backButton", deleteButton: "deleteButton", duplicateButton: "duplicateButton", saveButton: "saveButton", exportButton: "exportButton", printButton: "printButton", addButton: "addButton", clearButton: "clearButton", searchButton: "searchButton", showFreeSearchInput: "showFreeSearchInput" }, outputs: { back: "back", save: "save", delete: "delete", duplicate: "duplicate", print: "print", triggerCustoAction: "triggerCustoAction", add: "add", search: "search", clear: "clear" }, ngImport: i0, template: "<p-toolbar>\n <ng-template #start>\n <div class=\"flex items-center gap-3\">\n @if (isDetailState || backButton) {\n <ef-button\n icon=\"pi pi-angle-left\"\n severity=\"primary\"\n styleClass=\"action-btn-text\"\n tooltipKey=\"common.back\"\n labelKey=\"common.back\"\n size=\"small\"\n (clickEvent)=\"backAction()\"\n />\n }\n <!-- Custom content slot for start section (e.g., status badge) -->\n <ng-content select=\"[toolbarStart]\" />\n </div>\n </ng-template>\n <ng-template #center>\n @if (showFreeSearchInput) {\n <p-iconfield iconPosition=\"left\">\n <p-inputicon styleClass=\"pi pi-search\" />\n <input\n id=\"freeTextSearch\"\n type=\"text\"\n pInputText\n [placeholder]=\"'common.search' | translate\"\n />\n </p-iconfield>\n }\n </ng-template>\n <ng-template #end>\n <!-- DETAIL state -->\n <!-- Custom content slot for start section (e.g., status badge) -->\n <ng-content select=\"[toolbarEnd]\" />\n @if (isDetailState && isDuplicateMode) {\n <span\n class=\"duplicate-badge flex items-center gap-1 rounded bg-blue-100 px-2 py-1 text-sm text-blue-700\"\n >\n <i class=\"pi pi-copy\"></i> {{ 'common.duplicate' | translate }}\n </span>\n }\n @if (isDetailState && deleteButton && hasDeletePermission) {\n <ef-button\n icon=\"pi pi-trash\"\n severity=\"danger\"\n styleClass=\"action-btn\"\n tooltipPosition=\"top\"\n tooltipKey=\"common.delete\"\n size=\"small\"\n [disabled]=\"disabled\"\n (clickEvent)=\"deleteAction()\"\n />\n }\n @if (isDetailState && printButton) {\n <ef-button\n icon=\"pi pi-print\"\n severity=\"primary\"\n styleClass=\"action-btn\"\n tooltipPosition=\"top\"\n tooltipKey=\"common.print\"\n size=\"small\"\n [disabled]=\"disabled\"\n (clickEvent)=\"printAction()\"\n />\n }\n @if (\n isDetailState &&\n duplicateButton &&\n hasDuplicatePermission &&\n !isDuplicateMode\n ) {\n <ef-button\n icon=\"pi pi-copy\"\n severity=\"primary\"\n styleClass=\"action-btn\"\n tooltipPosition=\"left\"\n tooltipKey=\"common.duplicate\"\n size=\"small\"\n [disabled]=\"disabled\"\n (clickEvent)=\"duplicateAction()\"\n />\n }\n @if (isDetailState && saveButton && (hasCreatePermission || hasEditPermission)) {\n <ef-button\n icon=\"pi pi-save\"\n severity=\"primary\"\n styleClass=\"action-btn\"\n tooltipPosition=\"top\"\n tooltipKey=\"common.save\"\n size=\"small\"\n [disabled]=\"disabled\"\n (clickEvent)=\"saveAction()\"\n />\n }\n <!-- SEARCH state -->\n @if (isSearchState && exportButton && hasExportPermission) {\n <ef-button\n icon=\"pi pi-upload\"\n severity=\"primary\"\n styleClass=\"action-btn\"\n tooltipPosition=\"top\"\n tooltipKey=\"common.export\"\n size=\"small\"\n (clickEvent)=\"exportAction()\"\n />\n }\n @if (isSearchState && addButton && hasCreatePermission) {\n <ef-button\n icon=\"pi pi-plus\"\n severity=\"primary\"\n styleClass=\"action-btn-text\"\n tooltipPosition=\"top\"\n tooltipKey=\"common.add\"\n labelKey=\"common.add\"\n size=\"small\"\n (clickEvent)=\"addAction()\"\n />\n }\n @if (isSearchState && clearButton) {\n <ef-button\n icon=\"pi pi-filter-slash\"\n severity=\"primary\"\n styleClass=\"action-btn-text\"\n tooltipPosition=\"top\"\n tooltipKey=\"common.clear_search_criteria\"\n labelKey=\"common.clear\"\n size=\"small\"\n (clickEvent)=\"clearAction()\"\n />\n }\n @if (isSearchState && searchButton && hasReadPermission) {\n <ef-button\n icon=\"pi pi-search\"\n severity=\"primary\"\n styleClass=\"action-btn-text\"\n tooltipPosition=\"top\"\n tooltipKey=\"common.search\"\n labelKey=\"common.search\"\n size=\"small\"\n [disabled]=\"disabled\"\n (clickEvent)=\"searchAction()\"\n />\n }\n </ng-template>\n</p-toolbar>\n", styles: [":host ::ng-deep .p-toolbar{padding:4px!important;border-radius:0;border-left:none;border-right:none;overflow:visible}:host ::ng-deep .p-toolbar-end{flex-wrap:wrap;gap:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ToolbarModule }, { kind: "component", type: i1$a.Toolbar, selector: "p-toolbar", inputs: ["styleClass", "ariaLabelledBy"] }, { kind: "component", type: EfButtonComponent, selector: "ef-button", inputs: ["label", "labelKey", "icon", "variant", "severity", "size", "disabled", "rounded", "outlined", "raised", "text", "loading", "styleClass", "type", "badge", "badgeSeverity", "tooltip", "tooltipKey", "tooltipPosition"], outputs: ["clickEvent"] }, { kind: "ngmodule", type: IconFieldModule }, { kind: "component", type: i7.IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["hostName", "iconPosition", "styleClass"] }, { kind: "ngmodule", type: InputIconModule }, { kind: "component", type: i8.InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["hostName", "styleClass"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i9.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
7001
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfToolbarComponent, isStandalone: true, selector: "ef-toolbar", inputs: { context: "context", state: "state", disabled: "disabled", backButton: "backButton", deleteButton: "deleteButton", duplicateButton: "duplicateButton", saveButton: "saveButton", exportButton: "exportButton", printButton: "printButton", addButton: "addButton", clearButton: "clearButton", searchButton: "searchButton", showFreeSearchInput: "showFreeSearchInput" }, outputs: { back: "back", save: "save", delete: "delete", duplicate: "duplicate", print: "print", triggerCustoAction: "triggerCustoAction", add: "add", search: "search", clear: "clear" }, ngImport: i0, template: "<p-toolbar>\n <ng-template #start>\n <div class=\"flex items-center gap-3\">\n @if (isDetailState || backButton) {\n <ef-button\n icon=\"pi pi-angle-left\"\n severity=\"primary\"\n styleClass=\"action-btn-text\"\n tooltipKey=\"common.back\"\n labelKey=\"common.back\"\n size=\"small\"\n (clickEvent)=\"backAction()\"\n />\n }\n <!-- Custom content slot for start section (e.g., status badge) -->\n <ng-content select=\"[toolbarStart]\" />\n </div>\n </ng-template>\n <ng-template #center>\n @if (showFreeSearchInput) {\n <p-iconfield iconPosition=\"left\">\n <p-inputicon styleClass=\"pi pi-search\" />\n <input\n id=\"freeTextSearch\"\n type=\"text\"\n pInputText\n [placeholder]=\"'common.search' | translate\"\n />\n </p-iconfield>\n }\n </ng-template>\n <ng-template #end>\n <!-- DETAIL state -->\n <!-- Custom content slot for start section (e.g., status badge) -->\n <ng-content select=\"[toolbarEnd]\" />\n @if (isDetailState && isDuplicateMode) {\n <span\n class=\"duplicate-badge flex items-center gap-1 rounded bg-blue-100 px-2 py-1 text-sm text-blue-700\"\n >\n <i class=\"pi pi-copy\"></i> {{ 'common.duplicate' | translate }}\n </span>\n }\n @if (isDetailState && deleteButton && hasDeletePermission) {\n <ef-button\n icon=\"pi pi-trash\"\n severity=\"danger\"\n styleClass=\"action-btn\"\n tooltipPosition=\"top\"\n tooltipKey=\"common.delete\"\n size=\"small\"\n [disabled]=\"disabled\"\n (clickEvent)=\"deleteAction()\"\n />\n }\n @if (isDetailState && printButton) {\n <ef-button\n icon=\"pi pi-print\"\n severity=\"primary\"\n styleClass=\"action-btn\"\n tooltipPosition=\"top\"\n tooltipKey=\"common.print\"\n size=\"small\"\n [disabled]=\"disabled\"\n (clickEvent)=\"printAction()\"\n />\n }\n @if (\n isDetailState &&\n duplicateButton &&\n hasDuplicatePermission &&\n !isDuplicateMode\n ) {\n <ef-button\n icon=\"pi pi-copy\"\n severity=\"primary\"\n styleClass=\"action-btn\"\n tooltipPosition=\"left\"\n tooltipKey=\"common.duplicate\"\n size=\"small\"\n [disabled]=\"disabled\"\n (clickEvent)=\"duplicateAction()\"\n />\n }\n @if (isDetailState && saveButton && (hasCreatePermission || hasEditPermission)) {\n <ef-button\n icon=\"pi pi-save\"\n severity=\"primary\"\n styleClass=\"action-btn\"\n tooltipPosition=\"top\"\n tooltipKey=\"common.save\"\n size=\"small\"\n [disabled]=\"disabled\"\n (clickEvent)=\"saveAction()\"\n />\n }\n <!-- SEARCH state -->\n @if (isSearchState && exportButton && hasExportPermission) {\n <ef-button\n icon=\"pi pi-upload\"\n severity=\"primary\"\n styleClass=\"action-btn\"\n tooltipPosition=\"top\"\n tooltipKey=\"common.export\"\n size=\"small\"\n (clickEvent)=\"exportAction()\"\n />\n }\n @if (isSearchState && addButton && hasCreatePermission) {\n <ef-button\n icon=\"pi pi-plus\"\n severity=\"primary\"\n styleClass=\"action-btn-text\"\n tooltipPosition=\"top\"\n tooltipKey=\"common.add\"\n labelKey=\"common.add\"\n size=\"small\"\n (clickEvent)=\"addAction()\"\n />\n }\n @if (isSearchState && clearButton) {\n <ef-button\n icon=\"pi pi-filter-slash\"\n severity=\"primary\"\n styleClass=\"action-btn-text\"\n tooltipPosition=\"top\"\n tooltipKey=\"common.clear_search_criteria\"\n labelKey=\"common.clear\"\n size=\"small\"\n (clickEvent)=\"clearAction()\"\n />\n }\n @if (isSearchState && searchButton && hasReadPermission) {\n <ef-button\n icon=\"pi pi-search\"\n severity=\"primary\"\n styleClass=\"action-btn-text\"\n tooltipPosition=\"top\"\n tooltipKey=\"common.search\"\n labelKey=\"common.search\"\n size=\"small\"\n [disabled]=\"disabled\"\n (clickEvent)=\"searchAction()\"\n />\n }\n </ng-template>\n</p-toolbar>\n", styles: [":host ::ng-deep .p-toolbar{padding:4px!important;border-radius:0;border-left:none;border-right:none;overflow:visible}:host ::ng-deep .p-toolbar-end{flex-wrap:wrap;gap:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ToolbarModule }, { kind: "component", type: i1$a.Toolbar, selector: "p-toolbar", inputs: ["styleClass", "ariaLabelledBy"] }, { kind: "component", type: EfButtonComponent, selector: "ef-button", inputs: ["label", "labelKey", "icon", "variant", "severity", "size", "disabled", "rounded", "outlined", "raised", "text", "loading", "styleClass", "type", "badge", "badgeSeverity", "tooltip", "tooltipKey", "tooltipPosition", "autofocus"], outputs: ["clickEvent"] }, { kind: "ngmodule", type: IconFieldModule }, { kind: "component", type: i7.IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["hostName", "iconPosition", "styleClass"] }, { kind: "ngmodule", type: InputIconModule }, { kind: "component", type: i8.InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["hostName", "styleClass"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i9.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
6900
7002
|
}
|
|
6901
7003
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfToolbarComponent, decorators: [{
|
|
6902
7004
|
type: Component,
|
|
@@ -8399,7 +8501,7 @@ class EfDetailToolbarComponent {
|
|
|
8399
8501
|
/** Stable trackBy across renders. */
|
|
8400
8502
|
trackByAction = (i, a) => a.id ?? a.labelKey ?? a.label ?? i;
|
|
8401
8503
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfDetailToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8402
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfDetailToolbarComponent, isStandalone: true, selector: "ef-detail-toolbar", inputs: { customActions: { classPropertyName: "customActions", publicName: "customActions", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, showPrintAction: { classPropertyName: "showPrintAction", publicName: "showPrintAction", isSignal: true, isRequired: false, transformFunction: null }, showDuplicateAction: { classPropertyName: "showDuplicateAction", publicName: "showDuplicateAction", isSignal: true, isRequired: false, transformFunction: null }, showDeleteAction: { classPropertyName: "showDeleteAction", publicName: "showDeleteAction", isSignal: true, isRequired: false, transformFunction: null }, showSaveAction: { classPropertyName: "showSaveAction", publicName: "showSaveAction", isSignal: true, isRequired: false, transformFunction: null }, saving: { classPropertyName: "saving", publicName: "saving", isSignal: true, isRequired: false, transformFunction: null }, saveLabelKey: { classPropertyName: "saveLabelKey", publicName: "saveLabelKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { customAction: "customAction", print: "print", duplicate: "duplicate", delete: "delete", save: "save" }, host: { classAttribute: "detail-toolbar" }, ngImport: i0, template: "<div class=\"left\">\n <ng-content></ng-content>\n</div>\n\n<div class=\"right\">\n <!-- Custom screen actions (before the standard group). -->\n @for (action of visibleCustomActions(); track trackByAction($index, action)) {\n <ef-button\n variant=\"comptoir\"\n size=\"small\"\n [severity]=\"action.severity ?? 'ghost'\"\n [icon]=\"action.icon\"\n [label]=\"action.label\"\n [labelKey]=\"action.labelKey\"\n [disabled]=\"!!action.disabled\"\n (clickEvent)=\"onCustomClick(action)\"\n />\n }\n\n <!-- Full-template escape hatch \u2014 anything projected here renders\n after the customActions array, before the standard group. -->\n <ng-content select=\"[actions]\"></ng-content>\n\n <!-- Separator between custom and standard groups. -->\n @if (showSeparator()) {\n <span class=\"sep\" aria-hidden=\"true\">|</span>\n }\n\n <!-- Standard actions: Print \u2192 Duplicate \u2192 Delete \u2192 Save. -->\n @if (canPrint()) {\n <ef-button\n variant=\"comptoir\"\n severity=\"ghost\"\n size=\"small\"\n icon=\"pi pi-print\"\n labelKey=\"common_print\"\n (clickEvent)=\"print.emit()\"\n />\n }\n\n @if (canDuplicate()) {\n <ef-button\n variant=\"comptoir\"\n severity=\"ghost\"\n size=\"small\"\n icon=\"pi pi-clone\"\n labelKey=\"common_duplicate\"\n (clickEvent)=\"duplicate.emit()\"\n />\n }\n\n @if (canDelete()) {\n <ef-button\n variant=\"comptoir\"\n severity=\"danger\"\n size=\"small\"\n icon=\"pi pi-trash\"\n labelKey=\"common_delete\"\n (clickEvent)=\"delete.emit()\"\n />\n }\n\n @if (canSave()) {\n <ef-button\n variant=\"comptoir\"\n severity=\"tenant\"\n size=\"small\"\n icon=\"pi pi-save\"\n [labelKey]=\"saveLabelKey()\"\n [disabled]=\"saving()\"\n [loading]=\"saving()\"\n (clickEvent)=\"save.emit()\"\n />\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfButtonComponent, selector: "ef-button", inputs: ["label", "labelKey", "icon", "variant", "severity", "size", "disabled", "rounded", "outlined", "raised", "text", "loading", "styleClass", "type", "badge", "badgeSeverity", "tooltip", "tooltipKey", "tooltipPosition"], outputs: ["clickEvent"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
8504
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfDetailToolbarComponent, isStandalone: true, selector: "ef-detail-toolbar", inputs: { customActions: { classPropertyName: "customActions", publicName: "customActions", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, showPrintAction: { classPropertyName: "showPrintAction", publicName: "showPrintAction", isSignal: true, isRequired: false, transformFunction: null }, showDuplicateAction: { classPropertyName: "showDuplicateAction", publicName: "showDuplicateAction", isSignal: true, isRequired: false, transformFunction: null }, showDeleteAction: { classPropertyName: "showDeleteAction", publicName: "showDeleteAction", isSignal: true, isRequired: false, transformFunction: null }, showSaveAction: { classPropertyName: "showSaveAction", publicName: "showSaveAction", isSignal: true, isRequired: false, transformFunction: null }, saving: { classPropertyName: "saving", publicName: "saving", isSignal: true, isRequired: false, transformFunction: null }, saveLabelKey: { classPropertyName: "saveLabelKey", publicName: "saveLabelKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { customAction: "customAction", print: "print", duplicate: "duplicate", delete: "delete", save: "save" }, host: { classAttribute: "detail-toolbar" }, ngImport: i0, template: "<div class=\"left\">\n <ng-content></ng-content>\n</div>\n\n<div class=\"right\">\n <!-- Custom screen actions (before the standard group). -->\n @for (action of visibleCustomActions(); track trackByAction($index, action)) {\n <ef-button\n variant=\"comptoir\"\n size=\"small\"\n [severity]=\"action.severity ?? 'ghost'\"\n [icon]=\"action.icon\"\n [label]=\"action.label\"\n [labelKey]=\"action.labelKey\"\n [disabled]=\"!!action.disabled\"\n (clickEvent)=\"onCustomClick(action)\"\n />\n }\n\n <!-- Full-template escape hatch \u2014 anything projected here renders\n after the customActions array, before the standard group. -->\n <ng-content select=\"[actions]\"></ng-content>\n\n <!-- Separator between custom and standard groups. -->\n @if (showSeparator()) {\n <span class=\"sep\" aria-hidden=\"true\">|</span>\n }\n\n <!-- Standard actions: Print \u2192 Duplicate \u2192 Delete \u2192 Save. -->\n @if (canPrint()) {\n <ef-button\n variant=\"comptoir\"\n severity=\"ghost\"\n size=\"small\"\n icon=\"pi pi-print\"\n labelKey=\"common_print\"\n (clickEvent)=\"print.emit()\"\n />\n }\n\n @if (canDuplicate()) {\n <ef-button\n variant=\"comptoir\"\n severity=\"ghost\"\n size=\"small\"\n icon=\"pi pi-clone\"\n labelKey=\"common_duplicate\"\n (clickEvent)=\"duplicate.emit()\"\n />\n }\n\n @if (canDelete()) {\n <ef-button\n variant=\"comptoir\"\n severity=\"danger\"\n size=\"small\"\n icon=\"pi pi-trash\"\n labelKey=\"common_delete\"\n (clickEvent)=\"delete.emit()\"\n />\n }\n\n @if (canSave()) {\n <ef-button\n variant=\"comptoir\"\n severity=\"tenant\"\n size=\"small\"\n icon=\"pi pi-save\"\n [labelKey]=\"saveLabelKey()\"\n [disabled]=\"saving()\"\n [loading]=\"saving()\"\n (clickEvent)=\"save.emit()\"\n />\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfButtonComponent, selector: "ef-button", inputs: ["label", "labelKey", "icon", "variant", "severity", "size", "disabled", "rounded", "outlined", "raised", "text", "loading", "styleClass", "type", "badge", "badgeSeverity", "tooltip", "tooltipKey", "tooltipPosition", "autofocus"], outputs: ["clickEvent"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
8403
8505
|
}
|
|
8404
8506
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfDetailToolbarComponent, decorators: [{
|
|
8405
8507
|
type: Component,
|
|
@@ -8522,7 +8624,7 @@ class EfSearchToolbarComponent {
|
|
|
8522
8624
|
/** Stable trackBy across renders. */
|
|
8523
8625
|
trackByAction = (i, a) => a.id ?? a.labelKey ?? a.label ?? i;
|
|
8524
8626
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfSearchToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8525
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfSearchToolbarComponent, isStandalone: true, selector: "ef-search-toolbar", inputs: { customActions: { classPropertyName: "customActions", publicName: "customActions", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, showExportAction: { classPropertyName: "showExportAction", publicName: "showExportAction", isSignal: true, isRequired: false, transformFunction: null }, showAddAction: { classPropertyName: "showAddAction", publicName: "showAddAction", isSignal: true, isRequired: false, transformFunction: null }, busy: { classPropertyName: "busy", publicName: "busy", isSignal: true, isRequired: false, transformFunction: null }, addLabelKey: { classPropertyName: "addLabelKey", publicName: "addLabelKey", isSignal: true, isRequired: false, transformFunction: null }, exportLabelKey: { classPropertyName: "exportLabelKey", publicName: "exportLabelKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { customAction: "customAction", export: "export", add: "add" }, host: { classAttribute: "search-toolbar" }, ngImport: i0, template: "<div class=\"left\">\n <ng-content></ng-content>\n</div>\n\n<div class=\"right\">\n <!-- Custom screen actions (before the standard group). -->\n @for (action of visibleCustomActions(); track trackByAction($index, action)) {\n <ef-button\n variant=\"comptoir\"\n size=\"small\"\n [severity]=\"action.severity ?? 'ghost'\"\n [icon]=\"action.icon\"\n [label]=\"action.label\"\n [labelKey]=\"action.labelKey\"\n [disabled]=\"!!action.disabled\"\n (clickEvent)=\"onCustomClick(action)\"\n />\n }\n\n <!-- Full-template escape hatch \u2014 anything projected here renders\n after the customActions array, before the standard group. -->\n <ng-content select=\"[actions]\"></ng-content>\n\n <!-- Separator between custom and standard groups. -->\n @if (showSeparator()) {\n <span class=\"sep\" aria-hidden=\"true\">|</span>\n }\n\n <!-- Standard actions: Export \u2192 Add. -->\n @if (canExport()) {\n <ef-button\n variant=\"comptoir\"\n severity=\"ghost\"\n size=\"small\"\n icon=\"pi pi-download\"\n [labelKey]=\"exportLabelKey()\"\n [disabled]=\"busy()\"\n (clickEvent)=\"export.emit()\"\n />\n }\n\n @if (canAdd()) {\n <ef-button\n variant=\"comptoir\"\n severity=\"tenant\"\n size=\"small\"\n icon=\"pi pi-plus\"\n [labelKey]=\"addLabelKey()\"\n [disabled]=\"busy()\"\n (clickEvent)=\"add.emit()\"\n />\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfButtonComponent, selector: "ef-button", inputs: ["label", "labelKey", "icon", "variant", "severity", "size", "disabled", "rounded", "outlined", "raised", "text", "loading", "styleClass", "type", "badge", "badgeSeverity", "tooltip", "tooltipKey", "tooltipPosition"], outputs: ["clickEvent"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
8627
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfSearchToolbarComponent, isStandalone: true, selector: "ef-search-toolbar", inputs: { customActions: { classPropertyName: "customActions", publicName: "customActions", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, showExportAction: { classPropertyName: "showExportAction", publicName: "showExportAction", isSignal: true, isRequired: false, transformFunction: null }, showAddAction: { classPropertyName: "showAddAction", publicName: "showAddAction", isSignal: true, isRequired: false, transformFunction: null }, busy: { classPropertyName: "busy", publicName: "busy", isSignal: true, isRequired: false, transformFunction: null }, addLabelKey: { classPropertyName: "addLabelKey", publicName: "addLabelKey", isSignal: true, isRequired: false, transformFunction: null }, exportLabelKey: { classPropertyName: "exportLabelKey", publicName: "exportLabelKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { customAction: "customAction", export: "export", add: "add" }, host: { classAttribute: "search-toolbar" }, ngImport: i0, template: "<div class=\"left\">\n <ng-content></ng-content>\n</div>\n\n<div class=\"right\">\n <!-- Custom screen actions (before the standard group). -->\n @for (action of visibleCustomActions(); track trackByAction($index, action)) {\n <ef-button\n variant=\"comptoir\"\n size=\"small\"\n [severity]=\"action.severity ?? 'ghost'\"\n [icon]=\"action.icon\"\n [label]=\"action.label\"\n [labelKey]=\"action.labelKey\"\n [disabled]=\"!!action.disabled\"\n (clickEvent)=\"onCustomClick(action)\"\n />\n }\n\n <!-- Full-template escape hatch \u2014 anything projected here renders\n after the customActions array, before the standard group. -->\n <ng-content select=\"[actions]\"></ng-content>\n\n <!-- Separator between custom and standard groups. -->\n @if (showSeparator()) {\n <span class=\"sep\" aria-hidden=\"true\">|</span>\n }\n\n <!-- Standard actions: Export \u2192 Add. -->\n @if (canExport()) {\n <ef-button\n variant=\"comptoir\"\n severity=\"ghost\"\n size=\"small\"\n icon=\"pi pi-download\"\n [labelKey]=\"exportLabelKey()\"\n [disabled]=\"busy()\"\n (clickEvent)=\"export.emit()\"\n />\n }\n\n @if (canAdd()) {\n <ef-button\n variant=\"comptoir\"\n severity=\"tenant\"\n size=\"small\"\n icon=\"pi pi-plus\"\n [labelKey]=\"addLabelKey()\"\n [disabled]=\"busy()\"\n (clickEvent)=\"add.emit()\"\n />\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfButtonComponent, selector: "ef-button", inputs: ["label", "labelKey", "icon", "variant", "severity", "size", "disabled", "rounded", "outlined", "raised", "text", "loading", "styleClass", "type", "badge", "badgeSeverity", "tooltip", "tooltipKey", "tooltipPosition", "autofocus"], outputs: ["clickEvent"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
8526
8628
|
}
|
|
8527
8629
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfSearchToolbarComponent, decorators: [{
|
|
8528
8630
|
type: Component,
|
|
@@ -9273,6 +9375,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
9273
9375
|
* ```
|
|
9274
9376
|
*/
|
|
9275
9377
|
class EfToggleSwitchComponent extends AbstractEfFormControl {
|
|
9378
|
+
/**
|
|
9379
|
+
* Take focus on load. Bound explicitly rather than left unset: PrimeNG's
|
|
9380
|
+
* AutoFocus directive tests `autofocus === false`, and the control declares
|
|
9381
|
+
* it with no initialiser, so an unbound instance arrives as `undefined`,
|
|
9382
|
+
* misses that check and gets a real `autofocus` attribute written onto it.
|
|
9383
|
+
* A table of these then puts one autofocus candidate per row on the page.
|
|
9384
|
+
*/
|
|
9385
|
+
autofocus = false;
|
|
9276
9386
|
/** Two-way bindable `[(checked)]` — boolean only. */
|
|
9277
9387
|
checked = false;
|
|
9278
9388
|
checkedChange = new EventEmitter();
|
|
@@ -9304,8 +9414,9 @@ class EfToggleSwitchComponent extends AbstractEfFormControl {
|
|
|
9304
9414
|
this.onTouched();
|
|
9305
9415
|
}
|
|
9306
9416
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfToggleSwitchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9307
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfToggleSwitchComponent, isStandalone: true, selector: "ef-toggleswitch", inputs: { checked: "checked" }, outputs: { checkedChange: "checkedChange" }, usesInheritance: true, ngImport: i0, template: `
|
|
9417
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfToggleSwitchComponent, isStandalone: true, selector: "ef-toggleswitch", inputs: { autofocus: ["autofocus", "autofocus", booleanAttribute], checked: "checked" }, outputs: { checkedChange: "checkedChange" }, usesInheritance: true, ngImport: i0, template: `
|
|
9308
9418
|
<p-toggleswitch
|
|
9419
|
+
[autofocus]="autofocus"
|
|
9309
9420
|
[inputId]="effectiveId"
|
|
9310
9421
|
[name]="name() || undefined"
|
|
9311
9422
|
[ngModel]="checked"
|
|
@@ -9332,6 +9443,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
9332
9443
|
imports: [ToggleSwitchModule, FormsModule, TranslateModule, EfLabelComponent],
|
|
9333
9444
|
template: `
|
|
9334
9445
|
<p-toggleswitch
|
|
9446
|
+
[autofocus]="autofocus"
|
|
9335
9447
|
[inputId]="effectiveId"
|
|
9336
9448
|
[name]="name() || undefined"
|
|
9337
9449
|
[ngModel]="checked"
|
|
@@ -9350,7 +9462,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
9350
9462
|
}
|
|
9351
9463
|
`,
|
|
9352
9464
|
}]
|
|
9353
|
-
}], ctorParameters: () => [], propDecorators: {
|
|
9465
|
+
}], ctorParameters: () => [], propDecorators: { autofocus: [{
|
|
9466
|
+
type: Input,
|
|
9467
|
+
args: [{ transform: booleanAttribute }]
|
|
9468
|
+
}], checked: [{
|
|
9354
9469
|
type: Input
|
|
9355
9470
|
}], checkedChange: [{
|
|
9356
9471
|
type: Output
|
|
@@ -9386,6 +9501,15 @@ class EfDatepickerComponent {
|
|
|
9386
9501
|
showButtonBar = false;
|
|
9387
9502
|
minDate;
|
|
9388
9503
|
maxDate;
|
|
9504
|
+
/**
|
|
9505
|
+
* Take focus on load. Bound explicitly rather than left unset: PrimeNG's
|
|
9506
|
+
* AutoFocus directive tests `autofocus === false`, and the control declares
|
|
9507
|
+
* it with no initialiser, so an unbound instance arrives as `undefined`,
|
|
9508
|
+
* misses that check and has a real `autofocus` attribute written onto it.
|
|
9509
|
+
* Every such control on a page then becomes an autofocus candidate, and the
|
|
9510
|
+
* browser scrolls its container to whichever one it picks on load.
|
|
9511
|
+
*/
|
|
9512
|
+
autofocus = false;
|
|
9389
9513
|
get isInline() { return this.inline; }
|
|
9390
9514
|
dateSelectEvent = new EventEmitter();
|
|
9391
9515
|
value = null;
|
|
@@ -9436,11 +9560,11 @@ class EfDatepickerComponent {
|
|
|
9436
9560
|
this.onTouched();
|
|
9437
9561
|
}
|
|
9438
9562
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfDatepickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9439
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfDatepickerComponent, isStandalone: true, selector: "ef-datepicker", inputs: { label: "label", labelKey: "labelKey", inputId: "inputId", name: "name", placeholder: "placeholder", placeholderKey: "placeholderKey", size: "size", required: ["required", "required", booleanAttribute], fluid: ["fluid", "fluid", booleanAttribute], inline: ["inline", "inline", booleanAttribute], disabled: ["disabled", "disabled", booleanAttribute], showIcon: ["showIcon", "showIcon", booleanAttribute], iconDisplay: "iconDisplay", selectionMode: "selectionMode", dateFormat: "dateFormat", appendTo: "appendTo", showTime: ["showTime", "showTime", booleanAttribute], showButtonBar: ["showButtonBar", "showButtonBar", booleanAttribute], minDate: "minDate", maxDate: "maxDate" }, outputs: { dateSelectEvent: "dateSelectEvent" }, host: { properties: { "class.ef-inline": "this.isInline" } }, ngImport: i0, template: "@if (labelKey || label) {\n <ef-label [labelKey]=\"labelKey\" [label]=\"label\" [for]=\"effectiveId\" [required]=\"required\" />\n}\n<div class=\"ef-field-control\">\n <p-datepicker\n [inputId]=\"effectiveId\"\n [name]=\"name\"\n [ngModel]=\"value\"\n [ngModelOptions]=\"{standalone: true}\"\n (ngModelChange)=\"handleChange($event)\"\n (onBlur)=\"handleBlur()\"\n [placeholder]=\"effectivePlaceholder\"\n [size]=\"size\"\n [disabled]=\"disabled\"\n [showIcon]=\"showIcon\"\n [iconDisplay]=\"iconDisplay\"\n [selectionMode]=\"selectionMode\"\n [dateFormat]=\"dateFormat\"\n [appendTo]=\"appendTo\"\n [showTime]=\"showTime\"\n [showButtonBar]=\"showButtonBar\"\n [minDate]=\"minDate\"\n [maxDate]=\"maxDate\"\n [fluid]=\"fluid\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n />\n @if (showRequired) {\n <small class=\"text-danger\">{{ 'validation.required' | translate }}</small>\n }\n @if (serverErrors; as errors) {\n @for (error of errors; track error) {\n <small class=\"text-danger block\">{{ error }}</small>\n }\n }\n</div>\n", styles: [":host{display:block}:host(.ef-inline){display:flex;align-items:baseline;gap:.5rem}:host(.ef-inline)>label{white-space:nowrap;flex-shrink:0}:host(.ef-inline)>.ef-field-control{flex:1;min-width:0}\n"], dependencies: [{ kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i1$d.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfLabelComponent, selector: "ef-label", inputs: ["label", "labelKey", "for", "styleClass", "required"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
9563
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfDatepickerComponent, isStandalone: true, selector: "ef-datepicker", inputs: { label: "label", labelKey: "labelKey", inputId: "inputId", name: "name", placeholder: "placeholder", placeholderKey: "placeholderKey", size: "size", required: ["required", "required", booleanAttribute], fluid: ["fluid", "fluid", booleanAttribute], inline: ["inline", "inline", booleanAttribute], disabled: ["disabled", "disabled", booleanAttribute], showIcon: ["showIcon", "showIcon", booleanAttribute], iconDisplay: "iconDisplay", selectionMode: "selectionMode", dateFormat: "dateFormat", appendTo: "appendTo", showTime: ["showTime", "showTime", booleanAttribute], showButtonBar: ["showButtonBar", "showButtonBar", booleanAttribute], minDate: "minDate", maxDate: "maxDate", autofocus: ["autofocus", "autofocus", booleanAttribute] }, outputs: { dateSelectEvent: "dateSelectEvent" }, host: { properties: { "class.ef-inline": "this.isInline" } }, ngImport: i0, template: "@if (labelKey || label) {\n <ef-label [labelKey]=\"labelKey\" [label]=\"label\" [for]=\"effectiveId\" [required]=\"required\" />\n}\n<div class=\"ef-field-control\">\n <p-datepicker\n [autofocus]=\"autofocus\"\n [inputId]=\"effectiveId\"\n [name]=\"name\"\n [ngModel]=\"value\"\n [ngModelOptions]=\"{standalone: true}\"\n (ngModelChange)=\"handleChange($event)\"\n (onBlur)=\"handleBlur()\"\n [placeholder]=\"effectivePlaceholder\"\n [size]=\"size\"\n [disabled]=\"disabled\"\n [showIcon]=\"showIcon\"\n [iconDisplay]=\"iconDisplay\"\n [selectionMode]=\"selectionMode\"\n [dateFormat]=\"dateFormat\"\n [appendTo]=\"appendTo\"\n [showTime]=\"showTime\"\n [showButtonBar]=\"showButtonBar\"\n [minDate]=\"minDate\"\n [maxDate]=\"maxDate\"\n [fluid]=\"fluid\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n />\n @if (showRequired) {\n <small class=\"text-danger\">{{ 'validation.required' | translate }}</small>\n }\n @if (serverErrors; as errors) {\n @for (error of errors; track error) {\n <small class=\"text-danger block\">{{ error }}</small>\n }\n }\n</div>\n", styles: [":host{display:block}:host(.ef-inline){display:flex;align-items:baseline;gap:.5rem}:host(.ef-inline)>label{white-space:nowrap;flex-shrink:0}:host(.ef-inline)>.ef-field-control{flex:1;min-width:0}\n"], dependencies: [{ kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i1$d.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfLabelComponent, selector: "ef-label", inputs: ["label", "labelKey", "for", "styleClass", "required"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
9440
9564
|
}
|
|
9441
9565
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfDatepickerComponent, decorators: [{
|
|
9442
9566
|
type: Component,
|
|
9443
|
-
args: [{ selector: 'ef-datepicker', standalone: true, imports: [DatePickerModule, FormsModule, TranslateModule, EfLabelComponent], template: "@if (labelKey || label) {\n <ef-label [labelKey]=\"labelKey\" [label]=\"label\" [for]=\"effectiveId\" [required]=\"required\" />\n}\n<div class=\"ef-field-control\">\n <p-datepicker\n [inputId]=\"effectiveId\"\n [name]=\"name\"\n [ngModel]=\"value\"\n [ngModelOptions]=\"{standalone: true}\"\n (ngModelChange)=\"handleChange($event)\"\n (onBlur)=\"handleBlur()\"\n [placeholder]=\"effectivePlaceholder\"\n [size]=\"size\"\n [disabled]=\"disabled\"\n [showIcon]=\"showIcon\"\n [iconDisplay]=\"iconDisplay\"\n [selectionMode]=\"selectionMode\"\n [dateFormat]=\"dateFormat\"\n [appendTo]=\"appendTo\"\n [showTime]=\"showTime\"\n [showButtonBar]=\"showButtonBar\"\n [minDate]=\"minDate\"\n [maxDate]=\"maxDate\"\n [fluid]=\"fluid\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n />\n @if (showRequired) {\n <small class=\"text-danger\">{{ 'validation.required' | translate }}</small>\n }\n @if (serverErrors; as errors) {\n @for (error of errors; track error) {\n <small class=\"text-danger block\">{{ error }}</small>\n }\n }\n</div>\n", styles: [":host{display:block}:host(.ef-inline){display:flex;align-items:baseline;gap:.5rem}:host(.ef-inline)>label{white-space:nowrap;flex-shrink:0}:host(.ef-inline)>.ef-field-control{flex:1;min-width:0}\n"] }]
|
|
9567
|
+
args: [{ selector: 'ef-datepicker', standalone: true, imports: [DatePickerModule, FormsModule, TranslateModule, EfLabelComponent], template: "@if (labelKey || label) {\n <ef-label [labelKey]=\"labelKey\" [label]=\"label\" [for]=\"effectiveId\" [required]=\"required\" />\n}\n<div class=\"ef-field-control\">\n <p-datepicker\n [autofocus]=\"autofocus\"\n [inputId]=\"effectiveId\"\n [name]=\"name\"\n [ngModel]=\"value\"\n [ngModelOptions]=\"{standalone: true}\"\n (ngModelChange)=\"handleChange($event)\"\n (onBlur)=\"handleBlur()\"\n [placeholder]=\"effectivePlaceholder\"\n [size]=\"size\"\n [disabled]=\"disabled\"\n [showIcon]=\"showIcon\"\n [iconDisplay]=\"iconDisplay\"\n [selectionMode]=\"selectionMode\"\n [dateFormat]=\"dateFormat\"\n [appendTo]=\"appendTo\"\n [showTime]=\"showTime\"\n [showButtonBar]=\"showButtonBar\"\n [minDate]=\"minDate\"\n [maxDate]=\"maxDate\"\n [fluid]=\"fluid\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n />\n @if (showRequired) {\n <small class=\"text-danger\">{{ 'validation.required' | translate }}</small>\n }\n @if (serverErrors; as errors) {\n @for (error of errors; track error) {\n <small class=\"text-danger block\">{{ error }}</small>\n }\n }\n</div>\n", styles: [":host{display:block}:host(.ef-inline){display:flex;align-items:baseline;gap:.5rem}:host(.ef-inline)>label{white-space:nowrap;flex-shrink:0}:host(.ef-inline)>.ef-field-control{flex:1;min-width:0}\n"] }]
|
|
9444
9568
|
}], ctorParameters: () => [], propDecorators: { label: [{
|
|
9445
9569
|
type: Input
|
|
9446
9570
|
}], labelKey: [{
|
|
@@ -9488,6 +9612,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
9488
9612
|
type: Input
|
|
9489
9613
|
}], maxDate: [{
|
|
9490
9614
|
type: Input
|
|
9615
|
+
}], autofocus: [{
|
|
9616
|
+
type: Input,
|
|
9617
|
+
args: [{ transform: booleanAttribute }]
|
|
9491
9618
|
}], isInline: [{
|
|
9492
9619
|
type: HostBinding,
|
|
9493
9620
|
args: ['class.ef-inline']
|
|
@@ -9505,6 +9632,15 @@ class EfPasswordComponent extends AbstractEfFormControl {
|
|
|
9505
9632
|
toggleMask = true;
|
|
9506
9633
|
feedback = false;
|
|
9507
9634
|
autocomplete;
|
|
9635
|
+
/**
|
|
9636
|
+
* Take focus on load. Bound explicitly rather than left unset: PrimeNG's
|
|
9637
|
+
* AutoFocus directive tests `autofocus === false`, and the control declares
|
|
9638
|
+
* it with no initialiser, so an unbound instance arrives as `undefined`,
|
|
9639
|
+
* misses that check and has a real `autofocus` attribute written onto it.
|
|
9640
|
+
* Every such control on a page then becomes an autofocus candidate, and the
|
|
9641
|
+
* browser scrolls its container to whichever one it picks on load.
|
|
9642
|
+
*/
|
|
9643
|
+
autofocus = false;
|
|
9508
9644
|
get isInline() { return this.inline; }
|
|
9509
9645
|
valueChangeEvent = new EventEmitter();
|
|
9510
9646
|
value = '';
|
|
@@ -9558,11 +9694,11 @@ class EfPasswordComponent extends AbstractEfFormControl {
|
|
|
9558
9694
|
this.onTouched();
|
|
9559
9695
|
}
|
|
9560
9696
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfPasswordComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9561
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfPasswordComponent, isStandalone: true, selector: "ef-password", inputs: { size: "size", fluid: ["fluid", "fluid", booleanAttribute], inline: ["inline", "inline", booleanAttribute], toggleMask: ["toggleMask", "toggleMask", booleanAttribute], feedback: ["feedback", "feedback", booleanAttribute], autocomplete: "autocomplete" }, outputs: { valueChangeEvent: "valueChangeEvent" }, host: { properties: { "class.ef-inline": "this.isInline" } }, usesInheritance: true, ngImport: i0, template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n <p-password\n [inputId]=\"effectiveId\"\n [name]=\"name()\"\n [ngModel]=\"value\"\n [ngModelOptions]=\"{standalone: true}\"\n (ngModelChange)=\"handleChange($event)\"\n (onBlur)=\"handleBlur()\"\n [toggleMask]=\"toggleMask\"\n [feedback]=\"feedback\"\n [placeholder]=\"effectivePlaceholder\"\n [size]=\"size\"\n [disabled]=\"isDisabled()\"\n [attr.autocomplete]=\"autocomplete\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n [showClear]=\"canClear\"\n (onClear)=\"clearValue()\"\n styleClass=\"ef-password-field\"\n fluid\n >\n <ng-template #clearicon>\n <span class=\"ef-clear\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\">\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </span>\n </ng-template>\n </p-password>\n @if (showRequired) {\n <small class=\"text-danger\">{{ 'validation.required' | translate }}</small>\n }\n @if (serverErrors; as errors) {\n @for (error of errors; track error) {\n <small class=\"text-danger block\">{{ error }}</small>\n }\n }\n</div>\n", styles: [":host{display:block}:host(.ef-inline){display:flex;align-items:baseline;gap:.5rem}:host(.ef-inline)>label{white-space:nowrap;flex-shrink:0}:host(.ef-inline)>.ef-field-control{flex:1;min-width:0}\n"], dependencies: [{ kind: "ngmodule", type: PasswordModule }, { kind: "component", type: i1$e.Password, selector: "p-password", inputs: ["ariaLabel", "ariaLabelledBy", "label", "promptLabel", "mediumRegex", "strongRegex", "weakLabel", "mediumLabel", "maxLength", "strongLabel", "inputId", "feedback", "toggleMask", "inputStyleClass", "styleClass", "inputStyle", "showTransitionOptions", "hideTransitionOptions", "autocomplete", "placeholder", "showClear", "autofocus", "tabindex", "appendTo", "motionOptions", "overlayOptions"], outputs: ["onFocus", "onBlur", "onClear"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfLabelComponent, selector: "ef-label", inputs: ["label", "labelKey", "for", "styleClass", "required"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
9697
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfPasswordComponent, isStandalone: true, selector: "ef-password", inputs: { size: "size", fluid: ["fluid", "fluid", booleanAttribute], inline: ["inline", "inline", booleanAttribute], toggleMask: ["toggleMask", "toggleMask", booleanAttribute], feedback: ["feedback", "feedback", booleanAttribute], autocomplete: "autocomplete", autofocus: ["autofocus", "autofocus", booleanAttribute] }, outputs: { valueChangeEvent: "valueChangeEvent" }, host: { properties: { "class.ef-inline": "this.isInline" } }, usesInheritance: true, ngImport: i0, template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n <p-password\n [autofocus]=\"autofocus\"\n [inputId]=\"effectiveId\"\n [name]=\"name()\"\n [ngModel]=\"value\"\n [ngModelOptions]=\"{standalone: true}\"\n (ngModelChange)=\"handleChange($event)\"\n (onBlur)=\"handleBlur()\"\n [toggleMask]=\"toggleMask\"\n [feedback]=\"feedback\"\n [placeholder]=\"effectivePlaceholder\"\n [size]=\"size\"\n [disabled]=\"isDisabled()\"\n [attr.autocomplete]=\"autocomplete\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n [showClear]=\"canClear\"\n (onClear)=\"clearValue()\"\n styleClass=\"ef-password-field\"\n fluid\n >\n <ng-template #clearicon>\n <span class=\"ef-clear\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\">\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </span>\n </ng-template>\n </p-password>\n @if (showRequired) {\n <small class=\"text-danger\">{{ 'validation.required' | translate }}</small>\n }\n @if (serverErrors; as errors) {\n @for (error of errors; track error) {\n <small class=\"text-danger block\">{{ error }}</small>\n }\n }\n</div>\n", styles: [":host{display:block}:host(.ef-inline){display:flex;align-items:baseline;gap:.5rem}:host(.ef-inline)>label{white-space:nowrap;flex-shrink:0}:host(.ef-inline)>.ef-field-control{flex:1;min-width:0}\n"], dependencies: [{ kind: "ngmodule", type: PasswordModule }, { kind: "component", type: i1$e.Password, selector: "p-password", inputs: ["ariaLabel", "ariaLabelledBy", "label", "promptLabel", "mediumRegex", "strongRegex", "weakLabel", "mediumLabel", "maxLength", "strongLabel", "inputId", "feedback", "toggleMask", "inputStyleClass", "styleClass", "inputStyle", "showTransitionOptions", "hideTransitionOptions", "autocomplete", "placeholder", "showClear", "autofocus", "tabindex", "appendTo", "motionOptions", "overlayOptions"], outputs: ["onFocus", "onBlur", "onClear"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfLabelComponent, selector: "ef-label", inputs: ["label", "labelKey", "for", "styleClass", "required"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
9562
9698
|
}
|
|
9563
9699
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfPasswordComponent, decorators: [{
|
|
9564
9700
|
type: Component,
|
|
9565
|
-
args: [{ selector: 'ef-password', standalone: true, imports: [PasswordModule, FormsModule, TranslateModule, EfLabelComponent], template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n <p-password\n [inputId]=\"effectiveId\"\n [name]=\"name()\"\n [ngModel]=\"value\"\n [ngModelOptions]=\"{standalone: true}\"\n (ngModelChange)=\"handleChange($event)\"\n (onBlur)=\"handleBlur()\"\n [toggleMask]=\"toggleMask\"\n [feedback]=\"feedback\"\n [placeholder]=\"effectivePlaceholder\"\n [size]=\"size\"\n [disabled]=\"isDisabled()\"\n [attr.autocomplete]=\"autocomplete\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n [showClear]=\"canClear\"\n (onClear)=\"clearValue()\"\n styleClass=\"ef-password-field\"\n fluid\n >\n <ng-template #clearicon>\n <span class=\"ef-clear\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\">\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </span>\n </ng-template>\n </p-password>\n @if (showRequired) {\n <small class=\"text-danger\">{{ 'validation.required' | translate }}</small>\n }\n @if (serverErrors; as errors) {\n @for (error of errors; track error) {\n <small class=\"text-danger block\">{{ error }}</small>\n }\n }\n</div>\n", styles: [":host{display:block}:host(.ef-inline){display:flex;align-items:baseline;gap:.5rem}:host(.ef-inline)>label{white-space:nowrap;flex-shrink:0}:host(.ef-inline)>.ef-field-control{flex:1;min-width:0}\n"] }]
|
|
9701
|
+
args: [{ selector: 'ef-password', standalone: true, imports: [PasswordModule, FormsModule, TranslateModule, EfLabelComponent], template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n <p-password\n [autofocus]=\"autofocus\"\n [inputId]=\"effectiveId\"\n [name]=\"name()\"\n [ngModel]=\"value\"\n [ngModelOptions]=\"{standalone: true}\"\n (ngModelChange)=\"handleChange($event)\"\n (onBlur)=\"handleBlur()\"\n [toggleMask]=\"toggleMask\"\n [feedback]=\"feedback\"\n [placeholder]=\"effectivePlaceholder\"\n [size]=\"size\"\n [disabled]=\"isDisabled()\"\n [attr.autocomplete]=\"autocomplete\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n [showClear]=\"canClear\"\n (onClear)=\"clearValue()\"\n styleClass=\"ef-password-field\"\n fluid\n >\n <ng-template #clearicon>\n <span class=\"ef-clear\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\">\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </span>\n </ng-template>\n </p-password>\n @if (showRequired) {\n <small class=\"text-danger\">{{ 'validation.required' | translate }}</small>\n }\n @if (serverErrors; as errors) {\n @for (error of errors; track error) {\n <small class=\"text-danger block\">{{ error }}</small>\n }\n }\n</div>\n", styles: [":host{display:block}:host(.ef-inline){display:flex;align-items:baseline;gap:.5rem}:host(.ef-inline)>label{white-space:nowrap;flex-shrink:0}:host(.ef-inline)>.ef-field-control{flex:1;min-width:0}\n"] }]
|
|
9566
9702
|
}], ctorParameters: () => [], propDecorators: { size: [{
|
|
9567
9703
|
type: Input
|
|
9568
9704
|
}], fluid: [{
|
|
@@ -9579,6 +9715,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
9579
9715
|
args: [{ transform: booleanAttribute }]
|
|
9580
9716
|
}], autocomplete: [{
|
|
9581
9717
|
type: Input
|
|
9718
|
+
}], autofocus: [{
|
|
9719
|
+
type: Input,
|
|
9720
|
+
args: [{ transform: booleanAttribute }]
|
|
9582
9721
|
}], isInline: [{
|
|
9583
9722
|
type: HostBinding,
|
|
9584
9723
|
args: ['class.ef-inline']
|
|
@@ -9871,7 +10010,7 @@ class EfDatatableActionBarComponent {
|
|
|
9871
10010
|
this.delete.emit();
|
|
9872
10011
|
}
|
|
9873
10012
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfDatatableActionBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9874
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfDatatableActionBarComponent, isStandalone: true, selector: "ef-datatable-actionbar", inputs: { context: "context", state: "state", duplicateButton: "duplicateButton", editButton: "editButton", deleteButton: "deleteButton" }, outputs: { duplicate: "duplicate", edit: "edit", delete: "delete" }, ngImport: i0, template: "<div class=\"flex justify-end\" role=\"toolbar\" tabindex=\"0\" (click)=\"$event.stopPropagation()\" (keyup.enter)=\"$event.stopPropagation()\">\n @if (duplicateButton) {\n <ef-button\n icon=\"pi pi-copy\"\n severity=\"primary\"\n styleClass=\"action-btn\"\n tooltipKey=\"common.duplicate\"\n (clickEvent)=\"duplicateAction()\" />\n }\n @if (editButton && hasEditPermission) {\n <ef-button\n icon=\"pi pi-pencil\"\n severity=\"primary\"\n styleClass=\"action-btn\"\n size=\"small\"\n tooltipKey=\"common.edit\"\n (clickEvent)=\"editAction()\" />\n }\n @if (deleteButton && hasDeletePermission) {\n <ef-button\n icon=\"pi pi-trash\"\n severity=\"primary\"\n styleClass=\"action-btn\"\n size=\"small\"\n tooltipPosition=\"top\"\n tooltipKey=\"common.delete\"\n (clickEvent)=\"deleteAction()\" />\n }\n</div>\n", dependencies: [{ kind: "component", type: EfButtonComponent, selector: "ef-button", inputs: ["label", "labelKey", "icon", "variant", "severity", "size", "disabled", "rounded", "outlined", "raised", "text", "loading", "styleClass", "type", "badge", "badgeSeverity", "tooltip", "tooltipKey", "tooltipPosition"], outputs: ["clickEvent"] }, { kind: "ngmodule", type: TranslateModule }] });
|
|
10013
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfDatatableActionBarComponent, isStandalone: true, selector: "ef-datatable-actionbar", inputs: { context: "context", state: "state", duplicateButton: "duplicateButton", editButton: "editButton", deleteButton: "deleteButton" }, outputs: { duplicate: "duplicate", edit: "edit", delete: "delete" }, ngImport: i0, template: "<div class=\"flex justify-end\" role=\"toolbar\" tabindex=\"0\" (click)=\"$event.stopPropagation()\" (keyup.enter)=\"$event.stopPropagation()\">\n @if (duplicateButton) {\n <ef-button\n icon=\"pi pi-copy\"\n severity=\"primary\"\n styleClass=\"action-btn\"\n tooltipKey=\"common.duplicate\"\n (clickEvent)=\"duplicateAction()\" />\n }\n @if (editButton && hasEditPermission) {\n <ef-button\n icon=\"pi pi-pencil\"\n severity=\"primary\"\n styleClass=\"action-btn\"\n size=\"small\"\n tooltipKey=\"common.edit\"\n (clickEvent)=\"editAction()\" />\n }\n @if (deleteButton && hasDeletePermission) {\n <ef-button\n icon=\"pi pi-trash\"\n severity=\"primary\"\n styleClass=\"action-btn\"\n size=\"small\"\n tooltipPosition=\"top\"\n tooltipKey=\"common.delete\"\n (clickEvent)=\"deleteAction()\" />\n }\n</div>\n", dependencies: [{ kind: "component", type: EfButtonComponent, selector: "ef-button", inputs: ["label", "labelKey", "icon", "variant", "severity", "size", "disabled", "rounded", "outlined", "raised", "text", "loading", "styleClass", "type", "badge", "badgeSeverity", "tooltip", "tooltipKey", "tooltipPosition", "autofocus"], outputs: ["clickEvent"] }, { kind: "ngmodule", type: TranslateModule }] });
|
|
9875
10014
|
}
|
|
9876
10015
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfDatatableActionBarComponent, decorators: [{
|
|
9877
10016
|
type: Component,
|
|
@@ -10739,7 +10878,7 @@ class EfChangePasswordComponent {
|
|
|
10739
10878
|
});
|
|
10740
10879
|
}
|
|
10741
10880
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfChangePasswordComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10742
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfChangePasswordComponent, isStandalone: true, selector: "ef-change-password", inputs: { requireCurrent: { classPropertyName: "requireCurrent", publicName: "requireCurrent", isSignal: true, isRequired: false, transformFunction: null }, busy: { classPropertyName: "busy", publicName: "busy", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { submitted: "submitted" }, ngImport: i0, template: "<ef-form-grid>\n @if (requireCurrent()) {\n <ef-password\n class=\"col-12\"\n name=\"currentPassword\"\n labelKey=\"ef_change_password_current\"\n autocomplete=\"current-password\"\n required\n (valueChangeEvent)=\"currentPassword.set($event)\"\n />\n }\n <ef-password\n class=\"col-6\"\n name=\"newPassword\"\n labelKey=\"ef_change_password_new\"\n autocomplete=\"new-password\"\n required\n (valueChangeEvent)=\"newPassword.set($event)\"\n />\n <ef-password\n class=\"col-6\"\n name=\"newPasswordConfirmation\"\n labelKey=\"ef_change_password_confirm\"\n autocomplete=\"new-password\"\n required\n (valueChangeEvent)=\"confirmation.set($event)\"\n />\n</ef-form-grid>\n\n@if (validationKeys().length || errors().length) {\n <ul class=\"ef-change-password__errors\">\n @for (key of validationKeys(); track $index) {\n <li>{{ key | translate }}</li>\n }\n <!-- Server messages arrive already translated (Identity returns prose,\n not keys), so they are printed verbatim. -->\n @for (error of errors(); track $index) {\n <li>{{ error }}</li>\n }\n </ul>\n}\n", styles: [":host{display:grid;gap:var(--s-2, 8px);min-width:0}.ef-change-password__errors{display:grid;gap:4px;margin:0;padding:0;list-style:none;min-width:0;font-size:12px;line-height:1.4;color:var(--st-cancelled-fg, #b42318)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfPasswordComponent, selector: "ef-password", inputs: ["size", "fluid", "inline", "toggleMask", "feedback", "autocomplete"], outputs: ["valueChangeEvent"] }, { kind: "component", type: EfFormGridComponent, selector: "ef-form-grid" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10881
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfChangePasswordComponent, isStandalone: true, selector: "ef-change-password", inputs: { requireCurrent: { classPropertyName: "requireCurrent", publicName: "requireCurrent", isSignal: true, isRequired: false, transformFunction: null }, busy: { classPropertyName: "busy", publicName: "busy", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { submitted: "submitted" }, ngImport: i0, template: "<ef-form-grid>\n @if (requireCurrent()) {\n <ef-password\n class=\"col-12\"\n name=\"currentPassword\"\n labelKey=\"ef_change_password_current\"\n autocomplete=\"current-password\"\n required\n (valueChangeEvent)=\"currentPassword.set($event)\"\n />\n }\n <ef-password\n class=\"col-6\"\n name=\"newPassword\"\n labelKey=\"ef_change_password_new\"\n autocomplete=\"new-password\"\n required\n (valueChangeEvent)=\"newPassword.set($event)\"\n />\n <ef-password\n class=\"col-6\"\n name=\"newPasswordConfirmation\"\n labelKey=\"ef_change_password_confirm\"\n autocomplete=\"new-password\"\n required\n (valueChangeEvent)=\"confirmation.set($event)\"\n />\n</ef-form-grid>\n\n@if (validationKeys().length || errors().length) {\n <ul class=\"ef-change-password__errors\">\n @for (key of validationKeys(); track $index) {\n <li>{{ key | translate }}</li>\n }\n <!-- Server messages arrive already translated (Identity returns prose,\n not keys), so they are printed verbatim. -->\n @for (error of errors(); track $index) {\n <li>{{ error }}</li>\n }\n </ul>\n}\n", styles: [":host{display:grid;gap:var(--s-2, 8px);min-width:0}.ef-change-password__errors{display:grid;gap:4px;margin:0;padding:0;list-style:none;min-width:0;font-size:12px;line-height:1.4;color:var(--st-cancelled-fg, #b42318)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfPasswordComponent, selector: "ef-password", inputs: ["size", "fluid", "inline", "toggleMask", "feedback", "autocomplete", "autofocus"], outputs: ["valueChangeEvent"] }, { kind: "component", type: EfFormGridComponent, selector: "ef-form-grid" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10743
10882
|
}
|
|
10744
10883
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfChangePasswordComponent, decorators: [{
|
|
10745
10884
|
type: Component,
|
|
@@ -11405,13 +11544,15 @@ class EfThemeConfiguratorComponent {
|
|
|
11405
11544
|
<div class="flex-1">
|
|
11406
11545
|
<div class="config-panel-settings">
|
|
11407
11546
|
<span class="config-panel-label">{{ rippleLabelKey | translate }}</span>
|
|
11408
|
-
<p-toggleswitch
|
|
11547
|
+
<p-toggleswitch
|
|
11548
|
+
[autofocus]="false" [(ngModel)]="ripple" />
|
|
11409
11549
|
</div>
|
|
11410
11550
|
</div>
|
|
11411
11551
|
<div class="flex-1">
|
|
11412
11552
|
<div class="config-panel-settings items-end">
|
|
11413
11553
|
<span class="config-panel-label">{{ rtlLabelKey | translate }}</span>
|
|
11414
|
-
<p-toggleswitch
|
|
11554
|
+
<p-toggleswitch
|
|
11555
|
+
[autofocus]="false" [ngModel]="isRTL" (ngModelChange)="onRTLChange($event)" />
|
|
11415
11556
|
</div>
|
|
11416
11557
|
</div>
|
|
11417
11558
|
</div>
|
|
@@ -11478,13 +11619,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
11478
11619
|
<div class="flex-1">
|
|
11479
11620
|
<div class="config-panel-settings">
|
|
11480
11621
|
<span class="config-panel-label">{{ rippleLabelKey | translate }}</span>
|
|
11481
|
-
<p-toggleswitch
|
|
11622
|
+
<p-toggleswitch
|
|
11623
|
+
[autofocus]="false" [(ngModel)]="ripple" />
|
|
11482
11624
|
</div>
|
|
11483
11625
|
</div>
|
|
11484
11626
|
<div class="flex-1">
|
|
11485
11627
|
<div class="config-panel-settings items-end">
|
|
11486
11628
|
<span class="config-panel-label">{{ rtlLabelKey | translate }}</span>
|
|
11487
|
-
<p-toggleswitch
|
|
11629
|
+
<p-toggleswitch
|
|
11630
|
+
[autofocus]="false" [ngModel]="isRTL" (ngModelChange)="onRTLChange($event)" />
|
|
11488
11631
|
</div>
|
|
11489
11632
|
</div>
|
|
11490
11633
|
</div>
|
|
@@ -11526,6 +11669,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
11526
11669
|
* />
|
|
11527
11670
|
*/
|
|
11528
11671
|
class EfEmailMetricsCardComponent {
|
|
11672
|
+
/**
|
|
11673
|
+
* PrimeNG's Button reads `autofocus || buttonProps?.autofocus`, so a bare
|
|
11674
|
+
* `false` collapses to `undefined` and its AutoFocus directive writes the
|
|
11675
|
+
* attribute anyway. Passing the flag here too makes it resolve to `false`.
|
|
11676
|
+
*/
|
|
11677
|
+
noAutofocus = { autofocus: false };
|
|
11529
11678
|
metrics = input(null, ...(ngDevMode ? [{ debugName: "metrics" }] : /* istanbul ignore next */ []));
|
|
11530
11679
|
recentEvents = input([], ...(ngDevMode ? [{ debugName: "recentEvents" }] : /* istanbul ignore next */ []));
|
|
11531
11680
|
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
@@ -11578,7 +11727,7 @@ class EfEmailMetricsCardComponent {
|
|
|
11578
11727
|
return 'warn';
|
|
11579
11728
|
}
|
|
11580
11729
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfEmailMetricsCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11581
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfEmailMetricsCardComponent, isStandalone: true, selector: "ef-email-metrics-card", inputs: { metrics: { classPropertyName: "metrics", publicName: "metrics", isSignal: true, isRequired: false, transformFunction: null }, recentEvents: { classPropertyName: "recentEvents", publicName: "recentEvents", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rangeChange: "rangeChange" }, ngImport: i0, template: "<p-card styleClass=\"ef-email-metrics-card\">\n <ng-template pTemplate=\"header\">\n <div class=\"ef-email-metrics-card__header\">\n <div>\n <h3 class=\"ef-email-metrics-card__title\">{{ title() }}</h3>\n @if (metrics(); as m) {\n <p class=\"ef-email-metrics-card__subtitle\">\n {{ m.from | date: 'dd MMM' }} \u2013 {{ m.to | date: 'dd MMM yyyy' }}\n </p>\n }\n </div>\n <p-selectButton\n [options]=\"rangeOptions\"\n [(ngModel)]=\"selectedRange\"\n optionLabel=\"label\"\n optionValue=\"value\"\n styleClass=\"ef-email-metrics-card__range\"\n (onChange)=\"onRangeChange($event.value)\"\n />\n </div>\n </ng-template>\n\n @if (metrics(); as m) {\n <div class=\"ef-email-metrics-card__kpis\">\n @for (kpi of kpis(); track kpi.label) {\n <div class=\"ef-email-metrics-card__kpi\" [attr.data-tone]=\"kpi.tone\">\n <span class=\"ef-email-metrics-card__kpi-label\">{{ kpi.label }}</span>\n <span class=\"ef-email-metrics-card__kpi-value\">\n @if (kpi.rate) {\n {{ kpi.value | number: '1.1-1' : 'fr' }}\n <span class=\"ef-email-metrics-card__kpi-unit\">%</span>\n } @else {\n {{ kpi.value | number: '1.0-0' : 'fr' }}\n }\n </span>\n </div>\n }\n </div>\n\n @if (m.categories.length > 0) {\n <div class=\"ef-email-metrics-card__section\">\n <h4 class=\"ef-email-metrics-card__section-title\">Par cat\u00E9gorie</h4>\n <p-table [value]=\"m.categories\" styleClass=\"ef-email-metrics-card__table\" [scrollable]=\"true\" scrollHeight=\"180px\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th>Cat\u00E9gorie</th>\n <th class=\"ef-email-metrics-card__num\">Envoy\u00E9s</th>\n <th class=\"ef-email-metrics-card__num\">Ouverts</th>\n <th class=\"ef-email-metrics-card__num\">Cliqu\u00E9s</th>\n <th class=\"ef-email-metrics-card__num\">Rebonds</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-row>\n <tr>\n <td class=\"ef-email-metrics-card__category\">{{ row.category }}</td>\n <td class=\"ef-email-metrics-card__num\">{{ row.sent }}</td>\n <td class=\"ef-email-metrics-card__num\">{{ row.opened }}</td>\n <td class=\"ef-email-metrics-card__num\">{{ row.clicked }}</td>\n <td class=\"ef-email-metrics-card__num\" [class.ef-email-metrics-card__num--danger]=\"row.bounced > 0\">{{ row.bounced }}</td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n }\n\n @if (recentEvents().length > 0) {\n <div class=\"ef-email-metrics-card__section\">\n <h4 class=\"ef-email-metrics-card__section-title\">\u00C9v\u00E9nements r\u00E9cents</h4>\n <p-table [value]=\"recentEvents()\" styleClass=\"ef-email-metrics-card__table\" [scrollable]=\"true\" scrollHeight=\"240px\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th>Quand</th>\n <th>Destinataire</th>\n <th>Cat\u00E9gorie</th>\n <th>Type</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-row>\n <tr>\n <td class=\"ef-email-metrics-card__when\">{{ row.occurredAt | date: 'dd/MM HH:mm' }}</td>\n <td class=\"ef-email-metrics-card__recipient\">{{ row.recipient }}</td>\n <td>{{ row.category || '\u2014' }}</td>\n <td>\n <p-tag [severity]=\"kindSeverity(row.kind)\" [value]=\"row.kind\" styleClass=\"ef-email-metrics-card__kind\" />\n </td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n }\n } @else {\n <div class=\"ef-email-metrics-card__empty\">\n <p-button label=\"Aucune donn\u00E9e encore\" [text]=\"true\" icon=\"pi pi-envelope\" [disabled]=\"true\" />\n </div>\n }\n</p-card>\n", styles: [":host{display:block}.ef-email-metrics-card__header{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem;padding:1rem 1.25rem 0;flex-wrap:wrap}.ef-email-metrics-card__title{margin:0;font-size:1rem;font-weight:600;letter-spacing:-.01em;color:var(--p-text-color)}.ef-email-metrics-card__subtitle{margin:.15rem 0 0;font-size:.8125rem;color:var(--p-text-muted-color)}.ef-email-metrics-card__range :global(.p-selectbutton){border-radius:999px}.ef-email-metrics-card__range :global(.p-selectbutton .p-button){border-radius:999px;padding:.25rem .75rem;font-size:.75rem}.ef-email-metrics-card__kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:.75rem;padding:1rem 0}.ef-email-metrics-card__kpi{display:flex;flex-direction:column;gap:.25rem;padding:.85rem 1rem;border-radius:12px;background:var(--p-surface-50, #f8fafc);border:1px solid var(--p-surface-200, #e2e8f0)}.ef-email-metrics-card__kpi[data-tone=good]{background:color-mix(in srgb,var(--p-green-500, #10b981) 8%,transparent);border-color:color-mix(in srgb,var(--p-green-500, #10b981) 25%,transparent)}.ef-email-metrics-card__kpi[data-tone=warn]{background:color-mix(in srgb,var(--p-orange-500, #f97316) 8%,transparent);border-color:color-mix(in srgb,var(--p-orange-500, #f97316) 25%,transparent)}.ef-email-metrics-card__kpi-label{font-size:.75rem;font-weight:500;text-transform:uppercase;letter-spacing:.06em;color:var(--p-text-muted-color)}.ef-email-metrics-card__kpi-value{font-size:1.5rem;font-weight:700;letter-spacing:-.02em;color:var(--p-text-color)}.ef-email-metrics-card__kpi-unit{font-size:.875rem;font-weight:500;margin-left:.125rem;color:var(--p-text-muted-color)}.ef-email-metrics-card__section{margin-top:.75rem;padding-top:.75rem;border-top:1px solid var(--p-surface-200, #e2e8f0)}.ef-email-metrics-card__section-title{margin:0 0 .5rem;font-size:.8125rem;font-weight:600;color:var(--p-text-color)}.ef-email-metrics-card__table{font-size:.8125rem}.ef-email-metrics-card__num{text-align:right;font-variant-numeric:tabular-nums}.ef-email-metrics-card__num--danger{color:var(--p-red-600, #dc2626);font-weight:600}.ef-email-metrics-card__category{text-transform:capitalize;font-weight:500}.ef-email-metrics-card__recipient{font-family:var(--font-mono);font-size:.75rem;color:var(--p-text-muted-color)}.ef-email-metrics-card__when{font-variant-numeric:tabular-nums;white-space:nowrap;font-size:.75rem}.ef-email-metrics-card__kind{border-radius:999px;padding:.1rem .6rem;font-size:.7rem;letter-spacing:.02em}.ef-email-metrics-card__empty{padding:2rem 1.25rem;text-align:center;color:var(--p-text-muted-color)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i5$1.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i2$5.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i5$2.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: SelectButtonModule }, { kind: "component", type: i1$f.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: "pipe", type: i1$3.DecimalPipe, name: "number" }, { kind: "pipe", type: i1$3.DatePipe, name: "date" }] });
|
|
11730
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfEmailMetricsCardComponent, isStandalone: true, selector: "ef-email-metrics-card", inputs: { metrics: { classPropertyName: "metrics", publicName: "metrics", isSignal: true, isRequired: false, transformFunction: null }, recentEvents: { classPropertyName: "recentEvents", publicName: "recentEvents", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rangeChange: "rangeChange" }, ngImport: i0, template: "<p-card styleClass=\"ef-email-metrics-card\">\n <ng-template pTemplate=\"header\">\n <div class=\"ef-email-metrics-card__header\">\n <div>\n <h3 class=\"ef-email-metrics-card__title\">{{ title() }}</h3>\n @if (metrics(); as m) {\n <p class=\"ef-email-metrics-card__subtitle\">\n {{ m.from | date: 'dd MMM' }} \u2013 {{ m.to | date: 'dd MMM yyyy' }}\n </p>\n }\n </div>\n <p-selectButton\n [options]=\"rangeOptions\"\n [(ngModel)]=\"selectedRange\"\n optionLabel=\"label\"\n optionValue=\"value\"\n styleClass=\"ef-email-metrics-card__range\"\n (onChange)=\"onRangeChange($event.value)\"\n />\n </div>\n </ng-template>\n\n @if (metrics(); as m) {\n <div class=\"ef-email-metrics-card__kpis\">\n @for (kpi of kpis(); track kpi.label) {\n <div class=\"ef-email-metrics-card__kpi\" [attr.data-tone]=\"kpi.tone\">\n <span class=\"ef-email-metrics-card__kpi-label\">{{ kpi.label }}</span>\n <span class=\"ef-email-metrics-card__kpi-value\">\n @if (kpi.rate) {\n {{ kpi.value | number: '1.1-1' : 'fr' }}\n <span class=\"ef-email-metrics-card__kpi-unit\">%</span>\n } @else {\n {{ kpi.value | number: '1.0-0' : 'fr' }}\n }\n </span>\n </div>\n }\n </div>\n\n @if (m.categories.length > 0) {\n <div class=\"ef-email-metrics-card__section\">\n <h4 class=\"ef-email-metrics-card__section-title\">Par cat\u00E9gorie</h4>\n <p-table [value]=\"m.categories\" styleClass=\"ef-email-metrics-card__table\" [scrollable]=\"true\" scrollHeight=\"180px\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th>Cat\u00E9gorie</th>\n <th class=\"ef-email-metrics-card__num\">Envoy\u00E9s</th>\n <th class=\"ef-email-metrics-card__num\">Ouverts</th>\n <th class=\"ef-email-metrics-card__num\">Cliqu\u00E9s</th>\n <th class=\"ef-email-metrics-card__num\">Rebonds</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-row>\n <tr>\n <td class=\"ef-email-metrics-card__category\">{{ row.category }}</td>\n <td class=\"ef-email-metrics-card__num\">{{ row.sent }}</td>\n <td class=\"ef-email-metrics-card__num\">{{ row.opened }}</td>\n <td class=\"ef-email-metrics-card__num\">{{ row.clicked }}</td>\n <td class=\"ef-email-metrics-card__num\" [class.ef-email-metrics-card__num--danger]=\"row.bounced > 0\">{{ row.bounced }}</td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n }\n\n @if (recentEvents().length > 0) {\n <div class=\"ef-email-metrics-card__section\">\n <h4 class=\"ef-email-metrics-card__section-title\">\u00C9v\u00E9nements r\u00E9cents</h4>\n <p-table [value]=\"recentEvents()\" styleClass=\"ef-email-metrics-card__table\" [scrollable]=\"true\" scrollHeight=\"240px\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th>Quand</th>\n <th>Destinataire</th>\n <th>Cat\u00E9gorie</th>\n <th>Type</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-row>\n <tr>\n <td class=\"ef-email-metrics-card__when\">{{ row.occurredAt | date: 'dd/MM HH:mm' }}</td>\n <td class=\"ef-email-metrics-card__recipient\">{{ row.recipient }}</td>\n <td>{{ row.category || '\u2014' }}</td>\n <td>\n <p-tag [severity]=\"kindSeverity(row.kind)\" [value]=\"row.kind\" styleClass=\"ef-email-metrics-card__kind\" />\n </td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n }\n } @else {\n <div class=\"ef-email-metrics-card__empty\">\n <p-button\n [autofocus]=\"false\"\n [buttonProps]=\"noAutofocus\" label=\"Aucune donn\u00E9e encore\" [text]=\"true\" icon=\"pi pi-envelope\" [disabled]=\"true\" />\n </div>\n }\n</p-card>\n", styles: [":host{display:block}.ef-email-metrics-card__header{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem;padding:1rem 1.25rem 0;flex-wrap:wrap}.ef-email-metrics-card__title{margin:0;font-size:1rem;font-weight:600;letter-spacing:-.01em;color:var(--p-text-color)}.ef-email-metrics-card__subtitle{margin:.15rem 0 0;font-size:.8125rem;color:var(--p-text-muted-color)}.ef-email-metrics-card__range :global(.p-selectbutton){border-radius:999px}.ef-email-metrics-card__range :global(.p-selectbutton .p-button){border-radius:999px;padding:.25rem .75rem;font-size:.75rem}.ef-email-metrics-card__kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:.75rem;padding:1rem 0}.ef-email-metrics-card__kpi{display:flex;flex-direction:column;gap:.25rem;padding:.85rem 1rem;border-radius:12px;background:var(--p-surface-50, #f8fafc);border:1px solid var(--p-surface-200, #e2e8f0)}.ef-email-metrics-card__kpi[data-tone=good]{background:color-mix(in srgb,var(--p-green-500, #10b981) 8%,transparent);border-color:color-mix(in srgb,var(--p-green-500, #10b981) 25%,transparent)}.ef-email-metrics-card__kpi[data-tone=warn]{background:color-mix(in srgb,var(--p-orange-500, #f97316) 8%,transparent);border-color:color-mix(in srgb,var(--p-orange-500, #f97316) 25%,transparent)}.ef-email-metrics-card__kpi-label{font-size:.75rem;font-weight:500;text-transform:uppercase;letter-spacing:.06em;color:var(--p-text-muted-color)}.ef-email-metrics-card__kpi-value{font-size:1.5rem;font-weight:700;letter-spacing:-.02em;color:var(--p-text-color)}.ef-email-metrics-card__kpi-unit{font-size:.875rem;font-weight:500;margin-left:.125rem;color:var(--p-text-muted-color)}.ef-email-metrics-card__section{margin-top:.75rem;padding-top:.75rem;border-top:1px solid var(--p-surface-200, #e2e8f0)}.ef-email-metrics-card__section-title{margin:0 0 .5rem;font-size:.8125rem;font-weight:600;color:var(--p-text-color)}.ef-email-metrics-card__table{font-size:.8125rem}.ef-email-metrics-card__num{text-align:right;font-variant-numeric:tabular-nums}.ef-email-metrics-card__num--danger{color:var(--p-red-600, #dc2626);font-weight:600}.ef-email-metrics-card__category{text-transform:capitalize;font-weight:500}.ef-email-metrics-card__recipient{font-family:var(--font-mono);font-size:.75rem;color:var(--p-text-muted-color)}.ef-email-metrics-card__when{font-variant-numeric:tabular-nums;white-space:nowrap;font-size:.75rem}.ef-email-metrics-card__kind{border-radius:999px;padding:.1rem .6rem;font-size:.7rem;letter-spacing:.02em}.ef-email-metrics-card__empty{padding:2rem 1.25rem;text-align:center;color:var(--p-text-muted-color)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i5$1.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i2$5.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i5$2.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: SelectButtonModule }, { kind: "component", type: i1$f.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: "pipe", type: i1$3.DecimalPipe, name: "number" }, { kind: "pipe", type: i1$3.DatePipe, name: "date" }] });
|
|
11582
11731
|
}
|
|
11583
11732
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfEmailMetricsCardComponent, decorators: [{
|
|
11584
11733
|
type: Component,
|
|
@@ -11592,7 +11741,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
11592
11741
|
SelectButtonModule,
|
|
11593
11742
|
DecimalPipe,
|
|
11594
11743
|
DatePipe,
|
|
11595
|
-
], template: "<p-card styleClass=\"ef-email-metrics-card\">\n <ng-template pTemplate=\"header\">\n <div class=\"ef-email-metrics-card__header\">\n <div>\n <h3 class=\"ef-email-metrics-card__title\">{{ title() }}</h3>\n @if (metrics(); as m) {\n <p class=\"ef-email-metrics-card__subtitle\">\n {{ m.from | date: 'dd MMM' }} \u2013 {{ m.to | date: 'dd MMM yyyy' }}\n </p>\n }\n </div>\n <p-selectButton\n [options]=\"rangeOptions\"\n [(ngModel)]=\"selectedRange\"\n optionLabel=\"label\"\n optionValue=\"value\"\n styleClass=\"ef-email-metrics-card__range\"\n (onChange)=\"onRangeChange($event.value)\"\n />\n </div>\n </ng-template>\n\n @if (metrics(); as m) {\n <div class=\"ef-email-metrics-card__kpis\">\n @for (kpi of kpis(); track kpi.label) {\n <div class=\"ef-email-metrics-card__kpi\" [attr.data-tone]=\"kpi.tone\">\n <span class=\"ef-email-metrics-card__kpi-label\">{{ kpi.label }}</span>\n <span class=\"ef-email-metrics-card__kpi-value\">\n @if (kpi.rate) {\n {{ kpi.value | number: '1.1-1' : 'fr' }}\n <span class=\"ef-email-metrics-card__kpi-unit\">%</span>\n } @else {\n {{ kpi.value | number: '1.0-0' : 'fr' }}\n }\n </span>\n </div>\n }\n </div>\n\n @if (m.categories.length > 0) {\n <div class=\"ef-email-metrics-card__section\">\n <h4 class=\"ef-email-metrics-card__section-title\">Par cat\u00E9gorie</h4>\n <p-table [value]=\"m.categories\" styleClass=\"ef-email-metrics-card__table\" [scrollable]=\"true\" scrollHeight=\"180px\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th>Cat\u00E9gorie</th>\n <th class=\"ef-email-metrics-card__num\">Envoy\u00E9s</th>\n <th class=\"ef-email-metrics-card__num\">Ouverts</th>\n <th class=\"ef-email-metrics-card__num\">Cliqu\u00E9s</th>\n <th class=\"ef-email-metrics-card__num\">Rebonds</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-row>\n <tr>\n <td class=\"ef-email-metrics-card__category\">{{ row.category }}</td>\n <td class=\"ef-email-metrics-card__num\">{{ row.sent }}</td>\n <td class=\"ef-email-metrics-card__num\">{{ row.opened }}</td>\n <td class=\"ef-email-metrics-card__num\">{{ row.clicked }}</td>\n <td class=\"ef-email-metrics-card__num\" [class.ef-email-metrics-card__num--danger]=\"row.bounced > 0\">{{ row.bounced }}</td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n }\n\n @if (recentEvents().length > 0) {\n <div class=\"ef-email-metrics-card__section\">\n <h4 class=\"ef-email-metrics-card__section-title\">\u00C9v\u00E9nements r\u00E9cents</h4>\n <p-table [value]=\"recentEvents()\" styleClass=\"ef-email-metrics-card__table\" [scrollable]=\"true\" scrollHeight=\"240px\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th>Quand</th>\n <th>Destinataire</th>\n <th>Cat\u00E9gorie</th>\n <th>Type</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-row>\n <tr>\n <td class=\"ef-email-metrics-card__when\">{{ row.occurredAt | date: 'dd/MM HH:mm' }}</td>\n <td class=\"ef-email-metrics-card__recipient\">{{ row.recipient }}</td>\n <td>{{ row.category || '\u2014' }}</td>\n <td>\n <p-tag [severity]=\"kindSeverity(row.kind)\" [value]=\"row.kind\" styleClass=\"ef-email-metrics-card__kind\" />\n </td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n }\n } @else {\n <div class=\"ef-email-metrics-card__empty\">\n <p-button label=\"Aucune donn\u00E9e encore\" [text]=\"true\" icon=\"pi pi-envelope\" [disabled]=\"true\" />\n </div>\n }\n</p-card>\n", styles: [":host{display:block}.ef-email-metrics-card__header{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem;padding:1rem 1.25rem 0;flex-wrap:wrap}.ef-email-metrics-card__title{margin:0;font-size:1rem;font-weight:600;letter-spacing:-.01em;color:var(--p-text-color)}.ef-email-metrics-card__subtitle{margin:.15rem 0 0;font-size:.8125rem;color:var(--p-text-muted-color)}.ef-email-metrics-card__range :global(.p-selectbutton){border-radius:999px}.ef-email-metrics-card__range :global(.p-selectbutton .p-button){border-radius:999px;padding:.25rem .75rem;font-size:.75rem}.ef-email-metrics-card__kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:.75rem;padding:1rem 0}.ef-email-metrics-card__kpi{display:flex;flex-direction:column;gap:.25rem;padding:.85rem 1rem;border-radius:12px;background:var(--p-surface-50, #f8fafc);border:1px solid var(--p-surface-200, #e2e8f0)}.ef-email-metrics-card__kpi[data-tone=good]{background:color-mix(in srgb,var(--p-green-500, #10b981) 8%,transparent);border-color:color-mix(in srgb,var(--p-green-500, #10b981) 25%,transparent)}.ef-email-metrics-card__kpi[data-tone=warn]{background:color-mix(in srgb,var(--p-orange-500, #f97316) 8%,transparent);border-color:color-mix(in srgb,var(--p-orange-500, #f97316) 25%,transparent)}.ef-email-metrics-card__kpi-label{font-size:.75rem;font-weight:500;text-transform:uppercase;letter-spacing:.06em;color:var(--p-text-muted-color)}.ef-email-metrics-card__kpi-value{font-size:1.5rem;font-weight:700;letter-spacing:-.02em;color:var(--p-text-color)}.ef-email-metrics-card__kpi-unit{font-size:.875rem;font-weight:500;margin-left:.125rem;color:var(--p-text-muted-color)}.ef-email-metrics-card__section{margin-top:.75rem;padding-top:.75rem;border-top:1px solid var(--p-surface-200, #e2e8f0)}.ef-email-metrics-card__section-title{margin:0 0 .5rem;font-size:.8125rem;font-weight:600;color:var(--p-text-color)}.ef-email-metrics-card__table{font-size:.8125rem}.ef-email-metrics-card__num{text-align:right;font-variant-numeric:tabular-nums}.ef-email-metrics-card__num--danger{color:var(--p-red-600, #dc2626);font-weight:600}.ef-email-metrics-card__category{text-transform:capitalize;font-weight:500}.ef-email-metrics-card__recipient{font-family:var(--font-mono);font-size:.75rem;color:var(--p-text-muted-color)}.ef-email-metrics-card__when{font-variant-numeric:tabular-nums;white-space:nowrap;font-size:.75rem}.ef-email-metrics-card__kind{border-radius:999px;padding:.1rem .6rem;font-size:.7rem;letter-spacing:.02em}.ef-email-metrics-card__empty{padding:2rem 1.25rem;text-align:center;color:var(--p-text-muted-color)}\n"] }]
|
|
11744
|
+
], template: "<p-card styleClass=\"ef-email-metrics-card\">\n <ng-template pTemplate=\"header\">\n <div class=\"ef-email-metrics-card__header\">\n <div>\n <h3 class=\"ef-email-metrics-card__title\">{{ title() }}</h3>\n @if (metrics(); as m) {\n <p class=\"ef-email-metrics-card__subtitle\">\n {{ m.from | date: 'dd MMM' }} \u2013 {{ m.to | date: 'dd MMM yyyy' }}\n </p>\n }\n </div>\n <p-selectButton\n [options]=\"rangeOptions\"\n [(ngModel)]=\"selectedRange\"\n optionLabel=\"label\"\n optionValue=\"value\"\n styleClass=\"ef-email-metrics-card__range\"\n (onChange)=\"onRangeChange($event.value)\"\n />\n </div>\n </ng-template>\n\n @if (metrics(); as m) {\n <div class=\"ef-email-metrics-card__kpis\">\n @for (kpi of kpis(); track kpi.label) {\n <div class=\"ef-email-metrics-card__kpi\" [attr.data-tone]=\"kpi.tone\">\n <span class=\"ef-email-metrics-card__kpi-label\">{{ kpi.label }}</span>\n <span class=\"ef-email-metrics-card__kpi-value\">\n @if (kpi.rate) {\n {{ kpi.value | number: '1.1-1' : 'fr' }}\n <span class=\"ef-email-metrics-card__kpi-unit\">%</span>\n } @else {\n {{ kpi.value | number: '1.0-0' : 'fr' }}\n }\n </span>\n </div>\n }\n </div>\n\n @if (m.categories.length > 0) {\n <div class=\"ef-email-metrics-card__section\">\n <h4 class=\"ef-email-metrics-card__section-title\">Par cat\u00E9gorie</h4>\n <p-table [value]=\"m.categories\" styleClass=\"ef-email-metrics-card__table\" [scrollable]=\"true\" scrollHeight=\"180px\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th>Cat\u00E9gorie</th>\n <th class=\"ef-email-metrics-card__num\">Envoy\u00E9s</th>\n <th class=\"ef-email-metrics-card__num\">Ouverts</th>\n <th class=\"ef-email-metrics-card__num\">Cliqu\u00E9s</th>\n <th class=\"ef-email-metrics-card__num\">Rebonds</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-row>\n <tr>\n <td class=\"ef-email-metrics-card__category\">{{ row.category }}</td>\n <td class=\"ef-email-metrics-card__num\">{{ row.sent }}</td>\n <td class=\"ef-email-metrics-card__num\">{{ row.opened }}</td>\n <td class=\"ef-email-metrics-card__num\">{{ row.clicked }}</td>\n <td class=\"ef-email-metrics-card__num\" [class.ef-email-metrics-card__num--danger]=\"row.bounced > 0\">{{ row.bounced }}</td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n }\n\n @if (recentEvents().length > 0) {\n <div class=\"ef-email-metrics-card__section\">\n <h4 class=\"ef-email-metrics-card__section-title\">\u00C9v\u00E9nements r\u00E9cents</h4>\n <p-table [value]=\"recentEvents()\" styleClass=\"ef-email-metrics-card__table\" [scrollable]=\"true\" scrollHeight=\"240px\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th>Quand</th>\n <th>Destinataire</th>\n <th>Cat\u00E9gorie</th>\n <th>Type</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-row>\n <tr>\n <td class=\"ef-email-metrics-card__when\">{{ row.occurredAt | date: 'dd/MM HH:mm' }}</td>\n <td class=\"ef-email-metrics-card__recipient\">{{ row.recipient }}</td>\n <td>{{ row.category || '\u2014' }}</td>\n <td>\n <p-tag [severity]=\"kindSeverity(row.kind)\" [value]=\"row.kind\" styleClass=\"ef-email-metrics-card__kind\" />\n </td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n }\n } @else {\n <div class=\"ef-email-metrics-card__empty\">\n <p-button\n [autofocus]=\"false\"\n [buttonProps]=\"noAutofocus\" label=\"Aucune donn\u00E9e encore\" [text]=\"true\" icon=\"pi pi-envelope\" [disabled]=\"true\" />\n </div>\n }\n</p-card>\n", styles: [":host{display:block}.ef-email-metrics-card__header{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem;padding:1rem 1.25rem 0;flex-wrap:wrap}.ef-email-metrics-card__title{margin:0;font-size:1rem;font-weight:600;letter-spacing:-.01em;color:var(--p-text-color)}.ef-email-metrics-card__subtitle{margin:.15rem 0 0;font-size:.8125rem;color:var(--p-text-muted-color)}.ef-email-metrics-card__range :global(.p-selectbutton){border-radius:999px}.ef-email-metrics-card__range :global(.p-selectbutton .p-button){border-radius:999px;padding:.25rem .75rem;font-size:.75rem}.ef-email-metrics-card__kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:.75rem;padding:1rem 0}.ef-email-metrics-card__kpi{display:flex;flex-direction:column;gap:.25rem;padding:.85rem 1rem;border-radius:12px;background:var(--p-surface-50, #f8fafc);border:1px solid var(--p-surface-200, #e2e8f0)}.ef-email-metrics-card__kpi[data-tone=good]{background:color-mix(in srgb,var(--p-green-500, #10b981) 8%,transparent);border-color:color-mix(in srgb,var(--p-green-500, #10b981) 25%,transparent)}.ef-email-metrics-card__kpi[data-tone=warn]{background:color-mix(in srgb,var(--p-orange-500, #f97316) 8%,transparent);border-color:color-mix(in srgb,var(--p-orange-500, #f97316) 25%,transparent)}.ef-email-metrics-card__kpi-label{font-size:.75rem;font-weight:500;text-transform:uppercase;letter-spacing:.06em;color:var(--p-text-muted-color)}.ef-email-metrics-card__kpi-value{font-size:1.5rem;font-weight:700;letter-spacing:-.02em;color:var(--p-text-color)}.ef-email-metrics-card__kpi-unit{font-size:.875rem;font-weight:500;margin-left:.125rem;color:var(--p-text-muted-color)}.ef-email-metrics-card__section{margin-top:.75rem;padding-top:.75rem;border-top:1px solid var(--p-surface-200, #e2e8f0)}.ef-email-metrics-card__section-title{margin:0 0 .5rem;font-size:.8125rem;font-weight:600;color:var(--p-text-color)}.ef-email-metrics-card__table{font-size:.8125rem}.ef-email-metrics-card__num{text-align:right;font-variant-numeric:tabular-nums}.ef-email-metrics-card__num--danger{color:var(--p-red-600, #dc2626);font-weight:600}.ef-email-metrics-card__category{text-transform:capitalize;font-weight:500}.ef-email-metrics-card__recipient{font-family:var(--font-mono);font-size:.75rem;color:var(--p-text-muted-color)}.ef-email-metrics-card__when{font-variant-numeric:tabular-nums;white-space:nowrap;font-size:.75rem}.ef-email-metrics-card__kind{border-radius:999px;padding:.1rem .6rem;font-size:.7rem;letter-spacing:.02em}.ef-email-metrics-card__empty{padding:2rem 1.25rem;text-align:center;color:var(--p-text-muted-color)}\n"] }]
|
|
11596
11745
|
}], propDecorators: { metrics: [{ type: i0.Input, args: [{ isSignal: true, alias: "metrics", required: false }] }], recentEvents: [{ type: i0.Input, args: [{ isSignal: true, alias: "recentEvents", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], rangeChange: [{ type: i0.Output, args: ["rangeChange"] }] } });
|
|
11597
11746
|
|
|
11598
11747
|
// Pipes
|