@quadrel-enterprise-ui/framework 20.14.0 → 20.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,8 +18,8 @@ import { NG_VALUE_ACCESSOR, FormsModule, UntypedFormControl, UntypedFormArray, U
18
18
  import { ComponentPortal } from '@angular/cdk/portal';
19
19
  import { OverlayPositionBuilder, Overlay } from '@angular/cdk/overlay';
20
20
  import isNumber from 'lodash/isNumber';
21
- import { EventSourcePolyfill } from 'event-source-polyfill';
22
21
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
22
+ import { EventSourcePolyfill } from 'event-source-polyfill';
23
23
  import { DomSanitizer } from '@angular/platform-browser';
24
24
  import * as i3$1 from 'ngx-editor';
25
25
  import { Editor, NgxEditorModule } from 'ngx-editor';
@@ -35,6 +35,8 @@ import { ActiveDescendantKeyManager } from '@angular/cdk/a11y';
35
35
  import * as i1$1 from '@ngrx/store';
36
36
  import { createAction, props, createReducer, on, createSelector, createFeatureSelector, Store, StoreModule } from '@ngrx/store';
37
37
  import { diff } from 'deep-object-diff';
38
+ import * as i1$2 from '@angular/cdk/scrolling';
39
+ import { ScrollingModule } from '@angular/cdk/scrolling';
38
40
  import isObject from 'lodash/isObject';
39
41
  import omit from 'lodash/omit';
40
42
  import { Directionality } from '@angular/cdk/bidi';
@@ -973,6 +975,8 @@ class QdButtonAdditionalInfoComponent {
973
975
  return 'warningHexFilled';
974
976
  case 'info':
975
977
  return 'exclamationCircle';
978
+ default:
979
+ return '';
976
980
  }
977
981
  }
978
982
  get infoType() {
@@ -1604,6 +1608,24 @@ const updateHtmlLang = (lang) => {
1604
1608
  const htmlNode = document.documentElement;
1605
1609
  htmlNode.setAttribute('lang', lang);
1606
1610
  };
1611
+ const SERVICE_NAV_LOCALE_DEFAULTS = {
1612
+ DE: 'de-CH',
1613
+ IT: 'it-CH',
1614
+ FR: 'fr-CH',
1615
+ EN: 'en-GB'
1616
+ };
1617
+ const determineLocale = (serviceNavLanguage, browserLocales) => {
1618
+ const browserLocale = browserLocales?.[0] ?? navigator.language;
1619
+ if (!serviceNavLanguage) {
1620
+ const browserLocaleUpper = browserLocale.toUpperCase();
1621
+ return SERVICE_NAV_LOCALE_DEFAULTS[browserLocaleUpper] ?? browserLocale;
1622
+ }
1623
+ const serviceNavLangUpper = serviceNavLanguage.toUpperCase();
1624
+ const browserLanguage = browserLocale.split('-')[0].toUpperCase();
1625
+ if (browserLanguage === serviceNavLangUpper)
1626
+ return browserLocale;
1627
+ return SERVICE_NAV_LOCALE_DEFAULTS[serviceNavLangUpper] ?? browserLocale;
1628
+ };
1607
1629
 
1608
1630
  const constantCase = (str) => upperCase(str).replace(/ /g, '_');
1609
1631
 
@@ -2058,8 +2080,6 @@ class QdMockPopoverOnClickDirective {
2058
2080
  closed = new EventEmitter();
2059
2081
  _open = false;
2060
2082
  _embeddedView;
2061
- ngOnInit() { }
2062
- ngOnDestroy() { }
2063
2083
  show(event) {
2064
2084
  if (this.qdPopoverStopPropagation)
2065
2085
  event.stopPropagation();
@@ -6636,6 +6656,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
6636
6656
  }]
6637
6657
  }] });
6638
6658
 
6659
+ const QD_SAFE_BOTTOM_OFFSET = new InjectionToken('QD_SAFE_BOTTOM_OFFSET');
6660
+
6639
6661
  let QdFileSizePipe$1 = class QdFileSizePipe {
6640
6662
  translate = inject(TranslateService, { optional: true });
6641
6663
  transform(bytes) {
@@ -6687,6 +6709,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
6687
6709
  }]
6688
6710
  }] });
6689
6711
 
6712
+ const QD_POPOVER_TOP_FIRST = new InjectionToken('QD_POPOVER_TOP_FIRST');
6713
+
6690
6714
  class QdProjectionGuardComponent {
6691
6715
  elementRef = inject(ElementRef);
6692
6716
  isDisabled = false;
@@ -6715,406 +6739,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
6715
6739
  type: Input
6716
6740
  }] } });
6717
6741
 
6718
- class QdRwdDisabledDirective {
6719
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdRwdDisabledDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
6720
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.18", type: QdRwdDisabledDirective, isStandalone: false, selector: "[qdRwdDisabled]", host: { classAttribute: "qd-rwd-disabled" }, ngImport: i0 });
6721
- }
6722
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdRwdDisabledDirective, decorators: [{
6723
- type: Directive,
6724
- args: [{
6725
- selector: '[qdRwdDisabled]',
6726
- host: { class: 'qd-rwd-disabled' },
6727
- standalone: false
6728
- }]
6729
- }] });
6730
-
6731
- var breakpoints$1 = {
6732
- xs: 320,
6733
- sm: 600,
6734
- md: 960,
6735
- lg: 1280,
6736
- xl: 1600,
6737
- xxl: 1800
6738
- };
6739
- var panel = {
6740
- sm: 432,
6741
- md: 588,
6742
- lg: 720
6743
- };
6744
- var base = {
6745
- fontsize: 16
6746
- };
6747
- var globalVars = {
6748
- breakpoints: breakpoints$1,
6749
- panel: panel,
6750
- base: base
6751
- };
6752
-
6753
- const convertPxToRem = (pixel) => `${parseFloat((pixel / globalVars.base.fontsize).toFixed(3))}rem`;
6754
-
6755
- class QdTooltipComponent {
6756
- content;
6757
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdTooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6758
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdTooltipComponent, isStandalone: false, selector: "qd-tooltip", inputs: { content: "content" }, ngImport: i0, template: "<ng-container *ngIf=\"content?.headline\">\n <strong>{{ content.headline }}</strong>\n</ng-container>\n\n<ng-container *ngFor=\"let paragraph of content.paragraphs\">\n <p>{{ paragraph }}</p>\n</ng-container>\n", styles: [":host{box-shadow:0 0 .625rem #979797;display:block;width:100%;max-width:16rem;padding:.5rem;border-radius:.5rem;background-color:#000;color:#fff;font-size:.75rem;line-height:1rem}:host strong,:host p{display:block}:host p{margin:0 0 .5rem}:host p:last-child{margin-bottom:0}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
6759
- }
6760
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdTooltipComponent, decorators: [{
6761
- type: Component,
6762
- args: [{ selector: 'qd-tooltip', standalone: false, template: "<ng-container *ngIf=\"content?.headline\">\n <strong>{{ content.headline }}</strong>\n</ng-container>\n\n<ng-container *ngFor=\"let paragraph of content.paragraphs\">\n <p>{{ paragraph }}</p>\n</ng-container>\n", styles: [":host{box-shadow:0 0 .625rem #979797;display:block;width:100%;max-width:16rem;padding:.5rem;border-radius:.5rem;background-color:#000;color:#fff;font-size:.75rem;line-height:1rem}:host strong,:host p{display:block}:host p{margin:0 0 .5rem}:host p:last-child{margin-bottom:0}\n"] }]
6763
- }], propDecorators: { content: [{
6764
- type: Input
6765
- }] } });
6766
-
6767
- const TARGET_SELECTOR = '.qd-intersection-target';
6768
- const SHOW_EVENTS = ['mouseenter', 'mousemove'];
6769
- const HIDE_EVENTS = ['mouseleave', 'click'];
6770
- const HIDE_DELAY = 300;
6771
- const OVERLAY_WIDTH = 280;
6772
- const UNSUBSCRIBE_IMMEDIATELY = true;
6773
- const THRESHOLD = 1;
6774
- /**
6775
- * QdTooltipAtIntersectionDirective provides a tooltip. This will be triggered if the content is intersected.
6776
- *
6777
- * * Selector: [qdTooltipAtIntersection]
6778
- * * Target Selector: .qd-intersection-target
6779
- *
6780
- * The IntersectionObserver API is used for the implementation.
6781
- * * @see https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver
6782
- *
6783
- * * Note: The intersection of the target is calculated by the IntersectionObserver only once, initially (can be extended later if required). After that it will be unsubscribed immediately.
6784
- * */
6785
- class QdTooltipAtIntersectionDirective {
6786
- _host = inject(ElementRef);
6787
- _positionBuilder = inject(OverlayPositionBuilder);
6788
- _overlay = inject(Overlay);
6789
- _overlayRef;
6790
- _target;
6791
- _observer$;
6792
- _isIntersected = false;
6793
- _destroyed$ = new Subject();
6794
- ngAfterViewInit() {
6795
- this.setTarget();
6796
- this.observeTarget();
6797
- this.createOverlay();
6798
- this.subscribeShow();
6799
- this.subscribeHide();
6800
- }
6801
- ngOnDestroy() {
6802
- this._observer$.unobserve(this._target);
6803
- this._destroyed$.next();
6804
- this._destroyed$.complete();
6805
- }
6806
- setTarget() {
6807
- this._target = this._host.nativeElement.querySelector(TARGET_SELECTOR);
6808
- }
6809
- observeTarget() {
6810
- const options = {
6811
- root: this._host.nativeElement,
6812
- threshold: THRESHOLD
6813
- };
6814
- this._observer$ = new IntersectionObserver(entries => {
6815
- this._isIntersected = entries[0].intersectionRatio < 1;
6816
- if (this._isIntersected) {
6817
- this._setStyles();
6818
- if (UNSUBSCRIBE_IMMEDIATELY)
6819
- this._observer$.unobserve(this._target);
6820
- }
6821
- }, options);
6822
- this._observer$.observe(this._target);
6823
- }
6824
- _setStyles() {
6825
- this._target.style.overflow = 'hidden';
6826
- this._target.style.textOverflow = 'ellipsis';
6827
- this._target.style.cursor = 'help';
6828
- }
6829
- createOverlay() {
6830
- this._overlayRef = this._overlay.create({
6831
- positionStrategy: this._positionBuilder
6832
- .flexibleConnectedTo(this._host)
6833
- .withPositions([{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' }]),
6834
- width: convertPxToRem(OVERLAY_WIDTH)
6835
- });
6836
- }
6837
- subscribeShow() {
6838
- merge(...SHOW_EVENTS.map(event => fromEvent(this._host.nativeElement, event)))
6839
- .pipe(takeUntil(this._destroyed$), filter(() => !this._overlayRef.hasAttached() && this._isIntersected))
6840
- .subscribe(() => {
6841
- const content = this.getContent();
6842
- const tooltipPortal = new ComponentPortal(QdTooltipComponent);
6843
- const tooltipRef = this._overlayRef.attach(tooltipPortal);
6844
- tooltipRef.instance.content = content;
6845
- });
6846
- }
6847
- subscribeHide() {
6848
- merge(...HIDE_EVENTS.map(event => fromEvent(this._host.nativeElement, event)))
6849
- .pipe(takeUntil(this._destroyed$), filter(() => this._overlayRef.hasAttached()), debounceTime(HIDE_DELAY))
6850
- .subscribe(() => this._overlayRef.detach());
6851
- }
6852
- getContent() {
6853
- return {
6854
- headline: this._target.getAttribute('data-tooltip-headline') || undefined,
6855
- paragraphs: [this._target.textContent?.trim() || '']
6856
- };
6857
- }
6858
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdTooltipAtIntersectionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
6859
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.18", type: QdTooltipAtIntersectionDirective, isStandalone: false, selector: "[qdTooltipAtIntersection]", ngImport: i0 });
6860
- }
6861
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdTooltipAtIntersectionDirective, decorators: [{
6862
- type: Directive,
6863
- args: [{
6864
- selector: '[qdTooltipAtIntersection]',
6865
- standalone: false
6866
- }]
6867
- }] });
6868
-
6869
- class QdVisuallyHiddenDirective {
6870
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdVisuallyHiddenDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
6871
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.18", type: QdVisuallyHiddenDirective, isStandalone: false, selector: "[qdVisuallyHidden]", host: { classAttribute: "qd-visually-hidden" }, ngImport: i0 });
6872
- }
6873
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdVisuallyHiddenDirective, decorators: [{
6874
- type: Directive,
6875
- args: [{
6876
- selector: '[qdVisuallyHidden]',
6877
- host: { class: 'qd-visually-hidden' },
6878
- standalone: false
6879
- }]
6880
- }] });
6881
-
6882
- /**
6883
- * Manages a server-sent event (SSE) connection with automatic reconnection and heartbeat monitoring.
6884
- *
6885
- * All service endpoints — including SSE — must be protected. The connection is therefore secured
6886
- * via Quadrel Auth (Bearer token) by default. When the access token refreshes, the connection is
6887
- * transparently rebuilt. Only disable authentication for endpoints that are explicitly public.
6888
- *
6889
- * ### Reconnection behavior
6890
- *
6891
- * - **Heartbeat timeout**: If no HEARTBEAT event arrives within the expected interval, the service reconnects.
6892
- * - **401 Unauthorized**: Triggers exponential-backoff reconnection (max 5 attempts, capped at 30 s).
6893
- * - **Other errors**: Reconnects immediately when the EventSource transitions to CLOSED.
6894
- *
6895
- * Existing `observe()` subscriptions are preserved across reconnections.
6896
- *
6897
- * ### Usage
6898
- *
6899
- * ```ts
6900
- * pushEventsService.connect('https://api.example.com/events');
6901
- *
6902
- * const sub = pushEventsService.observe('RESOURCE_UPDATED').subscribe(event => handleEvent(event));
6903
- *
6904
- * sub.unsubscribe();
6905
- * pushEventsService.disconnect();
6906
- * ```
6907
- */
6908
- class QdPushEventsService {
6909
- authenticationService = inject('QdAuthenticationService', { optional: true });
6910
- _eventSource;
6911
- _subjects = new Map();
6912
- _listeners = [];
6913
- _accessTokenSub;
6914
- _options;
6915
- _heartbeatTimeout;
6916
- _heartbeatGracePeriod = 100;
6917
- _initialHeartbeatTimeout = 10000;
6918
- _isUnauthorized = false;
6919
- _reconnectAttempts = 0;
6920
- _maxReconnectAttempts = 5;
6921
- _backoffTimer;
6922
- /**
6923
- * Opens an SSE connection to the given URL.
6924
- *
6925
- * With authentication enabled (default), the service subscribes to the `accessToken$` observable
6926
- * provided by Quadrel Auth and rebuilds the connection whenever the token changes.
6927
- * No-op if already connected.
6928
- *
6929
- * @param url The SSE endpoint URL.
6930
- * @param options Set `{ disableAuthentication: true }` only for explicitly public endpoints.
6931
- *
6932
- * @example
6933
- * ```ts
6934
- * // Authenticated (default — requires Quadrel Auth)
6935
- * pushEventsService.connect('https://api.example.com/events');
6936
- *
6937
- * // Without authentication (only for public endpoints)
6938
- * pushEventsService.connect('https://api.example.com/public-events', { disableAuthentication: true });
6939
- * ```
6940
- */
6941
- connect(url, options) {
6942
- if (this.isConnectedOrConnecting())
6943
- return;
6944
- this._options = { url, options };
6945
- if (options?.disableAuthentication) {
6946
- this.openEventSource(url);
6947
- }
6948
- else {
6949
- this.connectWithAuth(url);
6950
- }
6951
- }
6952
- /**
6953
- * Closes the EventSource connection, clears all event listeners, and cancels pending backoff timers.
6954
- * Subscription subjects are preserved so that a subsequent `connect()` re-attaches them.
6955
- *
6956
- * @example
6957
- * ```ts
6958
- * pushEventsService.disconnect();
6959
- * // Subjects survive — a new connect() will re-attach existing observe() subscriptions.
6960
- * ```
6961
- */
6962
- disconnect() {
6963
- if (!this._eventSource) {
6964
- this.logWarn('No active connection to disconnect.');
6965
- return;
6966
- }
6967
- if (this._accessTokenSub) {
6968
- this._accessTokenSub.unsubscribe();
6969
- this._accessTokenSub = undefined;
6970
- }
6971
- if (this._heartbeatTimeout)
6972
- clearTimeout(this._heartbeatTimeout);
6973
- if (this._backoffTimer) {
6974
- clearTimeout(this._backoffTimer);
6975
- this._backoffTimer = undefined;
6976
- }
6977
- this.removeAllListeners();
6978
- this._eventSource.close();
6979
- }
6980
- /**
6981
- * Returns an Observable that emits whenever the server sends an event of the given type.
6982
- *
6983
- * Lazily registers an EventSource listener on first call per event name.
6984
- * Returns `NEVER` and logs an error if no connection exists.
6985
- *
6986
- * @param eventName The SSE event type to listen for.
6987
- *
6988
- * @example
6989
- * ```ts
6990
- * pushEventsService.observe('RESOURCE_UPDATED').subscribe(event => handleUpdate(event));
6991
- * ```
6992
- */
6993
- observe(eventName) {
6994
- if (!this._eventSource) {
6995
- this.logWarn('Cannot observe events without a connection. Call connect() first.');
6996
- return NEVER;
6997
- }
6998
- if (!this._subjects.has(eventName)) {
6999
- this._subjects.set(eventName, new Subject());
7000
- this.addListener(eventName, (event) => this._subjects.get(eventName).next(event));
7001
- }
7002
- return this._subjects.get(eventName).asObservable();
7003
- }
7004
- /**
7005
- * Removes all event listeners and clears all subscription subjects. The connection stays open.
7006
- * Use this to reset all subscriptions without disconnecting the SSE stream.
7007
- *
7008
- * @example
7009
- * ```ts
7010
- * pushEventsService.unobserveAll();
7011
- * // Connection remains open, but no events are forwarded until observe() is called again.
7012
- * ```
7013
- */
7014
- unobserveAll() {
7015
- this.removeAllListeners();
7016
- this._subjects.clear();
7017
- }
7018
- /** Returns `true` when the EventSource is in state OPEN or CONNECTING. */
7019
- isConnectedOrConnecting() {
7020
- return (this._eventSource &&
7021
- (this._eventSource.readyState === EventSource.OPEN || this._eventSource.readyState === EventSource.CONNECTING));
7022
- }
7023
- connectWithAuth(url) {
7024
- if (!this.authenticationService) {
7025
- this.logError("Can't connect to SSE without Quadrel Auth as the connection has to be secured. Please install Quadrel Auth or disable authentication when connecting.");
7026
- return;
7027
- }
7028
- this._accessTokenSub = this.authenticationService.accessToken$.subscribe((token) => {
7029
- this.openEventSource(url, { headers: { Authorization: `Bearer ${token}` } });
7030
- });
7031
- }
7032
- openEventSource(url, options = {}) {
7033
- this._isUnauthorized = false;
7034
- if (this._eventSource && this._eventSource.readyState !== EventSource.CLOSED)
7035
- this._eventSource.close();
7036
- this._eventSource = new EventSourcePolyfill(url, options);
7037
- this._eventSource.onerror = (err) => this.handleError(err);
7038
- this._eventSource.addEventListener('HEARTBEAT', (message) => this.handleHeartbeat(message));
7039
- if (this._heartbeatTimeout)
7040
- clearTimeout(this._heartbeatTimeout);
7041
- this._heartbeatTimeout = setTimeout(() => this.reconnect(), this._initialHeartbeatTimeout);
7042
- if (this._backoffTimer) {
7043
- clearTimeout(this._backoffTimer);
7044
- this._backoffTimer = undefined;
7045
- }
7046
- this._listeners = [];
7047
- this.reattachListeners();
7048
- }
7049
- reconnect() {
7050
- if (this.isConnectedOrConnecting() || this._isUnauthorized)
7051
- return;
7052
- this.disconnect();
7053
- this.connect(this._options.url, this._options.options);
7054
- }
7055
- handleError(err) {
7056
- const status = err?.status || err?.target?.status;
7057
- if (status === 401) {
7058
- this._isUnauthorized = true;
7059
- this.logError('SSE connection unauthorized (401):', err);
7060
- this._eventSource.close();
7061
- this.scheduleRetry();
7062
- return;
7063
- }
7064
- if (this._eventSource.readyState === EventSource.CLOSED)
7065
- this.reconnect();
7066
- this.logError('SSE connection error:', err);
7067
- }
7068
- scheduleRetry() {
7069
- if (this._reconnectAttempts >= this._maxReconnectAttempts) {
7070
- this.logError(`SSE reconnect aborted after ${this._maxReconnectAttempts} failed attempts.`);
7071
- return;
7072
- }
7073
- const delay = Math.min(1000 * Math.pow(2, this._reconnectAttempts), 30000);
7074
- this._reconnectAttempts++;
7075
- this._backoffTimer = setTimeout(() => {
7076
- this._isUnauthorized = false;
7077
- this.reconnect();
7078
- }, delay);
7079
- }
7080
- handleHeartbeat(message) {
7081
- if (this._isUnauthorized)
7082
- return;
7083
- if (this._heartbeatTimeout)
7084
- clearTimeout(this._heartbeatTimeout);
7085
- this._reconnectAttempts = 0;
7086
- const interval = JSON.parse(message.data).interval;
7087
- this._heartbeatTimeout = setTimeout(() => this.reconnect(), interval + this._heartbeatGracePeriod);
7088
- }
7089
- addListener(eventName, callback) {
7090
- this._eventSource.addEventListener(eventName, callback);
7091
- this._listeners.push([eventName, callback]);
7092
- }
7093
- reattachListeners() {
7094
- this._subjects.forEach((subject, eventName) => this.addListener(eventName, (event) => subject.next(event)));
7095
- }
7096
- removeAllListeners() {
7097
- if (!this._eventSource)
7098
- return;
7099
- this._listeners.forEach(([eventName, callback]) => this._eventSource.removeEventListener(eventName, callback));
7100
- this._listeners = [];
7101
- }
7102
- logWarn(message) {
7103
- console.warn(`Quadrel Framework | QdPushEvents - ${message}`);
7104
- }
7105
- logError(message, err) {
7106
- console.error(`Quadrel Framework | QdPushEvents - ${message}`, err);
7107
- }
7108
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPushEventsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
7109
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPushEventsService, providedIn: 'root' });
7110
- }
7111
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPushEventsService, decorators: [{
7112
- type: Injectable,
7113
- args: [{
7114
- providedIn: 'root'
7115
- }]
7116
- }] });
7117
-
7118
6742
  /**
7119
6743
  * Framework-wide funnel for syncing application state with the URL `?key=value` query string.
7120
6744
  *
@@ -7404,6 +7028,515 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
7404
7028
  args: [{ providedIn: 'root' }]
7405
7029
  }], ctorParameters: () => [] });
7406
7030
 
7031
+ class QdRwdDisabledDirective {
7032
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdRwdDisabledDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
7033
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.18", type: QdRwdDisabledDirective, isStandalone: false, selector: "[qdRwdDisabled]", host: { classAttribute: "qd-rwd-disabled" }, ngImport: i0 });
7034
+ }
7035
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdRwdDisabledDirective, decorators: [{
7036
+ type: Directive,
7037
+ args: [{
7038
+ selector: '[qdRwdDisabled]',
7039
+ host: { class: 'qd-rwd-disabled' },
7040
+ standalone: false
7041
+ }]
7042
+ }] });
7043
+
7044
+ class QdLocaleService {
7045
+ _serviceNavLanguage$ = new BehaviorSubject(null);
7046
+ locale$ = this._serviceNavLanguage$.pipe(map(serviceNavLanguage => determineLocale(serviceNavLanguage, navigator.languages)));
7047
+ setServiceNavigationLanguage(language) {
7048
+ this._serviceNavLanguage$.next(language);
7049
+ }
7050
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdLocaleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
7051
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdLocaleService, providedIn: 'root' });
7052
+ }
7053
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdLocaleService, decorators: [{
7054
+ type: Injectable,
7055
+ args: [{ providedIn: 'root' }]
7056
+ }] });
7057
+
7058
+ class QdNumberInputService {
7059
+ _locale;
7060
+ _decimalSeparator;
7061
+ _groupSeparator;
7062
+ localeService = inject(QdLocaleService, { optional: true });
7063
+ destroyRef = inject(DestroyRef);
7064
+ ambiguityHintKeyDot = 'i18n.qd.input.number.ambiguousHint.dot';
7065
+ ambiguityHintKeyComma = 'i18n.qd.input.number.ambiguousHint.comma';
7066
+ invalidCharactersErrorKeyComma = 'i18n.qd.input.number.invalidCharacters.comma';
7067
+ invalidCharactersErrorKeyDot = 'i18n.qd.input.number.invalidCharacters.dot';
7068
+ get invalidCharactersErrorKey() {
7069
+ return this._decimalSeparator === ',' ? this.invalidCharactersErrorKeyComma : this.invalidCharactersErrorKeyDot;
7070
+ }
7071
+ get decimalSeparator() {
7072
+ return this._decimalSeparator;
7073
+ }
7074
+ get groupSeparator() {
7075
+ return this._groupSeparator;
7076
+ }
7077
+ constructor() {
7078
+ if (this.localeService) {
7079
+ this.localeService.locale$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(locale => {
7080
+ this.detectSeparatorsForLocale(locale);
7081
+ });
7082
+ }
7083
+ else {
7084
+ this.detectSeparators();
7085
+ }
7086
+ }
7087
+ detectSeparators() {
7088
+ const locale = navigator.languages && navigator.languages.length ? navigator.languages[0] : navigator.language;
7089
+ this.detectSeparatorsForLocale(locale);
7090
+ }
7091
+ isValidNumber(value) {
7092
+ if (!value)
7093
+ return false;
7094
+ const escaped = this._decimalSeparator.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
7095
+ return new RegExp(`^-?\\d+(${escaped}\\d+)?$`).test(value);
7096
+ }
7097
+ detectSeparatorsForLocale(locale) {
7098
+ this._locale = locale;
7099
+ const parts = new Intl.NumberFormat(locale).formatToParts(1234567.89);
7100
+ this._decimalSeparator = parts.find(p => p.type === 'decimal')?.value ?? '.';
7101
+ this._groupSeparator = parts.find(p => p.type === 'group')?.value ?? ',';
7102
+ }
7103
+ filterValue(value) {
7104
+ let result = '';
7105
+ let hasDecimal = false;
7106
+ for (let i = 0; i < value.length; i++) {
7107
+ const char = value[i];
7108
+ if (char >= '0' && char <= '9') {
7109
+ result += char;
7110
+ }
7111
+ else if (char === this._decimalSeparator && !hasDecimal) {
7112
+ result += char;
7113
+ hasDecimal = true;
7114
+ }
7115
+ else if (char === '-' && i === 0) {
7116
+ result += char;
7117
+ }
7118
+ }
7119
+ return result;
7120
+ }
7121
+ parseValue(value) {
7122
+ if (!value)
7123
+ return value;
7124
+ const normalized = value.split(this._groupSeparator).join('').replace(this._decimalSeparator, '.');
7125
+ const parsed = parseFloat(normalized);
7126
+ return isNaN(parsed) ? value : parsed;
7127
+ }
7128
+ isAmbiguous(value) {
7129
+ if (typeof value !== 'string' || !value)
7130
+ return false;
7131
+ return /^-?[1-9]\d*[.,]\d{3}$/.test(value);
7132
+ }
7133
+ getAmbiguityHintKey(value) {
7134
+ if (typeof value === 'string' && value.includes('.'))
7135
+ return this.ambiguityHintKeyDot;
7136
+ return this.ambiguityHintKeyComma;
7137
+ }
7138
+ formatNumberForViewonly(value) {
7139
+ if (value == null || value === '')
7140
+ return '';
7141
+ const str = String(value);
7142
+ const parsed = typeof value === 'number' ? value : this.parseValue(str);
7143
+ if (typeof parsed !== 'number')
7144
+ return str;
7145
+ return new Intl.NumberFormat(this._locale).format(parsed);
7146
+ }
7147
+ formatValueForDisplay(value) {
7148
+ if (value == null || value === '')
7149
+ return '';
7150
+ const str = String(value);
7151
+ if (this._decimalSeparator === '.')
7152
+ return str;
7153
+ return str.replace('.', this._decimalSeparator);
7154
+ }
7155
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdNumberInputService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
7156
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdNumberInputService });
7157
+ }
7158
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdNumberInputService, decorators: [{
7159
+ type: Injectable
7160
+ }], ctorParameters: () => [] });
7161
+
7162
+ /**
7163
+ * Manages a server-sent event (SSE) connection with automatic reconnection and heartbeat monitoring.
7164
+ *
7165
+ * All service endpoints — including SSE — must be protected. The connection is therefore secured
7166
+ * via Quadrel Auth (Bearer token) by default. When the access token refreshes, the connection is
7167
+ * transparently rebuilt. Only disable authentication for endpoints that are explicitly public.
7168
+ *
7169
+ * ### Reconnection behavior
7170
+ *
7171
+ * - **Heartbeat timeout**: If no HEARTBEAT event arrives within the expected interval, the service reconnects.
7172
+ * - **401 Unauthorized**: Triggers exponential-backoff reconnection (max 5 attempts, capped at 30 s).
7173
+ * - **Other errors**: Reconnects immediately when the EventSource transitions to CLOSED.
7174
+ *
7175
+ * Existing `observe()` subscriptions are preserved across reconnections.
7176
+ *
7177
+ * ### Usage
7178
+ *
7179
+ * ```ts
7180
+ * pushEventsService.connect('https://api.example.com/events');
7181
+ *
7182
+ * const sub = pushEventsService.observe('RESOURCE_UPDATED').subscribe(event => handleEvent(event));
7183
+ *
7184
+ * sub.unsubscribe();
7185
+ * pushEventsService.disconnect();
7186
+ * ```
7187
+ */
7188
+ class QdPushEventsService {
7189
+ authenticationService = inject('QdAuthenticationService', { optional: true });
7190
+ _eventSource;
7191
+ _subjects = new Map();
7192
+ _listeners = [];
7193
+ _accessTokenSub;
7194
+ _options;
7195
+ _heartbeatTimeout;
7196
+ _heartbeatGracePeriod = 100;
7197
+ _initialHeartbeatTimeout = 10000;
7198
+ _isUnauthorized = false;
7199
+ _reconnectAttempts = 0;
7200
+ _maxReconnectAttempts = 5;
7201
+ _backoffTimer;
7202
+ /**
7203
+ * Opens an SSE connection to the given URL.
7204
+ *
7205
+ * With authentication enabled (default), the service subscribes to the `accessToken$` observable
7206
+ * provided by Quadrel Auth and rebuilds the connection whenever the token changes.
7207
+ * No-op if already connected.
7208
+ *
7209
+ * @param url The SSE endpoint URL.
7210
+ * @param options Set `{ disableAuthentication: true }` only for explicitly public endpoints.
7211
+ *
7212
+ * @example
7213
+ * ```ts
7214
+ * // Authenticated (default — requires Quadrel Auth)
7215
+ * pushEventsService.connect('https://api.example.com/events');
7216
+ *
7217
+ * // Without authentication (only for public endpoints)
7218
+ * pushEventsService.connect('https://api.example.com/public-events', { disableAuthentication: true });
7219
+ * ```
7220
+ */
7221
+ connect(url, options) {
7222
+ if (this.isConnectedOrConnecting())
7223
+ return;
7224
+ this._options = { url, options };
7225
+ if (options?.disableAuthentication) {
7226
+ this.openEventSource(url);
7227
+ }
7228
+ else {
7229
+ this.connectWithAuth(url);
7230
+ }
7231
+ }
7232
+ /**
7233
+ * Closes the EventSource connection, clears all event listeners, and cancels pending backoff timers.
7234
+ * Subscription subjects are preserved so that a subsequent `connect()` re-attaches them.
7235
+ *
7236
+ * @example
7237
+ * ```ts
7238
+ * pushEventsService.disconnect();
7239
+ * // Subjects survive — a new connect() will re-attach existing observe() subscriptions.
7240
+ * ```
7241
+ */
7242
+ disconnect() {
7243
+ if (!this._eventSource) {
7244
+ this.logWarn('No active connection to disconnect.');
7245
+ return;
7246
+ }
7247
+ if (this._accessTokenSub) {
7248
+ this._accessTokenSub.unsubscribe();
7249
+ this._accessTokenSub = undefined;
7250
+ }
7251
+ if (this._heartbeatTimeout)
7252
+ clearTimeout(this._heartbeatTimeout);
7253
+ if (this._backoffTimer) {
7254
+ clearTimeout(this._backoffTimer);
7255
+ this._backoffTimer = undefined;
7256
+ }
7257
+ this.removeAllListeners();
7258
+ this._eventSource.close();
7259
+ }
7260
+ /**
7261
+ * Returns an Observable that emits whenever the server sends an event of the given type.
7262
+ *
7263
+ * Lazily registers an EventSource listener on first call per event name.
7264
+ * Returns `NEVER` and logs an error if no connection exists.
7265
+ *
7266
+ * @param eventName The SSE event type to listen for.
7267
+ *
7268
+ * @example
7269
+ * ```ts
7270
+ * pushEventsService.observe('RESOURCE_UPDATED').subscribe(event => handleUpdate(event));
7271
+ * ```
7272
+ */
7273
+ observe(eventName) {
7274
+ if (!this._eventSource) {
7275
+ this.logWarn('Cannot observe events without a connection. Call connect() first.');
7276
+ return NEVER;
7277
+ }
7278
+ if (!this._subjects.has(eventName)) {
7279
+ this._subjects.set(eventName, new Subject());
7280
+ this.addListener(eventName, (event) => this._subjects.get(eventName).next(event));
7281
+ }
7282
+ return this._subjects.get(eventName).asObservable();
7283
+ }
7284
+ /**
7285
+ * Removes all event listeners and clears all subscription subjects. The connection stays open.
7286
+ * Use this to reset all subscriptions without disconnecting the SSE stream.
7287
+ *
7288
+ * @example
7289
+ * ```ts
7290
+ * pushEventsService.unobserveAll();
7291
+ * // Connection remains open, but no events are forwarded until observe() is called again.
7292
+ * ```
7293
+ */
7294
+ unobserveAll() {
7295
+ this.removeAllListeners();
7296
+ this._subjects.clear();
7297
+ }
7298
+ /** Returns `true` when the EventSource is in state OPEN or CONNECTING. */
7299
+ isConnectedOrConnecting() {
7300
+ return (this._eventSource &&
7301
+ (this._eventSource.readyState === EventSource.OPEN || this._eventSource.readyState === EventSource.CONNECTING));
7302
+ }
7303
+ connectWithAuth(url) {
7304
+ if (!this.authenticationService) {
7305
+ this.logError("Can't connect to SSE without Quadrel Auth as the connection has to be secured. Please install Quadrel Auth or disable authentication when connecting.");
7306
+ return;
7307
+ }
7308
+ this._accessTokenSub = this.authenticationService.accessToken$.subscribe((token) => {
7309
+ this.openEventSource(url, { headers: { Authorization: `Bearer ${token}` } });
7310
+ });
7311
+ }
7312
+ openEventSource(url, options = {}) {
7313
+ this._isUnauthorized = false;
7314
+ if (this._eventSource && this._eventSource.readyState !== EventSource.CLOSED)
7315
+ this._eventSource.close();
7316
+ this._eventSource = new EventSourcePolyfill(url, options);
7317
+ this._eventSource.onerror = (err) => this.handleError(err);
7318
+ this._eventSource.addEventListener('HEARTBEAT', (message) => this.handleHeartbeat(message));
7319
+ if (this._heartbeatTimeout)
7320
+ clearTimeout(this._heartbeatTimeout);
7321
+ this._heartbeatTimeout = setTimeout(() => this.reconnect(), this._initialHeartbeatTimeout);
7322
+ if (this._backoffTimer) {
7323
+ clearTimeout(this._backoffTimer);
7324
+ this._backoffTimer = undefined;
7325
+ }
7326
+ this._listeners = [];
7327
+ this.reattachListeners();
7328
+ }
7329
+ reconnect() {
7330
+ if (this.isConnectedOrConnecting() || this._isUnauthorized)
7331
+ return;
7332
+ this.disconnect();
7333
+ this.connect(this._options.url, this._options.options);
7334
+ }
7335
+ handleError(err) {
7336
+ const status = err?.status || err?.target?.status;
7337
+ if (status === 401) {
7338
+ this._isUnauthorized = true;
7339
+ this.logError('SSE connection unauthorized (401):', err);
7340
+ this._eventSource.close();
7341
+ this.scheduleRetry();
7342
+ return;
7343
+ }
7344
+ if (this._eventSource.readyState === EventSource.CLOSED)
7345
+ this.reconnect();
7346
+ this.logError('SSE connection error:', err);
7347
+ }
7348
+ scheduleRetry() {
7349
+ if (this._reconnectAttempts >= this._maxReconnectAttempts) {
7350
+ this.logError(`SSE reconnect aborted after ${this._maxReconnectAttempts} failed attempts.`);
7351
+ return;
7352
+ }
7353
+ const delay = Math.min(1000 * Math.pow(2, this._reconnectAttempts), 30000);
7354
+ this._reconnectAttempts++;
7355
+ this._backoffTimer = setTimeout(() => {
7356
+ this._isUnauthorized = false;
7357
+ this.reconnect();
7358
+ }, delay);
7359
+ }
7360
+ handleHeartbeat(message) {
7361
+ if (this._isUnauthorized)
7362
+ return;
7363
+ if (this._heartbeatTimeout)
7364
+ clearTimeout(this._heartbeatTimeout);
7365
+ this._reconnectAttempts = 0;
7366
+ const interval = JSON.parse(message.data).interval;
7367
+ this._heartbeatTimeout = setTimeout(() => this.reconnect(), interval + this._heartbeatGracePeriod);
7368
+ }
7369
+ addListener(eventName, callback) {
7370
+ this._eventSource.addEventListener(eventName, callback);
7371
+ this._listeners.push([eventName, callback]);
7372
+ }
7373
+ reattachListeners() {
7374
+ this._subjects.forEach((subject, eventName) => this.addListener(eventName, (event) => subject.next(event)));
7375
+ }
7376
+ removeAllListeners() {
7377
+ if (!this._eventSource)
7378
+ return;
7379
+ this._listeners.forEach(([eventName, callback]) => this._eventSource.removeEventListener(eventName, callback));
7380
+ this._listeners = [];
7381
+ }
7382
+ logWarn(message) {
7383
+ console.warn(`Quadrel Framework | QdPushEvents - ${message}`);
7384
+ }
7385
+ logError(message, err) {
7386
+ console.error(`Quadrel Framework | QdPushEvents - ${message}`, err);
7387
+ }
7388
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPushEventsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
7389
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPushEventsService, providedIn: 'root' });
7390
+ }
7391
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPushEventsService, decorators: [{
7392
+ type: Injectable,
7393
+ args: [{
7394
+ providedIn: 'root'
7395
+ }]
7396
+ }] });
7397
+
7398
+ var breakpoints$1 = {
7399
+ xs: 320,
7400
+ sm: 600,
7401
+ md: 960,
7402
+ lg: 1280,
7403
+ xl: 1600,
7404
+ xxl: 1800
7405
+ };
7406
+ var panel = {
7407
+ sm: 432,
7408
+ md: 588,
7409
+ lg: 720
7410
+ };
7411
+ var base = {
7412
+ fontsize: 16
7413
+ };
7414
+ var globalVars = {
7415
+ breakpoints: breakpoints$1,
7416
+ panel: panel,
7417
+ base: base
7418
+ };
7419
+
7420
+ const convertPxToRem = (pixel) => `${parseFloat((pixel / globalVars.base.fontsize).toFixed(3))}rem`;
7421
+
7422
+ class QdTooltipComponent {
7423
+ content;
7424
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdTooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7425
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdTooltipComponent, isStandalone: false, selector: "qd-tooltip", inputs: { content: "content" }, ngImport: i0, template: "<ng-container *ngIf=\"content?.headline\">\n <strong>{{ content.headline }}</strong>\n</ng-container>\n\n<ng-container *ngFor=\"let paragraph of content.paragraphs\">\n <p>{{ paragraph }}</p>\n</ng-container>\n", styles: [":host{box-shadow:0 0 .625rem #979797;display:block;width:100%;max-width:16rem;padding:.5rem;border-radius:.5rem;background-color:#000;color:#fff;font-size:.75rem;line-height:1rem}:host strong,:host p{display:block}:host p{margin:0 0 .5rem}:host p:last-child{margin-bottom:0}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
7426
+ }
7427
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdTooltipComponent, decorators: [{
7428
+ type: Component,
7429
+ args: [{ selector: 'qd-tooltip', standalone: false, template: "<ng-container *ngIf=\"content?.headline\">\n <strong>{{ content.headline }}</strong>\n</ng-container>\n\n<ng-container *ngFor=\"let paragraph of content.paragraphs\">\n <p>{{ paragraph }}</p>\n</ng-container>\n", styles: [":host{box-shadow:0 0 .625rem #979797;display:block;width:100%;max-width:16rem;padding:.5rem;border-radius:.5rem;background-color:#000;color:#fff;font-size:.75rem;line-height:1rem}:host strong,:host p{display:block}:host p{margin:0 0 .5rem}:host p:last-child{margin-bottom:0}\n"] }]
7430
+ }], propDecorators: { content: [{
7431
+ type: Input
7432
+ }] } });
7433
+
7434
+ const TARGET_SELECTOR = '.qd-intersection-target';
7435
+ const SHOW_EVENTS = ['mouseenter', 'mousemove'];
7436
+ const HIDE_EVENTS = ['mouseleave', 'click'];
7437
+ const HIDE_DELAY = 300;
7438
+ const OVERLAY_WIDTH = 280;
7439
+ const UNSUBSCRIBE_IMMEDIATELY = true;
7440
+ const THRESHOLD = 1;
7441
+ /**
7442
+ * @deprecated Will be removed in v21. This directive is no longer used inside
7443
+ * the framework. Use `QdTooltipOnClickDirective` (`[qdTooltipOnClick]`) instead.
7444
+ *
7445
+ * QdTooltipAtIntersectionDirective provides a tooltip. This will be triggered if the content is intersected.
7446
+ *
7447
+ * * Selector: [qdTooltipAtIntersection]
7448
+ * * Target Selector: .qd-intersection-target
7449
+ *
7450
+ * The IntersectionObserver API is used for the implementation.
7451
+ * * @see https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver
7452
+ *
7453
+ * * Note: The intersection of the target is calculated by the IntersectionObserver only once, initially (can be extended later if required). After that it will be unsubscribed immediately.
7454
+ * */
7455
+ class QdTooltipAtIntersectionDirective {
7456
+ _host = inject(ElementRef);
7457
+ _positionBuilder = inject(OverlayPositionBuilder);
7458
+ _overlay = inject(Overlay);
7459
+ _overlayRef;
7460
+ _target;
7461
+ _observer$;
7462
+ _isIntersected = false;
7463
+ _destroyed$ = new Subject();
7464
+ ngAfterViewInit() {
7465
+ this.setTarget();
7466
+ this.observeTarget();
7467
+ this.createOverlay();
7468
+ this.subscribeShow();
7469
+ this.subscribeHide();
7470
+ }
7471
+ ngOnDestroy() {
7472
+ this._observer$.unobserve(this._target);
7473
+ this._destroyed$.next();
7474
+ this._destroyed$.complete();
7475
+ }
7476
+ setTarget() {
7477
+ this._target = this._host.nativeElement.querySelector(TARGET_SELECTOR);
7478
+ }
7479
+ observeTarget() {
7480
+ const options = {
7481
+ root: this._host.nativeElement,
7482
+ threshold: THRESHOLD
7483
+ };
7484
+ this._observer$ = new IntersectionObserver(entries => {
7485
+ this._isIntersected = entries[0].intersectionRatio < 1;
7486
+ if (this._isIntersected) {
7487
+ this._setStyles();
7488
+ if (UNSUBSCRIBE_IMMEDIATELY)
7489
+ this._observer$.unobserve(this._target);
7490
+ }
7491
+ }, options);
7492
+ this._observer$.observe(this._target);
7493
+ }
7494
+ _setStyles() {
7495
+ this._target.style.overflow = 'hidden';
7496
+ this._target.style.textOverflow = 'ellipsis';
7497
+ this._target.style.cursor = 'help';
7498
+ }
7499
+ createOverlay() {
7500
+ this._overlayRef = this._overlay.create({
7501
+ positionStrategy: this._positionBuilder
7502
+ .flexibleConnectedTo(this._host)
7503
+ .withPositions([{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' }]),
7504
+ width: convertPxToRem(OVERLAY_WIDTH),
7505
+ scrollStrategy: this._overlay.scrollStrategies.reposition()
7506
+ });
7507
+ }
7508
+ subscribeShow() {
7509
+ merge(...SHOW_EVENTS.map(event => fromEvent(this._host.nativeElement, event)))
7510
+ .pipe(takeUntil(this._destroyed$), filter(() => !this._overlayRef.hasAttached() && this._isIntersected))
7511
+ .subscribe(() => {
7512
+ const content = this.getContent();
7513
+ const tooltipPortal = new ComponentPortal(QdTooltipComponent);
7514
+ const tooltipRef = this._overlayRef.attach(tooltipPortal);
7515
+ tooltipRef.instance.content = content;
7516
+ });
7517
+ }
7518
+ subscribeHide() {
7519
+ merge(...HIDE_EVENTS.map(event => fromEvent(this._host.nativeElement, event)))
7520
+ .pipe(takeUntil(this._destroyed$), filter(() => this._overlayRef.hasAttached()), debounceTime(HIDE_DELAY))
7521
+ .subscribe(() => this._overlayRef.detach());
7522
+ }
7523
+ getContent() {
7524
+ return {
7525
+ headline: this._target.getAttribute('data-tooltip-headline') || undefined,
7526
+ paragraphs: [this._target.textContent?.trim() || '']
7527
+ };
7528
+ }
7529
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdTooltipAtIntersectionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
7530
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.18", type: QdTooltipAtIntersectionDirective, isStandalone: false, selector: "[qdTooltipAtIntersection]", ngImport: i0 });
7531
+ }
7532
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdTooltipAtIntersectionDirective, decorators: [{
7533
+ type: Directive,
7534
+ args: [{
7535
+ selector: '[qdTooltipAtIntersection]',
7536
+ standalone: false
7537
+ }]
7538
+ }] });
7539
+
7407
7540
  const MAX_TOOLTIP_CHARACTER = 512;
7408
7541
  const TOOLTIP_POSITIONS = [
7409
7542
  { originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom' },
@@ -7435,7 +7568,10 @@ class QdTooltipOnClickDirective {
7435
7568
  .withFlexibleDimensions(false)
7436
7569
  .withPush(false)
7437
7570
  .withPositions(TOOLTIP_POSITIONS);
7438
- this._overlayRef = this.overlay.create({ positionStrategy });
7571
+ this._overlayRef = this.overlay.create({
7572
+ positionStrategy,
7573
+ scrollStrategy: this.overlay.scrollStrategies.reposition()
7574
+ });
7439
7575
  const tooltipRef = this._overlayRef.attach(new ComponentPortal(QdTooltipComponent));
7440
7576
  tooltipRef.instance.content = this.getContent();
7441
7577
  }
@@ -7509,9 +7645,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
7509
7645
  type: Input
7510
7646
  }] } });
7511
7647
 
7512
- const QD_SAFE_BOTTOM_OFFSET = new InjectionToken('QD_SAFE_BOTTOM_OFFSET');
7513
-
7514
- const QD_POPOVER_TOP_FIRST = new InjectionToken('QD_POPOVER_TOP_FIRST');
7648
+ class QdVisuallyHiddenDirective {
7649
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdVisuallyHiddenDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
7650
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.18", type: QdVisuallyHiddenDirective, isStandalone: false, selector: "[qdVisuallyHidden]", host: { classAttribute: "qd-visually-hidden" }, ngImport: i0 });
7651
+ }
7652
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdVisuallyHiddenDirective, decorators: [{
7653
+ type: Directive,
7654
+ args: [{
7655
+ selector: '[qdVisuallyHidden]',
7656
+ host: { class: 'qd-visually-hidden' },
7657
+ standalone: false
7658
+ }]
7659
+ }] });
7515
7660
 
7516
7661
  class QdCoreModule {
7517
7662
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdCoreModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
@@ -8041,6 +8186,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
8041
8186
  }] } });
8042
8187
 
8043
8188
  // @ts-strict-ignore
8189
+ /**
8190
+ * @deprecated Will be removed in v21. This directive is no longer used inside
8191
+ * the framework. Use `QdPopoverOnClickDirective` (`[qdPopoverOnClick]`) instead.
8192
+ */
8044
8193
  class QdPopoverOnHoverDirective {
8045
8194
  hostRef = inject(ElementRef);
8046
8195
  overlayPositionBuilder = inject(OverlayPositionBuilder);
@@ -8067,7 +8216,12 @@ class QdPopoverOnHoverDirective {
8067
8216
  overlayY: 'top'
8068
8217
  }
8069
8218
  ]);
8070
- this.overlayRef = this.overlay.create({ positionStrategy, width: this.qdPopoverWidth, disposeOnNavigation: true });
8219
+ this.overlayRef = this.overlay.create({
8220
+ positionStrategy,
8221
+ width: this.qdPopoverWidth,
8222
+ disposeOnNavigation: true,
8223
+ scrollStrategy: this.overlay.scrollStrategies.reposition()
8224
+ });
8071
8225
  }
8072
8226
  ngOnDestroy() {
8073
8227
  this.close();
@@ -8589,11 +8743,11 @@ class QdFormHintComponent {
8589
8743
  this.actionEmitterService.hintEventEmitterSubject.next(null);
8590
8744
  }
8591
8745
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdFormHintComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8592
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdFormHintComponent, isStandalone: false, selector: "qd-form-hint", inputs: { hint: "hint", control: "control", hasError: "hasError", hintAction: "hintAction", testId: ["data-test-id", "testId"] }, host: { classAttribute: "qd-form-hint" }, ngImport: i0, template: "<div class=\"qd-form-hint\" [attr.data-test-id]=\"testId + '-hint'\">\n <ng-container *ngIf=\"!hasError && !hintAction\">\n {{ hint | translate }}\n </ng-container>\n <ng-container *ngIf=\"!hasError && hintAction\">\n <div class=\"qd-form-hint--hint-action\" (click)=\"handleClick()\">\n {{ hint | translate }}\n </div>\n </ng-container>\n</div>\n\n<div class=\"qd-form-hint--error\" [attr.data-test-id]=\"testId + '-error'\">\n <ng-container *ngIf=\"hasError\">\n <qd-form-error [control]=\"control\"></qd-form-error>\n </ng-container>\n</div>\n", styles: [":host{display:block;min-height:.75rem;color:#757575;font-size:.75rem;font-weight:300;line-height:.75rem}:host .qd-form-hint--error{color:#c70023}.qd-form-disabled :host{color:#979797}:host .qd-form-hint--hint-action{color:#069;cursor:pointer}:host .qd-form-hint--hint-action:hover,:host .qd-form-hint--hint-action:active,:host .qd-form-hint--hint-action:focus{text-decoration:underline}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: QdFormErrorComponent, selector: "qd-form-error", inputs: ["control"] }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }] });
8746
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdFormHintComponent, isStandalone: false, selector: "qd-form-hint", inputs: { hint: "hint", control: "control", hasError: "hasError", hintAction: "hintAction", testId: ["data-test-id", "testId"] }, host: { classAttribute: "qd-form-hint" }, ngImport: i0, template: "<div class=\"qd-form-hint\" [attr.data-test-id]=\"testId + '-hint'\">\n <ng-container *ngIf=\"!hasError && !hintAction\">\n {{ hint | translate }}\n </ng-container>\n <ng-container *ngIf=\"!hasError && hintAction\">\n <div class=\"qd-form-hint--hint-action\" (click)=\"handleClick()\">\n {{ hint | translate }}\n </div>\n </ng-container>\n</div>\n\n<div class=\"qd-form-hint--error\" [attr.data-test-id]=\"testId + '-error'\">\n <ng-container *ngIf=\"hasError\">\n <qd-form-error [control]=\"control\"></qd-form-error>\n </ng-container>\n</div>\n", styles: [":host{display:block;min-height:.75rem;color:#757575;font-size:.75rem;font-weight:300;line-height:.75rem}:host .qd-form-hint--error{color:#c70023}.qd-form-disabled :host{color:#979797}.qd-input-ambiguous :host{color:#069}:host .qd-form-hint--hint-action{color:#069;cursor:pointer}:host .qd-form-hint--hint-action:hover,:host .qd-form-hint--hint-action:active,:host .qd-form-hint--hint-action:focus{text-decoration:underline}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: QdFormErrorComponent, selector: "qd-form-error", inputs: ["control"] }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }] });
8593
8747
  }
8594
8748
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdFormHintComponent, decorators: [{
8595
8749
  type: Component,
8596
- args: [{ selector: 'qd-form-hint', host: { class: 'qd-form-hint' }, standalone: false, template: "<div class=\"qd-form-hint\" [attr.data-test-id]=\"testId + '-hint'\">\n <ng-container *ngIf=\"!hasError && !hintAction\">\n {{ hint | translate }}\n </ng-container>\n <ng-container *ngIf=\"!hasError && hintAction\">\n <div class=\"qd-form-hint--hint-action\" (click)=\"handleClick()\">\n {{ hint | translate }}\n </div>\n </ng-container>\n</div>\n\n<div class=\"qd-form-hint--error\" [attr.data-test-id]=\"testId + '-error'\">\n <ng-container *ngIf=\"hasError\">\n <qd-form-error [control]=\"control\"></qd-form-error>\n </ng-container>\n</div>\n", styles: [":host{display:block;min-height:.75rem;color:#757575;font-size:.75rem;font-weight:300;line-height:.75rem}:host .qd-form-hint--error{color:#c70023}.qd-form-disabled :host{color:#979797}:host .qd-form-hint--hint-action{color:#069;cursor:pointer}:host .qd-form-hint--hint-action:hover,:host .qd-form-hint--hint-action:active,:host .qd-form-hint--hint-action:focus{text-decoration:underline}\n"] }]
8750
+ args: [{ selector: 'qd-form-hint', host: { class: 'qd-form-hint' }, standalone: false, template: "<div class=\"qd-form-hint\" [attr.data-test-id]=\"testId + '-hint'\">\n <ng-container *ngIf=\"!hasError && !hintAction\">\n {{ hint | translate }}\n </ng-container>\n <ng-container *ngIf=\"!hasError && hintAction\">\n <div class=\"qd-form-hint--hint-action\" (click)=\"handleClick()\">\n {{ hint | translate }}\n </div>\n </ng-container>\n</div>\n\n<div class=\"qd-form-hint--error\" [attr.data-test-id]=\"testId + '-error'\">\n <ng-container *ngIf=\"hasError\">\n <qd-form-error [control]=\"control\"></qd-form-error>\n </ng-container>\n</div>\n", styles: [":host{display:block;min-height:.75rem;color:#757575;font-size:.75rem;font-weight:300;line-height:.75rem}:host .qd-form-hint--error{color:#c70023}.qd-form-disabled :host{color:#979797}.qd-input-ambiguous :host{color:#069}:host .qd-form-hint--hint-action{color:#069;cursor:pointer}:host .qd-form-hint--hint-action:hover,:host .qd-form-hint--hint-action:active,:host .qd-form-hint--hint-action:focus{text-decoration:underline}\n"] }]
8597
8751
  }], propDecorators: { hint: [{
8598
8752
  type: Input
8599
8753
  }], control: [{
@@ -11218,6 +11372,7 @@ class QdInputComponent {
11218
11372
  resolverRegistry = inject(QdFormOptionsResolverRegistry);
11219
11373
  controlContainer = inject(ControlContainer, { optional: true, host: true, skipSelf: true });
11220
11374
  eventBrokerService = inject(QdEventBrokerService, { optional: true });
11375
+ numberInputService = inject(QdNumberInputService);
11221
11376
  /**
11222
11377
  * The form control name can be assigned here if you want to use Reactive Forms.
11223
11378
  */
@@ -11292,9 +11447,13 @@ class QdInputComponent {
11292
11447
  get isErrorFromOutside() {
11293
11448
  return this.isError;
11294
11449
  }
11450
+ get isAmbiguousState() {
11451
+ return this.isAmbiguousInput;
11452
+ }
11295
11453
  inputElement;
11296
11454
  inputType;
11297
11455
  inputMode;
11456
+ htmlInputType;
11298
11457
  placeholder;
11299
11458
  label;
11300
11459
  hint;
@@ -11306,6 +11465,7 @@ class QdInputComponent {
11306
11465
  control;
11307
11466
  _optionsResolver;
11308
11467
  _subs = new Subscription();
11468
+ _isUserTyped = false;
11309
11469
  _onChange = () => { };
11310
11470
  _onTouch = () => { };
11311
11471
  get hasOnlyUnitsError() {
@@ -11314,6 +11474,15 @@ class QdInputComponent {
11314
11474
  get hasUnits() {
11315
11475
  return this.config?.units?.length > 0;
11316
11476
  }
11477
+ get ambiguityHintKey() {
11478
+ return this.numberInputService.getAmbiguityHintKey(this._value.value);
11479
+ }
11480
+ get isAmbiguousInput() {
11481
+ return (this.inputType === 'number' &&
11482
+ !this.hasError &&
11483
+ this._isUserTyped &&
11484
+ this.numberInputService.isAmbiguous(this._value.value));
11485
+ }
11317
11486
  get numberOfCharacters() {
11318
11487
  if (!this._value.value)
11319
11488
  return 0;
@@ -11326,11 +11495,14 @@ class QdInputComponent {
11326
11495
  }
11327
11496
  get maxLength() {
11328
11497
  if (!(this.control instanceof QdFormControl))
11329
- return;
11498
+ return undefined;
11330
11499
  return this.control.getMaxLengthOrUndefined();
11331
11500
  }
11332
11501
  get valueAsList() {
11333
- return [`${this._value.value}${this._value.unit ? ' ' + this._value.unit : ''}`];
11502
+ const displayValue = this.inputType === 'number'
11503
+ ? this.numberInputService.formatNumberForViewonly(this._value.value)
11504
+ : this._value.value;
11505
+ return [`${displayValue}${this._value.unit ? ' ' + this._value.unit : ''}`];
11334
11506
  }
11335
11507
  ngOnInit() {
11336
11508
  this.initializeOptionsResolver();
@@ -11343,6 +11515,11 @@ class QdInputComponent {
11343
11515
  console.warn('Quadrel Framework | QdInput - Please use the QdFormControl instead of the Angular FormControl.');
11344
11516
  }
11345
11517
  }
11518
+ if (this.config.inputType === 'number' &&
11519
+ this.config.inputMode !== 'numeric' &&
11520
+ this.config.inputMode !== 'decimal' &&
11521
+ this.config.inputMode != null)
11522
+ console.error('QD-UI | QdInputComponent - Please use either decimal or numeric when using QdInputType number');
11346
11523
  this.writeValue(this.value ?? getValue(this.config));
11347
11524
  this.normalizeInitialControlValueIfNeeded();
11348
11525
  this._subs.add(this.actionEmitterService.hintEventEmitter$.subscribe(() => this.clickHint.emit()));
@@ -11373,6 +11550,8 @@ class QdInputComponent {
11373
11550
  writeValue(value) {
11374
11551
  this._value = getValueWithUnit(value, this.config);
11375
11552
  this._displayValue = String(this._value.value ?? '');
11553
+ this._isUserTyped = false;
11554
+ this.applyDisplayFormat();
11376
11555
  }
11377
11556
  setDisabledState(disabled) {
11378
11557
  this.disabled = disabled;
@@ -11384,6 +11563,36 @@ class QdInputComponent {
11384
11563
  if (input?.validity?.badInput)
11385
11564
  return;
11386
11565
  const value = event.target.value;
11566
+ if (this.inputType === 'number' && value && !this.numberInputService.isValidNumber(value)) {
11567
+ this.control?.setErrors({
11568
+ ...this.control.errors,
11569
+ invalidCharacters: this.numberInputService.invalidCharactersErrorKey
11570
+ });
11571
+ return;
11572
+ }
11573
+ if (this.inputType === 'number' && value) {
11574
+ const valueWithoutGroups = value.split(this.numberInputService.groupSeparator).join('');
11575
+ const filtered = this.numberInputService.filterValue(valueWithoutGroups);
11576
+ const hasInvalidChars = filtered !== valueWithoutGroups;
11577
+ if (hasInvalidChars) {
11578
+ this._value = { ...this._value, value: filtered };
11579
+ if (this.control) {
11580
+ this.control.setErrors({
11581
+ ...this.control.errors,
11582
+ invalidCharacters: this.numberInputService.invalidCharactersErrorKey
11583
+ });
11584
+ }
11585
+ this._isUserTyped = true;
11586
+ this._onTouch();
11587
+ this.emitValue();
11588
+ return;
11589
+ }
11590
+ if (this.control?.errors?.['invalidCharacters']) {
11591
+ const remainingErrors = Object.fromEntries(Object.entries(this.control.errors).filter(([key]) => key !== 'invalidCharacters'));
11592
+ this.control.setErrors(Object.keys(remainingErrors).length ? remainingErrors : null);
11593
+ }
11594
+ }
11595
+ this._isUserTyped = true;
11387
11596
  this._value = { ...this._value, value };
11388
11597
  this.emitValue();
11389
11598
  this._onTouch();
@@ -11440,6 +11649,15 @@ class QdInputComponent {
11440
11649
  updateConfig() {
11441
11650
  this.inputType = getInputType(this.config);
11442
11651
  this.inputMode = getInputMode(this.config);
11652
+ if (this.inputType === 'number') {
11653
+ this.htmlInputType = 'text';
11654
+ if (!this.inputMode) {
11655
+ this.inputMode = this.inputMode ?? 'decimal';
11656
+ }
11657
+ }
11658
+ else {
11659
+ this.htmlInputType = this.inputType;
11660
+ }
11443
11661
  this.placeholder = getPlaceholder(this.config);
11444
11662
  this.label = getLabel(this.config);
11445
11663
  this.hint = getHint(this.config);
@@ -11458,13 +11676,15 @@ class QdInputComponent {
11458
11676
  this._optionsResolver = this.resolverRegistry.findResolver();
11459
11677
  }
11460
11678
  emitValue() {
11679
+ const emittable = this.inputType === 'number' ? this.numberInputService.parseValue(this._value.value) : this._value.value;
11461
11680
  if (this.hasUnits) {
11462
- this.valueChange.emit(this._value);
11463
- this._onChange(this._value);
11681
+ const emittableWithUnit = { ...this._value, value: emittable };
11682
+ this.valueChange.emit(emittableWithUnit);
11683
+ this._onChange(emittableWithUnit);
11464
11684
  }
11465
11685
  else {
11466
- this.valueChange.emit(this._value.value);
11467
- this._onChange(this._value.value);
11686
+ this.valueChange.emit(emittable);
11687
+ this._onChange(emittable);
11468
11688
  }
11469
11689
  }
11470
11690
  initOpModeSubscription() {
@@ -11480,16 +11700,25 @@ class QdInputComponent {
11480
11700
  if (!this.control)
11481
11701
  return;
11482
11702
  const modelValue = this.control.value;
11483
- if (modelValue == null)
11484
- return void (this._value = getValueWithUnit(modelValue, this.config));
11703
+ if (modelValue == null) {
11704
+ this._value = getValueWithUnit(modelValue, this.config);
11705
+ return;
11706
+ }
11485
11707
  const normalized = getValueWithUnit(modelValue, this.config);
11486
11708
  const target = this.hasUnits ? normalized : normalized.value;
11487
11709
  if (!isEqual(modelValue, target))
11488
11710
  this.control.setValue(target, { emitEvent: false });
11489
11711
  this._value = normalized;
11712
+ this.applyDisplayFormat();
11713
+ }
11714
+ applyDisplayFormat() {
11715
+ if (this.inputType === 'number') {
11716
+ this._value = { ...this._value, value: this.numberInputService.formatValueForDisplay(this._value.value) };
11717
+ this._displayValue = String(this._value.value ?? '');
11718
+ }
11490
11719
  }
11491
11720
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
11492
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdInputComponent, isStandalone: false, selector: "qd-input", inputs: { formControlName: "formControlName", value: "value", config: "config", isError: "isError", testId: ["data-test-id", "testId"] }, outputs: { valueChange: "valueChange", enterClick: "enterClick", clickClear: "clickClear", clickHint: "clickHint", clickReadonly: "clickReadonly", clickViewonly: "clickViewonly" }, host: { properties: { "class.qd-input-readonly": "this.readonly", "class.qd-input--readonly-action": "this.readonlyAction", "class.qd-input-viewonly": "this.viewonly", "class.qd-input--viewonly-action": "this.viewonlyAction", "class.qd-form-hint-action": "this.hintAction", "class.qd-input-hint-action": "this.hintAction", "class.qd-form-disabled": "this.disabled", "class.qd-input-disabled": "this.disabled", "class.qd-input-focus": "this.isInputFocused", "class.qd-form-error": "this.hasError", "class.qd-input-error": "this.hasError", "class.qd-input-error-from-outside": "this.isErrorFromOutside" } }, providers: [
11721
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdInputComponent, isStandalone: false, selector: "qd-input", inputs: { formControlName: "formControlName", value: "value", config: "config", isError: "isError", testId: ["data-test-id", "testId"] }, outputs: { valueChange: "valueChange", enterClick: "enterClick", clickClear: "clickClear", clickHint: "clickHint", clickReadonly: "clickReadonly", clickViewonly: "clickViewonly" }, host: { properties: { "class.qd-input-readonly": "this.readonly", "class.qd-input--readonly-action": "this.readonlyAction", "class.qd-input-viewonly": "this.viewonly", "class.qd-input--viewonly-action": "this.viewonlyAction", "class.qd-form-hint-action": "this.hintAction", "class.qd-input-hint-action": "this.hintAction", "class.qd-form-disabled": "this.disabled", "class.qd-input-disabled": "this.disabled", "class.qd-input-focus": "this.isInputFocused", "class.qd-form-error": "this.hasError", "class.qd-input-error": "this.hasError", "class.qd-input-error-from-outside": "this.isErrorFromOutside", "class.qd-input-ambiguous": "this.isAmbiguousState" } }, providers: [
11493
11722
  {
11494
11723
  provide: NG_VALUE_ACCESSOR,
11495
11724
  useExisting: QdInputComponent,
@@ -11497,13 +11726,14 @@ class QdInputComponent {
11497
11726
  },
11498
11727
  QdFormsActionEmitterService,
11499
11728
  QdFormOptionsResolverRegistry,
11729
+ QdNumberInputService,
11500
11730
  // TODO: Remove when removing derived directive
11501
11731
  QdPopoverSizingService,
11502
11732
  {
11503
11733
  provide: QD_FOCUSABLE_TOKEN,
11504
11734
  useExisting: QdInputComponent
11505
11735
  }
11506
- ], viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["input"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<qd-form-label\n [label]=\"label\"\n [readonly]=\"readonly\"\n [viewonly]=\"viewonly\"\n [control]=\"control\"\n [tooltip]=\"config?.tooltip\"\n [data-test-id]=\"testId\"\n></qd-form-label>\n\n<ng-container *ngIf=\"!readonly && !viewonly && !hasOptions\">\n <div class=\"qd-input-input\" (keydown.enter)=\"emitEnterClick()\">\n <ng-container *ngTemplateOutlet=\"inputBox\"></ng-container>\n </div>\n\n <span class=\"qd-input-character-counter\" *ngIf=\"hasMaxLength\">{{ numberOfCharacters }} / {{ maxLength }}</span>\n\n <qd-form-hint\n *ngIf=\"hint || hasError\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n ></qd-form-hint>\n</ng-container>\n\n<div *ngIf=\"!readonly && !viewonly && hasOptions\">\n <div\n class=\"qd-input-input\"\n qdInputOptions\n [qdPopoverMinWidth]=\"200\"\n [config]=\"config\"\n [value]=\"_value.value\"\n (optionSelected)=\"handleOptionSelected($event)\"\n (enterClick)=\"emitEnterClick()\"\n >\n <!-- handle (enterClick) by options directive here because event has to be fired after selection -->\n <ng-container *ngTemplateOutlet=\"inputBox\"></ng-container>\n </div>\n\n <span class=\"qd-input-character-counter\" *ngIf=\"hasMaxLength\">{{ numberOfCharacters }} / {{ maxLength }}</span>\n\n <qd-form-hint\n *ngIf=\"hint || hasError\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n ></qd-form-hint>\n</div>\n\n<qd-form-readonly\n *ngIf=\"readonly\"\n [values]=\"valueAsList\"\n [readonlyAction]=\"readonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-readonly>\n\n<qd-form-viewonly\n *ngIf=\"viewonly\"\n [values]=\"valueAsList\"\n [viewonlyAction]=\"viewonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-viewonly>\n\n<ng-template #inputBox>\n <input\n #input\n [placeholder]=\"placeholder | translate\"\n [value]=\"hasOptions ? (_value.value.toString() | translate) : _displayValue\"\n (input)=\"handleInput($event)\"\n (focus)=\"handleInputFocus()\"\n (blur)=\"handleInputBlur()\"\n [disabled]=\"disabled || readonly\"\n [type]=\"inputType\"\n [attr.inputmode]=\"inputMode\"\n [qdAutofocus]=\"hasAutofocus\"\n [attr.data-test-id]=\"testId + '-input'\"\n [step]=\"config?.step\"\n required\n />\n <div class=\"qd-input-suffix\">\n <qd-icon *ngIf=\"hasError && !hasOnlyUnitsError\" class=\"qd-input-error-icon\" icon=\"exclamationCircleSolid\"></qd-icon>\n <qd-icon *ngIf=\"clearable\" class=\"qd-input-clearable-icon\" icon=\"timesLarge\" (click)=\"clearInput()\"></qd-icon>\n <ng-content select=\"[qdIconButton]\"></ng-content>\n </div>\n <qd-input-units\n *ngIf=\"hasUnits\"\n [unit]=\"_value.unit\"\n [config]=\"config\"\n (unitChange)=\"handleUnitChange($event)\"\n (opened)=\"handleUnitsOpened()\"\n (closed)=\"handleUnitsClosed()\"\n ></qd-input-units>\n <div class=\"qd-input-suffix\" *ngIf=\"hasError && hasOnlyUnitsError\">\n <qd-icon class=\"qd-input-error-icon\" icon=\"exclamationCircleSolid\"></qd-icon>\n </div>\n</ng-template>\n", styles: [":host{position:relative;display:block;width:100%;flex-direction:column;margin-bottom:.75rem}:host .qd-input-input{display:flex;overflow:hidden;height:2.25rem;align-items:center;padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(180,180,180);border-radius:0;margin-bottom:.375rem;background-color:#fff}:host .qd-input-input:hover,:host .qd-input-input:active{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(23,23,23);border-radius:0}:host .qd-input-input input{overflow:hidden;width:100%;flex-grow:1;border:none;background-color:#fff;color:#171717;font-size:.875rem;line-height:1.875rem}:host .qd-input-input input:hover,:host .qd-input-input input:focus,:host .qd-input-input input:active{border:none;outline:none}:host .qd-input-input input::placeholder{color:#b4b4b4}:host .qd-input-input input:focus::placeholder{display:block;color:#b4b4b4}:host .qd-input-input .qd-input-suffix{display:flex;align-items:center;margin-left:.75rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-error-icon{padding-right:.5rem;color:#c70023}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-error-icon+.qd-input-clearable-icon{margin-left:-.25rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon{margin-right:.5625rem;color:#979797;cursor:pointer;font-size:1.25rem;line-height:2rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:hover,:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:focus,:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:active{color:#171717}:host .qd-input-input qd-input-units+.qd-input-suffix{margin:0 0 0 -.1875rem}:host .qd-input-character-counter{padding-left:.125rem;color:#757575;float:right;font-size:.75rem;font-weight:300;line-height:.75rem}:host:after{display:block;height:0;clear:both;content:\".\";visibility:hidden}:host.qd-input-focus .qd-input-input{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(0,102,153);border-radius:0;outline:none}:host.qd-input-readonly .qd-input-readonly{color:#171717;font-size:.875rem;line-height:2.25rem}:host.qd-input-viewonly .qd-input-viewonly{color:#171717;font-size:.875rem;line-height:2.25rem}:host.qd-input-disabled .qd-input-input{border:.0625rem solid rgb(151,151,151);background-color:#f5f5f5}:host.qd-input-disabled .qd-input-input input{background-color:#f5f5f5;color:#979797}:host.qd-input-disabled .qd-input-input input::placeholder{opacity:0}:host.qd-input-disabled .qd-input-input:hover,:host.qd-input-disabled .qd-input-input:active{padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(151,151,151);background-color:#f5f5f5}:host.qd-input-disabled.qd-input-focus{border-color:#ff9b00}:host.qd-input--readonly-action .qd-input-readonly{color:#069;cursor:pointer}:host.qd-input--readonly-action .qd-input-readonly:hover,:host.qd-input--readonly-action .qd-input-readonly:active,:host.qd-input--readonly-action .qd-input-readonly:focus{text-decoration:underline}:host.qd-input--viewonly-action .qd-input-viewonly{color:#069;cursor:pointer}:host.qd-input--viewonly-action .qd-input-viewonly:hover,:host.qd-input--viewonly-action .qd-input-viewonly:active,:host.qd-input--viewonly-action .qd-input-viewonly:focus{text-decoration:underline}:host.qd-input-error .qd-input-input,:host.qd-input-error-from-outside .qd-input-input{padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(199,0,35)}:host.qd-input-error .qd-input-input:hover,:host.qd-input-error .qd-input-input:active,:host.qd-input-error-from-outside .qd-input-input:hover,:host.qd-input-error-from-outside .qd-input-input:active{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(199,0,35)}:host.qd-input-error.qd-input-focus,:host.qd-input-error-from-outside.qd-input-focus{border-color:#c70023}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: QdAutofocusDirective, selector: "[qdAutofocus]", inputs: ["qdAutofocus"] }, { kind: "component", type: QdIconComponent, selector: "qd-icon", inputs: ["icon"] }, { kind: "component", type: QdFormHintComponent, selector: "qd-form-hint", inputs: ["hint", "control", "hasError", "hintAction", "data-test-id"] }, { kind: "component", type: QdFormLabelComponent, selector: "qd-form-label", inputs: ["label", "isDisabled", "readonly", "viewonly", "control", "tooltip", "data-test-id"] }, { kind: "component", type: QdFormReadonlyComponent, selector: "qd-form-readonly", inputs: ["values", "readonlyAction", "data-test-id"] }, { kind: "component", type: QdFormViewonlyComponent, selector: "qd-form-viewonly", inputs: ["values", "viewonlyAction", "data-test-id"] }, { kind: "component", type: QdInputUnitsComponent, selector: "qd-input-units", inputs: ["config", "unit"], outputs: ["unitChange", "opened", "closed"] }, { kind: "directive", type: QdInputOptionsDirective, selector: "[qdInputOptions]", inputs: ["value", "config"], outputs: ["enterClick", "optionSelected"] }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }] });
11736
+ ], viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["input"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<qd-form-label\n [label]=\"label\"\n [readonly]=\"readonly\"\n [viewonly]=\"viewonly\"\n [control]=\"control\"\n [tooltip]=\"config?.tooltip\"\n [data-test-id]=\"testId\"\n></qd-form-label>\n\n<ng-container *ngIf=\"!readonly && !viewonly && !hasOptions\">\n <div class=\"qd-input-input\" (keydown.enter)=\"emitEnterClick()\">\n <ng-container *ngTemplateOutlet=\"inputBox\"></ng-container>\n </div>\n\n <span class=\"qd-input-character-counter\" *ngIf=\"hasMaxLength\">{{ numberOfCharacters }} / {{ maxLength }}</span>\n\n <qd-form-hint\n *ngIf=\"hint || hasError\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n ></qd-form-hint>\n <qd-form-hint *ngIf=\"isAmbiguousInput\" [hint]=\"ambiguityHintKey\" [data-test-id]=\"testId\"></qd-form-hint>\n</ng-container>\n\n<div *ngIf=\"!readonly && !viewonly && hasOptions\">\n <div\n class=\"qd-input-input\"\n qdInputOptions\n [qdPopoverMinWidth]=\"200\"\n [config]=\"config\"\n [value]=\"_value.value\"\n (optionSelected)=\"handleOptionSelected($event)\"\n (enterClick)=\"emitEnterClick()\"\n >\n <!-- handle (enterClick) by options directive here because event has to be fired after selection -->\n <ng-container *ngTemplateOutlet=\"inputBox\"></ng-container>\n </div>\n\n <span class=\"qd-input-character-counter\" *ngIf=\"hasMaxLength\">{{ numberOfCharacters }} / {{ maxLength }}</span>\n\n <qd-form-hint\n *ngIf=\"hint || hasError\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n ></qd-form-hint>\n <qd-form-hint *ngIf=\"isAmbiguousInput\" [hint]=\"ambiguityHintKey\" [data-test-id]=\"testId\"></qd-form-hint>\n</div>\n\n<qd-form-readonly\n *ngIf=\"readonly\"\n [values]=\"valueAsList\"\n [readonlyAction]=\"readonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-readonly>\n\n<qd-form-viewonly\n *ngIf=\"viewonly\"\n [values]=\"valueAsList\"\n [viewonlyAction]=\"viewonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-viewonly>\n\n<ng-template #inputBox>\n <input\n #input\n [placeholder]=\"placeholder | translate\"\n [value]=\"hasOptions ? (_value.value.toString() | translate) : _displayValue\"\n (input)=\"handleInput($event)\"\n (focus)=\"handleInputFocus()\"\n (blur)=\"handleInputBlur()\"\n [disabled]=\"disabled || readonly\"\n [type]=\"htmlInputType\"\n [attr.inputmode]=\"inputMode\"\n [qdAutofocus]=\"hasAutofocus\"\n [attr.data-test-id]=\"testId + '-input'\"\n [step]=\"config?.step\"\n required\n />\n <div class=\"qd-input-suffix\">\n <qd-icon *ngIf=\"hasError && !hasOnlyUnitsError\" class=\"qd-input-error-icon\" icon=\"exclamationCircleSolid\"></qd-icon>\n <qd-icon *ngIf=\"isAmbiguousInput\" class=\"qd-input-ambiguous-icon\" icon=\"circleInfoSolid\"></qd-icon>\n <qd-icon *ngIf=\"clearable\" class=\"qd-input-clearable-icon\" icon=\"timesLarge\" (click)=\"clearInput()\"></qd-icon>\n <ng-content select=\"[qdIconButton]\"></ng-content>\n </div>\n <qd-input-units\n *ngIf=\"hasUnits\"\n [unit]=\"_value.unit\"\n [config]=\"config\"\n (unitChange)=\"handleUnitChange($event)\"\n (opened)=\"handleUnitsOpened()\"\n (closed)=\"handleUnitsClosed()\"\n ></qd-input-units>\n <div class=\"qd-input-suffix\" *ngIf=\"hasError && hasOnlyUnitsError\">\n <qd-icon class=\"qd-input-error-icon\" icon=\"exclamationCircleSolid\"></qd-icon>\n </div>\n</ng-template>\n", styles: [":host{position:relative;display:block;width:100%;flex-direction:column;margin-bottom:.75rem}:host .qd-input-input{display:flex;overflow:hidden;height:2.25rem;align-items:center;padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(180,180,180);border-radius:0;margin-bottom:.375rem;background-color:#fff}:host .qd-input-input:hover,:host .qd-input-input:active{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(23,23,23);border-radius:0}:host .qd-input-input input{overflow:hidden;width:100%;flex-grow:1;border:none;background-color:#fff;color:#171717;font-size:.875rem;line-height:1.875rem}:host .qd-input-input input:hover,:host .qd-input-input input:focus,:host .qd-input-input input:active{border:none;outline:none}:host .qd-input-input input::placeholder{color:#b4b4b4}:host .qd-input-input input:focus::placeholder{display:block;color:#b4b4b4}:host .qd-input-input .qd-input-suffix{display:flex;align-items:center;margin-left:.75rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-error-icon{padding-right:.5rem;color:#c70023}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-error-icon+.qd-input-clearable-icon{margin-left:-.25rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon{margin-right:.5625rem;color:#979797;cursor:pointer;font-size:1.25rem;line-height:2rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:hover,:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:focus,:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:active{color:#171717}:host .qd-input-input qd-input-units+.qd-input-suffix{margin:0 0 0 -.1875rem}:host .qd-input-character-counter{padding-left:.125rem;color:#757575;float:right;font-size:.75rem;font-weight:300;line-height:.75rem}:host:after{display:block;height:0;clear:both;content:\".\";visibility:hidden}:host.qd-input-focus .qd-input-input{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(0,102,153);border-radius:0;outline:none}:host.qd-input-readonly .qd-input-readonly{color:#171717;font-size:.875rem;line-height:2.25rem}:host.qd-input-viewonly .qd-input-viewonly{color:#171717;font-size:.875rem;line-height:2.25rem}:host.qd-input-disabled .qd-input-input{border:.0625rem solid rgb(151,151,151);background-color:#f5f5f5}:host.qd-input-disabled .qd-input-input input{background-color:#f5f5f5;color:#979797}:host.qd-input-disabled .qd-input-input input::placeholder{opacity:0}:host.qd-input-disabled .qd-input-input:hover,:host.qd-input-disabled .qd-input-input:active{padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(151,151,151);background-color:#f5f5f5}:host.qd-input-disabled.qd-input-focus{border-color:#ff9b00}:host.qd-input--readonly-action .qd-input-readonly{color:#069;cursor:pointer}:host.qd-input--readonly-action .qd-input-readonly:hover,:host.qd-input--readonly-action .qd-input-readonly:active,:host.qd-input--readonly-action .qd-input-readonly:focus{text-decoration:underline}:host.qd-input--viewonly-action .qd-input-viewonly{color:#069;cursor:pointer}:host.qd-input--viewonly-action .qd-input-viewonly:hover,:host.qd-input--viewonly-action .qd-input-viewonly:active,:host.qd-input--viewonly-action .qd-input-viewonly:focus{text-decoration:underline}:host.qd-input-ambiguous .qd-input-input{padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(0,102,153)}:host.qd-input-ambiguous .qd-input-input:hover,:host.qd-input-ambiguous .qd-input-input:active{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(0,102,153)}:host.qd-input-ambiguous.qd-input-focus .qd-input-input{border-color:#069}:host.qd-input-ambiguous .qd-input-suffix ::ng-deep .qd-input-ambiguous-icon{padding-right:.5rem;color:#069}:host.qd-input-error .qd-input-input,:host.qd-input-error-from-outside .qd-input-input{padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(199,0,35)}:host.qd-input-error .qd-input-input:hover,:host.qd-input-error .qd-input-input:active,:host.qd-input-error-from-outside .qd-input-input:hover,:host.qd-input-error-from-outside .qd-input-input:active{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(199,0,35)}:host.qd-input-error.qd-input-focus,:host.qd-input-error-from-outside.qd-input-focus{border-color:#c70023}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: QdAutofocusDirective, selector: "[qdAutofocus]", inputs: ["qdAutofocus"] }, { kind: "component", type: QdIconComponent, selector: "qd-icon", inputs: ["icon"] }, { kind: "component", type: QdFormHintComponent, selector: "qd-form-hint", inputs: ["hint", "control", "hasError", "hintAction", "data-test-id"] }, { kind: "component", type: QdFormLabelComponent, selector: "qd-form-label", inputs: ["label", "isDisabled", "readonly", "viewonly", "control", "tooltip", "data-test-id"] }, { kind: "component", type: QdFormReadonlyComponent, selector: "qd-form-readonly", inputs: ["values", "readonlyAction", "data-test-id"] }, { kind: "component", type: QdFormViewonlyComponent, selector: "qd-form-viewonly", inputs: ["values", "viewonlyAction", "data-test-id"] }, { kind: "component", type: QdInputUnitsComponent, selector: "qd-input-units", inputs: ["config", "unit"], outputs: ["unitChange", "opened", "closed"] }, { kind: "directive", type: QdInputOptionsDirective, selector: "[qdInputOptions]", inputs: ["value", "config"], outputs: ["enterClick", "optionSelected"] }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }] });
11507
11737
  }
11508
11738
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdInputComponent, decorators: [{
11509
11739
  type: Component,
@@ -11515,13 +11745,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
11515
11745
  },
11516
11746
  QdFormsActionEmitterService,
11517
11747
  QdFormOptionsResolverRegistry,
11748
+ QdNumberInputService,
11518
11749
  // TODO: Remove when removing derived directive
11519
11750
  QdPopoverSizingService,
11520
11751
  {
11521
11752
  provide: QD_FOCUSABLE_TOKEN,
11522
11753
  useExisting: QdInputComponent
11523
11754
  }
11524
- ], standalone: false, template: "<qd-form-label\n [label]=\"label\"\n [readonly]=\"readonly\"\n [viewonly]=\"viewonly\"\n [control]=\"control\"\n [tooltip]=\"config?.tooltip\"\n [data-test-id]=\"testId\"\n></qd-form-label>\n\n<ng-container *ngIf=\"!readonly && !viewonly && !hasOptions\">\n <div class=\"qd-input-input\" (keydown.enter)=\"emitEnterClick()\">\n <ng-container *ngTemplateOutlet=\"inputBox\"></ng-container>\n </div>\n\n <span class=\"qd-input-character-counter\" *ngIf=\"hasMaxLength\">{{ numberOfCharacters }} / {{ maxLength }}</span>\n\n <qd-form-hint\n *ngIf=\"hint || hasError\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n ></qd-form-hint>\n</ng-container>\n\n<div *ngIf=\"!readonly && !viewonly && hasOptions\">\n <div\n class=\"qd-input-input\"\n qdInputOptions\n [qdPopoverMinWidth]=\"200\"\n [config]=\"config\"\n [value]=\"_value.value\"\n (optionSelected)=\"handleOptionSelected($event)\"\n (enterClick)=\"emitEnterClick()\"\n >\n <!-- handle (enterClick) by options directive here because event has to be fired after selection -->\n <ng-container *ngTemplateOutlet=\"inputBox\"></ng-container>\n </div>\n\n <span class=\"qd-input-character-counter\" *ngIf=\"hasMaxLength\">{{ numberOfCharacters }} / {{ maxLength }}</span>\n\n <qd-form-hint\n *ngIf=\"hint || hasError\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n ></qd-form-hint>\n</div>\n\n<qd-form-readonly\n *ngIf=\"readonly\"\n [values]=\"valueAsList\"\n [readonlyAction]=\"readonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-readonly>\n\n<qd-form-viewonly\n *ngIf=\"viewonly\"\n [values]=\"valueAsList\"\n [viewonlyAction]=\"viewonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-viewonly>\n\n<ng-template #inputBox>\n <input\n #input\n [placeholder]=\"placeholder | translate\"\n [value]=\"hasOptions ? (_value.value.toString() | translate) : _displayValue\"\n (input)=\"handleInput($event)\"\n (focus)=\"handleInputFocus()\"\n (blur)=\"handleInputBlur()\"\n [disabled]=\"disabled || readonly\"\n [type]=\"inputType\"\n [attr.inputmode]=\"inputMode\"\n [qdAutofocus]=\"hasAutofocus\"\n [attr.data-test-id]=\"testId + '-input'\"\n [step]=\"config?.step\"\n required\n />\n <div class=\"qd-input-suffix\">\n <qd-icon *ngIf=\"hasError && !hasOnlyUnitsError\" class=\"qd-input-error-icon\" icon=\"exclamationCircleSolid\"></qd-icon>\n <qd-icon *ngIf=\"clearable\" class=\"qd-input-clearable-icon\" icon=\"timesLarge\" (click)=\"clearInput()\"></qd-icon>\n <ng-content select=\"[qdIconButton]\"></ng-content>\n </div>\n <qd-input-units\n *ngIf=\"hasUnits\"\n [unit]=\"_value.unit\"\n [config]=\"config\"\n (unitChange)=\"handleUnitChange($event)\"\n (opened)=\"handleUnitsOpened()\"\n (closed)=\"handleUnitsClosed()\"\n ></qd-input-units>\n <div class=\"qd-input-suffix\" *ngIf=\"hasError && hasOnlyUnitsError\">\n <qd-icon class=\"qd-input-error-icon\" icon=\"exclamationCircleSolid\"></qd-icon>\n </div>\n</ng-template>\n", styles: [":host{position:relative;display:block;width:100%;flex-direction:column;margin-bottom:.75rem}:host .qd-input-input{display:flex;overflow:hidden;height:2.25rem;align-items:center;padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(180,180,180);border-radius:0;margin-bottom:.375rem;background-color:#fff}:host .qd-input-input:hover,:host .qd-input-input:active{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(23,23,23);border-radius:0}:host .qd-input-input input{overflow:hidden;width:100%;flex-grow:1;border:none;background-color:#fff;color:#171717;font-size:.875rem;line-height:1.875rem}:host .qd-input-input input:hover,:host .qd-input-input input:focus,:host .qd-input-input input:active{border:none;outline:none}:host .qd-input-input input::placeholder{color:#b4b4b4}:host .qd-input-input input:focus::placeholder{display:block;color:#b4b4b4}:host .qd-input-input .qd-input-suffix{display:flex;align-items:center;margin-left:.75rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-error-icon{padding-right:.5rem;color:#c70023}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-error-icon+.qd-input-clearable-icon{margin-left:-.25rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon{margin-right:.5625rem;color:#979797;cursor:pointer;font-size:1.25rem;line-height:2rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:hover,:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:focus,:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:active{color:#171717}:host .qd-input-input qd-input-units+.qd-input-suffix{margin:0 0 0 -.1875rem}:host .qd-input-character-counter{padding-left:.125rem;color:#757575;float:right;font-size:.75rem;font-weight:300;line-height:.75rem}:host:after{display:block;height:0;clear:both;content:\".\";visibility:hidden}:host.qd-input-focus .qd-input-input{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(0,102,153);border-radius:0;outline:none}:host.qd-input-readonly .qd-input-readonly{color:#171717;font-size:.875rem;line-height:2.25rem}:host.qd-input-viewonly .qd-input-viewonly{color:#171717;font-size:.875rem;line-height:2.25rem}:host.qd-input-disabled .qd-input-input{border:.0625rem solid rgb(151,151,151);background-color:#f5f5f5}:host.qd-input-disabled .qd-input-input input{background-color:#f5f5f5;color:#979797}:host.qd-input-disabled .qd-input-input input::placeholder{opacity:0}:host.qd-input-disabled .qd-input-input:hover,:host.qd-input-disabled .qd-input-input:active{padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(151,151,151);background-color:#f5f5f5}:host.qd-input-disabled.qd-input-focus{border-color:#ff9b00}:host.qd-input--readonly-action .qd-input-readonly{color:#069;cursor:pointer}:host.qd-input--readonly-action .qd-input-readonly:hover,:host.qd-input--readonly-action .qd-input-readonly:active,:host.qd-input--readonly-action .qd-input-readonly:focus{text-decoration:underline}:host.qd-input--viewonly-action .qd-input-viewonly{color:#069;cursor:pointer}:host.qd-input--viewonly-action .qd-input-viewonly:hover,:host.qd-input--viewonly-action .qd-input-viewonly:active,:host.qd-input--viewonly-action .qd-input-viewonly:focus{text-decoration:underline}:host.qd-input-error .qd-input-input,:host.qd-input-error-from-outside .qd-input-input{padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(199,0,35)}:host.qd-input-error .qd-input-input:hover,:host.qd-input-error .qd-input-input:active,:host.qd-input-error-from-outside .qd-input-input:hover,:host.qd-input-error-from-outside .qd-input-input:active{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(199,0,35)}:host.qd-input-error.qd-input-focus,:host.qd-input-error-from-outside.qd-input-focus{border-color:#c70023}\n"] }]
11755
+ ], standalone: false, template: "<qd-form-label\n [label]=\"label\"\n [readonly]=\"readonly\"\n [viewonly]=\"viewonly\"\n [control]=\"control\"\n [tooltip]=\"config?.tooltip\"\n [data-test-id]=\"testId\"\n></qd-form-label>\n\n<ng-container *ngIf=\"!readonly && !viewonly && !hasOptions\">\n <div class=\"qd-input-input\" (keydown.enter)=\"emitEnterClick()\">\n <ng-container *ngTemplateOutlet=\"inputBox\"></ng-container>\n </div>\n\n <span class=\"qd-input-character-counter\" *ngIf=\"hasMaxLength\">{{ numberOfCharacters }} / {{ maxLength }}</span>\n\n <qd-form-hint\n *ngIf=\"hint || hasError\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n ></qd-form-hint>\n <qd-form-hint *ngIf=\"isAmbiguousInput\" [hint]=\"ambiguityHintKey\" [data-test-id]=\"testId\"></qd-form-hint>\n</ng-container>\n\n<div *ngIf=\"!readonly && !viewonly && hasOptions\">\n <div\n class=\"qd-input-input\"\n qdInputOptions\n [qdPopoverMinWidth]=\"200\"\n [config]=\"config\"\n [value]=\"_value.value\"\n (optionSelected)=\"handleOptionSelected($event)\"\n (enterClick)=\"emitEnterClick()\"\n >\n <!-- handle (enterClick) by options directive here because event has to be fired after selection -->\n <ng-container *ngTemplateOutlet=\"inputBox\"></ng-container>\n </div>\n\n <span class=\"qd-input-character-counter\" *ngIf=\"hasMaxLength\">{{ numberOfCharacters }} / {{ maxLength }}</span>\n\n <qd-form-hint\n *ngIf=\"hint || hasError\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n ></qd-form-hint>\n <qd-form-hint *ngIf=\"isAmbiguousInput\" [hint]=\"ambiguityHintKey\" [data-test-id]=\"testId\"></qd-form-hint>\n</div>\n\n<qd-form-readonly\n *ngIf=\"readonly\"\n [values]=\"valueAsList\"\n [readonlyAction]=\"readonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-readonly>\n\n<qd-form-viewonly\n *ngIf=\"viewonly\"\n [values]=\"valueAsList\"\n [viewonlyAction]=\"viewonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-viewonly>\n\n<ng-template #inputBox>\n <input\n #input\n [placeholder]=\"placeholder | translate\"\n [value]=\"hasOptions ? (_value.value.toString() | translate) : _displayValue\"\n (input)=\"handleInput($event)\"\n (focus)=\"handleInputFocus()\"\n (blur)=\"handleInputBlur()\"\n [disabled]=\"disabled || readonly\"\n [type]=\"htmlInputType\"\n [attr.inputmode]=\"inputMode\"\n [qdAutofocus]=\"hasAutofocus\"\n [attr.data-test-id]=\"testId + '-input'\"\n [step]=\"config?.step\"\n required\n />\n <div class=\"qd-input-suffix\">\n <qd-icon *ngIf=\"hasError && !hasOnlyUnitsError\" class=\"qd-input-error-icon\" icon=\"exclamationCircleSolid\"></qd-icon>\n <qd-icon *ngIf=\"isAmbiguousInput\" class=\"qd-input-ambiguous-icon\" icon=\"circleInfoSolid\"></qd-icon>\n <qd-icon *ngIf=\"clearable\" class=\"qd-input-clearable-icon\" icon=\"timesLarge\" (click)=\"clearInput()\"></qd-icon>\n <ng-content select=\"[qdIconButton]\"></ng-content>\n </div>\n <qd-input-units\n *ngIf=\"hasUnits\"\n [unit]=\"_value.unit\"\n [config]=\"config\"\n (unitChange)=\"handleUnitChange($event)\"\n (opened)=\"handleUnitsOpened()\"\n (closed)=\"handleUnitsClosed()\"\n ></qd-input-units>\n <div class=\"qd-input-suffix\" *ngIf=\"hasError && hasOnlyUnitsError\">\n <qd-icon class=\"qd-input-error-icon\" icon=\"exclamationCircleSolid\"></qd-icon>\n </div>\n</ng-template>\n", styles: [":host{position:relative;display:block;width:100%;flex-direction:column;margin-bottom:.75rem}:host .qd-input-input{display:flex;overflow:hidden;height:2.25rem;align-items:center;padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(180,180,180);border-radius:0;margin-bottom:.375rem;background-color:#fff}:host .qd-input-input:hover,:host .qd-input-input:active{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(23,23,23);border-radius:0}:host .qd-input-input input{overflow:hidden;width:100%;flex-grow:1;border:none;background-color:#fff;color:#171717;font-size:.875rem;line-height:1.875rem}:host .qd-input-input input:hover,:host .qd-input-input input:focus,:host .qd-input-input input:active{border:none;outline:none}:host .qd-input-input input::placeholder{color:#b4b4b4}:host .qd-input-input input:focus::placeholder{display:block;color:#b4b4b4}:host .qd-input-input .qd-input-suffix{display:flex;align-items:center;margin-left:.75rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-error-icon{padding-right:.5rem;color:#c70023}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-error-icon+.qd-input-clearable-icon{margin-left:-.25rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon{margin-right:.5625rem;color:#979797;cursor:pointer;font-size:1.25rem;line-height:2rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:hover,:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:focus,:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:active{color:#171717}:host .qd-input-input qd-input-units+.qd-input-suffix{margin:0 0 0 -.1875rem}:host .qd-input-character-counter{padding-left:.125rem;color:#757575;float:right;font-size:.75rem;font-weight:300;line-height:.75rem}:host:after{display:block;height:0;clear:both;content:\".\";visibility:hidden}:host.qd-input-focus .qd-input-input{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(0,102,153);border-radius:0;outline:none}:host.qd-input-readonly .qd-input-readonly{color:#171717;font-size:.875rem;line-height:2.25rem}:host.qd-input-viewonly .qd-input-viewonly{color:#171717;font-size:.875rem;line-height:2.25rem}:host.qd-input-disabled .qd-input-input{border:.0625rem solid rgb(151,151,151);background-color:#f5f5f5}:host.qd-input-disabled .qd-input-input input{background-color:#f5f5f5;color:#979797}:host.qd-input-disabled .qd-input-input input::placeholder{opacity:0}:host.qd-input-disabled .qd-input-input:hover,:host.qd-input-disabled .qd-input-input:active{padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(151,151,151);background-color:#f5f5f5}:host.qd-input-disabled.qd-input-focus{border-color:#ff9b00}:host.qd-input--readonly-action .qd-input-readonly{color:#069;cursor:pointer}:host.qd-input--readonly-action .qd-input-readonly:hover,:host.qd-input--readonly-action .qd-input-readonly:active,:host.qd-input--readonly-action .qd-input-readonly:focus{text-decoration:underline}:host.qd-input--viewonly-action .qd-input-viewonly{color:#069;cursor:pointer}:host.qd-input--viewonly-action .qd-input-viewonly:hover,:host.qd-input--viewonly-action .qd-input-viewonly:active,:host.qd-input--viewonly-action .qd-input-viewonly:focus{text-decoration:underline}:host.qd-input-ambiguous .qd-input-input{padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(0,102,153)}:host.qd-input-ambiguous .qd-input-input:hover,:host.qd-input-ambiguous .qd-input-input:active{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(0,102,153)}:host.qd-input-ambiguous.qd-input-focus .qd-input-input{border-color:#069}:host.qd-input-ambiguous .qd-input-suffix ::ng-deep .qd-input-ambiguous-icon{padding-right:.5rem;color:#069}:host.qd-input-error .qd-input-input,:host.qd-input-error-from-outside .qd-input-input{padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(199,0,35)}:host.qd-input-error .qd-input-input:hover,:host.qd-input-error .qd-input-input:active,:host.qd-input-error-from-outside .qd-input-input:hover,:host.qd-input-error-from-outside .qd-input-input:active{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(199,0,35)}:host.qd-input-error.qd-input-focus,:host.qd-input-error-from-outside.qd-input-focus{border-color:#c70023}\n"] }]
11525
11756
  }], propDecorators: { formControlName: [{
11526
11757
  type: Input
11527
11758
  }], value: [{
@@ -11581,6 +11812,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
11581
11812
  }], isErrorFromOutside: [{
11582
11813
  type: HostBinding,
11583
11814
  args: ['class.qd-input-error-from-outside']
11815
+ }], isAmbiguousState: [{
11816
+ type: HostBinding,
11817
+ args: ['class.qd-input-ambiguous']
11584
11818
  }], inputElement: [{
11585
11819
  type: ViewChild,
11586
11820
  args: ['input']
@@ -15516,7 +15750,7 @@ class QdTextareaComponent {
15516
15750
  }
15517
15751
  get maxLength() {
15518
15752
  if (!(this.control instanceof QdFormControl))
15519
- return;
15753
+ return undefined;
15520
15754
  return this.control.getMaxLengthOrUndefined();
15521
15755
  }
15522
15756
  ngOnInit() {
@@ -25820,7 +26054,7 @@ class QdSectionToolbarComponent {
25820
26054
  toolbarComponents;
25821
26055
  get searchConfigData() {
25822
26056
  if (this.config.search === false)
25823
- return;
26057
+ return undefined;
25824
26058
  return this.config.search;
25825
26059
  }
25826
26060
  get filterData() {
@@ -27256,11 +27490,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
27256
27490
  class QdPageControlPanelComponent {
27257
27491
  config;
27258
27492
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPageControlPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
27259
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdPageControlPanelComponent, isStandalone: false, selector: "qd-page-control-panel", inputs: { config: "config" }, ngImport: i0, template: "<header>\n {{ config.title.i18n | translate }}\n</header>\n\n<main>\n <ng-content select=\"qd-text-section\"></ng-content>\n <ng-content select=\"qd-panel-section\"></ng-content>\n <ng-content select=\"qd-section\"></ng-content>\n</main>\n", styles: ["qd-page-control-panel{position:relative;display:flex;height:100%;flex-direction:column;background:#fff}qd-page-control-panel header{padding:.75rem 1rem .5rem;border-bottom:.125rem solid rgb(213,213,213);color:#171717;font-size:.875rem;font-weight:700;line-height:1.25rem}qd-page-control-panel main{flex-grow:99;overflow-y:auto}qd-page-control-panel qd-panel-section:last-child{margin-bottom:.75rem}qd-page-control-panel qd-section{margin:0 1rem}qd-page-control-panel qd-section:first-child{margin-top:1rem}qd-page-control-panel qd-section:last-child{margin-bottom:1rem}\n"], dependencies: [{ kind: "pipe", type: i3.TranslatePipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None });
27493
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdPageControlPanelComponent, isStandalone: false, selector: "qd-page-control-panel", inputs: { config: "config" }, ngImport: i0, template: "<header>\n {{ config.title.i18n | translate }}\n</header>\n\n<main cdkScrollable>\n <ng-content select=\"qd-text-section\"></ng-content>\n <ng-content select=\"qd-panel-section\"></ng-content>\n <ng-content select=\"qd-section\"></ng-content>\n</main>\n", styles: ["qd-page-control-panel{position:relative;display:flex;height:100%;flex-direction:column;background:#fff}qd-page-control-panel header{padding:.75rem 1rem .5rem;border-bottom:.125rem solid rgb(213,213,213);color:#171717;font-size:.875rem;font-weight:700;line-height:1.25rem}qd-page-control-panel main{flex-grow:99;overflow-y:auto}qd-page-control-panel qd-panel-section:last-child{margin-bottom:.75rem}qd-page-control-panel qd-section{margin:0 1rem}qd-page-control-panel qd-section:first-child{margin-top:1rem}qd-page-control-panel qd-section:last-child{margin-bottom:1rem}\n"], dependencies: [{ kind: "directive", type: i1$2.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None });
27260
27494
  }
27261
27495
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPageControlPanelComponent, decorators: [{
27262
27496
  type: Component,
27263
- args: [{ selector: 'qd-page-control-panel', encapsulation: ViewEncapsulation.None, standalone: false, template: "<header>\n {{ config.title.i18n | translate }}\n</header>\n\n<main>\n <ng-content select=\"qd-text-section\"></ng-content>\n <ng-content select=\"qd-panel-section\"></ng-content>\n <ng-content select=\"qd-section\"></ng-content>\n</main>\n", styles: ["qd-page-control-panel{position:relative;display:flex;height:100%;flex-direction:column;background:#fff}qd-page-control-panel header{padding:.75rem 1rem .5rem;border-bottom:.125rem solid rgb(213,213,213);color:#171717;font-size:.875rem;font-weight:700;line-height:1.25rem}qd-page-control-panel main{flex-grow:99;overflow-y:auto}qd-page-control-panel qd-panel-section:last-child{margin-bottom:.75rem}qd-page-control-panel qd-section{margin:0 1rem}qd-page-control-panel qd-section:first-child{margin-top:1rem}qd-page-control-panel qd-section:last-child{margin-bottom:1rem}\n"] }]
27497
+ args: [{ selector: 'qd-page-control-panel', encapsulation: ViewEncapsulation.None, standalone: false, template: "<header>\n {{ config.title.i18n | translate }}\n</header>\n\n<main cdkScrollable>\n <ng-content select=\"qd-text-section\"></ng-content>\n <ng-content select=\"qd-panel-section\"></ng-content>\n <ng-content select=\"qd-section\"></ng-content>\n</main>\n", styles: ["qd-page-control-panel{position:relative;display:flex;height:100%;flex-direction:column;background:#fff}qd-page-control-panel header{padding:.75rem 1rem .5rem;border-bottom:.125rem solid rgb(213,213,213);color:#171717;font-size:.875rem;font-weight:700;line-height:1.25rem}qd-page-control-panel main{flex-grow:99;overflow-y:auto}qd-page-control-panel qd-panel-section:last-child{margin-bottom:.75rem}qd-page-control-panel qd-section{margin:0 1rem}qd-page-control-panel qd-section:first-child{margin-top:1rem}qd-page-control-panel qd-section:last-child{margin-bottom:1rem}\n"] }]
27264
27498
  }], propDecorators: { config: [{
27265
27499
  type: Input,
27266
27500
  args: [{ required: true }]
@@ -28382,6 +28616,7 @@ class QdPageObjectHeaderComponent {
28382
28616
  get headerFacets() {
28383
28617
  if (this.hasHeaderFacets(this.config))
28384
28618
  return this.config.headerFacets;
28619
+ return undefined;
28385
28620
  }
28386
28621
  get isInspectAndViewMode$() {
28387
28622
  return this.pageStoreService.isViewonly$.pipe(takeUntil(this._destroyed$), map(isView => this.config.pageType === 'inspect' && isView));
@@ -29187,7 +29422,7 @@ class QdPageTabHeaderComponent extends CdkStepHeader {
29187
29422
  super(elementRef);
29188
29423
  }
29189
29424
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPageTabHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
29190
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdPageTabHeaderComponent, isStandalone: true, selector: "qd-page-tab-header", inputs: { state: "state", label: "label", counters: "counters", index: "index", isSelected: "isSelected", isDisabled: "isDisabled", testId: ["data-test-id", "testId"] }, host: { properties: { "attr.data-test-id": "testId", "class.qd-tab-current": "isSelected && !isDisabled", "class.qd-tab-disabled": "isDisabled", "class.qd-tab-done": "state === STEP_STATE.DONE", "class.qd-tab-edit": "state === STEP_STATE.EDIT", "class.qd-tab-error": "state === STEP_STATE.ERROR" } }, usesInheritance: true, ngImport: i0, template: "<span class=\"qd-tab-caption\">\n {{ label }}\n <qd-page-tab-header-counters [counters]=\"counters\" [data-test-id]=\"testId + '-counters'\" />\n</span>\n", styles: [":host{position:relative;display:inline-flex;height:2.5rem;padding:.625rem 0;cursor:pointer;color:#757575;font-size:14px;font-weight:400;line-height:18px}:host .qd-tab-caption{font-weight:500}:host:hover,:host.qd-tab-current{color:#069}:host.qd-tab-current .qd-tab-caption{position:relative}:host.qd-tab-current .qd-tab-caption:after{position:absolute;bottom:-.6875rem;left:0;display:inline-block;width:100%;height:.25rem;background-color:#069;content:\"\"}:host.qd-tab-done,:host.qd-tab-edit{color:#171717}:host.qd-tab-error{color:#c70023}:host.qd-tab-disabled{color:#b4b4b4;cursor:default}:host.qd-tab-disabled:hover{color:#b4b4b4}\n"], dependencies: [{ kind: "component", type: QdPageTabHeaderCountersComponent, selector: "qd-page-tab-header-counters", inputs: ["counters", "data-test-id"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
29425
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdPageTabHeaderComponent, isStandalone: true, selector: "qd-page-tab-header", inputs: { state: "state", label: "label", counters: "counters", index: "index", isSelected: "isSelected", isDisabled: "isDisabled", testId: ["data-test-id", "testId"] }, host: { properties: { "attr.data-test-id": "testId", "class.qd-tab-current": "isSelected && !isDisabled", "class.qd-tab-disabled": "isDisabled", "class.qd-tab-done": "state === STEP_STATE.DONE", "class.qd-tab-edit": "state === STEP_STATE.EDIT", "class.qd-tab-error": "state === STEP_STATE.ERROR" } }, usesInheritance: true, ngImport: i0, template: "<span class=\"qd-tab-caption\">\n {{ label }}\n <qd-page-tab-header-counters [counters]=\"counters\" [data-test-id]=\"testId + '-counters'\" />\n</span>\n", styles: [":host{position:relative;display:inline-flex;height:2.5rem;padding:.625rem 0;cursor:pointer;color:#757575;font-size:14px;font-weight:400;line-height:18px}:host .qd-tab-caption{font-weight:500;white-space:nowrap}:host:hover,:host.qd-tab-current{color:#069}:host.qd-tab-current .qd-tab-caption{position:relative}:host.qd-tab-current .qd-tab-caption:after{position:absolute;bottom:-.6875rem;left:0;display:inline-block;width:100%;height:.25rem;background-color:#069;content:\"\"}:host.qd-tab-done,:host.qd-tab-edit{color:#171717}:host.qd-tab-error{color:#c70023}:host.qd-tab-disabled{color:#b4b4b4;cursor:default}:host.qd-tab-disabled:hover{color:#b4b4b4}\n"], dependencies: [{ kind: "component", type: QdPageTabHeaderCountersComponent, selector: "qd-page-tab-header-counters", inputs: ["counters", "data-test-id"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
29191
29426
  }
29192
29427
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPageTabHeaderComponent, decorators: [{
29193
29428
  type: Component,
@@ -29198,7 +29433,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
29198
29433
  '[class.qd-tab-done]': 'state === STEP_STATE.DONE',
29199
29434
  '[class.qd-tab-edit]': 'state === STEP_STATE.EDIT',
29200
29435
  '[class.qd-tab-error]': 'state === STEP_STATE.ERROR'
29201
- }, standalone: true, imports: [QdPageTabHeaderCountersComponent], template: "<span class=\"qd-tab-caption\">\n {{ label }}\n <qd-page-tab-header-counters [counters]=\"counters\" [data-test-id]=\"testId + '-counters'\" />\n</span>\n", styles: [":host{position:relative;display:inline-flex;height:2.5rem;padding:.625rem 0;cursor:pointer;color:#757575;font-size:14px;font-weight:400;line-height:18px}:host .qd-tab-caption{font-weight:500}:host:hover,:host.qd-tab-current{color:#069}:host.qd-tab-current .qd-tab-caption{position:relative}:host.qd-tab-current .qd-tab-caption:after{position:absolute;bottom:-.6875rem;left:0;display:inline-block;width:100%;height:.25rem;background-color:#069;content:\"\"}:host.qd-tab-done,:host.qd-tab-edit{color:#171717}:host.qd-tab-error{color:#c70023}:host.qd-tab-disabled{color:#b4b4b4;cursor:default}:host.qd-tab-disabled:hover{color:#b4b4b4}\n"] }]
29436
+ }, standalone: true, imports: [QdPageTabHeaderCountersComponent], template: "<span class=\"qd-tab-caption\">\n {{ label }}\n <qd-page-tab-header-counters [counters]=\"counters\" [data-test-id]=\"testId + '-counters'\" />\n</span>\n", styles: [":host{position:relative;display:inline-flex;height:2.5rem;padding:.625rem 0;cursor:pointer;color:#757575;font-size:14px;font-weight:400;line-height:18px}:host .qd-tab-caption{font-weight:500;white-space:nowrap}:host:hover,:host.qd-tab-current{color:#069}:host.qd-tab-current .qd-tab-caption{position:relative}:host.qd-tab-current .qd-tab-caption:after{position:absolute;bottom:-.6875rem;left:0;display:inline-block;width:100%;height:.25rem;background-color:#069;content:\"\"}:host.qd-tab-done,:host.qd-tab-edit{color:#171717}:host.qd-tab-error{color:#c70023}:host.qd-tab-disabled{color:#b4b4b4;cursor:default}:host.qd-tab-disabled:hover{color:#b4b4b4}\n"] }]
29202
29437
  }], ctorParameters: () => [], propDecorators: { state: [{
29203
29438
  type: Input
29204
29439
  }], label: [{
@@ -30437,7 +30672,7 @@ class QdPageComponent {
30437
30672
  QdPageSubmitActionService,
30438
30673
  QdResolverTriggerService,
30439
30674
  QdPageNavigationInterceptorService
30440
- ], queries: [{ propertyName: "controlPanel", first: true, predicate: QdPageControlPanelComponent, descendants: true }, { propertyName: "stepperComponent", first: true, predicate: QdPageStepperComponent, descendants: true }, { propertyName: "tabsComponent", first: true, predicate: QdPageTabsComponent, descendants: true }, { propertyName: "stepperAdapterDirective", first: true, predicate: QdPageStepperAdapterDirective, descendants: true }, { propertyName: "tabsAdapterDirective", first: true, predicate: QdPageTabsAdapterDirective, descendants: true }, { propertyName: "sections", predicate: QdSectionComponent }, { propertyName: "infoBanners", predicate: QdPageInfoBannerComponent }], usesOnChanges: true, ngImport: i0, template: "<main qdSnackbarListener>\n <qd-page-object-header\n [data-test-id]=\"testId\"\n [attr.data-test-id]=\"testId + 'object-header'\"\n [config]=\"config\"\n [hasNavigation]=\"hasNavigation\"\n ></qd-page-object-header>\n\n <div class=\"page-info-banners\">\n <ng-content select=\"qd-page-info-banner\"></ng-content>\n </div>\n\n <ng-container *ngIf=\"config.pageType === 'create' || config.pageType === 'custom'\">\n <ng-content select=\"qd-page-stepper\"></ng-content>\n <ng-content select=\"[qdPageStepperAdapter]\"></ng-content>\n </ng-container>\n\n <ng-container *ngIf=\"config.pageType === 'overview' || config.pageType === 'inspect' || config.pageType === 'custom'\">\n <ng-content select=\"qd-page-tabs\"></ng-content>\n <ng-content select=\"[qdPageTabsAdapter]\"></ng-content>\n <ng-content select=\"qd-section\"></ng-content>\n <ng-content select=\"[qdSectionAdapter]\"></ng-content>\n </ng-container>\n\n <ng-container *ngIf=\"config.pageType === 'custom'\">\n <ng-container *ngTemplateOutlet=\"projectedContent\"></ng-container>\n </ng-container>\n</main>\n\n<footer *ngIf=\"footerHasContent$ | async\">\n <qd-page-footer [attr.data-test-id]=\"testId + '-footer'\">\n <ng-content select=\"[qdPageFooter]\"></ng-content>\n </qd-page-footer>\n</footer>\n\n<aside *ngIf=\"isControlPanelVisible\">\n <ng-content select=\"qd-page-control-panel\"></ng-content>\n</aside>\n\n<qd-projection-guard *ngIf=\"config.pageType !== 'custom'\" [warningMessage]=\"projectionGuardMessage\">\n <ng-container *ngTemplateOutlet=\"projectedContent\"></ng-container>\n</qd-projection-guard>\n\n<ng-template #projectedContent>\n <ng-content></ng-content>\n</ng-template>\n", styles: [":host{position:absolute;display:grid;overflow:hidden;width:100%;height:100%;background:#efefef;grid-template-areas:\"main\";grid-template-columns:1fr;grid-template-rows:1fr}:host.has-control-panel{grid-template-areas:\"main aside\";grid-template-columns:1fr 18.75rem}:host.control-panel-broad{grid-template-columns:1fr 27rem}:host.has-info-banners .page-info-banners{padding:1rem 1.25rem .5rem;border-bottom:rgb(213,213,213) solid .0625rem;background-color:#fff}@media (max-width: 599.98px){:host.has-info-banners .page-info-banners{padding-right:.9375rem;padding-left:.9375rem}}:host.has-info-banners qd-page-info-banner:last-child{margin-bottom:0}:host.has-footer{grid-template-areas:\"main\" \"footer\";grid-template-rows:calc(100% - 4rem) 4rem}:host.has-control-panel.has-footer{grid-template-areas:\"main aside\" \"footer aside\"}:host main{position:relative;grid-area:main;overflow-y:auto}:host aside{border-left:rgb(213,213,213) solid .0625rem;background:#fff;grid-area:aside}:host footer{grid-area:footer}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success{position:relative;top:-.5rem;padding-top:0rem;padding-bottom:0rem;border-top-width:0;margin-bottom:0rem}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .icon,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .icon,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .icon,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .icon{display:none}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .title,:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .message,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .title,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .message,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .title,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .message,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .title,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .message{position:relative;top:-.625rem}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info:before,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning:before,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical:before,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success:before{position:relative;top:-.625rem;left:-2.75rem;display:block;width:calc(100% + 4.75rem);height:.625rem;background-color:#fff;content:\"\"}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: QdProjectionGuardComponent, selector: "qd-projection-guard", inputs: ["isDisabled", "warningMessage"] }, { kind: "component", type: QdPageFooterComponent, selector: "qd-page-footer" }, { kind: "component", type: QdPageObjectHeaderComponent, selector: "qd-page-object-header", inputs: ["config", "hasNavigation", "data-test-id"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }] });
30675
+ ], queries: [{ propertyName: "controlPanel", first: true, predicate: QdPageControlPanelComponent, descendants: true }, { propertyName: "stepperComponent", first: true, predicate: QdPageStepperComponent, descendants: true }, { propertyName: "tabsComponent", first: true, predicate: QdPageTabsComponent, descendants: true }, { propertyName: "stepperAdapterDirective", first: true, predicate: QdPageStepperAdapterDirective, descendants: true }, { propertyName: "tabsAdapterDirective", first: true, predicate: QdPageTabsAdapterDirective, descendants: true }, { propertyName: "sections", predicate: QdSectionComponent }, { propertyName: "infoBanners", predicate: QdPageInfoBannerComponent }], usesOnChanges: true, ngImport: i0, template: "<main qdSnackbarListener cdkScrollable>\n <qd-page-object-header\n [data-test-id]=\"testId\"\n [attr.data-test-id]=\"testId + 'object-header'\"\n [config]=\"config\"\n [hasNavigation]=\"hasNavigation\"\n ></qd-page-object-header>\n\n <div class=\"page-info-banners\">\n <ng-content select=\"qd-page-info-banner\"></ng-content>\n </div>\n\n <ng-container *ngIf=\"config.pageType === 'create' || config.pageType === 'custom'\">\n <ng-content select=\"qd-page-stepper\"></ng-content>\n <ng-content select=\"[qdPageStepperAdapter]\"></ng-content>\n </ng-container>\n\n <ng-container *ngIf=\"config.pageType === 'overview' || config.pageType === 'inspect' || config.pageType === 'custom'\">\n <ng-content select=\"qd-page-tabs\"></ng-content>\n <ng-content select=\"[qdPageTabsAdapter]\"></ng-content>\n <ng-content select=\"qd-section\"></ng-content>\n <ng-content select=\"[qdSectionAdapter]\"></ng-content>\n </ng-container>\n\n <ng-container *ngIf=\"config.pageType === 'custom'\">\n <ng-container *ngTemplateOutlet=\"projectedContent\"></ng-container>\n </ng-container>\n</main>\n\n<footer *ngIf=\"footerHasContent$ | async\">\n <qd-page-footer [attr.data-test-id]=\"testId + '-footer'\">\n <ng-content select=\"[qdPageFooter]\"></ng-content>\n </qd-page-footer>\n</footer>\n\n<aside *ngIf=\"isControlPanelVisible\">\n <ng-content select=\"qd-page-control-panel\"></ng-content>\n</aside>\n\n<qd-projection-guard *ngIf=\"config.pageType !== 'custom'\" [warningMessage]=\"projectionGuardMessage\">\n <ng-container *ngTemplateOutlet=\"projectedContent\"></ng-container>\n</qd-projection-guard>\n\n<ng-template #projectedContent>\n <ng-content></ng-content>\n</ng-template>\n", styles: [":host{position:absolute;display:grid;overflow:hidden;width:100%;height:100%;background:#efefef;grid-template-areas:\"main\";grid-template-columns:1fr;grid-template-rows:1fr}:host.has-control-panel{grid-template-areas:\"main aside\";grid-template-columns:1fr 18.75rem}:host.control-panel-broad{grid-template-columns:1fr 27rem}:host.has-info-banners .page-info-banners{padding:1rem 1.25rem .5rem;border-bottom:rgb(213,213,213) solid .0625rem;background-color:#fff}@media (max-width: 599.98px){:host.has-info-banners .page-info-banners{padding-right:.9375rem;padding-left:.9375rem}}:host.has-info-banners qd-page-info-banner:last-child{margin-bottom:0}:host.has-footer{grid-template-areas:\"main\" \"footer\";grid-template-rows:calc(100% - 4rem) 4rem}:host.has-control-panel.has-footer{grid-template-areas:\"main aside\" \"footer aside\"}:host main{position:relative;grid-area:main;overflow-y:auto}:host aside{border-left:rgb(213,213,213) solid .0625rem;background:#fff;grid-area:aside}:host footer{grid-area:footer}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success{position:relative;top:-.5rem;padding-top:0rem;padding-bottom:0rem;border-top-width:0;margin-bottom:0rem}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .icon,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .icon,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .icon,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .icon{display:none}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .title,:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .message,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .title,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .message,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .title,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .message,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .title,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .message{position:relative;top:-.625rem}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info:before,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning:before,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical:before,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success:before{position:relative;top:-.625rem;left:-2.75rem;display:block;width:calc(100% + 4.75rem);height:.625rem;background-color:#fff;content:\"\"}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$2.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "component", type: QdProjectionGuardComponent, selector: "qd-projection-guard", inputs: ["isDisabled", "warningMessage"] }, { kind: "component", type: QdPageFooterComponent, selector: "qd-page-footer" }, { kind: "component", type: QdPageObjectHeaderComponent, selector: "qd-page-object-header", inputs: ["config", "hasNavigation", "data-test-id"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }] });
30441
30676
  }
30442
30677
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPageComponent, decorators: [{
30443
30678
  type: Component,
@@ -30447,7 +30682,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
30447
30682
  QdPageSubmitActionService,
30448
30683
  QdResolverTriggerService,
30449
30684
  QdPageNavigationInterceptorService
30450
- ], host: { '[class.has-control-panel]': 'isControlPanelVisible', '[class.control-panel-broad]': 'isControlPanelBroad' }, standalone: false, template: "<main qdSnackbarListener>\n <qd-page-object-header\n [data-test-id]=\"testId\"\n [attr.data-test-id]=\"testId + 'object-header'\"\n [config]=\"config\"\n [hasNavigation]=\"hasNavigation\"\n ></qd-page-object-header>\n\n <div class=\"page-info-banners\">\n <ng-content select=\"qd-page-info-banner\"></ng-content>\n </div>\n\n <ng-container *ngIf=\"config.pageType === 'create' || config.pageType === 'custom'\">\n <ng-content select=\"qd-page-stepper\"></ng-content>\n <ng-content select=\"[qdPageStepperAdapter]\"></ng-content>\n </ng-container>\n\n <ng-container *ngIf=\"config.pageType === 'overview' || config.pageType === 'inspect' || config.pageType === 'custom'\">\n <ng-content select=\"qd-page-tabs\"></ng-content>\n <ng-content select=\"[qdPageTabsAdapter]\"></ng-content>\n <ng-content select=\"qd-section\"></ng-content>\n <ng-content select=\"[qdSectionAdapter]\"></ng-content>\n </ng-container>\n\n <ng-container *ngIf=\"config.pageType === 'custom'\">\n <ng-container *ngTemplateOutlet=\"projectedContent\"></ng-container>\n </ng-container>\n</main>\n\n<footer *ngIf=\"footerHasContent$ | async\">\n <qd-page-footer [attr.data-test-id]=\"testId + '-footer'\">\n <ng-content select=\"[qdPageFooter]\"></ng-content>\n </qd-page-footer>\n</footer>\n\n<aside *ngIf=\"isControlPanelVisible\">\n <ng-content select=\"qd-page-control-panel\"></ng-content>\n</aside>\n\n<qd-projection-guard *ngIf=\"config.pageType !== 'custom'\" [warningMessage]=\"projectionGuardMessage\">\n <ng-container *ngTemplateOutlet=\"projectedContent\"></ng-container>\n</qd-projection-guard>\n\n<ng-template #projectedContent>\n <ng-content></ng-content>\n</ng-template>\n", styles: [":host{position:absolute;display:grid;overflow:hidden;width:100%;height:100%;background:#efefef;grid-template-areas:\"main\";grid-template-columns:1fr;grid-template-rows:1fr}:host.has-control-panel{grid-template-areas:\"main aside\";grid-template-columns:1fr 18.75rem}:host.control-panel-broad{grid-template-columns:1fr 27rem}:host.has-info-banners .page-info-banners{padding:1rem 1.25rem .5rem;border-bottom:rgb(213,213,213) solid .0625rem;background-color:#fff}@media (max-width: 599.98px){:host.has-info-banners .page-info-banners{padding-right:.9375rem;padding-left:.9375rem}}:host.has-info-banners qd-page-info-banner:last-child{margin-bottom:0}:host.has-footer{grid-template-areas:\"main\" \"footer\";grid-template-rows:calc(100% - 4rem) 4rem}:host.has-control-panel.has-footer{grid-template-areas:\"main aside\" \"footer aside\"}:host main{position:relative;grid-area:main;overflow-y:auto}:host aside{border-left:rgb(213,213,213) solid .0625rem;background:#fff;grid-area:aside}:host footer{grid-area:footer}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success{position:relative;top:-.5rem;padding-top:0rem;padding-bottom:0rem;border-top-width:0;margin-bottom:0rem}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .icon,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .icon,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .icon,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .icon{display:none}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .title,:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .message,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .title,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .message,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .title,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .message,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .title,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .message{position:relative;top:-.625rem}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info:before,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning:before,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical:before,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success:before{position:relative;top:-.625rem;left:-2.75rem;display:block;width:calc(100% + 4.75rem);height:.625rem;background-color:#fff;content:\"\"}\n"] }]
30685
+ ], host: { '[class.has-control-panel]': 'isControlPanelVisible', '[class.control-panel-broad]': 'isControlPanelBroad' }, standalone: false, template: "<main qdSnackbarListener cdkScrollable>\n <qd-page-object-header\n [data-test-id]=\"testId\"\n [attr.data-test-id]=\"testId + 'object-header'\"\n [config]=\"config\"\n [hasNavigation]=\"hasNavigation\"\n ></qd-page-object-header>\n\n <div class=\"page-info-banners\">\n <ng-content select=\"qd-page-info-banner\"></ng-content>\n </div>\n\n <ng-container *ngIf=\"config.pageType === 'create' || config.pageType === 'custom'\">\n <ng-content select=\"qd-page-stepper\"></ng-content>\n <ng-content select=\"[qdPageStepperAdapter]\"></ng-content>\n </ng-container>\n\n <ng-container *ngIf=\"config.pageType === 'overview' || config.pageType === 'inspect' || config.pageType === 'custom'\">\n <ng-content select=\"qd-page-tabs\"></ng-content>\n <ng-content select=\"[qdPageTabsAdapter]\"></ng-content>\n <ng-content select=\"qd-section\"></ng-content>\n <ng-content select=\"[qdSectionAdapter]\"></ng-content>\n </ng-container>\n\n <ng-container *ngIf=\"config.pageType === 'custom'\">\n <ng-container *ngTemplateOutlet=\"projectedContent\"></ng-container>\n </ng-container>\n</main>\n\n<footer *ngIf=\"footerHasContent$ | async\">\n <qd-page-footer [attr.data-test-id]=\"testId + '-footer'\">\n <ng-content select=\"[qdPageFooter]\"></ng-content>\n </qd-page-footer>\n</footer>\n\n<aside *ngIf=\"isControlPanelVisible\">\n <ng-content select=\"qd-page-control-panel\"></ng-content>\n</aside>\n\n<qd-projection-guard *ngIf=\"config.pageType !== 'custom'\" [warningMessage]=\"projectionGuardMessage\">\n <ng-container *ngTemplateOutlet=\"projectedContent\"></ng-container>\n</qd-projection-guard>\n\n<ng-template #projectedContent>\n <ng-content></ng-content>\n</ng-template>\n", styles: [":host{position:absolute;display:grid;overflow:hidden;width:100%;height:100%;background:#efefef;grid-template-areas:\"main\";grid-template-columns:1fr;grid-template-rows:1fr}:host.has-control-panel{grid-template-areas:\"main aside\";grid-template-columns:1fr 18.75rem}:host.control-panel-broad{grid-template-columns:1fr 27rem}:host.has-info-banners .page-info-banners{padding:1rem 1.25rem .5rem;border-bottom:rgb(213,213,213) solid .0625rem;background-color:#fff}@media (max-width: 599.98px){:host.has-info-banners .page-info-banners{padding-right:.9375rem;padding-left:.9375rem}}:host.has-info-banners qd-page-info-banner:last-child{margin-bottom:0}:host.has-footer{grid-template-areas:\"main\" \"footer\";grid-template-rows:calc(100% - 4rem) 4rem}:host.has-control-panel.has-footer{grid-template-areas:\"main aside\" \"footer aside\"}:host main{position:relative;grid-area:main;overflow-y:auto}:host aside{border-left:rgb(213,213,213) solid .0625rem;background:#fff;grid-area:aside}:host footer{grid-area:footer}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success{position:relative;top:-.5rem;padding-top:0rem;padding-bottom:0rem;border-top-width:0;margin-bottom:0rem}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .icon,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .icon,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .icon,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .icon{display:none}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .title,:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info .message,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .title,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning .message,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .title,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical .message,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .title,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success .message{position:relative;top:-.625rem}:host ::ng-deep .qd-page-info-banner-info+.qd-page-info-banner-info:before,:host ::ng-deep .qd-page-info-banner-warning+.qd-page-info-banner-warning:before,:host ::ng-deep .qd-page-info-banner-critical+.qd-page-info-banner-critical:before,:host ::ng-deep .qd-page-info-banner-success+.qd-page-info-banner-success:before{position:relative;top:-.625rem;left:-2.75rem;display:block;width:calc(100% + 4.75rem);height:.625rem;background-color:#fff;content:\"\"}\n"] }]
30451
30686
  }], ctorParameters: () => [], propDecorators: { config: [{
30452
30687
  type: Input,
30453
30688
  args: [{ required: true }]
@@ -30594,6 +30829,7 @@ class QdPageModule {
30594
30829
  QdPageFooterCustomContentDirective,
30595
30830
  QdContextSelectDialogComponent,
30596
30831
  QdPageInfoBannerComponent], imports: [CommonModule,
30832
+ ScrollingModule,
30597
30833
  TranslateModule,
30598
30834
  QdButtonModule,
30599
30835
  QdButtonModule,
@@ -30622,6 +30858,7 @@ class QdPageModule {
30622
30858
  useValue: DynamicFacetsServiceInstance
30623
30859
  }
30624
30860
  ], imports: [CommonModule,
30861
+ ScrollingModule,
30625
30862
  TranslateModule,
30626
30863
  QdButtonModule,
30627
30864
  QdButtonModule,
@@ -30643,6 +30880,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
30643
30880
  args: [{
30644
30881
  imports: [
30645
30882
  CommonModule,
30883
+ ScrollingModule,
30646
30884
  TranslateModule,
30647
30885
  QdButtonModule,
30648
30886
  QdButtonModule,
@@ -30999,7 +31237,7 @@ class QdShellHeaderBannerComponent {
30999
31237
  bannerService = inject(QdShellBannerService);
31000
31238
  get colorClassName() {
31001
31239
  if (this.bannerService.isProduction || this.bannerService.bannerText === '')
31002
- return;
31240
+ return '';
31003
31241
  return 'qd-shell__banner qd-shell__banner--' + this.bannerService.bannerText.toLowerCase();
31004
31242
  }
31005
31243
  get shouldRender() {
@@ -31415,6 +31653,7 @@ class QdShellServiceNavigationComponent {
31415
31653
  _config;
31416
31654
  _destroyed$ = new Subject();
31417
31655
  _attributesHaveBeenSet$ = new ReplaySubject(1);
31656
+ localeService = inject(QdLocaleService);
31418
31657
  ngOnInit() {
31419
31658
  loadJavascriptAsset(this.config?.javascriptAssetPath ?? DEFAULT_JAVASCRIPT_ASSET_PATH$1, {
31420
31659
  defer: '',
@@ -31457,6 +31696,7 @@ class QdShellServiceNavigationComponent {
31457
31696
  this._destroyed$.complete();
31458
31697
  }
31459
31698
  handleLanguageChange($event) {
31699
+ this.localeService.setServiceNavigationLanguage($event.detail);
31460
31700
  this.useLanguage($event.detail);
31461
31701
  }
31462
31702
  handleLoginStatusChange($event) {
@@ -33273,6 +33513,8 @@ class QdPageTabComponent extends CdkStep {
33273
33513
  }
33274
33514
  ngOnInit() {
33275
33515
  this.validateLabel();
33516
+ if (this.tabControl)
33517
+ this.initErrorCheck();
33276
33518
  }
33277
33519
  ngOnChanges(changes) {
33278
33520
  super.ngOnChanges();
@@ -33290,6 +33532,24 @@ class QdPageTabComponent extends CdkStep {
33290
33532
  if (!this.config?.label?.i18n)
33291
33533
  console.error('Quadrel Framework | QdPageTab - Please provide a label for the tab.');
33292
33534
  }
33535
+ initErrorCheck() {
33536
+ this.tabControl.statusChanges.pipe(takeUntil$1(this._destroyed$)).subscribe(() => {
33537
+ if (this.hasAnyError(this.tabControl)) {
33538
+ this.interacted = true;
33539
+ }
33540
+ });
33541
+ }
33542
+ hasAnyError(control) {
33543
+ if (control.errors && control.touched)
33544
+ return true;
33545
+ if (control instanceof FormGroup) {
33546
+ return Object.values(control.controls).some(this.hasAnyError);
33547
+ }
33548
+ if (control instanceof FormArray) {
33549
+ return control.controls.some(this.hasAnyError);
33550
+ }
33551
+ return false;
33552
+ }
33293
33553
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPageTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
33294
33554
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdPageTabComponent, isStandalone: true, selector: "qd-page-tab", inputs: { config: "config", tabControl: "tabControl" }, providers: [
33295
33555
  { provide: CdkStep, useExisting: QdPageTabComponent },
@@ -33993,5 +34253,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
33993
34253
  * Generated bundle index. Do not edit.
33994
34254
  */
33995
34255
 
33996
- export { APP_ENVIRONMENT, AVAILABLE_ICONS, BACKEND_ERROR_CODES, MockLocaleDatePipe, NavigationTileComponent, NavigationTilesComponent, QD_DIALOG_CONFIRMATION_RESOLVER_TOKEN, QD_FILE_MANAGER_TOKEN, QD_FILE_UPLOAD_MANAGER_TOKEN, QD_FORM_OPTIONS_RESOLVER, QD_PAGE_OBJECT_RESOLVER_TOKEN, QD_PAGE_STEP_RESOLVER_TOKEN, QD_POPOVER_TOP_FIRST, QD_SAFE_BOTTOM_OFFSET, QD_TABLE_DATA_RESOLVER_TOKEN, QD_UPLOAD_HTTP_OPTIONS, QdButtonComponent, QdButtonGhostDirective, QdButtonGridComponent, QdButtonLinkDirective, QdButtonModule, QdButtonStackButtonComponent, QdButtonStackComponent, QdCheckboxChipsComponent, QdCheckboxComponent, QdCheckboxesComponent, QdChipComponent, QdChipModule, QdColumnAutoFillDirective, QdColumnBreakBeforeDirective, QdColumnDirective, QdColumnDisableResponsiveColspansDirective, QdColumnFullGridWidthDirective, QdColumnNextInSameRowDirective, QdColumnsDirective, QdColumnsDisableAutoFillDirective, QdColumnsDisableResponsiveColspansDirective, QdColumnsMaxDirective, QdCommentsComponent, QdCommentsModule, QdConnectFormStateToPageDirective, QdConnectorTableContextDirective, QdConnectorTableFilterDirective, QdConnectorTableSearchDirective, QdContactCardComponent, QdContactCardModule, QdContainerPairsCaptionComponent, QdContainerPairsContainerComponent, QdContainerPairsHeaderComponent, QdContainerPairsItemComponent, QdContainerPairsValueComponent, QdContextService, QdCoreModule, QdDatepickerComponent, QdDialogActionComponent, QdDialogAuthSessionEndComponent, QdDialogAuthSessionEndService, QdDialogComponent, QdDialogConfirmationComponent, QdDialogConfirmationErrorDirective, QdDialogConfirmationInfoDirective, QdDialogConfirmationSuccessDirective, QdDialogModule, QdDialogRecordStepperComponent, QdDialogService, QdDialogSize, QdDisabledDirective, QdDropdownComponent, QdFileCollectorComponent, QdFileCollectorModule, QdFileSizePipe$1 as QdFileSizePipe, QdFileUploadComponent, QdFileUploadService, QdFilterComponent, QdFilterFormItemsComponent, QdFilterModule, QdFilterRestParamBuilder, QdFilterService, QdFormArray, QdFormBuilder, QdFormControl, QdFormGroup, QdFormModule, QdGridComponent, QdGridModule, QdHorizontalPairsCaptionComponent, QdHorizontalPairsComponent, QdHorizontalPairsItemComponent, QdHorizontalPairsValueComponent, QdIconButtonComponent, QdIconComponent, QdIconModule, QdImageComponent, QdImageModule, QdIndeterminateProgressBarComponent, QdInputComponent, QdListModule, QdMenuButtonComponent, QdMockBreakpointService, QdMockButtonComponent, QdMockButtonGhostDirective, QdMockButtonGridComponent, QdMockButtonLinkDirective, QdMockButtonModule, QdMockButtonStackButtonComponent, QdMockButtonStackComponent, QdMockCalendarComponent, QdMockCheckboxChipsComponent, QdMockCheckboxComponent, QdMockCheckboxesComponent, QdMockChipComponent, QdMockChipModule, QdMockColumnDirective, QdMockColumnsDirective, QdMockContactCardComponent, QdMockContactCardModule, QdMockContainerPairsCaptionComponent, QdMockContainerPairsContainerComponent, QdMockContainerPairsHeaderComponent, QdMockContainerPairsItemComponent, QdMockContainerPairsValueComponent, QdMockCoreModule, QdMockCounterBadgeComponent, QdMockDatepickerComponent, QdMockDisabledDirective, QdMockDropdownComponent, QdMockFileCollectorComponent, QdMockFileCollectorModule, QdMockFilterCategoryBooleanComponent, QdMockFilterCategoryComponent, QdMockFilterCategoryDateComponent, QdMockFilterCategoryDateRangeComponent, QdMockFilterCategoryFreeTextComponent, QdMockFilterCategorySelectComponent, QdMockFilterComponent, QdMockFilterFormItemsComponent, QdMockFilterItemBooleanComponent, QdMockFilterItemDateComponent, QdMockFilterItemDateRangeComponent, QdMockFilterItemFreeTextComponent, QdMockFilterItemMultiSelectComponent, QdMockFilterItemSingleSelectComponent, QdMockFilterModule, QdMockFilterService, QdMockFormErrorComponent, QdMockFormGroupErrorComponent, QdMockFormHintComponent, QdMockFormLabelComponent, QdMockFormReadonlyComponent, QdMockFormViewonlyComponent, QdMockFormsModule, QdMockGridModule, QdMockIconButtonComponent, QdMockIconComponent, QdMockIconModule, QdMockImageComponent, QdMockImageModule, QdMockIndeterminateProgressBarComponent, QdMockInputComponent, QdMockListModule, QdMockNavigationTileComponent, QdMockNavigationTilesComponent, QdMockNavigationTilesModule, QdMockNotificationComponent, QdMockNotificationContentComponent, QdMockNotificationsComponent, QdMockNotificationsModule, QdMockNotificationsService, QdMockPageComponent, QdMockPageModule, QdMockPercentageProgressBarComponent, QdMockPinCodeComponent, QdMockPlaceHolderModule, QdMockPopoverOnClickDirective, QdMockProgressBarModule, QdMockQdPlaceHolderComponent, QdMockRadioButtonsComponent, QdMockRwdDisabledDirective, QdMockSearchComponent, QdMockSearchModule, QdMockSectionComponent, QdMockSectionModule, QdMockShellComponent, QdMockShellFooterComponent, QdMockShellHeaderBannerComponent, QdMockShellHeaderComponent, QdMockShellHeaderSearchComponent, QdMockShellHeaderWidgetComponent, QdMockShellModule, QdMockShellToolbarComponent, QdMockShellToolbarItemComponent, QdMockStatusIndicatorCaptionComponent, QdMockStatusIndicatorComponent, QdMockStatusIndicatorItemComponent, QdMockStatusIndicatorModule, QdMockStatusPairsCaptionComponent, QdMockStatusPairsComponent, QdMockStatusPairsErrorComponent, QdMockStatusPairsItemComponent, QdMockStatusPairsValueComponent, QdMockSwitchComponent, QdMockSwitchesComponent, QdMockTableComponent, QdMockTableModule, QdMockTextSectionComponent, QdMockTextSectionHeadlineComponent, QdMockTextSectionModule, QdMockTextSectionParagraphComponent, QdMockTextareaComponent, QdMockTileButtonListComponent, QdMockTileComponent, QdMockTileTextListComponent, QdMockTileTextListItemComponent, QdMockTileTitleComponent, QdMockTilesContainerComponent, QdMockTilesContainerTitleComponent, QdMockTilesModule, QdMockTranslatePipe, QdMockVisuallyHiddenDirective, QdMultiInputComponent, QdNavigationTilesModule, QdNotificationComponent, QdNotificationContentComponent, QdNotificationsComponent, QdNotificationsHttpInterceptorService, QdNotificationsModule, QdNotificationsService, QdNotificationsSnackbarListenerDirective, QdPageComponent, QdPageControlPanelComponent, QdPageFooterComponent, QdPageFooterCustomContentDirective, QdPageInfoBannerComponent, QdPageModule, QdPageStepComponent, QdPageStepperAdapterDirective, QdPageStepperComponent, QdPageStepperModule, QdPageStoreService, QdPageTabComponent, QdPageTabsAdapterDirective, QdPageTabsComponent, QdPageTabsModule, QdPanelSectionActionsComponent, QdPanelSectionComponent, QdPanelSectionModule, QdPanelSectionStatusComponent, QdPanelSectionTextParagraphComponent, QdPendingChangesGuardDirective, QdPercentageProgressBarComponent, QdPinCodeComponent, QdPlaceHolderComponent, QdPlaceHolderModule, QdPlaceholderPipe, QdProgressBarModule, QdProjectionGuardComponent, QdPushEventsService, QdQuickEditComponent, QdQuickEditModule, QdRadioButtonsComponent, QdRichtextComponent, QdRouterQueryParamHubService, QdRwdDisabledDirective, QdSearchComponent, QdSearchModule, QdSectionAdapterDirective, QdSectionComponent, QdSectionModule, QdSectionToolbarComponent, QdShellComponent, QdShellModule, QdSortDirection, QdSpinnerComponent, QdSpinnerModule, QdStatusIndicatorComponent, QdStatusIndicatorModule, QdStatusPairsCaptionComponent, QdStatusPairsComponent, QdStatusPairsErrorComponent, QdStatusPairsItemComponent, QdStatusPairsValueComponent, QdSubgridComponent, QdSwitchComponent, QdSwitchesComponent, QdTableComponent, QdTableModule, QdTableSpringTools, QdTextSectionComponent, QdTextSectionHeadlineComponent, QdTextSectionModule, QdTextSectionParagraphComponent, QdTextareaComponent, QdTileButtonListComponent, QdTileComponent, QdTileTextListComponent, QdTileTextListItemComponent, QdTileTitleComponent, QdTilesComponent, QdTilesModule, QdTilesTitleComponent, QdTooltipAtIntersectionDirective, QdTooltipIconComponent, QdTreeComponent, QdTreeModule, QdTreeRowExpanderService, QdUiMockModule, QdUiModule, QdUploadErrorType, QdValidators, QdViewportAdaptiveDirective, QdVisuallyHiddenDirective, chipColorDefault, createMetadataStream, updateHtmlLang };
34256
+ export { APP_ENVIRONMENT, AVAILABLE_ICONS, BACKEND_ERROR_CODES, MockLocaleDatePipe, NavigationTileComponent, NavigationTilesComponent, QD_DIALOG_CONFIRMATION_RESOLVER_TOKEN, QD_FILE_MANAGER_TOKEN, QD_FILE_UPLOAD_MANAGER_TOKEN, QD_FORM_OPTIONS_RESOLVER, QD_PAGE_OBJECT_RESOLVER_TOKEN, QD_PAGE_STEP_RESOLVER_TOKEN, QD_POPOVER_TOP_FIRST, QD_SAFE_BOTTOM_OFFSET, QD_TABLE_DATA_RESOLVER_TOKEN, QD_UPLOAD_HTTP_OPTIONS, QdButtonComponent, QdButtonGhostDirective, QdButtonGridComponent, QdButtonLinkDirective, QdButtonModule, QdButtonStackButtonComponent, QdButtonStackComponent, QdCheckboxChipsComponent, QdCheckboxComponent, QdCheckboxesComponent, QdChipComponent, QdChipModule, QdColumnAutoFillDirective, QdColumnBreakBeforeDirective, QdColumnDirective, QdColumnDisableResponsiveColspansDirective, QdColumnFullGridWidthDirective, QdColumnNextInSameRowDirective, QdColumnsDirective, QdColumnsDisableAutoFillDirective, QdColumnsDisableResponsiveColspansDirective, QdColumnsMaxDirective, QdCommentsComponent, QdCommentsModule, QdConnectFormStateToPageDirective, QdConnectorTableContextDirective, QdConnectorTableFilterDirective, QdConnectorTableSearchDirective, QdContactCardComponent, QdContactCardModule, QdContainerPairsCaptionComponent, QdContainerPairsContainerComponent, QdContainerPairsHeaderComponent, QdContainerPairsItemComponent, QdContainerPairsValueComponent, QdContextService, QdCoreModule, QdDatepickerComponent, QdDialogActionComponent, QdDialogAuthSessionEndComponent, QdDialogAuthSessionEndService, QdDialogComponent, QdDialogConfirmationComponent, QdDialogConfirmationErrorDirective, QdDialogConfirmationInfoDirective, QdDialogConfirmationSuccessDirective, QdDialogModule, QdDialogRecordStepperComponent, QdDialogService, QdDialogSize, QdDisabledDirective, QdDropdownComponent, QdFileCollectorComponent, QdFileCollectorModule, QdFileSizePipe$1 as QdFileSizePipe, QdFileUploadComponent, QdFileUploadService, QdFilterComponent, QdFilterFormItemsComponent, QdFilterModule, QdFilterRestParamBuilder, QdFilterService, QdFormArray, QdFormBuilder, QdFormControl, QdFormGroup, QdFormModule, QdGridComponent, QdGridModule, QdHorizontalPairsCaptionComponent, QdHorizontalPairsComponent, QdHorizontalPairsItemComponent, QdHorizontalPairsValueComponent, QdIconButtonComponent, QdIconComponent, QdIconModule, QdImageComponent, QdImageModule, QdIndeterminateProgressBarComponent, QdInputComponent, QdListModule, QdMenuButtonComponent, QdMockBreakpointService, QdMockButtonComponent, QdMockButtonGhostDirective, QdMockButtonGridComponent, QdMockButtonLinkDirective, QdMockButtonModule, QdMockButtonStackButtonComponent, QdMockButtonStackComponent, QdMockCalendarComponent, QdMockCheckboxChipsComponent, QdMockCheckboxComponent, QdMockCheckboxesComponent, QdMockChipComponent, QdMockChipModule, QdMockColumnDirective, QdMockColumnsDirective, QdMockContactCardComponent, QdMockContactCardModule, QdMockContainerPairsCaptionComponent, QdMockContainerPairsContainerComponent, QdMockContainerPairsHeaderComponent, QdMockContainerPairsItemComponent, QdMockContainerPairsValueComponent, QdMockCoreModule, QdMockCounterBadgeComponent, QdMockDatepickerComponent, QdMockDisabledDirective, QdMockDropdownComponent, QdMockFileCollectorComponent, QdMockFileCollectorModule, QdMockFilterCategoryBooleanComponent, QdMockFilterCategoryComponent, QdMockFilterCategoryDateComponent, QdMockFilterCategoryDateRangeComponent, QdMockFilterCategoryFreeTextComponent, QdMockFilterCategorySelectComponent, QdMockFilterComponent, QdMockFilterFormItemsComponent, QdMockFilterItemBooleanComponent, QdMockFilterItemDateComponent, QdMockFilterItemDateRangeComponent, QdMockFilterItemFreeTextComponent, QdMockFilterItemMultiSelectComponent, QdMockFilterItemSingleSelectComponent, QdMockFilterModule, QdMockFilterService, QdMockFormErrorComponent, QdMockFormGroupErrorComponent, QdMockFormHintComponent, QdMockFormLabelComponent, QdMockFormReadonlyComponent, QdMockFormViewonlyComponent, QdMockFormsModule, QdMockGridModule, QdMockIconButtonComponent, QdMockIconComponent, QdMockIconModule, QdMockImageComponent, QdMockImageModule, QdMockIndeterminateProgressBarComponent, QdMockInputComponent, QdMockListModule, QdMockNavigationTileComponent, QdMockNavigationTilesComponent, QdMockNavigationTilesModule, QdMockNotificationComponent, QdMockNotificationContentComponent, QdMockNotificationsComponent, QdMockNotificationsModule, QdMockNotificationsService, QdMockPageComponent, QdMockPageModule, QdMockPercentageProgressBarComponent, QdMockPinCodeComponent, QdMockPlaceHolderModule, QdMockPopoverOnClickDirective, QdMockProgressBarModule, QdMockQdPlaceHolderComponent, QdMockRadioButtonsComponent, QdMockRwdDisabledDirective, QdMockSearchComponent, QdMockSearchModule, QdMockSectionComponent, QdMockSectionModule, QdMockShellComponent, QdMockShellFooterComponent, QdMockShellHeaderBannerComponent, QdMockShellHeaderComponent, QdMockShellHeaderSearchComponent, QdMockShellHeaderWidgetComponent, QdMockShellModule, QdMockShellToolbarComponent, QdMockShellToolbarItemComponent, QdMockStatusIndicatorCaptionComponent, QdMockStatusIndicatorComponent, QdMockStatusIndicatorItemComponent, QdMockStatusIndicatorModule, QdMockStatusPairsCaptionComponent, QdMockStatusPairsComponent, QdMockStatusPairsErrorComponent, QdMockStatusPairsItemComponent, QdMockStatusPairsValueComponent, QdMockSwitchComponent, QdMockSwitchesComponent, QdMockTableComponent, QdMockTableModule, QdMockTextSectionComponent, QdMockTextSectionHeadlineComponent, QdMockTextSectionModule, QdMockTextSectionParagraphComponent, QdMockTextareaComponent, QdMockTileButtonListComponent, QdMockTileComponent, QdMockTileTextListComponent, QdMockTileTextListItemComponent, QdMockTileTitleComponent, QdMockTilesContainerComponent, QdMockTilesContainerTitleComponent, QdMockTilesModule, QdMockTranslatePipe, QdMockVisuallyHiddenDirective, QdMultiInputComponent, QdNavigationTilesModule, QdNotificationComponent, QdNotificationContentComponent, QdNotificationsComponent, QdNotificationsHttpInterceptorService, QdNotificationsModule, QdNotificationsService, QdNotificationsSnackbarListenerDirective, QdNumberInputService, QdPageComponent, QdPageControlPanelComponent, QdPageFooterComponent, QdPageFooterCustomContentDirective, QdPageInfoBannerComponent, QdPageModule, QdPageStepComponent, QdPageStepperAdapterDirective, QdPageStepperComponent, QdPageStepperModule, QdPageStoreService, QdPageTabComponent, QdPageTabsAdapterDirective, QdPageTabsComponent, QdPageTabsModule, QdPanelSectionActionsComponent, QdPanelSectionComponent, QdPanelSectionModule, QdPanelSectionStatusComponent, QdPanelSectionTextParagraphComponent, QdPendingChangesGuardDirective, QdPercentageProgressBarComponent, QdPinCodeComponent, QdPlaceHolderComponent, QdPlaceHolderModule, QdPlaceholderPipe, QdProgressBarModule, QdProjectionGuardComponent, QdPushEventsService, QdQuickEditComponent, QdQuickEditModule, QdRadioButtonsComponent, QdRichtextComponent, QdRouterQueryParamHubService, QdRwdDisabledDirective, QdSearchComponent, QdSearchModule, QdSectionAdapterDirective, QdSectionComponent, QdSectionModule, QdSectionToolbarComponent, QdShellComponent, QdShellModule, QdSortDirection, QdSpinnerComponent, QdSpinnerModule, QdStatusIndicatorComponent, QdStatusIndicatorModule, QdStatusPairsCaptionComponent, QdStatusPairsComponent, QdStatusPairsErrorComponent, QdStatusPairsItemComponent, QdStatusPairsValueComponent, QdSubgridComponent, QdSwitchComponent, QdSwitchesComponent, QdTableComponent, QdTableModule, QdTableSpringTools, QdTextSectionComponent, QdTextSectionHeadlineComponent, QdTextSectionModule, QdTextSectionParagraphComponent, QdTextareaComponent, QdTileButtonListComponent, QdTileComponent, QdTileTextListComponent, QdTileTextListItemComponent, QdTileTitleComponent, QdTilesComponent, QdTilesModule, QdTilesTitleComponent, QdTooltipAtIntersectionDirective, QdTooltipIconComponent, QdTreeComponent, QdTreeModule, QdTreeRowExpanderService, QdUiMockModule, QdUiModule, QdUploadErrorType, QdValidators, QdViewportAdaptiveDirective, QdVisuallyHiddenDirective, chipColorDefault, createMetadataStream, updateHtmlLang };
33997
34257
  //# sourceMappingURL=quadrel-enterprise-ui-framework.mjs.map