@patter/ngx-components 0.5.2 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,26 +1,129 @@
1
1
  import * as i1 from '@angular/common';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { Component, ChangeDetectionStrategy, Input, EventEmitter, inject, ChangeDetectorRef, DestroyRef, Output } from '@angular/core';
4
+ import { Component, ChangeDetectionStrategy, Input, signal, EventEmitter, computed, HostBinding, Output, inject, ChangeDetectorRef, DestroyRef, ElementRef, ViewContainerRef, Renderer2, Directive, Injectable, ViewChild, createComponent } from '@angular/core';
5
5
  import * as i2 from '@angular/router';
6
- import { RouterModule, Router, ActivatedRoute, TitleStrategy, NavigationEnd } from '@angular/router';
6
+ import { RouterModule, RouterLink, Router, ActivatedRoute, TitleStrategy, NavigationEnd } from '@angular/router';
7
7
  import * as i2$1 from '@angular/forms';
8
8
  import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
9
9
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
10
- import { Observable, filter, map } from 'rxjs';
10
+ import { Observable, filter, map, Subject } from 'rxjs';
11
11
 
12
12
  class PtrMenuComponent {
13
13
  menuItems = [];
14
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.2", ngImport: i0, type: PtrMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
15
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.1.2", type: PtrMenuComponent, isStandalone: true, selector: "ptr-menu", inputs: { menuItems: "menuItems" }, ngImport: i0, template: "<nav class=\"ptr-menu\">\r\n <ul class=\"menu\">\r\n <li class=\"menu-item\" *ngFor=\"let item of menuItems\" routerLinkActive=\"current_page_item\"\r\n [routerLinkActiveOptions]=\"{exact: true}\">\r\n <a [routerLink]=\"item.link || '#'\">{{item.label}}</a>\r\n </li>\r\n </ul>\r\n</nav>\r\n", styles: [".menu{display:flex;flex-direction:row;gap:var(--wp--custom--content--gap, 40px);align-items:center}.menu>ul{display:flex;flex-direction:row;gap:var(--wp--custom--content--gap, 40px);align-items:center}.menu--vertical{flex-direction:column;align-items:flex-start;gap:calc(var(--wp--custom--content--gap, 40px) / 2)}.menu--vertical>ul{flex-direction:column;align-items:flex-start;gap:calc(var(--wp--custom--content--gap, 40px) / 2)}.menu li.current-menu-item>a,.menu li.current_page_item>a,.menu li.current-menu-parent>a{opacity:1;font-weight:700}.menu a{transition:color .33s}.menu a:hover,.menu a:focus{text-decoration:none}.menu a{position:relative;text-decoration:none;padding:8px 0;font-family:var(--wp--preset--font-family--heading-font);letter-spacing:-.72px;color:var(--ptr-menu-color, var(--wp--preset--color--black))}.menu a:before,.menu a:after{content:\"\";position:absolute;bottom:2px;left:0;right:0;height:2px;background-color:var(--wp--preset--color--primary)}.menu a:before{opacity:0;transform:translateY(-8px);transition:transform 0s cubic-bezier(.175,.885,.32,1.275),opacity 0s}.menu a:after{opacity:0;transform:translateY(4px);transition:transform .2s cubic-bezier(.175,.885,.32,1.275),opacity .2s}.menu a:hover:before,.menu a:hover:after,.menu a:focus:before,.menu a:focus:after{opacity:1;transform:translateY(0)}.menu a:hover:before,.menu a:focus:before{transition:transform .2s cubic-bezier(.175,.885,.32,1.275),opacity .2s}.menu a:hover:after,.menu a:focus:after{transition:transform 0s .2s cubic-bezier(.175,.885,.32,1.275),opacity 0s .2s}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i2.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
14
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
15
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.1.4", type: PtrMenuComponent, isStandalone: true, selector: "ptr-menu", inputs: { menuItems: "menuItems" }, ngImport: i0, template: "<nav class=\"ptr-menu\">\r\n <ul class=\"menu\">\r\n <li class=\"menu-item\" *ngFor=\"let item of menuItems\" routerLinkActive=\"current_page_item\"\r\n [routerLinkActiveOptions]=\"{exact: true}\">\r\n <a [routerLink]=\"item.link || '#'\">{{item.label}}</a>\r\n </li>\r\n </ul>\r\n</nav>\r\n", styles: [".menu{display:flex;flex-direction:row;gap:var(--wp--custom--content--gap, 40px);align-items:center}.menu>ul{display:flex;flex-direction:row;gap:var(--wp--custom--content--gap, 40px);align-items:center}.menu--vertical{flex-direction:column;align-items:flex-start;gap:calc(var(--wp--custom--content--gap, 40px) / 2)}.menu--vertical>ul{flex-direction:column;align-items:flex-start;gap:calc(var(--wp--custom--content--gap, 40px) / 2)}.menu li.current-menu-item>a,.menu li.current_page_item>a,.menu li.current-menu-parent>a{opacity:1;font-weight:700}.menu a{transition:color .33s}.menu a:hover,.menu a:focus{text-decoration:none}.menu a{position:relative;text-decoration:none;padding:8px 0;font-family:var(--wp--preset--font-family--heading-font);letter-spacing:-.72px;color:var(--ptr-menu-color, var(--wp--preset--color--black))}.menu a:before,.menu a:after{content:\"\";position:absolute;bottom:2px;left:0;right:0;height:2px;background-color:var(--wp--preset--color--primary)}.menu a:before{opacity:0;transform:translateY(-8px);transition:transform 0s cubic-bezier(.175,.885,.32,1.275),opacity 0s}.menu a:after{opacity:0;transform:translateY(4px);transition:transform .2s cubic-bezier(.175,.885,.32,1.275),opacity .2s}.menu a:hover:before,.menu a:hover:after,.menu a:focus:before,.menu a:focus:after{opacity:1;transform:translateY(0)}.menu a:hover:before,.menu a:focus:before{transition:transform .2s cubic-bezier(.175,.885,.32,1.275),opacity .2s}.menu a:hover:after,.menu a:focus:after{transition:transform 0s .2s cubic-bezier(.175,.885,.32,1.275),opacity 0s .2s}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i2.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
16
16
  }
17
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.2", ngImport: i0, type: PtrMenuComponent, decorators: [{
17
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrMenuComponent, decorators: [{
18
18
  type: Component,
19
19
  args: [{ selector: 'ptr-menu', standalone: true, imports: [CommonModule, RouterModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav class=\"ptr-menu\">\r\n <ul class=\"menu\">\r\n <li class=\"menu-item\" *ngFor=\"let item of menuItems\" routerLinkActive=\"current_page_item\"\r\n [routerLinkActiveOptions]=\"{exact: true}\">\r\n <a [routerLink]=\"item.link || '#'\">{{item.label}}</a>\r\n </li>\r\n </ul>\r\n</nav>\r\n", styles: [".menu{display:flex;flex-direction:row;gap:var(--wp--custom--content--gap, 40px);align-items:center}.menu>ul{display:flex;flex-direction:row;gap:var(--wp--custom--content--gap, 40px);align-items:center}.menu--vertical{flex-direction:column;align-items:flex-start;gap:calc(var(--wp--custom--content--gap, 40px) / 2)}.menu--vertical>ul{flex-direction:column;align-items:flex-start;gap:calc(var(--wp--custom--content--gap, 40px) / 2)}.menu li.current-menu-item>a,.menu li.current_page_item>a,.menu li.current-menu-parent>a{opacity:1;font-weight:700}.menu a{transition:color .33s}.menu a:hover,.menu a:focus{text-decoration:none}.menu a{position:relative;text-decoration:none;padding:8px 0;font-family:var(--wp--preset--font-family--heading-font);letter-spacing:-.72px;color:var(--ptr-menu-color, var(--wp--preset--color--black))}.menu a:before,.menu a:after{content:\"\";position:absolute;bottom:2px;left:0;right:0;height:2px;background-color:var(--wp--preset--color--primary)}.menu a:before{opacity:0;transform:translateY(-8px);transition:transform 0s cubic-bezier(.175,.885,.32,1.275),opacity 0s}.menu a:after{opacity:0;transform:translateY(4px);transition:transform .2s cubic-bezier(.175,.885,.32,1.275),opacity .2s}.menu a:hover:before,.menu a:hover:after,.menu a:focus:before,.menu a:focus:after{opacity:1;transform:translateY(0)}.menu a:hover:before,.menu a:focus:before{transition:transform .2s cubic-bezier(.175,.885,.32,1.275),opacity .2s}.menu a:hover:after,.menu a:focus:after{transition:transform 0s .2s cubic-bezier(.175,.885,.32,1.275),opacity 0s .2s}\n"] }]
20
20
  }], propDecorators: { menuItems: [{
21
21
  type: Input
22
22
  }] } });
23
23
 
24
+ class PtrButtonComponent {
25
+ get hostClasses() {
26
+ const hostClass = [];
27
+ if (this.style() === 'secondary') {
28
+ hostClass.push('is-style-outline');
29
+ }
30
+ if (this.style() === 'error') {
31
+ hostClass.push('is-style-error-button');
32
+ }
33
+ if (this.style() === 'icon') {
34
+ hostClass.push('is-style-icon-button');
35
+ }
36
+ if (this.smallSize()) {
37
+ hostClass.push('is-style-smaller-element');
38
+ }
39
+ return hostClass.join(' ');
40
+ }
41
+ style = signal('normal');
42
+ type = signal('button');
43
+ disabled = signal(false);
44
+ href = signal(null);
45
+ routerLink = signal(null);
46
+ additionalClasses = signal('');
47
+ smallSize = signal(false);
48
+ set buttonStyle(value) {
49
+ this.style.set(value);
50
+ }
51
+ set buttonType(value) {
52
+ this.type.set(value);
53
+ }
54
+ set isDisabled(value) {
55
+ this.disabled.set(value);
56
+ }
57
+ set hrefLink(value) {
58
+ this.href.set(value);
59
+ }
60
+ set routerLinkValue(value) {
61
+ this.routerLink.set(value);
62
+ }
63
+ set extraClasses(value) {
64
+ this.additionalClasses.set(value);
65
+ }
66
+ set isSmallSize(value) {
67
+ if (value) {
68
+ this.smallSize.set(true);
69
+ }
70
+ }
71
+ set isIconButton(value) {
72
+ if (value) {
73
+ this.style.set('icon');
74
+ }
75
+ }
76
+ clicked = new EventEmitter();
77
+ isLink = computed(() => !!this.href() || !!this.routerLink());
78
+ buttonClasses = computed(() => {
79
+ const classes = ['wp-block-button__link'];
80
+ if (this.style() !== 'normal') {
81
+ classes.push(`wp-block-button__link--${this.style()}`);
82
+ }
83
+ if (this.disabled() && this.isLink()) {
84
+ classes.push('disabled');
85
+ }
86
+ if (this.additionalClasses()) {
87
+ classes.push(this.additionalClasses());
88
+ }
89
+ return classes.join(' ');
90
+ });
91
+ onClick(event) {
92
+ if (this.disabled()) {
93
+ event.preventDefault();
94
+ return;
95
+ }
96
+ this.clicked.emit(event);
97
+ }
98
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
99
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.1.4", type: PtrButtonComponent, isStandalone: true, selector: "ptr-button", inputs: { buttonStyle: "buttonStyle", buttonType: "buttonType", isDisabled: "isDisabled", hrefLink: "hrefLink", routerLinkValue: "routerLinkValue", extraClasses: "extraClasses", isSmallSize: "isSmallSize", isIconButton: "isIconButton" }, outputs: { clicked: "clicked" }, host: { properties: { "class": "this.hostClasses" } }, ngImport: i0, template: "<ng-template #contentTpl>\r\n <ng-content></ng-content>\r\n</ng-template>\r\n\r\n@if (isLink()) {\r\n<a [attr.href]=\"href()\" [routerLink]=\"routerLink()\" [class]=\"buttonClasses()\" [attr.disabled]=\"disabled() ? '' : null\"\r\n (click)=\"onClick($event)\">\r\n <ng-container [ngTemplateOutlet]=\"contentTpl\"></ng-container>\r\n</a>\r\n} @else {\r\n<button [type]=\"type()\" [class]=\"buttonClasses()\" [disabled]=\"disabled()\" (click)=\"onClick($event)\">\r\n <ng-container [ngTemplateOutlet]=\"contentTpl\"></ng-container>\r\n</button>\r\n}", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
100
+ }
101
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrButtonComponent, decorators: [{
102
+ type: Component,
103
+ args: [{ selector: 'ptr-button', standalone: true, imports: [CommonModule, RouterLink], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template #contentTpl>\r\n <ng-content></ng-content>\r\n</ng-template>\r\n\r\n@if (isLink()) {\r\n<a [attr.href]=\"href()\" [routerLink]=\"routerLink()\" [class]=\"buttonClasses()\" [attr.disabled]=\"disabled() ? '' : null\"\r\n (click)=\"onClick($event)\">\r\n <ng-container [ngTemplateOutlet]=\"contentTpl\"></ng-container>\r\n</a>\r\n} @else {\r\n<button [type]=\"type()\" [class]=\"buttonClasses()\" [disabled]=\"disabled()\" (click)=\"onClick($event)\">\r\n <ng-container [ngTemplateOutlet]=\"contentTpl\"></ng-container>\r\n</button>\r\n}" }]
104
+ }], propDecorators: { hostClasses: [{
105
+ type: HostBinding,
106
+ args: ['class']
107
+ }], buttonStyle: [{
108
+ type: Input
109
+ }], buttonType: [{
110
+ type: Input
111
+ }], isDisabled: [{
112
+ type: Input
113
+ }], hrefLink: [{
114
+ type: Input
115
+ }], routerLinkValue: [{
116
+ type: Input
117
+ }], extraClasses: [{
118
+ type: Input
119
+ }], isSmallSize: [{
120
+ type: Input
121
+ }], isIconButton: [{
122
+ type: Input
123
+ }], clicked: [{
124
+ type: Output
125
+ }] } });
126
+
24
127
  class PtrFormComponent {
25
128
  config;
26
129
  loading = false;
@@ -78,15 +181,16 @@ class PtrFormComponent {
78
181
  this.flatOptions[fieldName] = options;
79
182
  }
80
183
  }
81
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.2", ngImport: i0, type: PtrFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
82
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.1.2", type: PtrFormComponent, isStandalone: true, selector: "ptr-form", inputs: { config: "config", loading: "loading", error: "error" }, outputs: { formSubmit: "formSubmit", formGroupCreated: "formGroupCreated" }, ngImport: i0, template: "<div [class]=\"'gform_wrapper ' + config.formClass\">\r\n\r\n <div class=\"gform_validation_errors\" *ngIf=\"error\">\r\n <h2 class=\"gform_submission_error hide_summary\">{{error}}</h2>\r\n </div>\r\n\r\n <div *ngIf=\"config.title\" class=\"gform_heading\">\r\n <h2 class=\"gform_title\">{{ config.title }}</h2>\r\n </div>\r\n\r\n <form [formGroup]=\"formGroup\" (ngSubmit)=\"onSubmit()\">\r\n\r\n <div class=\"gform_fields\">\r\n\r\n <ng-container *ngFor=\"let field of config.fields\">\r\n\r\n <div class=\"gfield gfield--width-{{field.size}}\" [class.gform_hidden]=\"field.type === 'hidden'\"\r\n [class.gfield_error]=\"formGroup.get(field.name)?.invalid && formGroup.get(field.name)?.touched\">\r\n\r\n <label class=\"gfield_label gform-field-label\" [for]=\"field.name\">{{ field.label }}</label>\r\n\r\n <ng-container [ngSwitch]=\"field.type\">\r\n\r\n <input *ngSwitchCase=\"'text'\" [formControlName]=\"field.name\" type=\"text\" [id]=\"field.name\" />\r\n\r\n <textarea *ngSwitchCase=\"'textarea'\" [id]=\"field.name\" [formControlName]=\"field.name\"></textarea>\r\n\r\n <input *ngSwitchCase=\"'date'\" [formControlName]=\"field.name\" type=\"date\" [id]=\"field.name\" />\r\n\r\n <input *ngSwitchCase=\"'number'\" [formControlName]=\"field.name\" type=\"number\" [id]=\"field.name\" />\r\n\r\n <input *ngSwitchCase=\"'email'\" [formControlName]=\"field.name\" type=\"email\" [id]=\"field.name\" />\r\n\r\n <input *ngSwitchCase=\"'password'\" [formControlName]=\"field.name\" type=\"password\" [id]=\"field.name\" />\r\n\r\n <ng-container *ngSwitchCase=\"'select'\">\r\n <select [formControlName]=\"field.name\" [id]=\"field.name\">\r\n <!-- Render grouped options -->\r\n <optgroup *ngFor=\"let group of groupedOptions[field.name]\" [label]=\"group.groupLabel\">\r\n <option *ngFor=\"let option of group.options\" [value]=\"option.value\">\r\n {{ option.label }}\r\n </option>\r\n </optgroup>\r\n <!-- Render flat options -->\r\n <option *ngFor=\"let option of flatOptions[field.name]\" [value]=\"option.value\">\r\n {{ option.label }}\r\n </option>\r\n </select>\r\n </ng-container>\r\n\r\n </ng-container>\r\n\r\n <div class=\"gfield_description validation_message gfield_validation_message\"\r\n *ngIf=\"formGroup.get(field.name)?.invalid && formGroup.get(field.name)?.touched\">\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['required']\">This field is required.</ng-container>\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['email']\">Please enter a valid email\r\n address.</ng-container>\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['minlength']\">\r\n Minimum length is {{ formGroup.get(field.name)?.errors?.['minlength'].requiredLength }} characters.\r\n </ng-container>\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['maxlength']\">\r\n Maximum length is {{ formGroup.get(field.name)?.errors?.['maxlength'].requiredLength }} characters.\r\n </ng-container>\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['pattern']\">\r\n Please match the required format.\r\n </ng-container>\r\n </div>\r\n\r\n </div>\r\n\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"gform_footer\">\r\n <button type=\"submit\" [disabled]=\"loading || !formGroup.valid\">{{config.submitText}}</button>\r\n </div>\r\n\r\n </form>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
184
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
185
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.1.4", type: PtrFormComponent, isStandalone: true, selector: "ptr-form", inputs: { config: "config", loading: "loading", error: "error" }, outputs: { formSubmit: "formSubmit", formGroupCreated: "formGroupCreated" }, ngImport: i0, template: "<div [class]=\"'gform_wrapper ' + config.formClass\">\r\n\r\n <div class=\"gform_validation_errors\" *ngIf=\"error\">\r\n <h2 class=\"gform_submission_error hide_summary\">{{error}}</h2>\r\n </div>\r\n\r\n <div *ngIf=\"config.title\" class=\"gform_heading\">\r\n <h2 class=\"gform_title\">{{ config.title }}</h2>\r\n </div>\r\n\r\n <form [formGroup]=\"formGroup\" (ngSubmit)=\"onSubmit()\">\r\n\r\n <div class=\"gform_fields\">\r\n\r\n <ng-container *ngFor=\"let field of config.fields\">\r\n\r\n <div class=\"gfield gfield--width-{{field.size}}\" [class.gform_hidden]=\"field.type === 'hidden'\"\r\n [class.gfield_error]=\"formGroup.get(field.name)?.invalid && formGroup.get(field.name)?.touched\">\r\n\r\n <label class=\"gfield_label gform-field-label\" [for]=\"field.name\">{{ field.label }}</label>\r\n\r\n <ng-container [ngSwitch]=\"field.type\">\r\n\r\n <input *ngSwitchCase=\"'text'\" [formControlName]=\"field.name\" type=\"text\" [id]=\"field.name\" />\r\n\r\n <textarea *ngSwitchCase=\"'textarea'\" [id]=\"field.name\" [formControlName]=\"field.name\"></textarea>\r\n\r\n <input *ngSwitchCase=\"'date'\" [formControlName]=\"field.name\" type=\"date\" [id]=\"field.name\" />\r\n\r\n <input *ngSwitchCase=\"'number'\" [formControlName]=\"field.name\" type=\"number\" [id]=\"field.name\" />\r\n\r\n <input *ngSwitchCase=\"'email'\" [formControlName]=\"field.name\" type=\"email\" [id]=\"field.name\" />\r\n\r\n <input *ngSwitchCase=\"'password'\" [formControlName]=\"field.name\" type=\"password\" [id]=\"field.name\" />\r\n\r\n <ng-container *ngSwitchCase=\"'select'\">\r\n <select [formControlName]=\"field.name\" [id]=\"field.name\">\r\n <!-- Render grouped options -->\r\n <optgroup *ngFor=\"let group of groupedOptions[field.name]\" [label]=\"group.groupLabel\">\r\n <option *ngFor=\"let option of group.options\" [value]=\"option.value\">\r\n {{ option.label }}\r\n </option>\r\n </optgroup>\r\n <!-- Render flat options -->\r\n <option *ngFor=\"let option of flatOptions[field.name]\" [value]=\"option.value\">\r\n {{ option.label }}\r\n </option>\r\n </select>\r\n </ng-container>\r\n\r\n </ng-container>\r\n\r\n <div class=\"gfield_description validation_message gfield_validation_message\"\r\n *ngIf=\"formGroup.get(field.name)?.invalid && formGroup.get(field.name)?.touched\">\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['required']\">This field is required.</ng-container>\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['email']\">Please enter a valid email\r\n address.</ng-container>\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['minlength']\">\r\n Minimum length is {{ formGroup.get(field.name)?.errors?.['minlength'].requiredLength }} characters.\r\n </ng-container>\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['maxlength']\">\r\n Maximum length is {{ formGroup.get(field.name)?.errors?.['maxlength'].requiredLength }} characters.\r\n </ng-container>\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['pattern']\">\r\n Please match the required format.\r\n </ng-container>\r\n </div>\r\n\r\n </div>\r\n\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"gform_footer\">\r\n <ptr-button buttonType=\"submit\" [isDisabled]=\"loading || !formGroup.valid\">{{config.submitText}}</ptr-button>\r\n </div>\r\n\r\n </form>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: PtrButtonComponent, selector: "ptr-button", inputs: ["buttonStyle", "buttonType", "isDisabled", "hrefLink", "routerLinkValue", "extraClasses", "isSmallSize", "isIconButton"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
83
186
  }
84
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.2", ngImport: i0, type: PtrFormComponent, decorators: [{
187
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrFormComponent, decorators: [{
85
188
  type: Component,
86
189
  args: [{ selector: 'ptr-form', standalone: true, imports: [
87
190
  CommonModule,
88
- ReactiveFormsModule
89
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"'gform_wrapper ' + config.formClass\">\r\n\r\n <div class=\"gform_validation_errors\" *ngIf=\"error\">\r\n <h2 class=\"gform_submission_error hide_summary\">{{error}}</h2>\r\n </div>\r\n\r\n <div *ngIf=\"config.title\" class=\"gform_heading\">\r\n <h2 class=\"gform_title\">{{ config.title }}</h2>\r\n </div>\r\n\r\n <form [formGroup]=\"formGroup\" (ngSubmit)=\"onSubmit()\">\r\n\r\n <div class=\"gform_fields\">\r\n\r\n <ng-container *ngFor=\"let field of config.fields\">\r\n\r\n <div class=\"gfield gfield--width-{{field.size}}\" [class.gform_hidden]=\"field.type === 'hidden'\"\r\n [class.gfield_error]=\"formGroup.get(field.name)?.invalid && formGroup.get(field.name)?.touched\">\r\n\r\n <label class=\"gfield_label gform-field-label\" [for]=\"field.name\">{{ field.label }}</label>\r\n\r\n <ng-container [ngSwitch]=\"field.type\">\r\n\r\n <input *ngSwitchCase=\"'text'\" [formControlName]=\"field.name\" type=\"text\" [id]=\"field.name\" />\r\n\r\n <textarea *ngSwitchCase=\"'textarea'\" [id]=\"field.name\" [formControlName]=\"field.name\"></textarea>\r\n\r\n <input *ngSwitchCase=\"'date'\" [formControlName]=\"field.name\" type=\"date\" [id]=\"field.name\" />\r\n\r\n <input *ngSwitchCase=\"'number'\" [formControlName]=\"field.name\" type=\"number\" [id]=\"field.name\" />\r\n\r\n <input *ngSwitchCase=\"'email'\" [formControlName]=\"field.name\" type=\"email\" [id]=\"field.name\" />\r\n\r\n <input *ngSwitchCase=\"'password'\" [formControlName]=\"field.name\" type=\"password\" [id]=\"field.name\" />\r\n\r\n <ng-container *ngSwitchCase=\"'select'\">\r\n <select [formControlName]=\"field.name\" [id]=\"field.name\">\r\n <!-- Render grouped options -->\r\n <optgroup *ngFor=\"let group of groupedOptions[field.name]\" [label]=\"group.groupLabel\">\r\n <option *ngFor=\"let option of group.options\" [value]=\"option.value\">\r\n {{ option.label }}\r\n </option>\r\n </optgroup>\r\n <!-- Render flat options -->\r\n <option *ngFor=\"let option of flatOptions[field.name]\" [value]=\"option.value\">\r\n {{ option.label }}\r\n </option>\r\n </select>\r\n </ng-container>\r\n\r\n </ng-container>\r\n\r\n <div class=\"gfield_description validation_message gfield_validation_message\"\r\n *ngIf=\"formGroup.get(field.name)?.invalid && formGroup.get(field.name)?.touched\">\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['required']\">This field is required.</ng-container>\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['email']\">Please enter a valid email\r\n address.</ng-container>\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['minlength']\">\r\n Minimum length is {{ formGroup.get(field.name)?.errors?.['minlength'].requiredLength }} characters.\r\n </ng-container>\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['maxlength']\">\r\n Maximum length is {{ formGroup.get(field.name)?.errors?.['maxlength'].requiredLength }} characters.\r\n </ng-container>\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['pattern']\">\r\n Please match the required format.\r\n </ng-container>\r\n </div>\r\n\r\n </div>\r\n\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"gform_footer\">\r\n <button type=\"submit\" [disabled]=\"loading || !formGroup.valid\">{{config.submitText}}</button>\r\n </div>\r\n\r\n </form>\r\n</div>\r\n" }]
191
+ ReactiveFormsModule,
192
+ PtrButtonComponent
193
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"'gform_wrapper ' + config.formClass\">\r\n\r\n <div class=\"gform_validation_errors\" *ngIf=\"error\">\r\n <h2 class=\"gform_submission_error hide_summary\">{{error}}</h2>\r\n </div>\r\n\r\n <div *ngIf=\"config.title\" class=\"gform_heading\">\r\n <h2 class=\"gform_title\">{{ config.title }}</h2>\r\n </div>\r\n\r\n <form [formGroup]=\"formGroup\" (ngSubmit)=\"onSubmit()\">\r\n\r\n <div class=\"gform_fields\">\r\n\r\n <ng-container *ngFor=\"let field of config.fields\">\r\n\r\n <div class=\"gfield gfield--width-{{field.size}}\" [class.gform_hidden]=\"field.type === 'hidden'\"\r\n [class.gfield_error]=\"formGroup.get(field.name)?.invalid && formGroup.get(field.name)?.touched\">\r\n\r\n <label class=\"gfield_label gform-field-label\" [for]=\"field.name\">{{ field.label }}</label>\r\n\r\n <ng-container [ngSwitch]=\"field.type\">\r\n\r\n <input *ngSwitchCase=\"'text'\" [formControlName]=\"field.name\" type=\"text\" [id]=\"field.name\" />\r\n\r\n <textarea *ngSwitchCase=\"'textarea'\" [id]=\"field.name\" [formControlName]=\"field.name\"></textarea>\r\n\r\n <input *ngSwitchCase=\"'date'\" [formControlName]=\"field.name\" type=\"date\" [id]=\"field.name\" />\r\n\r\n <input *ngSwitchCase=\"'number'\" [formControlName]=\"field.name\" type=\"number\" [id]=\"field.name\" />\r\n\r\n <input *ngSwitchCase=\"'email'\" [formControlName]=\"field.name\" type=\"email\" [id]=\"field.name\" />\r\n\r\n <input *ngSwitchCase=\"'password'\" [formControlName]=\"field.name\" type=\"password\" [id]=\"field.name\" />\r\n\r\n <ng-container *ngSwitchCase=\"'select'\">\r\n <select [formControlName]=\"field.name\" [id]=\"field.name\">\r\n <!-- Render grouped options -->\r\n <optgroup *ngFor=\"let group of groupedOptions[field.name]\" [label]=\"group.groupLabel\">\r\n <option *ngFor=\"let option of group.options\" [value]=\"option.value\">\r\n {{ option.label }}\r\n </option>\r\n </optgroup>\r\n <!-- Render flat options -->\r\n <option *ngFor=\"let option of flatOptions[field.name]\" [value]=\"option.value\">\r\n {{ option.label }}\r\n </option>\r\n </select>\r\n </ng-container>\r\n\r\n </ng-container>\r\n\r\n <div class=\"gfield_description validation_message gfield_validation_message\"\r\n *ngIf=\"formGroup.get(field.name)?.invalid && formGroup.get(field.name)?.touched\">\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['required']\">This field is required.</ng-container>\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['email']\">Please enter a valid email\r\n address.</ng-container>\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['minlength']\">\r\n Minimum length is {{ formGroup.get(field.name)?.errors?.['minlength'].requiredLength }} characters.\r\n </ng-container>\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['maxlength']\">\r\n Maximum length is {{ formGroup.get(field.name)?.errors?.['maxlength'].requiredLength }} characters.\r\n </ng-container>\r\n <ng-container *ngIf=\"formGroup.get(field.name)?.errors?.['pattern']\">\r\n Please match the required format.\r\n </ng-container>\r\n </div>\r\n\r\n </div>\r\n\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"gform_footer\">\r\n <ptr-button buttonType=\"submit\" [isDisabled]=\"loading || !formGroup.valid\">{{config.submitText}}</ptr-button>\r\n </div>\r\n\r\n </form>\r\n</div>\r\n" }]
90
194
  }], propDecorators: { config: [{
91
195
  type: Input
92
196
  }], loading: [{
@@ -121,10 +225,10 @@ class PtrTitleComponent {
121
225
  }
122
226
  return route;
123
227
  }
124
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.2", ngImport: i0, type: PtrTitleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
125
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.1.2", type: PtrTitleComponent, isStandalone: true, selector: "ptr-title", ngImport: i0, template: '<header class="entry-header is-layout-constrained my-3" *ngIf="!(hideTitle$ | async)"><h1 class="entry-title">{{ title$ | async }}</h1></header>', isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
228
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrTitleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
229
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.1.4", type: PtrTitleComponent, isStandalone: true, selector: "ptr-title", ngImport: i0, template: '<header class="entry-header is-layout-constrained my-3" *ngIf="!(hideTitle$ | async)"><h1 class="entry-title">{{ title$ | async }}</h1></header>', isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
126
230
  }
127
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.2", ngImport: i0, type: PtrTitleComponent, decorators: [{
231
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrTitleComponent, decorators: [{
128
232
  type: Component,
129
233
  args: [{
130
234
  selector: 'ptr-title',
@@ -135,14 +239,296 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.2", ngImpor
135
239
  }]
136
240
  }] });
137
241
 
242
+ class PtrLoadingSpinnerComponent {
243
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrLoadingSpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
244
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.1.4", type: PtrLoadingSpinnerComponent, isStandalone: true, selector: "ptr-loading-spinner", ngImport: i0, template: `<div class="vdx-progress-spinner"></div>`, isInline: true, styles: [":host{display:inline-block;line-height:0}.vdx-progress-spinner{display:inline-block;width:25px;height:25px;transform:scaleZ(1)}.vdx-progress-spinner:before{position:absolute;content:\"\";background-image:url(\"data:image/svg+xml,%3Csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 40 40' style='enable-background:new 0 0 40 40;' xml:space='preserve'%3E%3Cstyle type='text/css'%3E .st0%7Bfill:%23272e3e;%7D%0A%3C/style%3E%3Ccircle class='st0' cx='34' cy='6' r='6'/%3E%3Ccircle class='st0' cx='6' cy='6' r='6'/%3E%3Ccircle class='st0' cx='6' cy='34' r='6'/%3E%3Ccircle class='st0' cx='34' cy='34' r='6'/%3E%3C/svg%3E\");height:40px;width:40px;left:-8px;top:-8px;border:none;display:block;animation:loader-anim 1.5s 0s ease-in-out infinite}.vdx-progress-spinner:after{content:\"\";position:absolute;height:12px;width:12px;border:none;border-radius:12px;display:block;left:6px;top:6px;background-color:#272e3e;animation:loader-anim-dot 1.5s 0s ease-in-out infinite}@keyframes loader-anim{0%{transform:rotate(0) scale(0);opacity:.5}50%{transform:rotate(180deg) scale(1);opacity:1}to{transform:rotate(360deg) scale(0);opacity:.2}}@keyframes loader-anim-dot{0%{opacity:1}50%{opacity:0}to{opacity:1}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
245
+ }
246
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrLoadingSpinnerComponent, decorators: [{
247
+ type: Component,
248
+ args: [{ selector: 'ptr-loading-spinner', standalone: true, imports: [CommonModule], template: `<div class="vdx-progress-spinner"></div>`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:inline-block;line-height:0}.vdx-progress-spinner{display:inline-block;width:25px;height:25px;transform:scaleZ(1)}.vdx-progress-spinner:before{position:absolute;content:\"\";background-image:url(\"data:image/svg+xml,%3Csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 40 40' style='enable-background:new 0 0 40 40;' xml:space='preserve'%3E%3Cstyle type='text/css'%3E .st0%7Bfill:%23272e3e;%7D%0A%3C/style%3E%3Ccircle class='st0' cx='34' cy='6' r='6'/%3E%3Ccircle class='st0' cx='6' cy='6' r='6'/%3E%3Ccircle class='st0' cx='6' cy='34' r='6'/%3E%3Ccircle class='st0' cx='34' cy='34' r='6'/%3E%3C/svg%3E\");height:40px;width:40px;left:-8px;top:-8px;border:none;display:block;animation:loader-anim 1.5s 0s ease-in-out infinite}.vdx-progress-spinner:after{content:\"\";position:absolute;height:12px;width:12px;border:none;border-radius:12px;display:block;left:6px;top:6px;background-color:#272e3e;animation:loader-anim-dot 1.5s 0s ease-in-out infinite}@keyframes loader-anim{0%{transform:rotate(0) scale(0);opacity:.5}50%{transform:rotate(180deg) scale(1);opacity:1}to{transform:rotate(360deg) scale(0);opacity:.2}}@keyframes loader-anim-dot{0%{opacity:1}50%{opacity:0}to{opacity:1}}\n"] }]
249
+ }] });
250
+
251
+ class PtrLoadingSpinnerDirective {
252
+ targetEl = inject(ElementRef);
253
+ viewContainerRef = inject(ViewContainerRef);
254
+ renderer = inject(Renderer2);
255
+ spinnerInstance;
256
+ overlay;
257
+ hostPosition = 'relative';
258
+ set ptrLoadingSpinner(loading) {
259
+ if (loading) {
260
+ this.addBlurEffect();
261
+ this.addOverlay();
262
+ this.addProgressSpinnerComponent();
263
+ }
264
+ else {
265
+ this.removeBlurEffect();
266
+ this.removeOverlay();
267
+ this.removeProgressSpinnerComponent();
268
+ }
269
+ }
270
+ ngOnDestroy() {
271
+ this.spinnerInstance?.destroy();
272
+ this.removeBlurEffect();
273
+ }
274
+ addProgressSpinnerComponent() {
275
+ this.spinnerInstance = this.viewContainerRef.createComponent(PtrLoadingSpinnerComponent);
276
+ this.overlay?.appendChild(this.spinnerInstance.location.nativeElement);
277
+ }
278
+ removeProgressSpinnerComponent() {
279
+ this.spinnerInstance?.destroy();
280
+ }
281
+ addOverlay() {
282
+ this.overlay = this.renderer.createElement('div');
283
+ this.renderer.setStyle(this.overlay, 'display', 'flex');
284
+ this.renderer.setStyle(this.overlay, 'justify-content', 'center');
285
+ this.renderer.setStyle(this.overlay, 'align-items', 'center');
286
+ this.renderer.setStyle(this.overlay, 'position', 'absolute');
287
+ this.renderer.setStyle(this.overlay, 'top', '0');
288
+ this.renderer.setStyle(this.overlay, 'left', '0');
289
+ this.renderer.setStyle(this.overlay, 'width', '100%');
290
+ this.renderer.setStyle(this.overlay, 'height', '100%');
291
+ this.renderer.appendChild(this.targetEl.nativeElement, this.overlay);
292
+ }
293
+ removeOverlay() {
294
+ if (this.overlay) {
295
+ this.renderer.removeChild(this.targetEl.nativeElement, this.overlay);
296
+ this.overlay = undefined;
297
+ }
298
+ }
299
+ addBlurEffect() {
300
+ const style = this.renderer.createElement('style');
301
+ const blurRule = `
302
+ .ptr-loading-blur > *:not(:last-child) {
303
+ filter: blur(2px);
304
+ transition: filter 0.3s ease;
305
+ }
306
+ `;
307
+ this.renderer.appendChild(style, this.renderer.createText(blurRule));
308
+ this.renderer.appendChild(document.head, style);
309
+ this.renderer.addClass(this.targetEl.nativeElement, 'ptr-loading-blur');
310
+ }
311
+ removeBlurEffect() {
312
+ this.renderer.removeClass(this.targetEl.nativeElement, 'ptr-loading-blur');
313
+ }
314
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrLoadingSpinnerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
315
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.1.4", type: PtrLoadingSpinnerDirective, isStandalone: true, selector: "[ptrLoadingSpinner]", inputs: { ptrLoadingSpinner: "ptrLoadingSpinner" }, host: { properties: { "style.position": "this.hostPosition" } }, ngImport: i0 });
316
+ }
317
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrLoadingSpinnerDirective, decorators: [{
318
+ type: Directive,
319
+ args: [{
320
+ selector: '[ptrLoadingSpinner]',
321
+ standalone: true
322
+ }]
323
+ }], propDecorators: { hostPosition: [{
324
+ type: HostBinding,
325
+ args: ['style.position']
326
+ }], ptrLoadingSpinner: [{
327
+ type: Input,
328
+ args: [{ required: true }]
329
+ }] } });
330
+
331
+ /**
332
+ * Optimized Async Loading Service using Angular Signals
333
+ * Supports global loading state and named loading areas with auto-cleanup
334
+ *
335
+ * To use as a non-singleton service, add to providers array in @Component decorator:
336
+ * @Component({
337
+ * selector: 'app-example',
338
+ * templateUrl: './example.component.html',
339
+ * providers: [PtrLoadingService]
340
+ * })
341
+ *
342
+ * Usage:
343
+ * Set loading: this.loadingService.setLoading(true)
344
+ * - Set loading: this.loadingService.setLoading(true, 'areaName')
345
+ *
346
+ * - Get loading (template): {{ loadingService.isLoading()() }}
347
+ * - Get loading (template): {{ loadingService.isLoading('areaName')() }}
348
+ *
349
+ * - Get loading (component): this.loadingService.isLoading()()
350
+ * - Get loading (component): this.loadingService.isLoading('areaName')()
351
+ *
352
+ * - React to loading changes: effect(() => console.log('Loading:', this.loadingService.isLoading('areaName')()))
353
+ */
354
+ class PtrLoadingService {
355
+ globalTaskCount = signal(0);
356
+ loadingAreas = new Map();
357
+ isLoading(area) {
358
+ if (!area) {
359
+ return computed(() => this.globalTaskCount() > 0);
360
+ }
361
+ return computed(() => {
362
+ const areaSignal = this.loadingAreas.get(area);
363
+ return areaSignal ? areaSignal() > 0 : false;
364
+ });
365
+ }
366
+ setLoading(value, area) {
367
+ if (!area) {
368
+ this.updateTaskCount(this.globalTaskCount, value);
369
+ }
370
+ else {
371
+ this.updateNamedAreaLoading(area, value);
372
+ }
373
+ }
374
+ resetLoading(area) {
375
+ if (!area) {
376
+ this.globalTaskCount.set(0);
377
+ }
378
+ else if (this.loadingAreas.has(area)) {
379
+ this.loadingAreas.get(area).set(0);
380
+ this.loadingAreas.delete(area);
381
+ }
382
+ }
383
+ updateNamedAreaLoading(area, increment) {
384
+ let areaSignal = this.loadingAreas.get(area);
385
+ if (!areaSignal && increment) {
386
+ areaSignal = signal(0);
387
+ this.loadingAreas.set(area, areaSignal);
388
+ }
389
+ if (areaSignal) {
390
+ areaSignal.update(count => {
391
+ const newCount = increment ? count + 1 : Math.max(0, count - 1);
392
+ if (newCount === 0) {
393
+ this.loadingAreas.delete(area);
394
+ }
395
+ return newCount;
396
+ });
397
+ }
398
+ }
399
+ updateTaskCount(taskCount, increment) {
400
+ taskCount.update(count => increment ? count + 1 : Math.max(0, count - 1));
401
+ }
402
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrLoadingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
403
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrLoadingService, providedIn: 'root' });
404
+ }
405
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrLoadingService, decorators: [{
406
+ type: Injectable,
407
+ args: [{
408
+ providedIn: 'root'
409
+ }]
410
+ }] });
411
+
412
+ class PtrDialogComponent {
413
+ dialogElement;
414
+ message = '';
415
+ buttonText = 'Confirm';
416
+ buttonStyle = 'normal';
417
+ closed = new EventEmitter();
418
+ ngAfterViewInit() {
419
+ this.dialogElement.nativeElement.showModal();
420
+ }
421
+ close() {
422
+ this.dialogElement.nativeElement.close();
423
+ }
424
+ confirm() {
425
+ this.closed.emit(true);
426
+ this.close();
427
+ }
428
+ onClose() {
429
+ this.closed.emit(null);
430
+ }
431
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
432
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.1.4", type: PtrDialogComponent, isStandalone: true, selector: "ptr-dialog", inputs: { message: "message", buttonText: "buttonText", buttonStyle: "buttonStyle" }, outputs: { closed: "closed" }, viewQueries: [{ propertyName: "dialogElement", first: true, predicate: ["dialogElement"], descendants: true }], ngImport: i0, template: "<dialog #dialogElement class=\"ptr-modal\" (close)=\"onClose()\">\r\n <div class=\"ptr-modal__content\">\r\n <button class=\"ptr-modal__close\" (click)=\"close()\" aria-label=\"Close dialog\">\r\n &times;\r\n </button>\r\n <p>{{ message }}</p>\r\n <div class=\"ptr-modal__actions\">\r\n <ptr-button [buttonStyle]=\"buttonStyle\" (clicked)=\"confirm()\" [isSmallSize]=\"true\">{{buttonText}}</ptr-button>\r\n </div>\r\n </div>\r\n</dialog>", styles: [".ptr-modal{border-radius:var(--wp--custom--default-border-radius);border:none;padding:1rem}.ptr-modal__content{padding:1rem;position:relative}.ptr-modal__close{position:absolute;right:0;top:0;background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;line-height:1rem}.ptr-modal__actions{margin-top:20px;text-align:right}dialog.ptr-modal{opacity:0;transition:all .7s allow-discrete}dialog.ptr-modal[open]{opacity:1}dialog.ptr-modal::backdrop{background-color:#0000;transition:all .7s allow-discrete;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}dialog.ptr-modal[open]::backdrop{background-color:#0006}@starting-style{dialog[open]{opacity:0}}@starting-style{dialog[open]::backdrop{background-color:#0000}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: PtrButtonComponent, selector: "ptr-button", inputs: ["buttonStyle", "buttonType", "isDisabled", "hrefLink", "routerLinkValue", "extraClasses", "isSmallSize", "isIconButton"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
433
+ }
434
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrDialogComponent, decorators: [{
435
+ type: Component,
436
+ args: [{ selector: 'ptr-dialog', standalone: true, imports: [
437
+ CommonModule,
438
+ PtrButtonComponent
439
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<dialog #dialogElement class=\"ptr-modal\" (close)=\"onClose()\">\r\n <div class=\"ptr-modal__content\">\r\n <button class=\"ptr-modal__close\" (click)=\"close()\" aria-label=\"Close dialog\">\r\n &times;\r\n </button>\r\n <p>{{ message }}</p>\r\n <div class=\"ptr-modal__actions\">\r\n <ptr-button [buttonStyle]=\"buttonStyle\" (clicked)=\"confirm()\" [isSmallSize]=\"true\">{{buttonText}}</ptr-button>\r\n </div>\r\n </div>\r\n</dialog>", styles: [".ptr-modal{border-radius:var(--wp--custom--default-border-radius);border:none;padding:1rem}.ptr-modal__content{padding:1rem;position:relative}.ptr-modal__close{position:absolute;right:0;top:0;background:none;border:none;font-size:1.5rem;cursor:pointer;padding:0;line-height:1rem}.ptr-modal__actions{margin-top:20px;text-align:right}dialog.ptr-modal{opacity:0;transition:all .7s allow-discrete}dialog.ptr-modal[open]{opacity:1}dialog.ptr-modal::backdrop{background-color:#0000;transition:all .7s allow-discrete;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}dialog.ptr-modal[open]::backdrop{background-color:#0006}@starting-style{dialog[open]{opacity:0}}@starting-style{dialog[open]::backdrop{background-color:#0000}}\n"] }]
440
+ }], propDecorators: { dialogElement: [{
441
+ type: ViewChild,
442
+ args: ['dialogElement']
443
+ }], message: [{
444
+ type: Input
445
+ }], buttonText: [{
446
+ type: Input
447
+ }], buttonStyle: [{
448
+ type: Input
449
+ }], closed: [{
450
+ type: Output
451
+ }] } });
452
+
453
+ class PtrDialogService {
454
+ appRef;
455
+ injector;
456
+ dialogComponentRef = null;
457
+ constructor(appRef, injector) {
458
+ this.appRef = appRef;
459
+ this.injector = injector;
460
+ }
461
+ open(options) {
462
+ const dialogResult$ = new Subject();
463
+ this.dialogComponentRef = createComponent(PtrDialogComponent, {
464
+ environmentInjector: this.injector,
465
+ });
466
+ const { instance } = this.dialogComponentRef;
467
+ instance.message = options.message;
468
+ instance.buttonText = options.buttonText || 'Confirm';
469
+ instance.buttonStyle = options.buttonStyle || 'normal';
470
+ instance.closed.subscribe((result) => {
471
+ this.removeDialog();
472
+ dialogResult$.next(result ?? false);
473
+ dialogResult$.complete();
474
+ });
475
+ document.body.appendChild(this.dialogComponentRef.location.nativeElement);
476
+ this.appRef.attachView(this.dialogComponentRef.hostView);
477
+ return dialogResult$.asObservable();
478
+ }
479
+ removeDialog() {
480
+ if (this.dialogComponentRef) {
481
+ this.appRef.detachView(this.dialogComponentRef.hostView);
482
+ this.dialogComponentRef.destroy();
483
+ this.dialogComponentRef = null;
484
+ }
485
+ }
486
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrDialogService, deps: [{ token: i0.ApplicationRef }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable });
487
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrDialogService, providedIn: 'root' });
488
+ }
489
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrDialogService, decorators: [{
490
+ type: Injectable,
491
+ args: [{
492
+ providedIn: 'root'
493
+ }]
494
+ }], ctorParameters: () => [{ type: i0.ApplicationRef }, { type: i0.EnvironmentInjector }] });
495
+
496
+ class PtrTooltipComponent {
497
+ content = '';
498
+ tooltipDialog;
499
+ tooltipTimer;
500
+ showTooltip() {
501
+ clearTimeout(this.tooltipTimer);
502
+ this.tooltipTimer = setTimeout(() => {
503
+ this.tooltipDialog.nativeElement.show();
504
+ }, 200); // Small delay to prevent flickering on quick mouse movements
505
+ }
506
+ hideTooltip() {
507
+ clearTimeout(this.tooltipTimer);
508
+ this.tooltipTimer = setTimeout(() => {
509
+ this.tooltipDialog.nativeElement.close();
510
+ }, 200); // Small delay to allow moving mouse to tooltip
511
+ }
512
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrTooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
513
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.1.4", type: PtrTooltipComponent, isStandalone: true, selector: "ptr-tooltip", inputs: { content: "content" }, viewQueries: [{ propertyName: "tooltipDialog", first: true, predicate: ["tooltipDialog"], descendants: true }], ngImport: i0, template: "<span (mouseenter)=\"showTooltip()\" (mouseleave)=\"hideTooltip()\" class=\"tooltip-trigger\">\r\n <ng-content></ng-content>\r\n</span>\r\n<dialog #tooltipDialog class=\"ptr-tooltip\">\r\n <div class=\"ptr-tooltip__content\">{{ content }}</div>\r\n</dialog>", styles: [":host{display:inline-block;position:relative}.tooltip-trigger{cursor:help}.ptr-tooltip{position:absolute;bottom:100%;left:50%;transform:translate(-50%);border:none;border-radius:3px;padding:.5rem .75rem;background-color:#212121;border:0;color:#fff;font-size:.875rem;max-width:15.5rem;min-width:12.5rem;z-index:1000;margin:0 0 8px;box-shadow:0 3px 6px #00000029,0 3px 6px #0000003b}.ptr-tooltip:before{content:\"\";position:absolute;top:100%;left:50%;transform:translate(-50%);border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid #212121}.ptr-tooltip__content{white-space:pre-wrap;text-align:center;line-height:1.5}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
514
+ }
515
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: PtrTooltipComponent, decorators: [{
516
+ type: Component,
517
+ args: [{ selector: 'ptr-tooltip', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<span (mouseenter)=\"showTooltip()\" (mouseleave)=\"hideTooltip()\" class=\"tooltip-trigger\">\r\n <ng-content></ng-content>\r\n</span>\r\n<dialog #tooltipDialog class=\"ptr-tooltip\">\r\n <div class=\"ptr-tooltip__content\">{{ content }}</div>\r\n</dialog>", styles: [":host{display:inline-block;position:relative}.tooltip-trigger{cursor:help}.ptr-tooltip{position:absolute;bottom:100%;left:50%;transform:translate(-50%);border:none;border-radius:3px;padding:.5rem .75rem;background-color:#212121;border:0;color:#fff;font-size:.875rem;max-width:15.5rem;min-width:12.5rem;z-index:1000;margin:0 0 8px;box-shadow:0 3px 6px #00000029,0 3px 6px #0000003b}.ptr-tooltip:before{content:\"\";position:absolute;top:100%;left:50%;transform:translate(-50%);border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid #212121}.ptr-tooltip__content{white-space:pre-wrap;text-align:center;line-height:1.5}\n"] }]
518
+ }], propDecorators: { content: [{
519
+ type: Input
520
+ }], tooltipDialog: [{
521
+ type: ViewChild,
522
+ args: ['tooltipDialog']
523
+ }] } });
524
+
138
525
  /*
139
526
  * Public API Surface of ngx-components
140
527
  */
141
- // export { PtrTitleStrategy } from './lib/ptr-title/ptr-title-strategy';
142
528
 
143
529
  /**
144
530
  * Generated bundle index. Do not edit.
145
531
  */
146
532
 
147
- export { PtrFormComponent, PtrMenuComponent, PtrTitleComponent };
533
+ export { PtrButtonComponent, PtrDialogComponent, PtrDialogService, PtrFormComponent, PtrLoadingService, PtrLoadingSpinnerComponent, PtrLoadingSpinnerDirective, PtrMenuComponent, PtrTitleComponent, PtrTooltipComponent };
148
534
  //# sourceMappingURL=patter-ngx-components.mjs.map