@elasticias/ui 1.0.53 → 1.0.54
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-rich-text.mjs +336 -0
- package/fesm2022/elasticias-ui-rich-text.mjs.map +1 -0
- package/fesm2022/elasticias-ui.mjs +551 -67
- package/fesm2022/elasticias-ui.mjs.map +1 -1
- package/package.json +12 -2
- package/types/elasticias-ui-rich-text.d.ts +151 -0
- package/types/elasticias-ui.d.ts +316 -45
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Pipe, input, Component, output, booleanAttribute, Input, Directive, signal, computed, inject, EventEmitter, Injector, forwardRef, Output, ContentChild, HostBinding, ChangeDetectionStrategy, ElementRef, LOCALE_ID, ViewContainerRef, DestroyRef, ChangeDetectorRef, effect, HostListener, ViewChild, isDevMode, model, InjectionToken, afterNextRender, TemplateRef, ContentChildren, viewChild, untracked, contentChild, ViewEncapsulation, linkedSignal, ViewChildren, afterEveryRender, PLATFORM_ID } from '@angular/core';
|
|
2
|
+
import { Pipe, input, Component, output, booleanAttribute, Input, Directive, signal, computed, inject, EventEmitter, Injector, forwardRef, Output, ContentChild, HostBinding, ChangeDetectionStrategy, ElementRef, LOCALE_ID, ViewContainerRef, DestroyRef, ChangeDetectorRef, effect, HostListener, ViewChild, isDevMode, model, InjectionToken, afterNextRender, TemplateRef, ContentChildren, viewChild, untracked, contentChild, ViewEncapsulation, linkedSignal, ViewChildren, afterEveryRender, inputBinding, outputBinding, PLATFORM_ID } from '@angular/core';
|
|
3
3
|
import { NumberUtils, UuidUtils, PhoneUtils } from '@elasticias/utils';
|
|
4
4
|
import * as i1 from 'primeng/button';
|
|
5
5
|
import { ButtonModule } from 'primeng/button';
|
|
6
6
|
import * as i1$3 from '@angular/common';
|
|
7
7
|
import { CommonModule, formatDate, CurrencyPipe, DatePipe, DecimalPipe } from '@angular/common';
|
|
8
8
|
import * as i2$1 from '@angular/forms';
|
|
9
|
-
import { NgControl, Validators, FormControl, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
9
|
+
import { NgControl, Validators, FormControl, FormsModule, NG_VALUE_ACCESSOR, FormGroupDirective, NgForm, NG_VALIDATORS } from '@angular/forms';
|
|
10
10
|
import * as i1$1 from '@ngx-translate/core';
|
|
11
11
|
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
|
12
12
|
import * as i1$2 from 'primeng/select';
|
|
@@ -16,7 +16,7 @@ import { MultiSelectModule } from 'primeng/multiselect';
|
|
|
16
16
|
import { ObjectUtils, ZIndexUtils } from 'primeng/utils';
|
|
17
17
|
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
18
18
|
import { merge, Subject, tap, switchMap, catchError, EMPTY } from 'rxjs';
|
|
19
|
-
import { EfViewportService, EfShortcutService, EF_PREFERENCE_STORE, formatShortcut, efTablePrefsKey, EfThemeConfigService, EF_BUILD_INFO, EfSessionIdleService, EF_SESSION, EfPermissionService, EfActiveModuleService, EF_SIDE_COLLAPSED_KEY, EfToastService } from '@elasticias/core';
|
|
19
|
+
import { EfViewportService, EfShortcutService, EF_PREFERENCE_STORE, formatShortcut, efTablePrefsKey, EfThemeConfigService, EF_BUILD_INFO, EfSessionIdleService, EF_SESSION, EfPermissionService, EfActiveModuleService, EF_SIDE_COLLAPSED_KEY, EfToastService, EF_CONTENT_CULTURES, cleanLocalizedText, EF_DEFAULT_CONTENT_CULTURES } from '@elasticias/core';
|
|
20
20
|
import * as i1$4 from 'primeng/inputnumber';
|
|
21
21
|
import { InputNumberModule } from 'primeng/inputnumber';
|
|
22
22
|
import * as i1$5 from 'primeng/tooltip';
|
|
@@ -674,6 +674,24 @@ class EfServerErrorsDirective {
|
|
|
674
674
|
return null;
|
|
675
675
|
return map[name] ?? null;
|
|
676
676
|
}
|
|
677
|
+
/**
|
|
678
|
+
* Messages for every key that starts with `prefix`, keyed by what follows
|
|
679
|
+
* it: `errorsWithPrefix('title.')` turns `title.ar` into `ar`. For a control
|
|
680
|
+
* that owns several backend keys, such as a text per language. Empty lists
|
|
681
|
+
* are left out.
|
|
682
|
+
*/
|
|
683
|
+
errorsWithPrefix(prefix) {
|
|
684
|
+
const out = {};
|
|
685
|
+
const map = this.errors();
|
|
686
|
+
if (!prefix || !map)
|
|
687
|
+
return out;
|
|
688
|
+
for (const [key, messages] of Object.entries(map)) {
|
|
689
|
+
if (key.length > prefix.length && key.startsWith(prefix) && messages?.length) {
|
|
690
|
+
out[key.slice(prefix.length)] = messages;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return out;
|
|
694
|
+
}
|
|
677
695
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfServerErrorsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
678
696
|
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.11", type: EfServerErrorsDirective, isStandalone: true, selector: "[efServerErrors]", inputs: { errors: { classPropertyName: "errors", publicName: "efServerErrors", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
679
697
|
}
|
|
@@ -701,6 +719,9 @@ function resolveExternalErrors(explicit, scope, name) {
|
|
|
701
719
|
}
|
|
702
720
|
|
|
703
721
|
/**
|
|
722
|
+
* Exported for `@elasticias/ui/rich-text` only, not a supported extension
|
|
723
|
+
* point: it may change without a major version.
|
|
724
|
+
*
|
|
704
725
|
* Shared base for every Comptoir form control (`ef-input-text`,
|
|
705
726
|
* `ef-textarea`, `ef-select`, `ef-input-number`, `ef-checkbox`, …).
|
|
706
727
|
*
|
|
@@ -9906,6 +9927,7 @@ class EfTabsComponent {
|
|
|
9906
9927
|
* `fr.json` / `ar.json`. */
|
|
9907
9928
|
dirtyLabelKey = 'common.dirty';
|
|
9908
9929
|
valueChange = new EventEmitter();
|
|
9930
|
+
host = inject(ElementRef);
|
|
9909
9931
|
tabEls;
|
|
9910
9932
|
/* ── Content children (optional projected panels) ────────────── */
|
|
9911
9933
|
panels;
|
|
@@ -9967,6 +9989,13 @@ class EfTabsComponent {
|
|
|
9967
9989
|
default:
|
|
9968
9990
|
return;
|
|
9969
9991
|
}
|
|
9992
|
+
// In a right-to-left tablist the next tab sits to the left, so the
|
|
9993
|
+
// arrows swap (WAI-ARIA tabs pattern); Home and End keep their meaning.
|
|
9994
|
+
if ((event.key === 'ArrowRight' || event.key === 'ArrowLeft') && this.isRtl(event.currentTarget)) {
|
|
9995
|
+
nextPos = event.key === 'ArrowRight'
|
|
9996
|
+
? enabledPositions[(here - 1 + enabledPositions.length) % enabledPositions.length]
|
|
9997
|
+
: enabledPositions[(here + 1) % enabledPositions.length];
|
|
9998
|
+
}
|
|
9970
9999
|
event.preventDefault();
|
|
9971
10000
|
const target = all[nextPos];
|
|
9972
10001
|
this.select(target);
|
|
@@ -9975,11 +10004,19 @@ class EfTabsComponent {
|
|
|
9975
10004
|
const el = this.tabEls?.toArray()[nextPos]?.nativeElement;
|
|
9976
10005
|
el?.focus();
|
|
9977
10006
|
}
|
|
10007
|
+
isRtl(target) {
|
|
10008
|
+
const el = target instanceof HTMLElement ? target : this.host.nativeElement;
|
|
10009
|
+
if (getComputedStyle(el).direction === 'rtl')
|
|
10010
|
+
return true;
|
|
10011
|
+
// Only reached in jsdom, which does not inherit `direction`; a browser
|
|
10012
|
+
// answers above.
|
|
10013
|
+
return el.closest('[dir]')?.getAttribute('dir') === 'rtl';
|
|
10014
|
+
}
|
|
9978
10015
|
trackValue(_, item) {
|
|
9979
10016
|
return item.value;
|
|
9980
10017
|
}
|
|
9981
10018
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfTabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9982
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfTabsComponent, isStandalone: true, selector: "ef-tabs", inputs: { items: "items", value: "value", variant: "variant", module: "module", overflow: ["overflow", "overflow", booleanAttribute], hideCounts: ["hideCounts", "hideCounts", booleanAttribute], ariaLabel: "ariaLabel", ariaLabelKey: "ariaLabelKey", dirtyLabelKey: "dirtyLabelKey" }, outputs: { valueChange: "valueChange" }, host: { properties: { "class.ef-tabs--pill": "variant === 'pill'", "class.ef-tabs--underline": "variant === 'underline'", "class.ef-tabs--overflow": "overflow", "attr.data-module": "module ?? null" } }, queries: [{ propertyName: "panels", predicate: EfTabPanelDirective }], viewQueries: [{ propertyName: "tabEls", predicate: ["tabEl"], descendants: true }], ngImport: i0, template: "<div class=\"ef-tabs__list\" role=\"tablist\" [attr.aria-label]=\"ariaLabelKey ? (ariaLabelKey | translate) : ariaLabel\">\n @for (item of items; track trackValue($index, item); let i = $index) {\n <button\n #tabEl\n type=\"button\"\n class=\"ef-tabs__tab\"\n role=\"tab\"\n [class.is-active]=\"item.value === value\"\n [class.is-disabled]=\"!!item.disabled\"\n [attr.aria-selected]=\"item.value === value\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [disabled]=\"item.disabled\"\n [tabindex]=\"item.value === value ? 0 : -1\"\n (click)=\"select(item)\"\n (keydown)=\"onKeydown($event, i)\"\n >\n @if (item.icon) {\n <i class=\"ef-tabs__ico\" [class]=\"item.icon\" aria-hidden=\"true\"></i>\n }\n <span class=\"ef-tabs__label\">\n @if (item.labelKey) {\n {{ item.labelKey | translate }}\n } @else {\n {{ item.label }}\n }\n </span>\n @if (!hideCounts && item.count !== undefined && item.count !== null) {\n <span class=\"ef-tabs__count\">{{ item.count }}</span>\n }\n @if (item.dirty) {\n <span class=\"ef-tabs__dot\" [attr.aria-label]=\"dirtyLabelKey | translate\"></span>\n }\n </button>\n }\n</div>\n\n@if (hasPanels()) {\n <div class=\"ef-tabs__panels\" role=\"tabpanel\">\n @if (activePanel(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\"></ng-container>\n }\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:block;min-width:0}.ef-tabs__list{position:relative;display:flex;align-items:stretch;gap:2px;min-width:0;max-width:100%;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}.ef-tabs__list>*{flex:0 0 auto}.ef-tabs__panels{display:block;padding-top:var(--s-5);min-width:0;animation:ef-tabs-panel-in var(--t-base, .26s) var(--ease-out, ease-out)}@keyframes ef-tabs-panel-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}.ef-tabs__list::-webkit-scrollbar{display:none}.ef-tabs__tab{appearance:none;background:transparent;border:0;font:inherit;font-size:12.5px;font-weight:600;letter-spacing:-.005em;color:var(--text-mute);cursor:pointer;display:inline-flex;align-items:center;gap:8px;white-space:nowrap;transition:color var(--t-fast, .14s) var(--ease-out, ease-out),background-color var(--t-fast, .14s) var(--ease-out, ease-out),border-color var(--t-base, .26s) var(--ease-spring, cubic-bezier(.34, 1.56, .64, 1))}.ef-tabs__tab:focus-visible{outline:0}.ef-tabs__tab.is-disabled,.ef-tabs__tab[disabled]{opacity:.4;cursor:not-allowed}.ef-tabs__ico{font-size:13px;opacity:.75;flex-shrink:0}.ef-tabs__tab.is-active .ef-tabs__ico{opacity:1}.ef-tabs__count{font-family:var(--font-mono);font-size:10.5px;font-weight:700;background:var(--paper);border:1px solid var(--rule);color:var(--text-mute);padding:1px 7px;border-radius:var(--r-pill);min-width:20px;text-align:center;line-height:1.5;font-variant-numeric:tabular-nums}.ef-tabs__dot{width:6px;height:6px;border-radius:50%;background:var(--tenant-500);flex-shrink:0}:host(.ef-tabs--pill) .ef-tabs__list{background:var(--paper-alt);border:1px solid var(--rule);border-radius:var(--r-pill);padding:4px;gap:2px}:host(.ef-tabs--pill) .ef-tabs__tab{min-height:var(--hit, 32px);padding:7px 14px;border-radius:var(--r-pill)}:host(.ef-tabs--pill) .ef-tabs__tab:hover:not(.is-active):not(.is-disabled){color:var(--text)}:host(.ef-tabs--pill) .ef-tabs__tab:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--ink-active, #0f1115) 40%,transparent)}:host(.ef-tabs--pill) .ef-tabs__tab.is-active{background:var(--ink-active, #0f1115);color:var(--paper)}:host(.ef-tabs--pill) .ef-tabs__tab.is-active .ef-tabs__count{background:#ffffff2e;border-color:transparent;color:var(--paper)}:host(.ef-tabs--pill) .ef-tabs__tab.is-active .ef-tabs__dot{background:var(--paper)}:host(.ef-tabs--underline) .ef-tabs__list{display:flex;border-bottom:1px solid var(--rule);padding:0;gap:2px}:host(.ef-tabs--underline) .ef-tabs__tab{min-height:42px;padding:11px 14px;border-bottom:2px solid transparent;margin-bottom:-1px;border-radius:var(--r-sm) var(--r-sm) 0 0;font-size:13.5px}:host(.ef-tabs--underline) .ef-tabs__tab:hover:not(.is-active):not(.is-disabled){color:var(--text);background:var(--paper)}:host(.ef-tabs--underline) .ef-tabs__tab:focus-visible{background:var(--paper-alt);box-shadow:inset 0 0 0 2px var(--tenant-200)}:host(.ef-tabs--underline) .ef-tabs__tab.is-active{color:var(--text);border-bottom-color:var(--module, var(--ink-active))}:host(.ef-tabs--underline) .ef-tabs__tab.is-active .ef-tabs__count{background:color-mix(in srgb,var(--module, var(--ink-active)) 14%,var(--paper-alt));border-color:transparent;color:var(--module, var(--ink-active))}:host(.ef-tabs--underline) .ef-tabs__tab.is-active .ef-tabs__dot{background:var(--module, var(--tenant-500))}:host[data-module=sales]{--module: var(--m-sales)}:host[data-module=purchase]{--module: var(--m-purchase)}:host[data-module=stock]{--module: var(--m-stock)}:host[data-module=pos]{--module: var(--m-pos)}:host[data-module=marketing]{--module: var(--m-marketing)}:host[data-module=store]{--module: var(--m-store)}:host[data-module=finance]{--module: var(--m-finance)}:host[data-module=admin]{--module: var(--m-admin)}:host(.ef-tabs--overflow){position:relative;display:block}:host(.ef-tabs--overflow) .ef-tabs__list{display:flex;width:100%}:host(.ef-tabs--overflow):before,:host(.ef-tabs--overflow):after{content:\"\";position:absolute;top:0;bottom:0;width:36px;pointer-events:none;z-index:2}:host(.ef-tabs--overflow):before{inset-inline-start:0;background:linear-gradient(to right,var(--paper-alt),transparent)}:host(.ef-tabs--overflow):after{inset-inline-end:0;background:linear-gradient(to left,var(--paper-alt),transparent)}[data-theme=dark] :host(.ef-tabs--underline) .ef-tabs__tab.is-active .ef-tabs__count{background:color-mix(in srgb,var(--module, var(--ink-active)) 28%,transparent)}@media(pointer:coarse){:host(.ef-tabs--pill) .ef-tabs__tab,:host(.ef-tabs--underline) .ef-tabs__tab{min-height:var(--hit-touch)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10019
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfTabsComponent, isStandalone: true, selector: "ef-tabs", inputs: { items: "items", value: "value", variant: "variant", module: "module", overflow: ["overflow", "overflow", booleanAttribute], hideCounts: ["hideCounts", "hideCounts", booleanAttribute], ariaLabel: "ariaLabel", ariaLabelKey: "ariaLabelKey", dirtyLabelKey: "dirtyLabelKey" }, outputs: { valueChange: "valueChange" }, host: { properties: { "class.ef-tabs--pill": "variant === 'pill'", "class.ef-tabs--underline": "variant === 'underline'", "class.ef-tabs--overflow": "overflow", "attr.data-module": "module ?? null" } }, queries: [{ propertyName: "panels", predicate: EfTabPanelDirective }], viewQueries: [{ propertyName: "tabEls", predicate: ["tabEl"], descendants: true }], ngImport: i0, template: "<div class=\"ef-tabs__list\" role=\"tablist\" [attr.aria-label]=\"ariaLabelKey ? (ariaLabelKey | translate) : ariaLabel\">\n @for (item of items; track trackValue($index, item); let i = $index) {\n <button\n #tabEl\n type=\"button\"\n class=\"ef-tabs__tab\"\n role=\"tab\"\n [class.is-active]=\"item.value === value\"\n [class.is-disabled]=\"!!item.disabled\"\n [class.is-danger]=\"item.tone === 'danger'\"\n [attr.id]=\"item.id || null\"\n [attr.aria-controls]=\"item.panelId || null\"\n [attr.aria-selected]=\"item.value === value\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [disabled]=\"item.disabled\"\n [tabindex]=\"item.value === value ? 0 : -1\"\n (click)=\"select(item)\"\n (keydown)=\"onKeydown($event, i)\"\n >\n @if (item.icon) {\n <i class=\"ef-tabs__ico\" [class]=\"item.icon\" aria-hidden=\"true\"></i>\n }\n <span class=\"ef-tabs__label\">\n @if (item.labelKey) {\n {{ item.labelKey | translate }}\n } @else {\n {{ item.label }}\n }\n </span>\n @if (!hideCounts && item.count !== undefined && item.count !== null) {\n <span class=\"ef-tabs__count\">{{ item.count }}</span>\n }\n @if (item.noteKey) {\n <span class=\"ef-tabs__note\">{{ item.noteKey | translate }}</span>\n }\n @if (item.dirty) {\n <span class=\"ef-tabs__dot\" [attr.aria-label]=\"dirtyLabelKey | translate\"></span>\n }\n </button>\n }\n</div>\n\n@if (hasPanels()) {\n <div class=\"ef-tabs__panels\" role=\"tabpanel\">\n @if (activePanel(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\"></ng-container>\n }\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:block;min-width:0}.ef-tabs__list{position:relative;display:flex;align-items:stretch;gap:2px;min-width:0;max-width:100%;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}.ef-tabs__list>*{flex:0 0 auto}.ef-tabs__panels{display:block;padding-top:var(--s-5);min-width:0;animation:ef-tabs-panel-in var(--t-base, .26s) var(--ease-out, ease-out)}@keyframes ef-tabs-panel-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}.ef-tabs__list::-webkit-scrollbar{display:none}.ef-tabs__tab{appearance:none;background:transparent;border:0;font:inherit;font-size:12.5px;font-weight:600;letter-spacing:-.005em;color:var(--text-mute);cursor:pointer;display:inline-flex;align-items:center;gap:8px;white-space:nowrap;transition:color var(--t-fast, .14s) var(--ease-out, ease-out),background-color var(--t-fast, .14s) var(--ease-out, ease-out),border-color var(--t-base, .26s) var(--ease-spring, cubic-bezier(.34, 1.56, .64, 1))}.ef-tabs__tab:focus-visible{outline:0}.ef-tabs__tab.is-disabled,.ef-tabs__tab[disabled]{opacity:.4;cursor:not-allowed}.ef-tabs__ico{font-size:13px;opacity:.75;flex-shrink:0}.ef-tabs__tab.is-active .ef-tabs__ico{opacity:1}.ef-tabs__count{font-family:var(--font-mono);font-size:10.5px;font-weight:700;background:var(--paper);border:1px solid var(--rule);color:var(--text-mute);padding:1px 7px;border-radius:var(--r-pill);min-width:20px;text-align:center;line-height:1.5;font-variant-numeric:tabular-nums}.ef-tabs__dot{width:6px;height:6px;border-radius:50%;background:var(--tenant-500);flex-shrink:0}.ef-tabs__note{font-size:11px;font-weight:500}:host(.ef-tabs--pill) .ef-tabs__list{background:var(--paper-alt);border:1px solid var(--rule);border-radius:var(--r-pill);padding:4px;gap:2px}:host(.ef-tabs--pill) .ef-tabs__tab{min-height:var(--hit, 32px);padding:7px 14px;border-radius:var(--r-pill)}:host(.ef-tabs--pill) .ef-tabs__tab:hover:not(.is-active):not(.is-disabled){color:var(--text)}:host(.ef-tabs--pill) .ef-tabs__tab:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--ink-active, #0f1115) 40%,transparent)}:host(.ef-tabs--pill) .ef-tabs__tab.is-active{background:var(--ink-active, #0f1115);color:var(--paper)}:host(.ef-tabs--pill) .ef-tabs__tab.is-active .ef-tabs__count{background:#ffffff2e;border-color:transparent;color:var(--paper)}:host(.ef-tabs--pill) .ef-tabs__tab.is-active .ef-tabs__dot{background:var(--paper)}:host(.ef-tabs--underline) .ef-tabs__list{display:flex;border-bottom:1px solid var(--rule);padding:0;gap:2px}:host(.ef-tabs--underline) .ef-tabs__tab{min-height:42px;padding:11px 14px;border-bottom:2px solid transparent;margin-bottom:-1px;border-radius:var(--r-sm) var(--r-sm) 0 0;font-size:13.5px}:host(.ef-tabs--underline) .ef-tabs__tab:hover:not(.is-active):not(.is-disabled){color:var(--text);background:var(--paper)}:host(.ef-tabs--underline) .ef-tabs__tab:focus-visible{background:var(--paper-alt);box-shadow:inset 0 0 0 2px var(--tenant-200)}:host(.ef-tabs--underline) .ef-tabs__tab.is-active{color:var(--text);border-bottom-color:var(--module, var(--ink-active))}:host(.ef-tabs--underline) .ef-tabs__tab.is-active .ef-tabs__count{background:color-mix(in srgb,var(--module, var(--ink-active)) 14%,var(--paper-alt));border-color:transparent;color:var(--module, var(--ink-active))}:host(.ef-tabs--underline) .ef-tabs__tab.is-active .ef-tabs__dot{background:var(--module, var(--tenant-500))}.ef-tabs__tab.is-danger,:host(.ef-tabs--pill) .ef-tabs__tab.is-danger:hover:not(.is-active):not(.is-disabled),:host(.ef-tabs--underline) .ef-tabs__tab.is-danger:hover:not(.is-active):not(.is-disabled){color:var(--st-cancelled-fg)}:host(.ef-tabs--pill) .ef-tabs__tab.is-danger.is-active{color:var(--paper);box-shadow:inset 0 0 0 2px var(--st-cancelled-fg)}:host(.ef-tabs--underline) .ef-tabs__tab.is-danger.is-active{color:var(--st-cancelled-fg);border-bottom-color:var(--st-cancelled-fg)}:host(.ef-tabs--pill) .ef-tabs__tab.is-danger.is-active:focus-visible{box-shadow:inset 0 0 0 2px var(--st-cancelled-fg),0 0 0 2px color-mix(in srgb,var(--ink-active, #0f1115) 40%,transparent)}:host[data-module=sales]{--module: var(--m-sales)}:host[data-module=purchase]{--module: var(--m-purchase)}:host[data-module=stock]{--module: var(--m-stock)}:host[data-module=pos]{--module: var(--m-pos)}:host[data-module=marketing]{--module: var(--m-marketing)}:host[data-module=store]{--module: var(--m-store)}:host[data-module=finance]{--module: var(--m-finance)}:host[data-module=admin]{--module: var(--m-admin)}:host(.ef-tabs--overflow){position:relative;display:block}:host(.ef-tabs--overflow) .ef-tabs__list{display:flex;width:100%}:host(.ef-tabs--overflow):before,:host(.ef-tabs--overflow):after{content:\"\";position:absolute;top:0;bottom:0;width:36px;pointer-events:none;z-index:2}:host(.ef-tabs--overflow):before{inset-inline-start:0;background:linear-gradient(to right,var(--paper-alt),transparent)}:host(.ef-tabs--overflow):after{inset-inline-end:0;background:linear-gradient(to left,var(--paper-alt),transparent)}[data-theme=dark] :host(.ef-tabs--underline) .ef-tabs__tab.is-active .ef-tabs__count{background:color-mix(in srgb,var(--module, var(--ink-active)) 28%,transparent)}@media(pointer:coarse){:host(.ef-tabs--pill) .ef-tabs__tab,:host(.ef-tabs--underline) .ef-tabs__tab{min-height:var(--hit-touch)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9983
10020
|
}
|
|
9984
10021
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfTabsComponent, decorators: [{
|
|
9985
10022
|
type: Component,
|
|
@@ -9988,7 +10025,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
9988
10025
|
'[class.ef-tabs--underline]': "variant === 'underline'",
|
|
9989
10026
|
'[class.ef-tabs--overflow]': 'overflow',
|
|
9990
10027
|
'[attr.data-module]': 'module ?? null',
|
|
9991
|
-
}, template: "<div class=\"ef-tabs__list\" role=\"tablist\" [attr.aria-label]=\"ariaLabelKey ? (ariaLabelKey | translate) : ariaLabel\">\n @for (item of items; track trackValue($index, item); let i = $index) {\n <button\n #tabEl\n type=\"button\"\n class=\"ef-tabs__tab\"\n role=\"tab\"\n [class.is-active]=\"item.value === value\"\n [class.is-disabled]=\"!!item.disabled\"\n [attr.aria-selected]=\"item.value === value\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [disabled]=\"item.disabled\"\n [tabindex]=\"item.value === value ? 0 : -1\"\n (click)=\"select(item)\"\n (keydown)=\"onKeydown($event, i)\"\n >\n @if (item.icon) {\n <i class=\"ef-tabs__ico\" [class]=\"item.icon\" aria-hidden=\"true\"></i>\n }\n <span class=\"ef-tabs__label\">\n @if (item.labelKey) {\n {{ item.labelKey | translate }}\n } @else {\n {{ item.label }}\n }\n </span>\n @if (!hideCounts && item.count !== undefined && item.count !== null) {\n <span class=\"ef-tabs__count\">{{ item.count }}</span>\n }\n @if (item.dirty) {\n <span class=\"ef-tabs__dot\" [attr.aria-label]=\"dirtyLabelKey | translate\"></span>\n }\n </button>\n }\n</div>\n\n@if (hasPanels()) {\n <div class=\"ef-tabs__panels\" role=\"tabpanel\">\n @if (activePanel(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\"></ng-container>\n }\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:block;min-width:0}.ef-tabs__list{position:relative;display:flex;align-items:stretch;gap:2px;min-width:0;max-width:100%;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}.ef-tabs__list>*{flex:0 0 auto}.ef-tabs__panels{display:block;padding-top:var(--s-5);min-width:0;animation:ef-tabs-panel-in var(--t-base, .26s) var(--ease-out, ease-out)}@keyframes ef-tabs-panel-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}.ef-tabs__list::-webkit-scrollbar{display:none}.ef-tabs__tab{appearance:none;background:transparent;border:0;font:inherit;font-size:12.5px;font-weight:600;letter-spacing:-.005em;color:var(--text-mute);cursor:pointer;display:inline-flex;align-items:center;gap:8px;white-space:nowrap;transition:color var(--t-fast, .14s) var(--ease-out, ease-out),background-color var(--t-fast, .14s) var(--ease-out, ease-out),border-color var(--t-base, .26s) var(--ease-spring, cubic-bezier(.34, 1.56, .64, 1))}.ef-tabs__tab:focus-visible{outline:0}.ef-tabs__tab.is-disabled,.ef-tabs__tab[disabled]{opacity:.4;cursor:not-allowed}.ef-tabs__ico{font-size:13px;opacity:.75;flex-shrink:0}.ef-tabs__tab.is-active .ef-tabs__ico{opacity:1}.ef-tabs__count{font-family:var(--font-mono);font-size:10.5px;font-weight:700;background:var(--paper);border:1px solid var(--rule);color:var(--text-mute);padding:1px 7px;border-radius:var(--r-pill);min-width:20px;text-align:center;line-height:1.5;font-variant-numeric:tabular-nums}.ef-tabs__dot{width:6px;height:6px;border-radius:50%;background:var(--tenant-500);flex-shrink:0}:host(.ef-tabs--pill) .ef-tabs__list{background:var(--paper-alt);border:1px solid var(--rule);border-radius:var(--r-pill);padding:4px;gap:2px}:host(.ef-tabs--pill) .ef-tabs__tab{min-height:var(--hit, 32px);padding:7px 14px;border-radius:var(--r-pill)}:host(.ef-tabs--pill) .ef-tabs__tab:hover:not(.is-active):not(.is-disabled){color:var(--text)}:host(.ef-tabs--pill) .ef-tabs__tab:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--ink-active, #0f1115) 40%,transparent)}:host(.ef-tabs--pill) .ef-tabs__tab.is-active{background:var(--ink-active, #0f1115);color:var(--paper)}:host(.ef-tabs--pill) .ef-tabs__tab.is-active .ef-tabs__count{background:#ffffff2e;border-color:transparent;color:var(--paper)}:host(.ef-tabs--pill) .ef-tabs__tab.is-active .ef-tabs__dot{background:var(--paper)}:host(.ef-tabs--underline) .ef-tabs__list{display:flex;border-bottom:1px solid var(--rule);padding:0;gap:2px}:host(.ef-tabs--underline) .ef-tabs__tab{min-height:42px;padding:11px 14px;border-bottom:2px solid transparent;margin-bottom:-1px;border-radius:var(--r-sm) var(--r-sm) 0 0;font-size:13.5px}:host(.ef-tabs--underline) .ef-tabs__tab:hover:not(.is-active):not(.is-disabled){color:var(--text);background:var(--paper)}:host(.ef-tabs--underline) .ef-tabs__tab:focus-visible{background:var(--paper-alt);box-shadow:inset 0 0 0 2px var(--tenant-200)}:host(.ef-tabs--underline) .ef-tabs__tab.is-active{color:var(--text);border-bottom-color:var(--module, var(--ink-active))}:host(.ef-tabs--underline) .ef-tabs__tab.is-active .ef-tabs__count{background:color-mix(in srgb,var(--module, var(--ink-active)) 14%,var(--paper-alt));border-color:transparent;color:var(--module, var(--ink-active))}:host(.ef-tabs--underline) .ef-tabs__tab.is-active .ef-tabs__dot{background:var(--module, var(--tenant-500))}:host[data-module=sales]{--module: var(--m-sales)}:host[data-module=purchase]{--module: var(--m-purchase)}:host[data-module=stock]{--module: var(--m-stock)}:host[data-module=pos]{--module: var(--m-pos)}:host[data-module=marketing]{--module: var(--m-marketing)}:host[data-module=store]{--module: var(--m-store)}:host[data-module=finance]{--module: var(--m-finance)}:host[data-module=admin]{--module: var(--m-admin)}:host(.ef-tabs--overflow){position:relative;display:block}:host(.ef-tabs--overflow) .ef-tabs__list{display:flex;width:100%}:host(.ef-tabs--overflow):before,:host(.ef-tabs--overflow):after{content:\"\";position:absolute;top:0;bottom:0;width:36px;pointer-events:none;z-index:2}:host(.ef-tabs--overflow):before{inset-inline-start:0;background:linear-gradient(to right,var(--paper-alt),transparent)}:host(.ef-tabs--overflow):after{inset-inline-end:0;background:linear-gradient(to left,var(--paper-alt),transparent)}[data-theme=dark] :host(.ef-tabs--underline) .ef-tabs__tab.is-active .ef-tabs__count{background:color-mix(in srgb,var(--module, var(--ink-active)) 28%,transparent)}@media(pointer:coarse){:host(.ef-tabs--pill) .ef-tabs__tab,:host(.ef-tabs--underline) .ef-tabs__tab{min-height:var(--hit-touch)}}\n"] }]
|
|
10028
|
+
}, template: "<div class=\"ef-tabs__list\" role=\"tablist\" [attr.aria-label]=\"ariaLabelKey ? (ariaLabelKey | translate) : ariaLabel\">\n @for (item of items; track trackValue($index, item); let i = $index) {\n <button\n #tabEl\n type=\"button\"\n class=\"ef-tabs__tab\"\n role=\"tab\"\n [class.is-active]=\"item.value === value\"\n [class.is-disabled]=\"!!item.disabled\"\n [class.is-danger]=\"item.tone === 'danger'\"\n [attr.id]=\"item.id || null\"\n [attr.aria-controls]=\"item.panelId || null\"\n [attr.aria-selected]=\"item.value === value\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [disabled]=\"item.disabled\"\n [tabindex]=\"item.value === value ? 0 : -1\"\n (click)=\"select(item)\"\n (keydown)=\"onKeydown($event, i)\"\n >\n @if (item.icon) {\n <i class=\"ef-tabs__ico\" [class]=\"item.icon\" aria-hidden=\"true\"></i>\n }\n <span class=\"ef-tabs__label\">\n @if (item.labelKey) {\n {{ item.labelKey | translate }}\n } @else {\n {{ item.label }}\n }\n </span>\n @if (!hideCounts && item.count !== undefined && item.count !== null) {\n <span class=\"ef-tabs__count\">{{ item.count }}</span>\n }\n @if (item.noteKey) {\n <span class=\"ef-tabs__note\">{{ item.noteKey | translate }}</span>\n }\n @if (item.dirty) {\n <span class=\"ef-tabs__dot\" [attr.aria-label]=\"dirtyLabelKey | translate\"></span>\n }\n </button>\n }\n</div>\n\n@if (hasPanels()) {\n <div class=\"ef-tabs__panels\" role=\"tabpanel\">\n @if (activePanel(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\"></ng-container>\n }\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:block;min-width:0}.ef-tabs__list{position:relative;display:flex;align-items:stretch;gap:2px;min-width:0;max-width:100%;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}.ef-tabs__list>*{flex:0 0 auto}.ef-tabs__panels{display:block;padding-top:var(--s-5);min-width:0;animation:ef-tabs-panel-in var(--t-base, .26s) var(--ease-out, ease-out)}@keyframes ef-tabs-panel-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}.ef-tabs__list::-webkit-scrollbar{display:none}.ef-tabs__tab{appearance:none;background:transparent;border:0;font:inherit;font-size:12.5px;font-weight:600;letter-spacing:-.005em;color:var(--text-mute);cursor:pointer;display:inline-flex;align-items:center;gap:8px;white-space:nowrap;transition:color var(--t-fast, .14s) var(--ease-out, ease-out),background-color var(--t-fast, .14s) var(--ease-out, ease-out),border-color var(--t-base, .26s) var(--ease-spring, cubic-bezier(.34, 1.56, .64, 1))}.ef-tabs__tab:focus-visible{outline:0}.ef-tabs__tab.is-disabled,.ef-tabs__tab[disabled]{opacity:.4;cursor:not-allowed}.ef-tabs__ico{font-size:13px;opacity:.75;flex-shrink:0}.ef-tabs__tab.is-active .ef-tabs__ico{opacity:1}.ef-tabs__count{font-family:var(--font-mono);font-size:10.5px;font-weight:700;background:var(--paper);border:1px solid var(--rule);color:var(--text-mute);padding:1px 7px;border-radius:var(--r-pill);min-width:20px;text-align:center;line-height:1.5;font-variant-numeric:tabular-nums}.ef-tabs__dot{width:6px;height:6px;border-radius:50%;background:var(--tenant-500);flex-shrink:0}.ef-tabs__note{font-size:11px;font-weight:500}:host(.ef-tabs--pill) .ef-tabs__list{background:var(--paper-alt);border:1px solid var(--rule);border-radius:var(--r-pill);padding:4px;gap:2px}:host(.ef-tabs--pill) .ef-tabs__tab{min-height:var(--hit, 32px);padding:7px 14px;border-radius:var(--r-pill)}:host(.ef-tabs--pill) .ef-tabs__tab:hover:not(.is-active):not(.is-disabled){color:var(--text)}:host(.ef-tabs--pill) .ef-tabs__tab:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb,var(--ink-active, #0f1115) 40%,transparent)}:host(.ef-tabs--pill) .ef-tabs__tab.is-active{background:var(--ink-active, #0f1115);color:var(--paper)}:host(.ef-tabs--pill) .ef-tabs__tab.is-active .ef-tabs__count{background:#ffffff2e;border-color:transparent;color:var(--paper)}:host(.ef-tabs--pill) .ef-tabs__tab.is-active .ef-tabs__dot{background:var(--paper)}:host(.ef-tabs--underline) .ef-tabs__list{display:flex;border-bottom:1px solid var(--rule);padding:0;gap:2px}:host(.ef-tabs--underline) .ef-tabs__tab{min-height:42px;padding:11px 14px;border-bottom:2px solid transparent;margin-bottom:-1px;border-radius:var(--r-sm) var(--r-sm) 0 0;font-size:13.5px}:host(.ef-tabs--underline) .ef-tabs__tab:hover:not(.is-active):not(.is-disabled){color:var(--text);background:var(--paper)}:host(.ef-tabs--underline) .ef-tabs__tab:focus-visible{background:var(--paper-alt);box-shadow:inset 0 0 0 2px var(--tenant-200)}:host(.ef-tabs--underline) .ef-tabs__tab.is-active{color:var(--text);border-bottom-color:var(--module, var(--ink-active))}:host(.ef-tabs--underline) .ef-tabs__tab.is-active .ef-tabs__count{background:color-mix(in srgb,var(--module, var(--ink-active)) 14%,var(--paper-alt));border-color:transparent;color:var(--module, var(--ink-active))}:host(.ef-tabs--underline) .ef-tabs__tab.is-active .ef-tabs__dot{background:var(--module, var(--tenant-500))}.ef-tabs__tab.is-danger,:host(.ef-tabs--pill) .ef-tabs__tab.is-danger:hover:not(.is-active):not(.is-disabled),:host(.ef-tabs--underline) .ef-tabs__tab.is-danger:hover:not(.is-active):not(.is-disabled){color:var(--st-cancelled-fg)}:host(.ef-tabs--pill) .ef-tabs__tab.is-danger.is-active{color:var(--paper);box-shadow:inset 0 0 0 2px var(--st-cancelled-fg)}:host(.ef-tabs--underline) .ef-tabs__tab.is-danger.is-active{color:var(--st-cancelled-fg);border-bottom-color:var(--st-cancelled-fg)}:host(.ef-tabs--pill) .ef-tabs__tab.is-danger.is-active:focus-visible{box-shadow:inset 0 0 0 2px var(--st-cancelled-fg),0 0 0 2px color-mix(in srgb,var(--ink-active, #0f1115) 40%,transparent)}:host[data-module=sales]{--module: var(--m-sales)}:host[data-module=purchase]{--module: var(--m-purchase)}:host[data-module=stock]{--module: var(--m-stock)}:host[data-module=pos]{--module: var(--m-pos)}:host[data-module=marketing]{--module: var(--m-marketing)}:host[data-module=store]{--module: var(--m-store)}:host[data-module=finance]{--module: var(--m-finance)}:host[data-module=admin]{--module: var(--m-admin)}:host(.ef-tabs--overflow){position:relative;display:block}:host(.ef-tabs--overflow) .ef-tabs__list{display:flex;width:100%}:host(.ef-tabs--overflow):before,:host(.ef-tabs--overflow):after{content:\"\";position:absolute;top:0;bottom:0;width:36px;pointer-events:none;z-index:2}:host(.ef-tabs--overflow):before{inset-inline-start:0;background:linear-gradient(to right,var(--paper-alt),transparent)}:host(.ef-tabs--overflow):after{inset-inline-end:0;background:linear-gradient(to left,var(--paper-alt),transparent)}[data-theme=dark] :host(.ef-tabs--underline) .ef-tabs__tab.is-active .ef-tabs__count{background:color-mix(in srgb,var(--module, var(--ink-active)) 28%,transparent)}@media(pointer:coarse){:host(.ef-tabs--pill) .ef-tabs__tab,:host(.ef-tabs--underline) .ef-tabs__tab{min-height:var(--hit-touch)}}\n"] }]
|
|
9992
10029
|
}], propDecorators: { items: [{
|
|
9993
10030
|
type: Input,
|
|
9994
10031
|
args: [{ required: true }]
|
|
@@ -11644,6 +11681,10 @@ class EfInputTextComponent extends AbstractEfFormControl {
|
|
|
11644
11681
|
* follow the value's first strong character. The label and messages keep
|
|
11645
11682
|
* the page direction. Null or absent leaves the input unchanged. */
|
|
11646
11683
|
dir = null;
|
|
11684
|
+
/** Language of the typed value (`'ar'` for an Arabic title on a French
|
|
11685
|
+
* screen), applied to the native input only: the label and hint are page
|
|
11686
|
+
* text and keep the page language. Null or absent renders no attribute. */
|
|
11687
|
+
lang = null;
|
|
11647
11688
|
/** Clearable (showClear / canClear) is inherited from AbstractEfFormControl;
|
|
11648
11689
|
* we only supply the value predicate + the reset. */
|
|
11649
11690
|
get hasValue() {
|
|
@@ -11755,11 +11796,11 @@ class EfInputTextComponent extends AbstractEfFormControl {
|
|
|
11755
11796
|
this.onTouched();
|
|
11756
11797
|
}
|
|
11757
11798
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfInputTextComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11758
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfInputTextComponent, isStandalone: true, selector: "ef-input-text", inputs: { size: "size", type: "type", maxlength: "maxlength", fluid: ["fluid", "fluid", booleanAttribute], inline: ["inline", "inline", booleanAttribute], autocomplete: "autocomplete", dir: "dir", variant: "variant", prefix: "prefix", suffix: "suffix", value: "value" }, outputs: { valueChangeEvent: "valueChangeEvent" }, host: { listeners: { "focusin": "markFocused($event)" }, properties: { "class.ef-inline": "this.isInline" } }, usesInheritance: true, ngImport: i0, template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [labelParams]=\"labelParams()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n @if (variant === 'comptoir') {\n @if (prefix || suffix) {\n <!-- Comptoir variant with prefix/suffix \u2014 wraps the input in\n an .ef-input-group so the addons share the border + focus\n ring with the input. -->\n <div class=\"ef-input-group\" [class.is-invalid]=\"isInvalid\">\n @if (prefix) {\n <span class=\"ef-input-addon is-prefix\" aria-hidden=\"true\">{{ prefix }}</span>\n }\n <input\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [attr.dir]=\"dir || null\"\n [type]=\"type\"\n [value]=\"value\"\n (input)=\"handleInput($any($event.target).value)\"\n (blur)=\"handleBlur()\"\n [attr.placeholder]=\"effectivePlaceholder || null\"\n [attr.maxlength]=\"maxlength ?? null\"\n [readonly]=\"readonly()\"\n [disabled]=\"isDisabled()\"\n [attr.autocomplete]=\"autocomplete ?? null\"\n [attr.aria-label]=\"effectiveAriaLabel\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-invalid]=\"isInvalid ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy(showRequired || !!serverErrors)\"\n />\n @if (canClear) {\n <ef-clear-button\n class=\"ef-group-clear\"\n [ariaLabel]=\"'action.clear' | translate\"\n (clear)=\"clearValue()\"\n />\n }\n @if (suffix) {\n <span class=\"ef-input-addon is-suffix\" aria-hidden=\"true\">{{ suffix }}</span>\n }\n </div>\n } @else {\n <!-- Comptoir variant \u2014 bare native input (+ optional inline clear). -->\n <div class=\"ef-input-wrap\">\n <input\n class=\"ef-input\"\n [class.has-clear]=\"canClear\"\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [attr.dir]=\"dir || null\"\n [type]=\"type\"\n [value]=\"value\"\n (input)=\"handleInput($any($event.target).value)\"\n (blur)=\"handleBlur()\"\n [attr.placeholder]=\"effectivePlaceholder || null\"\n [attr.maxlength]=\"maxlength ?? null\"\n [readonly]=\"readonly()\"\n [disabled]=\"isDisabled()\"\n [attr.autocomplete]=\"autocomplete ?? null\"\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]=\"describedBy(showRequired || !!serverErrors)\"\n />\n @if (canClear) {\n <ef-clear-button\n class=\"ef-input-clear\"\n [ariaLabel]=\"'action.clear' | translate\"\n (clear)=\"clearValue()\"\n />\n }\n </div>\n }\n } @else {\n <!-- PrimeNG variant (default) \u2014 v1 styling. -->\n <input\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n
|
|
11799
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfInputTextComponent, isStandalone: true, selector: "ef-input-text", inputs: { size: "size", type: "type", maxlength: "maxlength", fluid: ["fluid", "fluid", booleanAttribute], inline: ["inline", "inline", booleanAttribute], autocomplete: "autocomplete", dir: "dir", lang: "lang", variant: "variant", prefix: "prefix", suffix: "suffix", value: "value" }, outputs: { valueChangeEvent: "valueChangeEvent" }, host: { listeners: { "focusin": "markFocused($event)" }, properties: { "attr.lang": "null", "class.ef-inline": "this.isInline" } }, usesInheritance: true, ngImport: i0, template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [labelParams]=\"labelParams()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n @if (variant === 'comptoir') {\n @if (prefix || suffix) {\n <!-- Comptoir variant with prefix/suffix \u2014 wraps the input in\n an .ef-input-group so the addons share the border + focus\n ring with the input. -->\n <div class=\"ef-input-group\" [class.is-invalid]=\"isInvalid\">\n @if (prefix) {\n <span class=\"ef-input-addon is-prefix\" aria-hidden=\"true\">{{ prefix }}</span>\n }\n <input\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [attr.dir]=\"dir || null\"\n [attr.lang]=\"lang || null\"\n [type]=\"type\"\n [value]=\"value\"\n (input)=\"handleInput($any($event.target).value)\"\n (blur)=\"handleBlur()\"\n [attr.placeholder]=\"effectivePlaceholder || null\"\n [attr.maxlength]=\"maxlength ?? null\"\n [readonly]=\"readonly()\"\n [disabled]=\"isDisabled()\"\n [attr.autocomplete]=\"autocomplete ?? null\"\n [attr.aria-label]=\"effectiveAriaLabel\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-invalid]=\"isInvalid ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy(showRequired || !!serverErrors)\"\n />\n @if (canClear) {\n <ef-clear-button\n class=\"ef-group-clear\"\n [ariaLabel]=\"'action.clear' | translate\"\n (clear)=\"clearValue()\"\n />\n }\n @if (suffix) {\n <span class=\"ef-input-addon is-suffix\" aria-hidden=\"true\">{{ suffix }}</span>\n }\n </div>\n } @else {\n <!-- Comptoir variant \u2014 bare native input (+ optional inline clear). -->\n <div class=\"ef-input-wrap\">\n <input\n class=\"ef-input\"\n [class.has-clear]=\"canClear\"\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [attr.dir]=\"dir || null\"\n [attr.lang]=\"lang || null\"\n [type]=\"type\"\n [value]=\"value\"\n (input)=\"handleInput($any($event.target).value)\"\n (blur)=\"handleBlur()\"\n [attr.placeholder]=\"effectivePlaceholder || null\"\n [attr.maxlength]=\"maxlength ?? null\"\n [readonly]=\"readonly()\"\n [disabled]=\"isDisabled()\"\n [attr.autocomplete]=\"autocomplete ?? null\"\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]=\"describedBy(showRequired || !!serverErrors)\"\n />\n @if (canClear) {\n <ef-clear-button\n class=\"ef-input-clear\"\n [ariaLabel]=\"'action.clear' | translate\"\n (clear)=\"clearValue()\"\n />\n }\n </div>\n }\n } @else {\n <!-- PrimeNG variant (default) \u2014 v1 styling. -->\n <input\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [attr.dir]=\"dir || null\"\n [attr.lang]=\"lang || null\"\n [type]=\"type\"\n pInputText\n [pSize]=\"size\"\n [value]=\"value\"\n (input)=\"handleInput($any($event.target).value)\"\n (blur)=\"handleBlur()\"\n [attr.placeholder]=\"effectivePlaceholder || null\"\n [attr.maxlength]=\"maxlength ?? null\"\n [readonly]=\"readonly()\"\n [disabled]=\"isDisabled()\"\n [attr.autocomplete]=\"autocomplete ?? null\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n [attr.aria-label]=\"effectiveAriaLabel\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-invalid]=\"isInvalid ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy(showRequired || !!serverErrors)\"\n fluid\n />\n }\n @if (effectiveHint) {\n <small class=\"ef-field-hint\" [id]=\"hintId\">{{ effectiveHint }}</small>\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([dir]){direction:inherit}:host([dir=rtl]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:rtl}:host([dir=ltr]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:ltr}:host([dir=auto]) .ef-field-control input,:host([dir=auto]) .ef-field-control textarea{unicode-bidi:plaintext}: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: 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: "component", type: EfLabelComponent, selector: "ef-label", inputs: ["label", "labelKey", "labelParams", "for", "styleClass", "required"] }, { kind: "component", type: EfClearButtonComponent, selector: "ef-clear-button", inputs: ["ariaLabel", "disabled"], outputs: ["clear"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
11759
11800
|
}
|
|
11760
11801
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfInputTextComponent, decorators: [{
|
|
11761
11802
|
type: Component,
|
|
11762
|
-
args: [{ selector: 'ef-input-text', standalone: true, imports: [InputTextModule, FormsModule, TranslateModule, EfLabelComponent, EfClearButtonComponent], template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [labelParams]=\"labelParams()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n @if (variant === 'comptoir') {\n @if (prefix || suffix) {\n <!-- Comptoir variant with prefix/suffix \u2014 wraps the input in\n an .ef-input-group so the addons share the border + focus\n ring with the input. -->\n <div class=\"ef-input-group\" [class.is-invalid]=\"isInvalid\">\n @if (prefix) {\n <span class=\"ef-input-addon is-prefix\" aria-hidden=\"true\">{{ prefix }}</span>\n }\n <input\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [attr.dir]=\"dir || null\"\n [type]=\"type\"\n [value]=\"value\"\n (input)=\"handleInput($any($event.target).value)\"\n (blur)=\"handleBlur()\"\n [attr.placeholder]=\"effectivePlaceholder || null\"\n [attr.maxlength]=\"maxlength ?? null\"\n [readonly]=\"readonly()\"\n [disabled]=\"isDisabled()\"\n [attr.autocomplete]=\"autocomplete ?? null\"\n [attr.aria-label]=\"effectiveAriaLabel\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-invalid]=\"isInvalid ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy(showRequired || !!serverErrors)\"\n />\n @if (canClear) {\n <ef-clear-button\n class=\"ef-group-clear\"\n [ariaLabel]=\"'action.clear' | translate\"\n (clear)=\"clearValue()\"\n />\n }\n @if (suffix) {\n <span class=\"ef-input-addon is-suffix\" aria-hidden=\"true\">{{ suffix }}</span>\n }\n </div>\n } @else {\n <!-- Comptoir variant \u2014 bare native input (+ optional inline clear). -->\n <div class=\"ef-input-wrap\">\n <input\n class=\"ef-input\"\n [class.has-clear]=\"canClear\"\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [attr.dir]=\"dir || null\"\n [type]=\"type\"\n [value]=\"value\"\n (input)=\"handleInput($any($event.target).value)\"\n (blur)=\"handleBlur()\"\n [attr.placeholder]=\"effectivePlaceholder || null\"\n [attr.maxlength]=\"maxlength ?? null\"\n [readonly]=\"readonly()\"\n [disabled]=\"isDisabled()\"\n [attr.autocomplete]=\"autocomplete ?? null\"\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]=\"describedBy(showRequired || !!serverErrors)\"\n />\n @if (canClear) {\n <ef-clear-button\n class=\"ef-input-clear\"\n [ariaLabel]=\"'action.clear' | translate\"\n (clear)=\"clearValue()\"\n />\n }\n </div>\n }\n } @else {\n <!-- PrimeNG variant (default) \u2014 v1 styling. -->\n <input\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n
|
|
11803
|
+
args: [{ selector: 'ef-input-text', standalone: true, imports: [InputTextModule, FormsModule, TranslateModule, EfLabelComponent, EfClearButtonComponent], host: { '[attr.lang]': 'null' }, template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [labelParams]=\"labelParams()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n @if (variant === 'comptoir') {\n @if (prefix || suffix) {\n <!-- Comptoir variant with prefix/suffix \u2014 wraps the input in\n an .ef-input-group so the addons share the border + focus\n ring with the input. -->\n <div class=\"ef-input-group\" [class.is-invalid]=\"isInvalid\">\n @if (prefix) {\n <span class=\"ef-input-addon is-prefix\" aria-hidden=\"true\">{{ prefix }}</span>\n }\n <input\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [attr.dir]=\"dir || null\"\n [attr.lang]=\"lang || null\"\n [type]=\"type\"\n [value]=\"value\"\n (input)=\"handleInput($any($event.target).value)\"\n (blur)=\"handleBlur()\"\n [attr.placeholder]=\"effectivePlaceholder || null\"\n [attr.maxlength]=\"maxlength ?? null\"\n [readonly]=\"readonly()\"\n [disabled]=\"isDisabled()\"\n [attr.autocomplete]=\"autocomplete ?? null\"\n [attr.aria-label]=\"effectiveAriaLabel\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-invalid]=\"isInvalid ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy(showRequired || !!serverErrors)\"\n />\n @if (canClear) {\n <ef-clear-button\n class=\"ef-group-clear\"\n [ariaLabel]=\"'action.clear' | translate\"\n (clear)=\"clearValue()\"\n />\n }\n @if (suffix) {\n <span class=\"ef-input-addon is-suffix\" aria-hidden=\"true\">{{ suffix }}</span>\n }\n </div>\n } @else {\n <!-- Comptoir variant \u2014 bare native input (+ optional inline clear). -->\n <div class=\"ef-input-wrap\">\n <input\n class=\"ef-input\"\n [class.has-clear]=\"canClear\"\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [attr.dir]=\"dir || null\"\n [attr.lang]=\"lang || null\"\n [type]=\"type\"\n [value]=\"value\"\n (input)=\"handleInput($any($event.target).value)\"\n (blur)=\"handleBlur()\"\n [attr.placeholder]=\"effectivePlaceholder || null\"\n [attr.maxlength]=\"maxlength ?? null\"\n [readonly]=\"readonly()\"\n [disabled]=\"isDisabled()\"\n [attr.autocomplete]=\"autocomplete ?? null\"\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]=\"describedBy(showRequired || !!serverErrors)\"\n />\n @if (canClear) {\n <ef-clear-button\n class=\"ef-input-clear\"\n [ariaLabel]=\"'action.clear' | translate\"\n (clear)=\"clearValue()\"\n />\n }\n </div>\n }\n } @else {\n <!-- PrimeNG variant (default) \u2014 v1 styling. -->\n <input\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [attr.dir]=\"dir || null\"\n [attr.lang]=\"lang || null\"\n [type]=\"type\"\n pInputText\n [pSize]=\"size\"\n [value]=\"value\"\n (input)=\"handleInput($any($event.target).value)\"\n (blur)=\"handleBlur()\"\n [attr.placeholder]=\"effectivePlaceholder || null\"\n [attr.maxlength]=\"maxlength ?? null\"\n [readonly]=\"readonly()\"\n [disabled]=\"isDisabled()\"\n [attr.autocomplete]=\"autocomplete ?? null\"\n [class.ng-invalid]=\"isInvalid\"\n [class.ng-touched]=\"ngControl?.touched\"\n [attr.aria-label]=\"effectiveAriaLabel\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-invalid]=\"isInvalid ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy(showRequired || !!serverErrors)\"\n fluid\n />\n }\n @if (effectiveHint) {\n <small class=\"ef-field-hint\" [id]=\"hintId\">{{ effectiveHint }}</small>\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([dir]){direction:inherit}:host([dir=rtl]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:rtl}:host([dir=ltr]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:ltr}:host([dir=auto]) .ef-field-control input,:host([dir=auto]) .ef-field-control textarea{unicode-bidi:plaintext}: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"] }]
|
|
11763
11804
|
}], ctorParameters: () => [], propDecorators: { size: [{
|
|
11764
11805
|
type: Input
|
|
11765
11806
|
}], type: [{
|
|
@@ -11776,6 +11817,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
11776
11817
|
type: Input
|
|
11777
11818
|
}], dir: [{
|
|
11778
11819
|
type: Input
|
|
11820
|
+
}], lang: [{
|
|
11821
|
+
type: Input
|
|
11779
11822
|
}], variant: [{
|
|
11780
11823
|
type: Input
|
|
11781
11824
|
}], prefix: [{
|
|
@@ -12349,6 +12392,19 @@ class EfMultiSelectComponent extends AbstractEfFormControl {
|
|
|
12349
12392
|
selectionLimit;
|
|
12350
12393
|
filters;
|
|
12351
12394
|
inline = false;
|
|
12395
|
+
/**
|
|
12396
|
+
* Rendering variant, as on `ef-select`.
|
|
12397
|
+
* - `'primeng'` (default): PrimeNG's own multiselect skin, unchanged.
|
|
12398
|
+
* - `'comptoir'`: the shared `.es` skin with `.es--comptoir`, the same hook
|
|
12399
|
+
* `ef-select variant="comptoir"` uses: a trigger on
|
|
12400
|
+
* `--hit-field` (`--hit-base` 40px, `--hit-touch` 48px on a
|
|
12401
|
+
* coarse pointer) and no minimum width, so a select and a
|
|
12402
|
+
* multi-select in one row align and both shrink with it.
|
|
12403
|
+
*/
|
|
12404
|
+
variant = 'primeng';
|
|
12405
|
+
get effectiveStyleClass() {
|
|
12406
|
+
return this.variant === 'comptoir' ? 'es es--comptoir' : undefined;
|
|
12407
|
+
}
|
|
12352
12408
|
get isInline() { return this.inline; }
|
|
12353
12409
|
get isRequired() { return this.required(); }
|
|
12354
12410
|
selectedValues = [];
|
|
@@ -12413,11 +12469,11 @@ class EfMultiSelectComponent extends AbstractEfFormControl {
|
|
|
12413
12469
|
this.selectedValues = [];
|
|
12414
12470
|
}
|
|
12415
12471
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfMultiSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
12416
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfMultiSelectComponent, isStandalone: true, selector: "ef-multi-select", inputs: { optionLabel: "optionLabel", optionValue: "optionValue", options: "options", filteredOptions: "filteredOptions", maxSelectedLabels: "maxSelectedLabels", display: "display", size: "size", selectionLimit: "selectionLimit", filters: "filters", inline: ["inline", "inline", booleanAttribute] }, outputs: { changeEvent: "changeEvent" }, host: { properties: { "class.ef-inline": "this.isInline", "class.ef-required": "this.isRequired" } }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [labelParams]=\"labelParams()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n <p-multiSelect\n [id]=\"effectiveId\"\n [name]=\"name()\"\n [placeholder]=\"effectivePlaceholder\"\n [options]=\"filteredOptions\"\n [optionLabel]=\"optionLabel\"\n [optionValue]=\"optionValue\"\n [maxSelectedLabels]=\"maxSelectedLabels\"\n [ngModel]=\"selectedValues\"\n [ngModelOptions]=\"{standalone: true}\"\n (ngModelChange)=\"onInternalModelChange($event)\"\n (onClear)=\"handleClear()\"\n [disabled]=\"isDisabled()\"\n [display]=\"display\"\n [size]=\"size\"\n [selectionLimit]=\"selectionLimit\"\n [showClear]=\"showClear()\"\n fluid\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([dir]){direction:inherit}:host([dir=rtl]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:rtl}:host([dir=ltr]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:ltr}:host([dir=auto]) .ef-field-control input,:host([dir=auto]) .ef-field-control textarea{unicode-bidi:plaintext}:host{display:block}:host:not(.ef-required) ::ng-deep .p-multiselect.ng-invalid.ng-dirty{border-color:var(--p-multiselect-border-color, #d1d5db)}: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: 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: 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: TranslateModule }, { kind: "component", type: EfLabelComponent, selector: "ef-label", inputs: ["label", "labelKey", "labelParams", "for", "styleClass", "required"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
12472
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfMultiSelectComponent, isStandalone: true, selector: "ef-multi-select", inputs: { optionLabel: "optionLabel", optionValue: "optionValue", options: "options", filteredOptions: "filteredOptions", maxSelectedLabels: "maxSelectedLabels", display: "display", size: "size", selectionLimit: "selectionLimit", filters: "filters", inline: ["inline", "inline", booleanAttribute], variant: "variant" }, outputs: { changeEvent: "changeEvent" }, host: { properties: { "class.ef-inline": "this.isInline", "class.ef-required": "this.isRequired" } }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [labelParams]=\"labelParams()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n <p-multiSelect\n [id]=\"effectiveId\"\n [name]=\"name()\"\n [placeholder]=\"effectivePlaceholder\"\n [options]=\"filteredOptions\"\n [optionLabel]=\"optionLabel\"\n [optionValue]=\"optionValue\"\n [maxSelectedLabels]=\"maxSelectedLabels\"\n [ngModel]=\"selectedValues\"\n [ngModelOptions]=\"{standalone: true}\"\n (ngModelChange)=\"onInternalModelChange($event)\"\n (onClear)=\"handleClear()\"\n [disabled]=\"isDisabled()\"\n [display]=\"display\"\n [size]=\"size\"\n [selectionLimit]=\"selectionLimit\"\n [showClear]=\"showClear()\"\n [styleClass]=\"effectiveStyleClass\"\n fluid\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([dir]){direction:inherit}:host([dir=rtl]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:rtl}:host([dir=ltr]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:ltr}:host([dir=auto]) .ef-field-control input,:host([dir=auto]) .ef-field-control textarea{unicode-bidi:plaintext}:host{display:block}:host:not(.ef-required) ::ng-deep .p-multiselect.ng-invalid.ng-dirty{border-color:var(--p-multiselect-border-color, #d1d5db)}: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: 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: 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: TranslateModule }, { kind: "component", type: EfLabelComponent, selector: "ef-label", inputs: ["label", "labelKey", "labelParams", "for", "styleClass", "required"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
12417
12473
|
}
|
|
12418
12474
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfMultiSelectComponent, decorators: [{
|
|
12419
12475
|
type: Component,
|
|
12420
|
-
args: [{ selector: 'ef-multi-select', standalone: true, imports: [FormsModule, MultiSelectModule, TranslateModule, EfLabelComponent], template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [labelParams]=\"labelParams()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n <p-multiSelect\n [id]=\"effectiveId\"\n [name]=\"name()\"\n [placeholder]=\"effectivePlaceholder\"\n [options]=\"filteredOptions\"\n [optionLabel]=\"optionLabel\"\n [optionValue]=\"optionValue\"\n [maxSelectedLabels]=\"maxSelectedLabels\"\n [ngModel]=\"selectedValues\"\n [ngModelOptions]=\"{standalone: true}\"\n (ngModelChange)=\"onInternalModelChange($event)\"\n (onClear)=\"handleClear()\"\n [disabled]=\"isDisabled()\"\n [display]=\"display\"\n [size]=\"size\"\n [selectionLimit]=\"selectionLimit\"\n [showClear]=\"showClear()\"\n fluid\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([dir]){direction:inherit}:host([dir=rtl]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:rtl}:host([dir=ltr]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:ltr}:host([dir=auto]) .ef-field-control input,:host([dir=auto]) .ef-field-control textarea{unicode-bidi:plaintext}:host{display:block}:host:not(.ef-required) ::ng-deep .p-multiselect.ng-invalid.ng-dirty{border-color:var(--p-multiselect-border-color, #d1d5db)}: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"] }]
|
|
12476
|
+
args: [{ selector: 'ef-multi-select', standalone: true, imports: [FormsModule, MultiSelectModule, TranslateModule, EfLabelComponent], template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [labelParams]=\"labelParams()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n <p-multiSelect\n [id]=\"effectiveId\"\n [name]=\"name()\"\n [placeholder]=\"effectivePlaceholder\"\n [options]=\"filteredOptions\"\n [optionLabel]=\"optionLabel\"\n [optionValue]=\"optionValue\"\n [maxSelectedLabels]=\"maxSelectedLabels\"\n [ngModel]=\"selectedValues\"\n [ngModelOptions]=\"{standalone: true}\"\n (ngModelChange)=\"onInternalModelChange($event)\"\n (onClear)=\"handleClear()\"\n [disabled]=\"isDisabled()\"\n [display]=\"display\"\n [size]=\"size\"\n [selectionLimit]=\"selectionLimit\"\n [showClear]=\"showClear()\"\n [styleClass]=\"effectiveStyleClass\"\n fluid\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([dir]){direction:inherit}:host([dir=rtl]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:rtl}:host([dir=ltr]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:ltr}:host([dir=auto]) .ef-field-control input,:host([dir=auto]) .ef-field-control textarea{unicode-bidi:plaintext}:host{display:block}:host:not(.ef-required) ::ng-deep .p-multiselect.ng-invalid.ng-dirty{border-color:var(--p-multiselect-border-color, #d1d5db)}: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"] }]
|
|
12421
12477
|
}], ctorParameters: () => [], propDecorators: { changeEvent: [{
|
|
12422
12478
|
type: Output
|
|
12423
12479
|
}], optionLabel: [{
|
|
@@ -12441,6 +12497,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
12441
12497
|
}], inline: [{
|
|
12442
12498
|
type: Input,
|
|
12443
12499
|
args: [{ transform: booleanAttribute }]
|
|
12500
|
+
}], variant: [{
|
|
12501
|
+
type: Input
|
|
12444
12502
|
}], isInline: [{
|
|
12445
12503
|
type: HostBinding,
|
|
12446
12504
|
args: ['class.ef-inline']
|
|
@@ -13330,6 +13388,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
13330
13388
|
class EfTextareaComponent extends AbstractEfFormControl {
|
|
13331
13389
|
rows = 4;
|
|
13332
13390
|
maxlength;
|
|
13391
|
+
/** Language of the typed value, applied to the native textarea only (the
|
|
13392
|
+
* label and hint keep the page language). Null or absent renders none. */
|
|
13393
|
+
lang = null;
|
|
13333
13394
|
autofocus = false;
|
|
13334
13395
|
/** Monospace face for source text (an HTML body, a JSON snippet), where
|
|
13335
13396
|
* tags and indentation must stay readable. */
|
|
@@ -13430,15 +13491,17 @@ class EfTextareaComponent extends AbstractEfFormControl {
|
|
|
13430
13491
|
this.onTouched();
|
|
13431
13492
|
}
|
|
13432
13493
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfTextareaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13433
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfTextareaComponent, isStandalone: true, selector: "ef-textarea", inputs: { rows: "rows", maxlength: "maxlength", autofocus: ["autofocus", "autofocus", booleanAttribute], mono: ["mono", "mono", booleanAttribute], value: "value" }, outputs: { valueChangeEvent: "valueChangeEvent" }, host: { listeners: { "focusin": "markFocused($event)" } }, usesInheritance: true, ngImport: i0, template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [labelParams]=\"labelParams()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n <div class=\"ef-textarea-wrap\">\n <textarea\n class=\"ef-textarea\"\n [class.has-clear]=\"canClear\"\n [class.ef-textarea--mono]=\"mono\"\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [rows]=\"rows\"\n [value]=\"value\"\n [attr.placeholder]=\"effectivePlaceholder || null\"\n [attr.maxlength]=\"maxlength ?? null\"\n [readonly]=\"readonly()\"\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]=\"describedBy(showRequired || !!serverErrors)\"\n (input)=\"handleInput($any($event.target).value)\"\n (blur)=\"handleBlur()\"\n ></textarea>\n @if (canClear) {\n <ef-clear-button\n class=\"ef-textarea-clear\"\n [ariaLabel]=\"'action.clear' | translate\"\n (clear)=\"clearValue()\"\n />\n }\n </div>\n @if (effectiveHint) {\n <small class=\"ef-field-hint\" [id]=\"hintId\">{{ effectiveHint }}</small>\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([dir]){direction:inherit}:host([dir=rtl]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:rtl}:host([dir=ltr]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:ltr}:host([dir=auto]) .ef-field-control input,:host([dir=auto]) .ef-field-control textarea{unicode-bidi:plaintext}.ef-textarea.ef-textarea--mono{font-family:var(--font-mono);font-size:12.5px;line-height:1.55}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfLabelComponent, selector: "ef-label", inputs: ["label", "labelKey", "labelParams", "for", "styleClass", "required"] }, { kind: "component", type: EfClearButtonComponent, selector: "ef-clear-button", inputs: ["ariaLabel", "disabled"], outputs: ["clear"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
13494
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfTextareaComponent, isStandalone: true, selector: "ef-textarea", inputs: { rows: "rows", maxlength: "maxlength", lang: "lang", autofocus: ["autofocus", "autofocus", booleanAttribute], mono: ["mono", "mono", booleanAttribute], value: "value" }, outputs: { valueChangeEvent: "valueChangeEvent" }, host: { listeners: { "focusin": "markFocused($event)" }, properties: { "attr.lang": "null" } }, usesInheritance: true, ngImport: i0, template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [labelParams]=\"labelParams()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n <div class=\"ef-textarea-wrap\">\n <textarea\n class=\"ef-textarea\"\n [class.has-clear]=\"canClear\"\n [class.ef-textarea--mono]=\"mono\"\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [attr.lang]=\"lang || null\"\n [rows]=\"rows\"\n [value]=\"value\"\n [attr.placeholder]=\"effectivePlaceholder || null\"\n [attr.maxlength]=\"maxlength ?? null\"\n [readonly]=\"readonly()\"\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]=\"describedBy(showRequired || !!serverErrors)\"\n (input)=\"handleInput($any($event.target).value)\"\n (blur)=\"handleBlur()\"\n ></textarea>\n @if (canClear) {\n <ef-clear-button\n class=\"ef-textarea-clear\"\n [ariaLabel]=\"'action.clear' | translate\"\n (clear)=\"clearValue()\"\n />\n }\n </div>\n @if (effectiveHint) {\n <small class=\"ef-field-hint\" [id]=\"hintId\">{{ effectiveHint }}</small>\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([dir]){direction:inherit}:host([dir=rtl]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:rtl}:host([dir=ltr]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:ltr}:host([dir=auto]) .ef-field-control input,:host([dir=auto]) .ef-field-control textarea{unicode-bidi:plaintext}.ef-textarea.ef-textarea--mono{font-family:var(--font-mono);font-size:12.5px;line-height:1.55}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfLabelComponent, selector: "ef-label", inputs: ["label", "labelKey", "labelParams", "for", "styleClass", "required"] }, { kind: "component", type: EfClearButtonComponent, selector: "ef-clear-button", inputs: ["ariaLabel", "disabled"], outputs: ["clear"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
|
|
13434
13495
|
}
|
|
13435
13496
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfTextareaComponent, decorators: [{
|
|
13436
13497
|
type: Component,
|
|
13437
|
-
args: [{ selector: 'ef-textarea', standalone: true, imports: [FormsModule, TranslateModule, EfLabelComponent, EfClearButtonComponent], template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [labelParams]=\"labelParams()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n <div class=\"ef-textarea-wrap\">\n <textarea\n class=\"ef-textarea\"\n [class.has-clear]=\"canClear\"\n [class.ef-textarea--mono]=\"mono\"\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [rows]=\"rows\"\n [value]=\"value\"\n [attr.placeholder]=\"effectivePlaceholder || null\"\n [attr.maxlength]=\"maxlength ?? null\"\n [readonly]=\"readonly()\"\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]=\"describedBy(showRequired || !!serverErrors)\"\n (input)=\"handleInput($any($event.target).value)\"\n (blur)=\"handleBlur()\"\n ></textarea>\n @if (canClear) {\n <ef-clear-button\n class=\"ef-textarea-clear\"\n [ariaLabel]=\"'action.clear' | translate\"\n (clear)=\"clearValue()\"\n />\n }\n </div>\n @if (effectiveHint) {\n <small class=\"ef-field-hint\" [id]=\"hintId\">{{ effectiveHint }}</small>\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([dir]){direction:inherit}:host([dir=rtl]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:rtl}:host([dir=ltr]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:ltr}:host([dir=auto]) .ef-field-control input,:host([dir=auto]) .ef-field-control textarea{unicode-bidi:plaintext}.ef-textarea.ef-textarea--mono{font-family:var(--font-mono);font-size:12.5px;line-height:1.55}\n"] }]
|
|
13498
|
+
args: [{ selector: 'ef-textarea', standalone: true, imports: [FormsModule, TranslateModule, EfLabelComponent, EfClearButtonComponent], host: { '[attr.lang]': 'null' }, template: "@if (labelKey() || label()) {\n <ef-label [labelKey]=\"labelKey()\" [labelParams]=\"labelParams()\" [label]=\"label()\" [for]=\"effectiveId\" [required]=\"required()\" />\n}\n<div class=\"ef-field-control\">\n <div class=\"ef-textarea-wrap\">\n <textarea\n class=\"ef-textarea\"\n [class.has-clear]=\"canClear\"\n [class.ef-textarea--mono]=\"mono\"\n [id]=\"effectiveId\"\n [attr.name]=\"name() || null\"\n [attr.lang]=\"lang || null\"\n [rows]=\"rows\"\n [value]=\"value\"\n [attr.placeholder]=\"effectivePlaceholder || null\"\n [attr.maxlength]=\"maxlength ?? null\"\n [readonly]=\"readonly()\"\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]=\"describedBy(showRequired || !!serverErrors)\"\n (input)=\"handleInput($any($event.target).value)\"\n (blur)=\"handleBlur()\"\n ></textarea>\n @if (canClear) {\n <ef-clear-button\n class=\"ef-textarea-clear\"\n [ariaLabel]=\"'action.clear' | translate\"\n (clear)=\"clearValue()\"\n />\n }\n </div>\n @if (effectiveHint) {\n <small class=\"ef-field-hint\" [id]=\"hintId\">{{ effectiveHint }}</small>\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([dir]){direction:inherit}:host([dir=rtl]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:rtl}:host([dir=ltr]) .ef-field-control>:not([role=alert]):not(.ef-field-hint){direction:ltr}:host([dir=auto]) .ef-field-control input,:host([dir=auto]) .ef-field-control textarea{unicode-bidi:plaintext}.ef-textarea.ef-textarea--mono{font-family:var(--font-mono);font-size:12.5px;line-height:1.55}\n"] }]
|
|
13438
13499
|
}], ctorParameters: () => [], propDecorators: { rows: [{
|
|
13439
13500
|
type: Input
|
|
13440
13501
|
}], maxlength: [{
|
|
13441
13502
|
type: Input
|
|
13503
|
+
}], lang: [{
|
|
13504
|
+
type: Input
|
|
13442
13505
|
}], autofocus: [{
|
|
13443
13506
|
type: Input,
|
|
13444
13507
|
args: [{ transform: booleanAttribute }]
|
|
@@ -13454,82 +13517,503 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
13454
13517
|
args: ['focusin', ['$event']]
|
|
13455
13518
|
}] } });
|
|
13456
13519
|
|
|
13520
|
+
/**
|
|
13521
|
+
* Loads the rich text editor component that `ef-localized-input`'s `rich`
|
|
13522
|
+
* mode renders. The editor lives in the `@elasticias/ui/rich-text` entry
|
|
13523
|
+
* point so an app that never edits rich text neither bundles PrimeNG's Editor
|
|
13524
|
+
* nor needs `quill` installed. Provide it with `provideEfRichText()` from that
|
|
13525
|
+
* entry (the editor code is in the app's main bundle, Quill itself still loads
|
|
13526
|
+
* lazily the first time an editor renders), or with your own loader to defer
|
|
13527
|
+
* the editor code too:
|
|
13528
|
+
*
|
|
13529
|
+
* ```ts
|
|
13530
|
+
* { provide: EF_RICH_TEXT, useValue: () => import('@elasticias/ui/rich-text').then(m => m.EfRichTextComponent) }
|
|
13531
|
+
* ```
|
|
13532
|
+
*/
|
|
13533
|
+
const EF_RICH_TEXT = new InjectionToken('EF_RICH_TEXT');
|
|
13534
|
+
/** Length of the text a reader sees in an HTML fragment, tags not counted. Browser only: it parses with `document`. */
|
|
13535
|
+
function plainTextLength(html) {
|
|
13536
|
+
if (!html)
|
|
13537
|
+
return 0;
|
|
13538
|
+
const tpl = document.createElement('template');
|
|
13539
|
+
tpl.innerHTML = html;
|
|
13540
|
+
return (tpl.content.textContent ?? '').length;
|
|
13541
|
+
}
|
|
13542
|
+
|
|
13457
13543
|
let nextId = 0;
|
|
13458
|
-
|
|
13459
|
-
|
|
13460
|
-
|
|
13461
|
-
|
|
13462
|
-
|
|
13544
|
+
/** Same texts once blanks are dropped. */
|
|
13545
|
+
function sameText(a, b) {
|
|
13546
|
+
const ka = Object.keys(a);
|
|
13547
|
+
return ka.length === Object.keys(b).length && ka.every(k => a[k] === b[k]);
|
|
13548
|
+
}
|
|
13463
13549
|
/**
|
|
13464
|
-
*
|
|
13465
|
-
*
|
|
13466
|
-
* and the
|
|
13467
|
-
*
|
|
13468
|
-
*
|
|
13550
|
+
* One owner-written text (a title, a description, an HTML body) in every
|
|
13551
|
+
* content language: a pill tab per culture, the active culture's field below
|
|
13552
|
+
* it, and the whole object out on every edit with blank cultures removed
|
|
13553
|
+
* (ADR-050 section 7).
|
|
13554
|
+
*
|
|
13555
|
+
* - **Cultures** come from `EF_CONTENT_CULTURES` (the ERP provides them from
|
|
13556
|
+
* the tenant profile) unless `cultures` is set. The active tab is local and
|
|
13557
|
+
* starts on the default culture.
|
|
13558
|
+
* - **Tabs** carry the `ef_localized_input_missing` note on every culture with
|
|
13559
|
+
* no text, the error tone on the default culture of a `required` field left
|
|
13560
|
+
* empty once the field is touched, changed or its form submitted, and the
|
|
13561
|
+
* dirty dot on cultures edited since the value arrived. Dirty detection
|
|
13562
|
+
* relies on the parent storing the emitted object by reference (the V2
|
|
13563
|
+
* signal pattern): a parent that clones the value resets the dots on every
|
|
13564
|
+
* edit, though it never loses text.
|
|
13565
|
+
* - **Direction.** Each field gets its culture's `dir` and `lang`. In `html`
|
|
13566
|
+
* mode the source stays `ltr` for every culture (raw HTML in an `rtl`
|
|
13567
|
+
* textarea reads reversed) and the sanitised preview takes the culture's
|
|
13568
|
+
* direction.
|
|
13569
|
+
* - **Rich mode** (`mode="rich"`) edits each culture with `ef-rich-text`, the
|
|
13570
|
+
* shared editor in `@elasticias/ui/rich-text`. The app turns it on once with
|
|
13571
|
+
* `provideEfRichText()` (and installs `quill`); without it the field falls
|
|
13572
|
+
* back to the `html` source and logs why in development, as it does when
|
|
13573
|
+
* the editor's chunk fails to load. With `advisedLength` the counter
|
|
13574
|
+
* counts the text a reader sees; with only `maxLength` it counts the
|
|
13575
|
+
* stored HTML, which is what the server measures. Neither caps typing in
|
|
13576
|
+
* this mode.
|
|
13577
|
+
* - **Read-only cultures** are shown read-only (still focusable, so the hint
|
|
13578
|
+
* is read and the text can be copied) with
|
|
13579
|
+
* `ef_localized_input_read_only_hint` and the projected `[read-only-link]`;
|
|
13580
|
+
* their text still travels in the emitted object. `[efReadOnly]`, `[disabled]`
|
|
13581
|
+
* and a form's `disable()` disable every culture; the tabs stay usable so the
|
|
13582
|
+
* other languages can still be read.
|
|
13583
|
+
* - **Forms.** A ControlValueAccessor (`[formControl]`, `formControlName`,
|
|
13584
|
+
* `[(ngModel)]`) as well as `[value]` + `(valueChangeEvent)`. With
|
|
13585
|
+
* `required`, the form control reports `required` while the default culture
|
|
13586
|
+
* is empty.
|
|
13587
|
+
* - **Server errors** (ADR-010) come from the enclosing `[efServerErrors]`
|
|
13588
|
+
* scope. `<name>.<culture>` errors tint that culture's tab, show under its
|
|
13589
|
+
* field while it is active (the field links itself by name) and, from another
|
|
13590
|
+
* tab, show as a hint naming the languages in error; a new set of errors
|
|
13591
|
+
* moves to the first of them. `<name>` errors, or an explicit `[errors]`,
|
|
13592
|
+
* show under the field on every tab, as do errors for a language the field
|
|
13593
|
+
* does not list (`title.xx`). Messages are translated as keys. Keys: `ef_localized_input_errors_in_other`.
|
|
13594
|
+
* - **Spoken limit.** `counterHintKey` is read with the counter (through
|
|
13595
|
+
* `aria-describedby`) and `counterOverKey` is announced politely when the
|
|
13596
|
+
* text passes the limit; both take `{{max}}`.
|
|
13597
|
+
* - **Names.** Each culture's field is named `<name>.<culture>` (`title.ar`),
|
|
13598
|
+
* the key the backend reports a per-culture error under.
|
|
13599
|
+
*
|
|
13600
|
+
* i18n keys the app's bundles must define (the libs ship no JSON):
|
|
13601
|
+
*
|
|
13602
|
+
* | key | fr | ar | en |
|
|
13603
|
+
* |---|---|---|---|
|
|
13604
|
+
* | `ef_localized_input_culture_fr` | Français | الفرنسية | French |
|
|
13605
|
+
* | `ef_localized_input_culture_ar` | Arabe | العربية | Arabic |
|
|
13606
|
+
* | `ef_localized_input_culture_en` | Anglais | الإنجليزية | English |
|
|
13607
|
+
* | `ef_localized_input_missing` | manquant | غير مكتوب | missing |
|
|
13608
|
+
* | `ef_localized_input_cultures` | Langues du texte | لغات النص | Text languages |
|
|
13609
|
+
* | `ef_localized_input_errors_in_other` | Erreur dans : | خطأ في: | Error in: |
|
|
13610
|
+
* | `ef_localized_input_read_only_hint` | Ce texte se modifie ailleurs. | يُعدَّل هذا النص في مكان آخر. | This text is edited elsewhere. |
|
|
13469
13611
|
*
|
|
13470
|
-
*
|
|
13471
|
-
*
|
|
13472
|
-
*
|
|
13612
|
+
* ```html
|
|
13613
|
+
* <ef-localized-input name="title" labelKey="product_title" required
|
|
13614
|
+
* [value]="product().title" (valueChangeEvent)="patch({ title: $event })"
|
|
13615
|
+
* [advisedLength]="60" [maxLength]="256" />
|
|
13616
|
+
*
|
|
13617
|
+
* <ef-localized-input name="title" [readOnlyCultures]="['fr']" ...>
|
|
13618
|
+
* <a read-only-link [routerLink]="catalogLink()">{{ 'store_open_catalog' | translate }}</a>
|
|
13619
|
+
* </ef-localized-input>
|
|
13620
|
+
* ```
|
|
13621
|
+
*/
|
|
13622
|
+
class EfLocalizedInputComponent {
|
|
13623
|
+
/** The camelCase backend property (`title`); each field is `<name>.<culture>`. */
|
|
13624
|
+
name = input.required(...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
|
|
13625
|
+
value = input(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
13626
|
+
mode = input('text', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
|
|
13627
|
+
rows = input(4, ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
|
|
13628
|
+
/** Hard cap, the server's limit. */
|
|
13629
|
+
maxLength = input(undefined, ...(ngDevMode ? [{ debugName: "maxLength" }] : /* istanbul ignore next */ []));
|
|
13630
|
+
/** What the counter measures against (what a search engine shows, say). */
|
|
13631
|
+
advisedLength = input(undefined, ...(ngDevMode ? [{ debugName: "advisedLength" }] : /* istanbul ignore next */ []));
|
|
13632
|
+
/** The default culture must be filled. */
|
|
13633
|
+
required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
13634
|
+
/** Cultures shown but not editable here, with the `[read-only-link]` slot. */
|
|
13635
|
+
readOnlyCultures = input([], ...(ngDevMode ? [{ debugName: "readOnlyCultures" }] : /* istanbul ignore next */ []));
|
|
13636
|
+
/** Labels the field and names its tablist; without it the tablist is
|
|
13637
|
+
* named `ef_localized_input_cultures`. */
|
|
13638
|
+
labelKey = input('', ...(ngDevMode ? [{ debugName: "labelKey" }] : /* istanbul ignore next */ []));
|
|
13639
|
+
placeholderKey = input('', ...(ngDevMode ? [{ debugName: "placeholderKey" }] : /* istanbul ignore next */ []));
|
|
13640
|
+
hintKey = input('', ...(ngDevMode ? [{ debugName: "hintKey" }] : /* istanbul ignore next */ []));
|
|
13641
|
+
/** i18n key (with `{{max}}`) read out with the counter, for a limit that is advice rather than a cap. */
|
|
13642
|
+
counterHintKey = input('', ...(ngDevMode ? [{ debugName: "counterHintKey" }] : /* istanbul ignore next */ []));
|
|
13643
|
+
/** i18n key (with `{{max}}`) announced politely when the text goes past the limit. */
|
|
13644
|
+
counterOverKey = input('', ...(ngDevMode ? [{ debugName: "counterOverKey" }] : /* istanbul ignore next */ []));
|
|
13645
|
+
/** Field style in `text` mode only, named like ef-input-text's (`primeng`
|
|
13646
|
+
* or `comptoir`); the textarea, html and rich modes have one style.
|
|
13647
|
+
* `default` is the former name of `primeng`, kept for one release. */
|
|
13648
|
+
variant = input('comptoir', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
13649
|
+
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
13650
|
+
/**
|
|
13651
|
+
* Messages for the whole field. Without it they come from the enclosing
|
|
13652
|
+
* `[efServerErrors]` scope under `name`; an explicit list wins. The
|
|
13653
|
+
* per-language messages (`<name>.<culture>`) always come from the scope.
|
|
13654
|
+
*/
|
|
13655
|
+
errors = input(undefined, ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
13656
|
+
/** Overrides the `EF_CONTENT_CULTURES` list for this field. */
|
|
13657
|
+
cultures = input(undefined, ...(ngDevMode ? [{ debugName: "cultures" }] : /* istanbul ignore next */ []));
|
|
13658
|
+
/** The whole new object, trimmed, with blank cultures removed. */
|
|
13659
|
+
valueChangeEvent = output();
|
|
13660
|
+
contentCultures = inject(EF_CONTENT_CULTURES);
|
|
13661
|
+
readOnlyScope = inject(EfReadOnlyDirective, { optional: true });
|
|
13662
|
+
ngControl = inject(NgControl, { self: true, optional: true });
|
|
13663
|
+
serverErrorsScope = inject(EfServerErrorsDirective, { optional: true });
|
|
13664
|
+
richLoader = inject(EF_RICH_TEXT, { optional: true });
|
|
13665
|
+
richType = signal(null, ...(ngDevMode ? [{ debugName: "richType" }] : /* istanbul ignore next */ []));
|
|
13666
|
+
/** The editor's chunk failed to load (offline, a stale deploy). */
|
|
13667
|
+
richFailed = signal(false, ...(ngDevMode ? [{ debugName: "richFailed" }] : /* istanbul ignore next */ []));
|
|
13668
|
+
richHost = viewChild('richHost', { ...(ngDevMode ? { debugName: "richHost" } : /* istanbul ignore next */ {}), read: ViewContainerRef });
|
|
13669
|
+
/** `rich` without a provided editor renders the html source instead. */
|
|
13670
|
+
effectiveMode = computed(() => this.mode() === 'rich' && (!this.richLoader || this.richFailed()) ? 'html' : this.mode(), ...(ngDevMode ? [{ debugName: "effectiveMode" }] : /* istanbul ignore next */ []));
|
|
13671
|
+
parentForm = inject(FormGroupDirective, { optional: true }) ?? inject(NgForm, { optional: true });
|
|
13672
|
+
host = inject(ElementRef);
|
|
13673
|
+
translateService = inject(TranslateService);
|
|
13674
|
+
/** The user typed in, or left, the field. */
|
|
13675
|
+
interacted = signal(false, ...(ngDevMode ? [{ debugName: "interacted" }] : /* istanbul ignore next */ []));
|
|
13676
|
+
/** The form control is touched or dirty, or its form was submitted; read on every check. */
|
|
13677
|
+
formTouched = signal(false, ...(ngDevMode ? [{ debugName: "formTouched" }] : /* istanbul ignore next */ []));
|
|
13678
|
+
/** Errors wait for touch, a change or a submit, like every ef-* control. */
|
|
13679
|
+
showErrors = computed(() => this.interacted() || this.formTouched(), ...(ngDevMode ? [{ debugName: "showErrors" }] : /* istanbul ignore next */ []));
|
|
13680
|
+
uid = `ef-localized-input-${nextId++}`;
|
|
13681
|
+
/** The object this component last emitted; an echo of it is not new data. */
|
|
13682
|
+
lastEmitted = null;
|
|
13683
|
+
/** The text as typed, blanks and spaces kept, so an echo never rewrites a field mid-word. */
|
|
13684
|
+
raw = linkedSignal({ ...(ngDevMode ? { debugName: "raw" } : /* istanbul ignore next */ {}), source: this.value,
|
|
13685
|
+
computation: (v, prev) => {
|
|
13686
|
+
if (prev && (v === this.lastEmitted || sameText(cleanLocalizedText(v), cleanLocalizedText(prev.value)))) {
|
|
13687
|
+
return prev.value;
|
|
13688
|
+
}
|
|
13689
|
+
return { ...(v ?? {}) };
|
|
13690
|
+
} });
|
|
13691
|
+
/** What the dirty dots compare against: the last value that came from outside. */
|
|
13692
|
+
baseline = linkedSignal({ ...(ngDevMode ? { debugName: "baseline" } : /* istanbul ignore next */ {}), source: this.value,
|
|
13693
|
+
computation: (v, prev) => (prev && v === this.lastEmitted ? prev.value : cleanLocalizedText(v)) });
|
|
13694
|
+
cleaned = computed(() => cleanLocalizedText(this.raw()), ...(ngDevMode ? [{ debugName: "cleaned" }] : /* istanbul ignore next */ []));
|
|
13695
|
+
list = computed(() => this.cultures() ?? this.contentCultures().cultures, ...(ngDevMode ? [{ debugName: "list" }] : /* istanbul ignore next */ []));
|
|
13696
|
+
defaultCode = computed(() => {
|
|
13697
|
+
const preferred = this.contentCultures().defaultCulture;
|
|
13698
|
+
const list = this.list();
|
|
13699
|
+
return list.some(c => c.code === preferred) ? preferred : (list[0]?.code ?? preferred);
|
|
13700
|
+
}, ...(ngDevMode ? [{ debugName: "defaultCode" }] : /* istanbul ignore next */ []));
|
|
13701
|
+
selected = signal(null, ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
|
|
13702
|
+
active = computed(() => {
|
|
13703
|
+
const list = this.list();
|
|
13704
|
+
const code = this.selected();
|
|
13705
|
+
return list.find(c => c.code === code) ?? list.find(c => c.code === this.defaultCode()) ?? list[0];
|
|
13706
|
+
}, ...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
|
|
13707
|
+
/** The active culture's code: unlike active(), equal when an equal culture list arrives. */
|
|
13708
|
+
activeCode = computed(() => this.active()?.code, ...(ngDevMode ? [{ debugName: "activeCode" }] : /* istanbul ignore next */ []));
|
|
13709
|
+
/** Server messages for the whole field (`title`). */
|
|
13710
|
+
fieldErrors = computed(() => {
|
|
13711
|
+
const messages = [...(resolveExternalErrors(this.errors(), this.serverErrorsScope, this.name()) ?? []), ...this.unlistedErrors()];
|
|
13712
|
+
return messages.length ? messages : null;
|
|
13713
|
+
}, ...(ngDevMode ? [{ debugName: "fieldErrors" }] : /* istanbul ignore next */ []));
|
|
13714
|
+
/** Every `<name>.<culture>` message the scope holds. */
|
|
13715
|
+
allCultureErrors = computed(() => this.serverErrorsScope?.errorsWithPrefix(`${this.name()}.`) ?? {}, ...(ngDevMode ? [{ debugName: "allCultureErrors" }] : /* istanbul ignore next */ []));
|
|
13716
|
+
/** Server messages per language (`title.ar` gives `ar`), only for listed cultures. */
|
|
13717
|
+
cultureErrors = computed(() => {
|
|
13718
|
+
const all = this.allCultureErrors();
|
|
13719
|
+
const out = {};
|
|
13720
|
+
for (const c of this.list())
|
|
13721
|
+
if (all[c.code])
|
|
13722
|
+
out[c.code] = all[c.code];
|
|
13723
|
+
return out;
|
|
13724
|
+
}, ...(ngDevMode ? [{ debugName: "cultureErrors" }] : /* istanbul ignore next */ []));
|
|
13725
|
+
/** Messages for a language this field does not list (`title.xx`): shown with the whole field, never dropped. */
|
|
13726
|
+
unlistedErrors = computed(() => {
|
|
13727
|
+
const listed = new Set(this.list().map(c => c.code));
|
|
13728
|
+
return Object.entries(this.allCultureErrors()).flatMap(([code, messages]) => (listed.has(code) ? [] : messages));
|
|
13729
|
+
}, ...(ngDevMode ? [{ debugName: "unlistedErrors" }] : /* istanbul ignore next */ []));
|
|
13730
|
+
/** Bumps when texts change, so translated messages follow the language. */
|
|
13731
|
+
textsVersion = signal(0, ...(ngDevMode ? [{ debugName: "textsVersion" }] : /* istanbul ignore next */ []));
|
|
13732
|
+
/** The active language's messages, translated once here for the field below. */
|
|
13733
|
+
activeErrors = computed(() => {
|
|
13734
|
+
this.textsVersion();
|
|
13735
|
+
const messages = this.cultureErrors()[this.active()?.code ?? ''];
|
|
13736
|
+
return messages?.length ? messages.map(m => this.translateService.instant(m)) : null;
|
|
13737
|
+
}, ...(ngDevMode ? [{ debugName: "activeErrors" }] : /* istanbul ignore next */ []));
|
|
13738
|
+
/** Cultures with a server error, in tab order. */
|
|
13739
|
+
culturesInError = computed(() => this.list().filter(c => this.cultureErrors()[c.code]), ...(ngDevMode ? [{ debugName: "culturesInError" }] : /* istanbul ignore next */ []));
|
|
13740
|
+
/** Cultures in error other than the one on show, for the hint under the tabs. */
|
|
13741
|
+
errorsElsewhere = computed(() => this.culturesInError().filter(c => c.code !== this.active()?.code), ...(ngDevMode ? [{ debugName: "errorsElsewhere" }] : /* istanbul ignore next */ []));
|
|
13742
|
+
/** Changes only when the set of errors does, so a tab the user picked stays picked. */
|
|
13743
|
+
errorSignature = computed(() => JSON.stringify(this.cultureErrors()), ...(ngDevMode ? [{ debugName: "errorSignature" }] : /* istanbul ignore next */ []));
|
|
13744
|
+
tabItems = computed(() => {
|
|
13745
|
+
const text = this.cleaned();
|
|
13746
|
+
const base = this.baseline();
|
|
13747
|
+
return this.list().map(c => {
|
|
13748
|
+
const missing = !text[c.code];
|
|
13749
|
+
return {
|
|
13750
|
+
value: c.code,
|
|
13751
|
+
labelKey: c.labelKey,
|
|
13752
|
+
noteKey: missing ? 'ef_localized_input_missing' : undefined,
|
|
13753
|
+
tone: this.cultureErrors()[c.code] ||
|
|
13754
|
+
(missing && this.required() && c.code === this.defaultCode() && this.showErrors())
|
|
13755
|
+
? 'danger'
|
|
13756
|
+
: undefined,
|
|
13757
|
+
dirty: (text[c.code] ?? '') !== (base[c.code] ?? ''),
|
|
13758
|
+
id: this.tabId(c.code),
|
|
13759
|
+
panelId: this.panelId,
|
|
13760
|
+
};
|
|
13761
|
+
});
|
|
13762
|
+
}, ...(ngDevMode ? [{ debugName: "tabItems" }] : /* istanbul ignore next */ []));
|
|
13763
|
+
cvaDisabled = signal(false, ...(ngDevMode ? [{ debugName: "cvaDisabled" }] : /* istanbul ignore next */ []));
|
|
13764
|
+
/** Every culture is disabled: `[disabled]`, a form's `disable()`, or `[efReadOnly]`. */
|
|
13765
|
+
isDisabled = computed(() => this.disabled() || this.cvaDisabled() || (this.readOnlyScope?.readOnly() ?? false), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
|
|
13766
|
+
activeReadOnly = computed(() => {
|
|
13767
|
+
const code = this.active()?.code;
|
|
13768
|
+
return !!code && this.readOnlyCultures().includes(code);
|
|
13769
|
+
}, ...(ngDevMode ? [{ debugName: "activeReadOnly" }] : /* istanbul ignore next */ []));
|
|
13770
|
+
activeText = computed(() => this.raw()[this.active()?.code ?? ''] ?? '', ...(ngDevMode ? [{ debugName: "activeText" }] : /* istanbul ignore next */ []));
|
|
13771
|
+
/**
|
|
13772
|
+
* What the counter counts. Rich text against `advisedLength` counts the
|
|
13773
|
+
* characters a reader sees; against `maxLength` alone it counts the stored
|
|
13774
|
+
* HTML, because that is what the server's limit measures.
|
|
13775
|
+
*/
|
|
13776
|
+
activeLength = computed(() => this.effectiveMode() === 'rich' && this.advisedLength() != null
|
|
13777
|
+
? plainTextLength(this.activeText())
|
|
13778
|
+
: this.activeText().length, ...(ngDevMode ? [{ debugName: "activeLength" }] : /* istanbul ignore next */ []));
|
|
13779
|
+
labelId = `${this.uid}-label`;
|
|
13780
|
+
counterLimit = computed(() => this.advisedLength() ?? this.maxLength(), ...(ngDevMode ? [{ debugName: "counterLimit" }] : /* istanbul ignore next */ []));
|
|
13781
|
+
panelId = `${this.uid}-panel`;
|
|
13782
|
+
counterId = `${this.uid}-counter`;
|
|
13783
|
+
onChange = () => { };
|
|
13784
|
+
touched = () => { };
|
|
13785
|
+
constructor() {
|
|
13786
|
+
if (this.ngControl)
|
|
13787
|
+
this.ngControl.valueAccessor = this;
|
|
13788
|
+
merge(this.translateService.onLangChange, this.translateService.onTranslationChange)
|
|
13789
|
+
.pipe(takeUntilDestroyed())
|
|
13790
|
+
.subscribe(() => this.textsVersion.update(v => v + 1));
|
|
13791
|
+
// The validator reads required and the default culture, which can
|
|
13792
|
+
// change without the value changing (tenant cultures arrive late).
|
|
13793
|
+
effect(() => {
|
|
13794
|
+
this.required();
|
|
13795
|
+
this.defaultCode();
|
|
13796
|
+
untracked(() => this.ngControl?.control?.updateValueAndValidity({ emitEvent: false }));
|
|
13797
|
+
});
|
|
13798
|
+
// A new set of server errors brings the first language in error into view.
|
|
13799
|
+
effect(() => {
|
|
13800
|
+
this.errorSignature();
|
|
13801
|
+
untracked(() => {
|
|
13802
|
+
const first = this.culturesInError()[0];
|
|
13803
|
+
if (first)
|
|
13804
|
+
this.selected.set(first.code);
|
|
13805
|
+
});
|
|
13806
|
+
});
|
|
13807
|
+
effect(() => {
|
|
13808
|
+
if (this.mode() !== 'rich')
|
|
13809
|
+
return;
|
|
13810
|
+
if (!this.richLoader) {
|
|
13811
|
+
if (isDevMode()) {
|
|
13812
|
+
console.error(`ef-localized-input "${untracked(this.name)}": mode="rich" needs provideEfRichText() from @elasticias/ui/rich-text; showing the html source instead.`);
|
|
13813
|
+
}
|
|
13814
|
+
return;
|
|
13815
|
+
}
|
|
13816
|
+
if (untracked(this.richType) || untracked(this.richFailed))
|
|
13817
|
+
return;
|
|
13818
|
+
this.richLoader()
|
|
13819
|
+
.then(t => this.richType.set(t))
|
|
13820
|
+
.catch((err) => {
|
|
13821
|
+
if (isDevMode()) {
|
|
13822
|
+
console.error(`ef-localized-input "${untracked(this.name)}": could not load the rich text editor; showing the html source instead.`, err);
|
|
13823
|
+
}
|
|
13824
|
+
this.richFailed.set(true);
|
|
13825
|
+
});
|
|
13826
|
+
});
|
|
13827
|
+
// One editor per active culture: the @for recreates the host on a
|
|
13828
|
+
// culture switch, and the editor is created in it with live bindings.
|
|
13829
|
+
effect(() => {
|
|
13830
|
+
const vcr = this.richHost();
|
|
13831
|
+
const type = this.richType();
|
|
13832
|
+
const code = this.activeCode();
|
|
13833
|
+
if (!vcr || !type || !code || this.effectiveMode() !== 'rich')
|
|
13834
|
+
return;
|
|
13835
|
+
untracked(() => this.createRich(vcr, type, code));
|
|
13836
|
+
});
|
|
13837
|
+
}
|
|
13838
|
+
createRich(vcr, type, code) {
|
|
13839
|
+
vcr.clear();
|
|
13840
|
+
const culture = () => this.list().find(c => c.code === code);
|
|
13841
|
+
const readOnly = () => this.readOnlyCultures().includes(code);
|
|
13842
|
+
vcr.createComponent(type, {
|
|
13843
|
+
bindings: [
|
|
13844
|
+
inputBinding('value', () => this.raw()[code] ?? ''),
|
|
13845
|
+
inputBinding('name', () => `${this.name()}.${code}`),
|
|
13846
|
+
inputBinding('inputId', () => this.controlId(code)),
|
|
13847
|
+
inputBinding('dir', () => culture()?.dir ?? null),
|
|
13848
|
+
inputBinding('lang', () => code),
|
|
13849
|
+
inputBinding('rows', () => this.rows()),
|
|
13850
|
+
inputBinding('labelledBy', () => (this.labelKey() ? this.labelId : null)),
|
|
13851
|
+
inputBinding('required', () => this.required() && code === this.defaultCode()),
|
|
13852
|
+
inputBinding('errors', () => this.activeErrors()),
|
|
13853
|
+
inputBinding('disabled', () => this.isDisabled()),
|
|
13854
|
+
inputBinding('readonly', readOnly),
|
|
13855
|
+
inputBinding('placeholderKey', () => this.placeholderKey()),
|
|
13856
|
+
inputBinding('hintKey', () => (readOnly() ? 'ef_localized_input_read_only_hint' : this.hintKey())),
|
|
13857
|
+
inputBinding('describedByExtra', () => (this.counterLimit() ? this.counterId : '')),
|
|
13858
|
+
outputBinding('valueChangeEvent', v => this.setText(code, v)),
|
|
13859
|
+
],
|
|
13860
|
+
});
|
|
13861
|
+
}
|
|
13862
|
+
tabId(code) {
|
|
13863
|
+
return `${this.uid}-tab-${code}`;
|
|
13864
|
+
}
|
|
13865
|
+
controlId(code) {
|
|
13866
|
+
return `${this.uid}-${code}`;
|
|
13867
|
+
}
|
|
13868
|
+
select(code) {
|
|
13869
|
+
this.selected.set(code);
|
|
13870
|
+
}
|
|
13871
|
+
setText(code, text) {
|
|
13872
|
+
this.raw.update(r => ({ ...r, [code]: text }));
|
|
13873
|
+
const out = this.cleaned();
|
|
13874
|
+
this.lastEmitted = out;
|
|
13875
|
+
this.interacted.set(true);
|
|
13876
|
+
this.onChange(out);
|
|
13877
|
+
this.valueChangeEvent.emit(out);
|
|
13878
|
+
}
|
|
13879
|
+
/** Touched when focus leaves the whole field, not when it moves from a tab to the text. */
|
|
13880
|
+
onFocusOut(event) {
|
|
13881
|
+
const next = event.relatedTarget;
|
|
13882
|
+
if (next instanceof Node && this.host.nativeElement.contains(next))
|
|
13883
|
+
return;
|
|
13884
|
+
this.interacted.set(true);
|
|
13885
|
+
this.touched();
|
|
13886
|
+
}
|
|
13887
|
+
ngDoCheck() {
|
|
13888
|
+
// A form's markAllAsTouched() or submit does not reach the accessor,
|
|
13889
|
+
// so the control's state is read each time the parent is checked.
|
|
13890
|
+
const c = this.ngControl;
|
|
13891
|
+
this.formTouched.set(!!(c?.touched || c?.dirty || this.parentForm?.submitted));
|
|
13892
|
+
}
|
|
13893
|
+
/** `{ required: true }` while a required field's default culture has no text. */
|
|
13894
|
+
validateRequired(control) {
|
|
13895
|
+
if (!this.required())
|
|
13896
|
+
return null;
|
|
13897
|
+
return cleanLocalizedText(control.value)[this.defaultCode()] ? null : { required: true };
|
|
13898
|
+
}
|
|
13899
|
+
writeValue(v) {
|
|
13900
|
+
this.raw.set({ ...(v ?? {}) });
|
|
13901
|
+
this.baseline.set(cleanLocalizedText(v));
|
|
13902
|
+
}
|
|
13903
|
+
registerOnChange(fn) {
|
|
13904
|
+
this.onChange = fn;
|
|
13905
|
+
}
|
|
13906
|
+
registerOnTouched(fn) {
|
|
13907
|
+
this.touched = fn;
|
|
13908
|
+
}
|
|
13909
|
+
setDisabledState(disabled) {
|
|
13910
|
+
this.cvaDisabled.set(disabled);
|
|
13911
|
+
}
|
|
13912
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfLocalizedInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13913
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfLocalizedInputComponent, isStandalone: true, selector: "ef-localized-input", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, advisedLength: { classPropertyName: "advisedLength", publicName: "advisedLength", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, readOnlyCultures: { classPropertyName: "readOnlyCultures", publicName: "readOnlyCultures", isSignal: true, isRequired: false, transformFunction: null }, labelKey: { classPropertyName: "labelKey", publicName: "labelKey", isSignal: true, isRequired: false, transformFunction: null }, placeholderKey: { classPropertyName: "placeholderKey", publicName: "placeholderKey", isSignal: true, isRequired: false, transformFunction: null }, hintKey: { classPropertyName: "hintKey", publicName: "hintKey", isSignal: true, isRequired: false, transformFunction: null }, counterHintKey: { classPropertyName: "counterHintKey", publicName: "counterHintKey", isSignal: true, isRequired: false, transformFunction: null }, counterOverKey: { classPropertyName: "counterOverKey", publicName: "counterOverKey", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, cultures: { classPropertyName: "cultures", publicName: "cultures", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChangeEvent: "valueChangeEvent" }, host: { listeners: { "focusout": "onFocusOut($event)" } }, providers: [
|
|
13914
|
+
{
|
|
13915
|
+
// A form's required validator reads an empty object as filled (it
|
|
13916
|
+
// checks length), so the field validates its default culture
|
|
13917
|
+
// itself. The component is looked up when the form validates, not
|
|
13918
|
+
// here: it injects NgControl, which injects these validators.
|
|
13919
|
+
provide: NG_VALIDATORS,
|
|
13920
|
+
multi: true,
|
|
13921
|
+
useFactory: () => {
|
|
13922
|
+
const injector = inject(Injector);
|
|
13923
|
+
return (control) => injector.get(EfLocalizedInputComponent).validateRequired(control);
|
|
13924
|
+
},
|
|
13925
|
+
},
|
|
13926
|
+
], viewQueries: [{ propertyName: "richHost", first: true, predicate: ["richHost"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<div class=\"eli-head\">\n @if (labelKey()) {\n <span class=\"eli-label\" [id]=\"labelId\">\n <ef-label [labelKey]=\"labelKey()\" [for]=\"controlId(active()?.code ?? '')\" [required]=\"required()\" />\n </span>\n }\n <div class=\"eli-tabs\">\n <ef-tabs\n variant=\"pill\"\n [items]=\"tabItems()\"\n [value]=\"active()?.code ?? null\"\n [ariaLabelKey]=\"labelKey() || 'ef_localized_input_cultures'\"\n (valueChange)=\"select($event)\"\n />\n </div>\n</div>\n\n<div class=\"eli-panel\" role=\"tabpanel\" [id]=\"panelId\" [attr.aria-labelledby]=\"tabId(active()?.code ?? '')\">\n @for (c of active() ? [active()!] : []; track c.code) {\n @switch (effectiveMode()) {\n @case ('text') {\n <ef-input-text\n [variant]=\"variant() === 'comptoir' ? 'comptoir' : 'primeng'\"\n [inputId]=\"controlId(c.code)\"\n [name]=\"name() + '.' + c.code\"\n [dir]=\"c.dir\"\n [lang]=\"c.code\"\n [value]=\"activeText()\"\n [maxlength]=\"maxLength()\"\n [required]=\"required() && c.code === defaultCode()\"\n [errors]=\"activeErrors()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"activeReadOnly()\"\n [placeholderKey]=\"placeholderKey()\"\n [hintKey]=\"activeReadOnly() ? 'ef_localized_input_read_only_hint' : hintKey()\"\n [describedByExtra]=\"counterLimit() ? counterId : ''\"\n (valueChangeEvent)=\"setText(c.code, $event)\"\n />\n }\n @case ('textarea') {\n <ef-textarea\n [inputId]=\"controlId(c.code)\"\n [name]=\"name() + '.' + c.code\"\n [dir]=\"c.dir\"\n [lang]=\"c.code\"\n [rows]=\"rows()\"\n [value]=\"activeText()\"\n [maxlength]=\"maxLength()\"\n [required]=\"required() && c.code === defaultCode()\"\n [errors]=\"activeErrors()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"activeReadOnly()\"\n [placeholderKey]=\"placeholderKey()\"\n [hintKey]=\"activeReadOnly() ? 'ef_localized_input_read_only_hint' : hintKey()\"\n [describedByExtra]=\"counterLimit() ? counterId : ''\"\n (valueChangeEvent)=\"setText(c.code, $event)\"\n />\n }\n @case ('rich') {\n <!-- ef-rich-text, created from EF_RICH_TEXT (see createRich). -->\n <ng-container #richHost />\n }\n @case ('html') {\n <!-- The source stays ltr for every culture: raw HTML in an rtl\n textarea reads reversed (ADR-036). The preview takes the\n culture's direction. -->\n <ef-textarea\n mono\n dir=\"ltr\"\n [inputId]=\"controlId(c.code)\"\n [name]=\"name() + '.' + c.code\"\n [lang]=\"c.code\"\n [rows]=\"rows()\"\n [value]=\"activeText()\"\n [maxlength]=\"maxLength()\"\n [required]=\"required() && c.code === defaultCode()\"\n [errors]=\"activeErrors()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"activeReadOnly()\"\n [placeholderKey]=\"placeholderKey()\"\n [hintKey]=\"activeReadOnly() ? 'ef_localized_input_read_only_hint' : hintKey()\"\n [describedByExtra]=\"counterLimit() ? counterId : ''\"\n (valueChangeEvent)=\"setText(c.code, $event)\"\n />\n }\n }\n }\n\n @if (counterLimit(); as limit) {\n <span class=\"eli-counter\" data-counter [id]=\"counterId\" [class.is-over]=\"activeLength() > limit\">\n <bdi dir=\"ltr\">{{ activeLength() }} / {{ limit }}</bdi>\n @if (counterHintKey()) {\n <span class=\"eli-counter__sr\">{{ counterHintKey() | translate: { max: limit } }}</span>\n }\n </span>\n @if (counterOverKey()) {\n <!-- Always present, so a screen reader hears the text appear. -->\n <span class=\"eli-counter__sr\" data-over-message aria-live=\"polite\">\n @if (activeLength() > limit) {\n {{ counterOverKey() | translate: { max: limit } }}\n }\n </span>\n }\n }\n\n @if (effectiveMode() === 'html' && activeText().trim()) {\n @if (active(); as c) {\n <!-- Angular's default [innerHTML] sanitising strips scripts and handlers. -->\n <div class=\"eli-preview\" data-preview [attr.dir]=\"c.dir\" [attr.lang]=\"c.code\" [innerHTML]=\"activeText()\"></div>\n }\n }\n\n @if (fieldErrors(); as messages) {\n <div class=\"eli-errors\" data-field-errors role=\"alert\" aria-live=\"polite\">\n @for (message of messages; track message) {\n <small class=\"text-danger block\">{{ message | translate }}</small>\n }\n </div>\n }\n\n @if (errorsElsewhere(); as others) {\n @if (others.length) {\n <small class=\"eli-elsewhere text-danger block\" data-errors-elsewhere role=\"status\">\n {{ 'ef_localized_input_errors_in_other' | translate }}\n @for (c of others; track c.code; let last = $last) {\n {{ c.labelKey | translate }}{{ last ? '' : ',' }}\n }\n </small>\n }\n }\n\n @if (activeReadOnly()) {\n <div class=\"eli-link\">\n <ng-content select=\"[read-only-link]\" />\n </div>\n }\n</div>\n", styles: [":host{position:relative;display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-2);min-width:0}.eli-head{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--s-2);min-width:0}.eli-label{min-width:0}.eli-tabs{min-width:0;max-width:100%;overflow-x:auto}.eli-panel{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-2);min-width:0}.eli-counter{position:relative;font-size:12px;color:var(--text-mute);text-align:end;font-variant-numeric:tabular-nums}.eli-counter.is-over{color:var(--st-pending-fg);font-weight:600}.eli-counter__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.eli-preview{min-width:0;overflow-x:auto;overflow-wrap:anywhere;padding:var(--s-3);border:1px solid var(--rule);border-radius:var(--r-sm);background:var(--paper-alt);color:var(--text);font-size:13.5px;line-height:1.55}.eli-link{font-size:12px}@media(max-width:767px){.eli-tabs{--hit: var(--hit-touch);flex:1 1 100%}}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfLabelComponent, selector: "ef-label", inputs: ["label", "labelKey", "labelParams", "for", "styleClass", "required"] }, { kind: "component", type: EfTabsComponent, selector: "ef-tabs", inputs: ["items", "value", "variant", "module", "overflow", "hideCounts", "ariaLabel", "ariaLabelKey", "dirtyLabelKey"], outputs: ["valueChange"] }, { kind: "component", type: EfInputTextComponent, selector: "ef-input-text", inputs: ["size", "type", "maxlength", "fluid", "inline", "autocomplete", "dir", "lang", "variant", "prefix", "suffix", "value"], outputs: ["valueChangeEvent"] }, { kind: "component", type: EfTextareaComponent, selector: "ef-textarea", inputs: ["rows", "maxlength", "lang", "autofocus", "mono", "value"], outputs: ["valueChangeEvent"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
13927
|
+
}
|
|
13928
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfLocalizedInputComponent, decorators: [{
|
|
13929
|
+
type: Component,
|
|
13930
|
+
args: [{ selector: 'ef-localized-input', standalone: true, imports: [TranslateModule, EfLabelComponent, EfTabsComponent, EfInputTextComponent, EfTextareaComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: { '(focusout)': 'onFocusOut($event)' }, providers: [
|
|
13931
|
+
{
|
|
13932
|
+
// A form's required validator reads an empty object as filled (it
|
|
13933
|
+
// checks length), so the field validates its default culture
|
|
13934
|
+
// itself. The component is looked up when the form validates, not
|
|
13935
|
+
// here: it injects NgControl, which injects these validators.
|
|
13936
|
+
provide: NG_VALIDATORS,
|
|
13937
|
+
multi: true,
|
|
13938
|
+
useFactory: () => {
|
|
13939
|
+
const injector = inject(Injector);
|
|
13940
|
+
return (control) => injector.get(EfLocalizedInputComponent).validateRequired(control);
|
|
13941
|
+
},
|
|
13942
|
+
},
|
|
13943
|
+
], template: "<div class=\"eli-head\">\n @if (labelKey()) {\n <span class=\"eli-label\" [id]=\"labelId\">\n <ef-label [labelKey]=\"labelKey()\" [for]=\"controlId(active()?.code ?? '')\" [required]=\"required()\" />\n </span>\n }\n <div class=\"eli-tabs\">\n <ef-tabs\n variant=\"pill\"\n [items]=\"tabItems()\"\n [value]=\"active()?.code ?? null\"\n [ariaLabelKey]=\"labelKey() || 'ef_localized_input_cultures'\"\n (valueChange)=\"select($event)\"\n />\n </div>\n</div>\n\n<div class=\"eli-panel\" role=\"tabpanel\" [id]=\"panelId\" [attr.aria-labelledby]=\"tabId(active()?.code ?? '')\">\n @for (c of active() ? [active()!] : []; track c.code) {\n @switch (effectiveMode()) {\n @case ('text') {\n <ef-input-text\n [variant]=\"variant() === 'comptoir' ? 'comptoir' : 'primeng'\"\n [inputId]=\"controlId(c.code)\"\n [name]=\"name() + '.' + c.code\"\n [dir]=\"c.dir\"\n [lang]=\"c.code\"\n [value]=\"activeText()\"\n [maxlength]=\"maxLength()\"\n [required]=\"required() && c.code === defaultCode()\"\n [errors]=\"activeErrors()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"activeReadOnly()\"\n [placeholderKey]=\"placeholderKey()\"\n [hintKey]=\"activeReadOnly() ? 'ef_localized_input_read_only_hint' : hintKey()\"\n [describedByExtra]=\"counterLimit() ? counterId : ''\"\n (valueChangeEvent)=\"setText(c.code, $event)\"\n />\n }\n @case ('textarea') {\n <ef-textarea\n [inputId]=\"controlId(c.code)\"\n [name]=\"name() + '.' + c.code\"\n [dir]=\"c.dir\"\n [lang]=\"c.code\"\n [rows]=\"rows()\"\n [value]=\"activeText()\"\n [maxlength]=\"maxLength()\"\n [required]=\"required() && c.code === defaultCode()\"\n [errors]=\"activeErrors()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"activeReadOnly()\"\n [placeholderKey]=\"placeholderKey()\"\n [hintKey]=\"activeReadOnly() ? 'ef_localized_input_read_only_hint' : hintKey()\"\n [describedByExtra]=\"counterLimit() ? counterId : ''\"\n (valueChangeEvent)=\"setText(c.code, $event)\"\n />\n }\n @case ('rich') {\n <!-- ef-rich-text, created from EF_RICH_TEXT (see createRich). -->\n <ng-container #richHost />\n }\n @case ('html') {\n <!-- The source stays ltr for every culture: raw HTML in an rtl\n textarea reads reversed (ADR-036). The preview takes the\n culture's direction. -->\n <ef-textarea\n mono\n dir=\"ltr\"\n [inputId]=\"controlId(c.code)\"\n [name]=\"name() + '.' + c.code\"\n [lang]=\"c.code\"\n [rows]=\"rows()\"\n [value]=\"activeText()\"\n [maxlength]=\"maxLength()\"\n [required]=\"required() && c.code === defaultCode()\"\n [errors]=\"activeErrors()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"activeReadOnly()\"\n [placeholderKey]=\"placeholderKey()\"\n [hintKey]=\"activeReadOnly() ? 'ef_localized_input_read_only_hint' : hintKey()\"\n [describedByExtra]=\"counterLimit() ? counterId : ''\"\n (valueChangeEvent)=\"setText(c.code, $event)\"\n />\n }\n }\n }\n\n @if (counterLimit(); as limit) {\n <span class=\"eli-counter\" data-counter [id]=\"counterId\" [class.is-over]=\"activeLength() > limit\">\n <bdi dir=\"ltr\">{{ activeLength() }} / {{ limit }}</bdi>\n @if (counterHintKey()) {\n <span class=\"eli-counter__sr\">{{ counterHintKey() | translate: { max: limit } }}</span>\n }\n </span>\n @if (counterOverKey()) {\n <!-- Always present, so a screen reader hears the text appear. -->\n <span class=\"eli-counter__sr\" data-over-message aria-live=\"polite\">\n @if (activeLength() > limit) {\n {{ counterOverKey() | translate: { max: limit } }}\n }\n </span>\n }\n }\n\n @if (effectiveMode() === 'html' && activeText().trim()) {\n @if (active(); as c) {\n <!-- Angular's default [innerHTML] sanitising strips scripts and handlers. -->\n <div class=\"eli-preview\" data-preview [attr.dir]=\"c.dir\" [attr.lang]=\"c.code\" [innerHTML]=\"activeText()\"></div>\n }\n }\n\n @if (fieldErrors(); as messages) {\n <div class=\"eli-errors\" data-field-errors role=\"alert\" aria-live=\"polite\">\n @for (message of messages; track message) {\n <small class=\"text-danger block\">{{ message | translate }}</small>\n }\n </div>\n }\n\n @if (errorsElsewhere(); as others) {\n @if (others.length) {\n <small class=\"eli-elsewhere text-danger block\" data-errors-elsewhere role=\"status\">\n {{ 'ef_localized_input_errors_in_other' | translate }}\n @for (c of others; track c.code; let last = $last) {\n {{ c.labelKey | translate }}{{ last ? '' : ',' }}\n }\n </small>\n }\n }\n\n @if (activeReadOnly()) {\n <div class=\"eli-link\">\n <ng-content select=\"[read-only-link]\" />\n </div>\n }\n</div>\n", styles: [":host{position:relative;display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-2);min-width:0}.eli-head{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--s-2);min-width:0}.eli-label{min-width:0}.eli-tabs{min-width:0;max-width:100%;overflow-x:auto}.eli-panel{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-2);min-width:0}.eli-counter{position:relative;font-size:12px;color:var(--text-mute);text-align:end;font-variant-numeric:tabular-nums}.eli-counter.is-over{color:var(--st-pending-fg);font-weight:600}.eli-counter__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.eli-preview{min-width:0;overflow-x:auto;overflow-wrap:anywhere;padding:var(--s-3);border:1px solid var(--rule);border-radius:var(--r-sm);background:var(--paper-alt);color:var(--text);font-size:13.5px;line-height:1.55}.eli-link{font-size:12px}@media(max-width:767px){.eli-tabs{--hit: var(--hit-touch);flex:1 1 100%}}\n"] }]
|
|
13944
|
+
}], ctorParameters: () => [], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], advisedLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "advisedLength", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], readOnlyCultures: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnlyCultures", required: false }] }], labelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelKey", required: false }] }], placeholderKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholderKey", required: false }] }], hintKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintKey", required: false }] }], counterHintKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "counterHintKey", required: false }] }], counterOverKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "counterOverKey", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], cultures: [{ type: i0.Input, args: [{ isSignal: true, alias: "cultures", required: false }] }], valueChangeEvent: [{ type: i0.Output, args: ["valueChangeEvent"] }], richHost: [{ type: i0.ViewChild, args: ['richHost', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
|
|
13945
|
+
|
|
13946
|
+
/**
|
|
13947
|
+
* The content cultures the SEO fields start from, shared with `ef-localized-input`.
|
|
13948
|
+
* @deprecated use `EF_DEFAULT_CONTENT_CULTURES` from `@elasticias/core`.
|
|
13949
|
+
*/
|
|
13950
|
+
const EF_SEO_DEFAULT_LOCALES = EF_DEFAULT_CONTENT_CULTURES;
|
|
13951
|
+
/**
|
|
13952
|
+
* SEO title and description in every content language, each an
|
|
13953
|
+
* `ef-localized-input` with a counter against what a search engine shows
|
|
13954
|
+
* (60 / 160, read out to screen readers), capped at the server's limits
|
|
13955
|
+
* (256 / 512), and the shared `ef-seo-preview` of the default language's
|
|
13956
|
+
* result with the entity's own title and description as the fallback the shop
|
|
13957
|
+
* uses. Card-less: each screen wraps it in its own `ef-card`.
|
|
13958
|
+
*
|
|
13959
|
+
* The controls are named `seoTitle` and `seoDescription`, so under
|
|
13960
|
+
* `[efServerErrors]` a `seoTitle.ar` error lands on the Arabic tab and shows
|
|
13961
|
+
* under its field. Languages come from `EF_CONTENT_CULTURES` unless `cultures`
|
|
13962
|
+
* is set.
|
|
13963
|
+
*
|
|
13964
|
+
* i18n keys the app's bundles must define, besides those of
|
|
13965
|
+
* `ef-localized-input`:
|
|
13966
|
+
*
|
|
13967
|
+
* | key | fr | ar | en |
|
|
13968
|
+
* |---|---|---|---|
|
|
13969
|
+
* | `ef_seo_fields_title_label` | Titre SEO | عنوان SEO | SEO title |
|
|
13970
|
+
* | `ef_seo_fields_description_label` | Description SEO | وصف SEO | SEO description |
|
|
13971
|
+
* | `ef_seo_fields_counter_hint` | Au-delà de {{max}} caractères, Google coupe le texte. | بعد {{max}} حرفا، يقتطع Google النص. | Past {{max}} characters, Google cuts the text. |
|
|
13972
|
+
* | `ef_seo_fields_over_hint` | Le texte dépasse {{max}} caractères. | النص يتجاوز {{max}} حرفا. | The text is over {{max}} characters. |
|
|
13973
|
+
* | `ef_seo_fields_preview` | Aperçu dans Google | المعاينة في Google | Google preview |
|
|
13974
|
+
* | `ef_seo_fields_fallback_hint` | Vide : la boutique reprend le titre et la description. | فارغ: يستخدم المتجر العنوان والوصف. | Empty: the shop uses the title and description. |
|
|
13473
13975
|
*
|
|
13474
13976
|
* ```html
|
|
13475
|
-
* <ef-seo-fields [seoTitle]="p.seoTitle"
|
|
13977
|
+
* <ef-seo-fields [seoTitle]="p.seoTitle" [seoDescription]="p.seoDescription"
|
|
13978
|
+
* [fallbackTitle]="p.title" [fallbackDescription]="p.description"
|
|
13979
|
+
* [previewUrl]="url()" (seoChange)="patch($event)" />
|
|
13476
13980
|
* ```
|
|
13477
13981
|
*/
|
|
13478
13982
|
class EfSeoFieldsComponent {
|
|
13479
|
-
seoTitle = input(
|
|
13480
|
-
seoDescription = input(
|
|
13481
|
-
seoTitleTranslations = input({}, ...(ngDevMode ? [{ debugName: "seoTitleTranslations" }] : /* istanbul ignore next */ []));
|
|
13482
|
-
seoDescriptionTranslations = input({}, ...(ngDevMode ? [{ debugName: "seoDescriptionTranslations" }] : /* istanbul ignore next */ []));
|
|
13983
|
+
seoTitle = input(null, ...(ngDevMode ? [{ debugName: "seoTitle" }] : /* istanbul ignore next */ []));
|
|
13984
|
+
seoDescription = input(null, ...(ngDevMode ? [{ debugName: "seoDescription" }] : /* istanbul ignore next */ []));
|
|
13483
13985
|
/** The entity's own texts, which the shop uses when SEO is empty. */
|
|
13484
|
-
fallbackTitle = input(
|
|
13485
|
-
fallbackDescription = input(
|
|
13986
|
+
fallbackTitle = input(null, ...(ngDevMode ? [{ debugName: "fallbackTitle" }] : /* istanbul ignore next */ []));
|
|
13987
|
+
fallbackDescription = input(null, ...(ngDevMode ? [{ debugName: "fallbackDescription" }] : /* istanbul ignore next */ []));
|
|
13486
13988
|
/** The page address shown in the preview, computed by the app. */
|
|
13487
13989
|
previewUrl = input('', ...(ngDevMode ? [{ debugName: "previewUrl" }] : /* istanbul ignore next */ []));
|
|
13488
13990
|
titleMax = input(256, ...(ngDevMode ? [{ debugName: "titleMax" }] : /* istanbul ignore next */ []));
|
|
13489
13991
|
descriptionMax = input(512, ...(ngDevMode ? [{ debugName: "descriptionMax" }] : /* istanbul ignore next */ []));
|
|
13490
13992
|
titleAdvised = input(60, ...(ngDevMode ? [{ debugName: "titleAdvised" }] : /* istanbul ignore next */ []));
|
|
13491
13993
|
descriptionAdvised = input(160, ...(ngDevMode ? [{ debugName: "descriptionAdvised" }] : /* istanbul ignore next */ []));
|
|
13492
|
-
|
|
13994
|
+
/** Overrides the `EF_CONTENT_CULTURES` list for both fields. */
|
|
13995
|
+
cultures = input(undefined, ...(ngDevMode ? [{ debugName: "cultures" }] : /* istanbul ignore next */ []));
|
|
13493
13996
|
seoChange = output();
|
|
13494
|
-
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
const
|
|
13498
|
-
|
|
13499
|
-
|
|
13500
|
-
|
|
13501
|
-
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
name(locale, field) {
|
|
13507
|
-
const base = field === 'title' ? 'seoTitle' : 'seoDescription';
|
|
13508
|
-
return locale === 'fr' ? base : `${base}${locale.charAt(0).toUpperCase()}${locale.slice(1)}`;
|
|
13509
|
-
}
|
|
13510
|
-
setText(locale, field, value) {
|
|
13511
|
-
if (locale === 'fr') {
|
|
13512
|
-
this.seoChange.emit(field === 'title' ? { seoTitle: value } : { seoDescription: value });
|
|
13513
|
-
return;
|
|
13514
|
-
}
|
|
13515
|
-
const key = field === 'title' ? 'seoTitleTranslations' : 'seoDescriptionTranslations';
|
|
13516
|
-
const next = { ...((field === 'title' ? this.seoTitleTranslations() : this.seoDescriptionTranslations()) ?? {}) };
|
|
13517
|
-
// A cleared field removes the entry, so the shop falls back instead of showing nothing.
|
|
13518
|
-
if (value)
|
|
13519
|
-
next[locale] = value;
|
|
13520
|
-
else
|
|
13521
|
-
delete next[locale];
|
|
13522
|
-
this.seoChange.emit({ [key]: next });
|
|
13997
|
+
contentCultures = inject(EF_CONTENT_CULTURES);
|
|
13998
|
+
/** The language the preview shows: the tenant's default if listed, else the first listed. */
|
|
13999
|
+
previewCode = computed(() => {
|
|
14000
|
+
const list = this.cultures() ?? this.contentCultures().cultures;
|
|
14001
|
+
const preferred = this.contentCultures().defaultCulture;
|
|
14002
|
+
return list.some(c => c.code === preferred) ? preferred : (list[0]?.code ?? preferred);
|
|
14003
|
+
}, ...(ngDevMode ? [{ debugName: "previewCode" }] : /* istanbul ignore next */ []));
|
|
14004
|
+
previewTitle = computed(() => this.shown(this.seoTitle(), this.fallbackTitle()), ...(ngDevMode ? [{ debugName: "previewTitle" }] : /* istanbul ignore next */ []));
|
|
14005
|
+
previewDescription = computed(() => this.shown(this.seoDescription(), this.fallbackDescription()), ...(ngDevMode ? [{ debugName: "previewDescription" }] : /* istanbul ignore next */ []));
|
|
14006
|
+
shown(seo, fallback) {
|
|
14007
|
+
const code = this.previewCode();
|
|
14008
|
+
return (seo?.[code]?.trim() || fallback?.[code]?.trim() || '');
|
|
13523
14009
|
}
|
|
13524
|
-
previewTitle = computed(() => (this.seoTitle() || this.fallbackTitle() || '').trim(), ...(ngDevMode ? [{ debugName: "previewTitle" }] : /* istanbul ignore next */ []));
|
|
13525
|
-
previewDescription = computed(() => (this.seoDescription() || this.fallbackDescription() || '').trim(), ...(ngDevMode ? [{ debugName: "previewDescription" }] : /* istanbul ignore next */ []));
|
|
13526
14010
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfSeoFieldsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13527
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.
|
|
14011
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.11", type: EfSeoFieldsComponent, isStandalone: true, selector: "ef-seo-fields", inputs: { seoTitle: { classPropertyName: "seoTitle", publicName: "seoTitle", isSignal: true, isRequired: false, transformFunction: null }, seoDescription: { classPropertyName: "seoDescription", publicName: "seoDescription", isSignal: true, isRequired: false, transformFunction: null }, fallbackTitle: { classPropertyName: "fallbackTitle", publicName: "fallbackTitle", isSignal: true, isRequired: false, transformFunction: null }, fallbackDescription: { classPropertyName: "fallbackDescription", publicName: "fallbackDescription", isSignal: true, isRequired: false, transformFunction: null }, previewUrl: { classPropertyName: "previewUrl", publicName: "previewUrl", isSignal: true, isRequired: false, transformFunction: null }, titleMax: { classPropertyName: "titleMax", publicName: "titleMax", isSignal: true, isRequired: false, transformFunction: null }, descriptionMax: { classPropertyName: "descriptionMax", publicName: "descriptionMax", isSignal: true, isRequired: false, transformFunction: null }, titleAdvised: { classPropertyName: "titleAdvised", publicName: "titleAdvised", isSignal: true, isRequired: false, transformFunction: null }, descriptionAdvised: { classPropertyName: "descriptionAdvised", publicName: "descriptionAdvised", isSignal: true, isRequired: false, transformFunction: null }, cultures: { classPropertyName: "cultures", publicName: "cultures", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { seoChange: "seoChange" }, ngImport: i0, template: "<div class=\"seo-body\">\n <p class=\"seo-note text-mute\">{{ 'ef_seo_fields_fallback_hint' | translate }}</p>\n\n <ef-localized-input\n name=\"seoTitle\"\n labelKey=\"ef_seo_fields_title_label\"\n [value]=\"seoTitle()\"\n [cultures]=\"cultures()\"\n [maxLength]=\"titleMax()\"\n [advisedLength]=\"titleAdvised()\"\n counterHintKey=\"ef_seo_fields_counter_hint\"\n counterOverKey=\"ef_seo_fields_over_hint\"\n (valueChangeEvent)=\"seoChange.emit({ seoTitle: $event })\"\n />\n\n <ef-localized-input\n name=\"seoDescription\"\n mode=\"textarea\"\n [rows]=\"3\"\n labelKey=\"ef_seo_fields_description_label\"\n [value]=\"seoDescription()\"\n [cultures]=\"cultures()\"\n [maxLength]=\"descriptionMax()\"\n [advisedLength]=\"descriptionAdvised()\"\n counterHintKey=\"ef_seo_fields_counter_hint\"\n counterOverKey=\"ef_seo_fields_over_hint\"\n (valueChangeEvent)=\"seoChange.emit({ seoDescription: $event })\"\n />\n\n <ef-seo-preview\n labelKey=\"ef_seo_fields_preview\"\n [contentLang]=\"previewCode()\"\n [pageTitle]=\"previewTitle()\"\n [url]=\"previewUrl()\"\n [description]=\"previewDescription()\"\n />\n</div>\n", styles: [":host{display:block;min-width:0}.seo-body{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-3);min-width:0}.seo-note{margin:0;font-size:12px}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "component", type: EfLocalizedInputComponent, selector: "ef-localized-input", inputs: ["name", "value", "mode", "rows", "maxLength", "advisedLength", "required", "readOnlyCultures", "labelKey", "placeholderKey", "hintKey", "counterHintKey", "counterOverKey", "variant", "disabled", "errors", "cultures"], outputs: ["valueChangeEvent"] }, { kind: "component", type: EfSeoPreviewComponent, selector: "ef-seo-preview", inputs: ["pageTitle", "url", "description", "labelKey", "titleMaxLength", "descriptionMaxLength", "contentLang"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
13528
14012
|
}
|
|
13529
14013
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfSeoFieldsComponent, decorators: [{
|
|
13530
14014
|
type: Component,
|
|
13531
|
-
args: [{ selector: 'ef-seo-fields', standalone: true, imports: [TranslateModule,
|
|
13532
|
-
}], propDecorators: { seoTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "seoTitle", required: false }] }], seoDescription: [{ type: i0.Input, args: [{ isSignal: true, alias: "seoDescription", required: false }] }],
|
|
14015
|
+
args: [{ selector: 'ef-seo-fields', standalone: true, imports: [TranslateModule, EfLocalizedInputComponent, EfSeoPreviewComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"seo-body\">\n <p class=\"seo-note text-mute\">{{ 'ef_seo_fields_fallback_hint' | translate }}</p>\n\n <ef-localized-input\n name=\"seoTitle\"\n labelKey=\"ef_seo_fields_title_label\"\n [value]=\"seoTitle()\"\n [cultures]=\"cultures()\"\n [maxLength]=\"titleMax()\"\n [advisedLength]=\"titleAdvised()\"\n counterHintKey=\"ef_seo_fields_counter_hint\"\n counterOverKey=\"ef_seo_fields_over_hint\"\n (valueChangeEvent)=\"seoChange.emit({ seoTitle: $event })\"\n />\n\n <ef-localized-input\n name=\"seoDescription\"\n mode=\"textarea\"\n [rows]=\"3\"\n labelKey=\"ef_seo_fields_description_label\"\n [value]=\"seoDescription()\"\n [cultures]=\"cultures()\"\n [maxLength]=\"descriptionMax()\"\n [advisedLength]=\"descriptionAdvised()\"\n counterHintKey=\"ef_seo_fields_counter_hint\"\n counterOverKey=\"ef_seo_fields_over_hint\"\n (valueChangeEvent)=\"seoChange.emit({ seoDescription: $event })\"\n />\n\n <ef-seo-preview\n labelKey=\"ef_seo_fields_preview\"\n [contentLang]=\"previewCode()\"\n [pageTitle]=\"previewTitle()\"\n [url]=\"previewUrl()\"\n [description]=\"previewDescription()\"\n />\n</div>\n", styles: [":host{display:block;min-width:0}.seo-body{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-3);min-width:0}.seo-note{margin:0;font-size:12px}\n"] }]
|
|
14016
|
+
}], propDecorators: { seoTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "seoTitle", required: false }] }], seoDescription: [{ type: i0.Input, args: [{ isSignal: true, alias: "seoDescription", required: false }] }], fallbackTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "fallbackTitle", required: false }] }], fallbackDescription: [{ type: i0.Input, args: [{ isSignal: true, alias: "fallbackDescription", required: false }] }], previewUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewUrl", required: false }] }], titleMax: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleMax", required: false }] }], descriptionMax: [{ type: i0.Input, args: [{ isSignal: true, alias: "descriptionMax", required: false }] }], titleAdvised: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleAdvised", required: false }] }], descriptionAdvised: [{ type: i0.Input, args: [{ isSignal: true, alias: "descriptionAdvised", required: false }] }], cultures: [{ type: i0.Input, args: [{ isSignal: true, alias: "cultures", required: false }] }], seoChange: [{ type: i0.Output, args: ["seoChange"] }] } });
|
|
13533
14017
|
|
|
13534
14018
|
/**
|
|
13535
14019
|
* A button that opens the native file picker and emits the chosen `File`.
|
|
@@ -14439,5 +14923,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
14439
14923
|
* Generated bundle index. Do not edit.
|
|
14440
14924
|
*/
|
|
14441
14925
|
|
|
14442
|
-
export { EF_BADGE_BG_COLORS, EF_BADGE_BG_LIGHT_COLORS, EF_BADGE_BORDER_COLORS, EF_BADGE_DEFAULTS, EF_BADGE_TEXT_COLORS, EF_CHART_PALETTE, EF_DATATABLE_ACTIONS_DEFAULTS, EF_DATATABLE_COLUMN_DEFAULTS, EF_DATATABLE_DEFAULTS, EF_DATA_CARD_MOBILE_LAYOUT, EF_HTML_PREVIEW_DEFAULT_TITLE_KEY, EF_SEO_DEFAULT_LOCALES, EF_STATUS_COLORS, EF_STATUS_COLOR_ALIASES, EfAboutDialogComponent, EfActivationFilterComponent, EfAppMainComponent, EfAppShellComponent, EfAppShellMobileComponent, EfAppTopComponent, EfBadgeComponent, EfBlockUiComponent, EfBlockableDivComponent, EfBottomSheetComponent, EfBuildStampComponent, EfBulkBarComponent, EfButtonComponent, EfButtonGroupComponent, EfCardComponent, EfChangeHistoryComponent, EfChangePasswordComponent, EfChartComponent, EfCheckboxComponent, EfClearButtonComponent, EfColumnHeaderTemplateDirective, EfColumnTemplateDirective, EfCompactPipe, EfConfirmDialogComponent, EfCurrencyPipe, EfDataCardComponent, EfDatatableActionBarComponent, EfDatatableComponent, EfDatepickerAdvancedComponent, EfDatepickerComponent, EfDetailToolbarComponent, EfDialogComponent, EfEmailMetricsCardComponent, EfEmptyStateComponent, EfFabComponent, EfFieldsetComponent, EfFileUploadComponent, EfFilterDrawerComponent, EfFilterPillComponent, EfFormGridComponent, EfHtmlPreviewComponent, EfIdentityThumbComponent, EfInputNumberComponent, EfInputTextComponent, EfKpiCardComponent, EfLabelComponent, EfModuleRailComponent, EfModuleSideComponent, EfMultiSelectComponent, EfOrderBuilderComponent, EfOrderSummaryComponent, EfOverflowTooltipDirective, EfPagerComponent, EfPasswordComponent, EfPdfPreviewComponent, EfPillGroupComponent, EfPresetPillComponent, EfPriceDisplayComponent, EfProductCatalogueComponent, EfProductCatalogueFilterComponent, EfProductPickerComponent, EfProductTypeaheadComponent, EfProfileChipComponent, EfProfileMenuComponent, EfPulseComponent, EfQuantitySelectorComponent, EfQuantityStepperComponent, EfRadioComponent, EfRankListComponent, EfReadOnlyDirective, EfRowActionsComponent, EfSearchToolbarComponent, EfSelectButtonComponent, EfSelectComponent, EfSeoFieldsComponent, EfSeoPreviewComponent, EfServerErrorsDirective, EfSessionIdleDialogComponent, EfShortcutsDialogComponent, EfSkeletonComponent, EfSmartBarComponent, EfStatsComponent, EfStatusChipComponent, EfTabPanelDirective, EfTabsComponent, EfTextareaComponent, EfThemeConfiguratorComponent, EfThemeToggleComponent, EfTimelineComponent, EfToastRegionComponent, EfToggleSwitchComponent, EfToolbarComponent, EfTooltipDirective, EfTotalsComponent, OrderEntityHelper, OrderLineItemHelper, TruncatePipe, buildChartConfig, defaultUnitPrice, getColumnAlignment, mergeColumnDefaults, resolveEfStatusColor };
|
|
14926
|
+
export { AbstractEfFormControl, EF_BADGE_BG_COLORS, EF_BADGE_BG_LIGHT_COLORS, EF_BADGE_BORDER_COLORS, EF_BADGE_DEFAULTS, EF_BADGE_TEXT_COLORS, EF_CHART_PALETTE, EF_DATATABLE_ACTIONS_DEFAULTS, EF_DATATABLE_COLUMN_DEFAULTS, EF_DATATABLE_DEFAULTS, EF_DATA_CARD_MOBILE_LAYOUT, EF_HTML_PREVIEW_DEFAULT_TITLE_KEY, EF_RICH_TEXT, EF_SEO_DEFAULT_LOCALES, EF_STATUS_COLORS, EF_STATUS_COLOR_ALIASES, EfAboutDialogComponent, EfActivationFilterComponent, EfAppMainComponent, EfAppShellComponent, EfAppShellMobileComponent, EfAppTopComponent, EfBadgeComponent, EfBlockUiComponent, EfBlockableDivComponent, EfBottomSheetComponent, EfBuildStampComponent, EfBulkBarComponent, EfButtonComponent, EfButtonGroupComponent, EfCardComponent, EfChangeHistoryComponent, EfChangePasswordComponent, EfChartComponent, EfCheckboxComponent, EfClearButtonComponent, EfColumnHeaderTemplateDirective, EfColumnTemplateDirective, EfCompactPipe, EfConfirmDialogComponent, EfCurrencyPipe, EfDataCardComponent, EfDatatableActionBarComponent, EfDatatableComponent, EfDatepickerAdvancedComponent, EfDatepickerComponent, EfDetailToolbarComponent, EfDialogComponent, EfEmailMetricsCardComponent, EfEmptyStateComponent, EfFabComponent, EfFieldsetComponent, EfFileUploadComponent, EfFilterDrawerComponent, EfFilterPillComponent, EfFormGridComponent, EfHtmlPreviewComponent, EfIdentityThumbComponent, EfInputNumberComponent, EfInputTextComponent, EfKpiCardComponent, EfLabelComponent, EfLocalizedInputComponent, EfModuleRailComponent, EfModuleSideComponent, EfMultiSelectComponent, EfOrderBuilderComponent, EfOrderSummaryComponent, EfOverflowTooltipDirective, EfPagerComponent, EfPasswordComponent, EfPdfPreviewComponent, EfPillGroupComponent, EfPresetPillComponent, EfPriceDisplayComponent, EfProductCatalogueComponent, EfProductCatalogueFilterComponent, EfProductPickerComponent, EfProductTypeaheadComponent, EfProfileChipComponent, EfProfileMenuComponent, EfPulseComponent, EfQuantitySelectorComponent, EfQuantityStepperComponent, EfRadioComponent, EfRankListComponent, EfReadOnlyDirective, EfRowActionsComponent, EfSearchToolbarComponent, EfSelectButtonComponent, EfSelectComponent, EfSeoFieldsComponent, EfSeoPreviewComponent, EfServerErrorsDirective, EfSessionIdleDialogComponent, EfShortcutsDialogComponent, EfSkeletonComponent, EfSmartBarComponent, EfStatsComponent, EfStatusChipComponent, EfTabPanelDirective, EfTabsComponent, EfTextareaComponent, EfThemeConfiguratorComponent, EfThemeToggleComponent, EfTimelineComponent, EfToastRegionComponent, EfToggleSwitchComponent, EfToolbarComponent, EfTooltipDirective, EfTotalsComponent, OrderEntityHelper, OrderLineItemHelper, TruncatePipe, buildChartConfig, defaultUnitPrice, getColumnAlignment, mergeColumnDefaults, plainTextLength, resolveEfStatusColor };
|
|
14443
14927
|
//# sourceMappingURL=elasticias-ui.mjs.map
|