@a.nemreen/dga-dynamic-form 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/fesm2022/a.nemreen-dga-dynamic-form.mjs +375 -121
- package/package.json +1 -1
- package/types/a.nemreen-dga-dynamic-form.d.ts +71 -24
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Schema-driven dynamic forms for Angular, rendered with [`@a.nemreen/dga-ui`](https://www.npmjs.com/package/@a.nemreen/dga-ui) controls.
|
|
4
4
|
|
|
5
|
-
**Version 0.
|
|
5
|
+
**Version 0.2.0** — wizard card chrome, Back / Save as draft actions, and selectable option cards.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -176,12 +176,14 @@ When both `password` and `confirmPassword` fields exist, `passwordMismatch` vali
|
|
|
176
176
|
| `consentBaseUrl` | `string?` | — | CMS base for `consentServiceName` fields → GET `{base}/consents/{name}`. |
|
|
177
177
|
| `wizard` | `DgaWizardConfig?` | — | Multi-step mode (see below). |
|
|
178
178
|
|
|
179
|
-
`DgaFormLabel` is
|
|
179
|
+
`DgaFormLabel` is a map of locale code → string. `en` and `ar` are required; extra keys match `provideDgaLocales` (e.g. `{ en, ar, ur }`). Resolution: exact locale → `en` → `ar` → first non-empty value.
|
|
180
180
|
|
|
181
181
|
---
|
|
182
182
|
|
|
183
183
|
## Wizard (`config.wizard`)
|
|
184
184
|
|
|
185
|
+
When `enabled`, the form renders DGA chrome: a numbered stepper with a compact radial step counter, the current step in a card (title, description, optional badge), **Back** (outline, start), **Save as draft** (ghost), and **Next** / **Submit** (primary, end). Reloading restores a local draft behind an info banner when `enableLocalStorageSave` is on.
|
|
186
|
+
|
|
185
187
|
| Key | Type | Default | Description |
|
|
186
188
|
|-----|------|---------|-------------|
|
|
187
189
|
| `enabled` | `boolean` | — | Turn on stepper UI. |
|
|
@@ -262,7 +264,9 @@ HTTP adapter maps `Id/Title`, `Code/Name`, and `{UserName,Email,DisplayName}` sh
|
|
|
262
264
|
| `monthPicker` | date | Month-only mode. |
|
|
263
265
|
| `maxChips` | chips | Max chip count validator. |
|
|
264
266
|
| `allowDuplicates` | chips | Allow duplicate chip values. |
|
|
267
|
+
| `countries` | phone | Extra dial codes after KSA (`+966`). `{ code, label?, name?: { en, ar } }`. Duplicate codes are skipped. Saudi mobile rules still apply to `+966`; other codes only require digits. |
|
|
265
268
|
| `alwaysOpen` | select | `openMode="always"` on `dga-select`. |
|
|
269
|
+
| `optionsLayout` | radio, checkbox | `'stack'` (default), `'grid'`, or `'cards'` (selectable DGA option cards). |
|
|
266
270
|
| `consentServiceName` | checkbox | Fetch label from CMS (`consentBaseUrl`). |
|
|
267
271
|
| `excludeFromDraft` / `sensitive` | any | Strip from localStorage drafts. |
|
|
268
272
|
|
|
@@ -306,7 +310,7 @@ Supports `pattern`, `minLength`, `maxLength`, `min`, `max`, `minDate`, `maxDate`
|
|
|
306
310
|
|
|
307
311
|
### Exported utilities
|
|
308
312
|
|
|
309
|
-
`dgaBuildFormGroup`, `dgaIsFieldVisible`, `dgaIsRequiredWhen`, `dgaApplyCrossFieldValidators`, `dgaSaudiMobileValidator`, `dgaPasswordMatchValidator`, `dgaAssertSafeHttpUrl`, `createHttpLookupAdapter`, `createHttpSubmitAdapter`.
|
|
313
|
+
`dgaBuildFormGroup`, `dgaIsFieldVisible`, `dgaIsRequiredWhen`, `dgaApplyCrossFieldValidators`, `dgaSaudiMobileValidator`, `dgaPhoneFieldValidator`, `dgaPasswordMatchValidator`, `dgaAssertSafeHttpUrl`, `createHttpLookupAdapter`, `createHttpSubmitAdapter`.
|
|
310
314
|
|
|
311
315
|
## License
|
|
312
316
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import*as l from"@angular/core";import{InjectionToken as y,inject as c,Injectable as Y,isDevMode as ze,makeEnvironmentProviders as Be,input as u,booleanAttribute as J,signal as m,computed as p,output as g,ChangeDetectionStrategy as V,Component as R,DestroyRef as Q,effect as k,untracked as q}from"@angular/core";import{NgComponentOutlet as X}from"@angular/common";import*as h from"@angular/forms";import{Validators as b,ReactiveFormsModule as O,FormsModule as Z,FormBuilder as _e}from"@angular/forms";import{switchMap as ee,catchError as $e,map as Ue,startWith as Ge}from"rxjs/operators";import{takeUntilDestroyed as T}from"@angular/core/rxjs-interop";import{DgaToastService as je,DgaButton as A,DgaIcon as te,dgaProvideValueAccessor as ae,DgaField as ie,DgaInput as ne,DgaSelect as oe,DgaCheckbox as re,DgaRadio as le,DgaPhoneInput as se,DgaChipInput as de,DgaSwitch as ue,DgaUpload as ce,DgaNumberInput as pe,DgaOtp as fe,DgaStepper as me}from"@a.nemreen/dga-ui";import{of as x,throwError as ge,startWith as We,catchError as Ke}from"rxjs";import{HttpClient as S,HttpHeaders as He}from"@angular/common/http";import{DgaDatePicker as he}from"@a.nemreen/dga-ui/date-picker";const z=new y("DGA_LOOKUP_ADAPTER"),E=new y("DGA_SUBMIT_ADAPTER"),B=new y("DGA_FORM_TOAST_ADAPTER"),_=new y("DGA_CAPTCHA_ADAPTER"),$=new y("DGA_HTTP_SECURITY"),U=new y("DGA_FORM_I18N_ADAPTER"),be=new y("DGA_DYNAMIC_FORM_FIELD_REGISTRY"),ve=[["StartDate","EndDate"],["UseCaseStartDate","UseCaseEndDate"],["startDate","endDate"]];function ye(i){return e=>e.value&&i.value!==e.value?{passwordMismatch:!0}:null}function Ye(i){return e=>{if(!e.value||!i.value)return null;const t=new Date(e.value),a=new Date(i.value),n=new Date(a);return n.setDate(n.getDate()+1),t>=n?null:{endDateAfterStartDate:!0}}}function xe(i){const e=(i.value??"").toString().trim();if(!e)return null;let t=e;return e.startsWith("+966")?t=e.slice(4):e.startsWith("966")&&(t=e.slice(3)),/^\d+$/.test(t)?t.startsWith("0")?t.length===10?null:{invalidLength:!0}:t.startsWith("5")?t.length===9?null:{invalidLength:!0}:{invalidPrefix:!0}:{invalidFormat:!0}}function Je(i){return e=>{if(!e.value)return null;const t=new Date(e.value),a=new Date(i);return t>=a?null:{minDate:!0}}}function Qe(i){return e=>{if(!e.value)return null;const t=new Date(e.value),a=new Date(i);return t<=a?null:{maxDate:!0}}}function Xe(i){const e=i.value;return Array.isArray(e)&&e.some(a=>a&&typeof a=="object"&&a.status==="uploading")?{uploadInProgress:!0}:null}function De(i,e){const t=i.get("password"),a=i.get("confirmPassword");t&&a&&(a.addValidators(ye(t)),a.updateValueAndValidity({emitEvent:!1}));for(const[n,o]of ve){const r=i.get(n),s=i.get(o);if(!r||!s)continue;s.addValidators(Ye(r));const d=e.find(w=>w.name===o),f=w=>{if(d?.validation){if(w){const qe=new Date(w),P=new Date(qe);P.setDate(P.getDate()+1),d.validation.minDate=P.toISOString().split("T")[0]}else delete d.validation.minDate;s.updateValueAndValidity({emitEvent:!1})}};f(r.value),r.valueChanges.subscribe(w=>f(w))}}const we=["checkbox","multiselect","chips","file","multifile","multifilestaged"],Ze=["toggle"];function Se(i){return i.value!==void 0?i.value:we.includes(i.type)?[]:Ze.includes(i.type)?!1:""}function G(i,e){const t=[],a=i.validation;(e||i.required||a?.required)&&(we.includes(i.type)?t.push(et):i.type==="toggle"?t.push(b.requiredTrue):t.push(b.required)),(i.type==="email"||a?.pattern==="email")&&t.push(b.email);const n=a?.minLength;n!=null&&t.push(b.minLength(n));const o=a?.maxLength??i.maxLength;if(o!=null&&t.push(b.maxLength(o)),a?.pattern&&a.pattern!=="email"){const r=a.pattern;if(typeof r=="string"&&r.length>0&&r.length<=200)try{t.push(b.pattern(r))}catch{}}return a?.min!=null&&t.push(b.min(a.min)),a?.max!=null&&t.push(b.max(a.max)),i.maxChips!=null&&i.type==="chips"&&t.push(tt(i.maxChips)),i.type==="phone"&&t.push(xe),i.type==="multifilestaged"&&t.push(Xe),a?.minDate&&t.push(Je(a.minDate)),a?.maxDate&&t.push(Qe(a.maxDate)),t}function et(i){const e=i.value;return Array.isArray(e)&&e.length>0?null:{required:!0}}function tt(i){return e=>{const t=e.value;return Array.isArray(t)&&t.length>i?{maxChips:{max:i,actual:t.length}}:null}}function Ie(i,e,t=!0){const a=!!e.disabled;return i.control({value:Se(e),disabled:a},{validators:G(e,t&&!e.requiredWhen)})}function Ce(i,e){const t={};for(const a of e){if(a.hidden&&a.type==="hidden"){t[a.name]=i.control(a.value??"");continue}t[a.name]=Ie(i,a)}return i.group(t)}function Le(i,e){return e?.length?e.flatMap(t=>t.fields):i}function Fe(i,e,t){i.setValidators(G(e,t)),i.updateValueAndValidity({emitEvent:!1})}function j(i,e){return Array.isArray(i)?i.some(t=>t==e):i==e}function at(i){return i.label?.en??""}function it(i){return i.label?.ar??""}function M(i,e,t,a){return ke(a?.(i)??{name:i,type:"select",label:{en:"",ar:""}},e,t?.(i))}function nt(i,e,t,a,n){if(!i.showOnTitleEn&&!i.showOnTitleAr||t==null||t==="")return!1;const o=M(e,t,a,n);if(!o)return!1;const r=i.showOnTitleEn?at(o)===i.showOnTitleEn:!0,s=i.showOnTitleAr?it(o)===i.showOnTitleAr:!0;return r&&s}function Ne(i,e,t,a){if(!i.extraField)return!0;const n=i.extraFieldTrigger||i.dependsOn;if(!n)return!1;const o=e[n];return M(n,o,t,a)?.requiresTextInput===!0}function ke(i,e,t){return i?[...t??[],...i.options??[],...i.groupedOptions?.flatMap(n=>n.options)??[]].find(n=>n.value==e):void 0}function W(i,e,t,a){if(i.hidden&&i.type!=="hidden"||i.type==="hidden")return!1;if(!i.dependsOn&&!i.extraField)return!0;const n=i.dependsOn??i.extraFieldTrigger;if(!n)return Ne(i,e,t,a);const o=e[n];if(i.showOnValues?.length&&!i.showOnValues.some(r=>j(o,r))||(i.showOnTitleEn||i.showOnTitleAr)&&!nt(i,n,o,t,a))return!1;if(i.showWhenOptionProperty){const r=M(n,o,t,a),s=i.showWhenOptionProperty.property;if(!r||r[s]!==i.showWhenOptionProperty.value)return!1}return!(i.extraField&&!Ne(i,e,t,a)||i.dependsOn&&!i.showOnValues?.length&&!i.showWhenOptionProperty&&!i.showOnTitleEn&&!i.showOnTitleAr&&!i.extraField&&(o==null||o===""||Array.isArray(o)&&o.length===0))}function K(i,e,t,a){const n=i.requiredWhen;if(!n)return!!i.required;const o=e[n.field];if(n.optionProperty!=null){const r=M(n.field,o,t,a);return!!r&&r[n.optionProperty]===n.optionPropertyValue}return n.values?.length?n.values.some(r=>j(o,r)):n.value!==void 0?j(o,n.value):o!=null&&o!==""}const ot=new Set(["otp","file"]),Oe=/password|passwd|secret|token|otp|national.?id|ssn|pin$/i;class C{submitAdapter=c(E,{optional:!0});captcha=c(_,{optional:!0});buildPayload(e,t,a){const n=new Set(a.filter(r=>r.excludeFromPayload).map(r=>r.name));let o={};for(const[r,s]of Object.entries(t)){if(n.has(r))continue;const d=e.fieldMapping?.[r]??r;o[d]=s}return e.payloadTransformer?e.payloadTransformer(o):o}hasFileValues(e){return Object.values(e).some(t=>t instanceof File||Array.isArray(t)&&t.some(a=>a instanceof File||a?.file instanceof File))}toFormData(e){const t=new FormData;for(const[a,n]of Object.entries(e))if(n!=null)if(n instanceof File)t.append(a,n);else if(Array.isArray(n))for(const o of n)o instanceof File?t.append(a,o):o?.file instanceof File?t.append(a,o.file,o.name):t.append(a,typeof o=="string"?o:JSON.stringify(o));else typeof n=="object"?t.append(a,JSON.stringify(n)):t.append(a,String(n));return t}submitForm(e,t,a){if(!e.endpoint||!this.submitAdapter)return x(t);const n=this.buildPayload(e,t,a),o=n instanceof FormData?n:this.hasFileValues(n)?this.toFormData(n):n,r={};return e.idempotencyKey&&(r["Idempotency-Key"]=e.idempotencyKey),(this.captcha?.getToken("submit")??x(null)).pipe(ee(d=>(d&&(r["X-Recaptcha-Token"]=d),x({endpoint:e.endpoint,method:e.method??"POST",body:o,headers:r})))).pipe(ee(d=>this.submitAdapter.submit(d)),$e(d=>{throw d}))}saveDraft(e,t,a=[]){if(typeof localStorage>"u")return;const n=new Map(a.map(r=>[r.name,r])),o={};for(const[r,s]of Object.entries(t)){const d=n.get(r);d&&this.isDraftBlocked(d)||!d&&Oe.test(r)||s instanceof File||(o[r]=s)}localStorage.setItem(this.storageKey(e),JSON.stringify(o))}loadDraft(e){if(typeof localStorage>"u")return null;const t=localStorage.getItem(this.storageKey(e));if(!t)return null;try{return JSON.parse(t)}catch{return null}}clearDraft(e){typeof localStorage>"u"||localStorage.removeItem(this.storageKey(e))}isDraftBlocked(e){return e.excludeFromDraft||e.sensitive||e.excludeFromPayload||ot.has(e.type)?!0:Oe.test(e.name)}storageKey(e){return`dga-dynamic-form:${e}`}static ɵfac=l.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.0.7",ngImport:l,type:C,deps:[],target:l.ɵɵFactoryTarget.Injectable});static ɵprov=l.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"22.0.7",ngImport:l,type:C,providedIn:"root"})}l.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"22.0.7",ngImport:l,type:C,decorators:[{type:Y,args:[{providedIn:"root"}]}]});function I(i,e,t=""){return i?e==="en"?i.en||i.ar:i.ar||i.en:t}function Te(){return typeof document>"u"?"ar":(document.documentElement.lang||"ar").toLowerCase().startsWith("en")?"en":"ar"}class L{extras=c(be,{optional:!0});map=new Map;constructor(){for(const e of this.extras??[])this.register(e)}register(e){this.map.set(e.type,e.component)}get(e){return this.map.get(e)??null}hasCustom(e){return this.map.has(e)}isBuiltIn(e){return rt.has(e)}static ɵfac=l.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.0.7",ngImport:l,type:L,deps:[],target:l.ɵɵFactoryTarget.Injectable});static ɵprov=l.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"22.0.7",ngImport:l,type:L,providedIn:"root"})}l.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"22.0.7",ngImport:l,type:L,decorators:[{type:Y,args:[{providedIn:"root"}]}],ctorParameters:()=>[]});const rt=new Set(["text","email","textarea","select","multiselect","checkbox","radio","phone","file","multifile","multifilestaged","date","chips","toggle","hidden","number","otp","password"]),Ae={resolveLabel(i,e){return e==="en"?i.en:i.ar}},Ee={getToken:()=>x(null)},Me={lookup:()=>x([])},lt=new Set(["__proto__","constructor","prototype"]);function F(i,e){const t=i.trim();if(!t)throw new Error("DGA dynamic form: empty HTTP URL");if(t.startsWith("/")&&!t.startsWith("//"))return t.replace(/\/$/,"")||"/";let a;try{a=new URL(t)}catch{throw new Error(`DGA dynamic form: invalid HTTP URL "${i}"`)}if(a.protocol!=="http:"&&a.protocol!=="https:")throw new Error(`DGA dynamic form: blocked URL protocol "${a.protocol}"`);if(e?.length&&!e.some(o=>{try{return new URL(o).origin===a.origin}catch{return o===a.origin}}))throw new Error(`DGA dynamic form: origin not allowlisted "${a.origin}"`);return a.toString().replace(/\/$/,"")}function Pe(i=c(S),e={}){return{lookup(t){try{const n=`${F(t.domain,e.allowedOrigins)}/lookup/${encodeURIComponent(t.name)}`,o={};if(t.parentId!=null&&t.parentId!==""&&(o.parentId=String(t.parentId)),t.search){const r=t.searchParamName||"q";o[r]=t.search}return i.get(n,{params:o}).pipe(Ue(r=>Array.isArray(r)?r.map(st):[]))}catch(a){return ge(()=>a)}}}}function st(i){const e=i??{},t=e.DisplayName??e.UserName??e.Email,a=e.value??e.id??e.Id??e.Code??t??"",n=String(e.labelEn??e.titleEn??e.en??e.TitleEn??e.Name??e.name??t??a),o=String(e.labelAr??e.titleAr??e.ar??e.TitleAr??e.NameAr??e.nameAr??n),r={value:a,label:{en:n,ar:o}};for(const[s,d]of Object.entries(e))lt.has(s)||s==="value"||s==="label"||s==="id"||s==="Id"||s==="labelEn"||s==="titleEn"||s==="en"||s==="TitleEn"||s==="labelAr"||s==="titleAr"||s==="ar"||s==="TitleAr"||(r[s]=d);return e.disabled!=null&&(r.disabled=!!e.disabled),e.requiresTextInput!=null&&(r.requiresTextInput=!!e.requiresTextInput),e.description&&typeof e.description=="object"&&(r.description=e.description),r}function Ve(i=c(S),e={}){return{submit(t){try{const a=F(t.endpoint,e.allowedOrigins),n=new He(t.headers??{}),o=t.method.toUpperCase();return o==="GET"?i.get(a,{headers:n}):o==="DELETE"?i.delete(a,{headers:n,body:t.body}):o==="PUT"?i.put(a,t.body,{headers:n}):o==="PATCH"?i.patch(a,t.body,{headers:n}):i.post(a,t.body,{headers:n})}catch(a){return ge(()=>a)}}}}function Re(i=c(je)){return{show(e){i.show({title:e.title,message:e.message,variant:e.variant??"info"})}}}function dt(i={}){const e=i.httpLookup??!1,t=i.httpSubmit??!0,a=i.dgaToast??!0,n=i.requireAllowedOrigins??!1,o={allowedOrigins:i.allowedOrigins};if(n&&(e||t)&&!i.allowedOrigins?.length)throw new Error("DGA dynamic form: provideDgaDynamicForm({ allowedOrigins: [...] }) is required when requireAllowedOrigins is true. ");return ze()&&(e||t)&&!i.allowedOrigins?.length&&console.warn("[dga-dynamic-form] HTTP adapters enabled without allowedOrigins. Absolute schema URLs can reach any https host — set allowedOrigins (and requireAllowedOrigins: true) for CMS schemas."),Be([{provide:$,useValue:o},{provide:U,useValue:Ae},{provide:_,useValue:Ee},{provide:z,useFactory:()=>e?Pe(c(S),o):Me},{provide:E,useFactory:()=>t?Ve(c(S),o):{submit:()=>x(null)}},{provide:B,useFactory:()=>a?Re():{show:()=>{}}}])}function ut(i,e,t=""){return i?e==="en"?i.en:i.ar:t}class v{accept=u("",...ngDevMode?[{debugName:"accept"}]:[]);maxFileSize=u(0,...ngDevMode?[{debugName:"maxFileSize"}]:[]);maxFiles=u(0,...ngDevMode?[{debugName:"maxFiles"}]:[]);uploadEndpoint=u("",...ngDevMode?[{debugName:"uploadEndpoint"}]:[]);deleteEndpoint=u("",...ngDevMode?[{debugName:"deleteEndpoint"}]:[]);deleteMethod=u("DELETE",...ngDevMode?[{debugName:"deleteMethod"}]:[]);hint=u("Drag files here or browse",...ngDevMode?[{debugName:"hint"}]:[]);browseLabel=u("Choose files",...ngDevMode?[{debugName:"browseLabel"}]:[]);removeLabel=u("Remove",...ngDevMode?[{debugName:"removeLabel"}]:[]);downloadLabel=u("Download",...ngDevMode?[{debugName:"downloadLabel"}]:[]);uploadingLabel=u("Uploading…",...ngDevMode?[{debugName:"uploadingLabel"}]:[]);errorLabel=u("Upload failed",...ngDevMode?[{debugName:"errorLabel"}]:[]);disabledInput=u(!1,{...ngDevMode?{debugName:"disabledInput"}:{},alias:"disabled",transform:J});cvaDisabled=m(!1,...ngDevMode?[{debugName:"cvaDisabled"}]:[]);disabled=p(()=>this.disabledInput()||this.cvaDisabled(),...ngDevMode?[{debugName:"disabled"}]:[]);fileDownload=g();http=c(S);httpSecurity=c($,{optional:!0});files=m([],...ngDevMode?[{debugName:"files"}]:[]);dragging=m(!1,...ngDevMode?[{debugName:"dragging"}]:[]);onChange=()=>{};onTouched=()=>{};atLimit=p(()=>{const e=this.maxFiles();return e>0&&this.files().length>=e},...ngDevMode?[{debugName:"atLimit"}]:[]);onDragOver(e){e.preventDefault(),!this.disabled()&&!this.atLimit()&&this.dragging.set(!0)}onDrop(e){if(e.preventDefault(),this.dragging.set(!1),this.disabled()||this.atLimit())return;const t=e.dataTransfer?.files;t?.length&&this.addFiles(Array.from(t))}onPick(e){const t=e.target;t.files?.length&&this.addFiles(Array.from(t.files)),t.value=""}remove(e){if(e.status==="uploading")return;const t=this.isExisting(e),a=this.deleteEndpoint();if(!t&&a&&e.fileId){const n=a.includes(":id")?a.replace(":id",encodeURIComponent(e.fileId)):a.includes(":fileId")?a.replace(":fileId",encodeURIComponent(e.fileId)):a;try{const o=F(n,this.httpSecurity?.allowedOrigins);this.deleteMethod()==="POST"?this.http.post(o,{FileName:e.fileName}).subscribe({complete:()=>this.commit(this.files().filter(r=>r!==e))}):this.http.delete(o).subscribe({complete:()=>this.commit(this.files().filter(r=>r!==e))});return}catch{}}this.commit(this.files().filter(n=>n!==e))}onDownload(e){this.isExisting(e)&&this.fileDownload.emit({Id:Number(e.fileId),FileName:e.fileName,ContentType:""})}isExisting(e){return e.listKey?.startsWith("existing-")??!1}addFiles(e){const t=this.maxFileSize(),a=this.maxFiles();let n=a>0?a-this.files().length:e.length;if(!(n<=0))for(const o of e.slice(0,n))t>0&&o.size>t||this.uploadOne(o)}uploadOne(e){const t=`new-${e.name}-${Date.now()}-${Math.random().toString(36).slice(2,7)}`,a={fileId:"",fileName:e.name,sizeBytes:e.size,status:"uploading",listKey:t},n=[...this.files(),a];this.files.set(n),this.onChange(n);const o=this.uploadEndpoint();if(!o){a.status="success",a.fileId=t,this.commit([...this.files()]);return}try{const r=F(o,this.httpSecurity?.allowedOrigins),s=new FormData;s.append("file",e),this.http.post(r,s).subscribe({next:d=>{a.status="success",a.fileId=d.fileId??t,d.fileName&&(a.fileName=d.fileName),this.commit([...this.files()])},error:d=>{a.status="error",a.errorMessage=d?.message??this.errorLabel(),this.commit([...this.files()])}})}catch(r){a.status="error",a.errorMessage=r?.message??this.errorLabel(),this.commit([...this.files()])}}commit(e){this.files.set(e),this.onChange(e),this.onTouched()}writeValue(e){const a=(Array.isArray(e)?e:[]).map(n=>{if("Id"in n&&"FileName"in n){const o=n;return{fileId:String(o.Id),fileName:o.FileName,status:"success",listKey:`existing-${o.Id}`}}return n});this.files.set(a)}registerOnChange(e){this.onChange=e}registerOnTouched(e){this.onTouched=e}setDisabledState(e){this.cvaDisabled.set(e)}static ɵfac=l.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.0.7",ngImport:l,type:v,deps:[],target:l.ɵɵFactoryTarget.Component});static ɵcmp=l.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"22.0.7",type:v,isStandalone:!0,selector:"dga-dynamic-form-staged-upload",inputs:{accept:{classPropertyName:"accept",publicName:"accept",isSignal:!0,isRequired:!1,transformFunction:null},maxFileSize:{classPropertyName:"maxFileSize",publicName:"maxFileSize",isSignal:!0,isRequired:!1,transformFunction:null},maxFiles:{classPropertyName:"maxFiles",publicName:"maxFiles",isSignal:!0,isRequired:!1,transformFunction:null},uploadEndpoint:{classPropertyName:"uploadEndpoint",publicName:"uploadEndpoint",isSignal:!0,isRequired:!1,transformFunction:null},deleteEndpoint:{classPropertyName:"deleteEndpoint",publicName:"deleteEndpoint",isSignal:!0,isRequired:!1,transformFunction:null},deleteMethod:{classPropertyName:"deleteMethod",publicName:"deleteMethod",isSignal:!0,isRequired:!1,transformFunction:null},hint:{classPropertyName:"hint",publicName:"hint",isSignal:!0,isRequired:!1,transformFunction:null},browseLabel:{classPropertyName:"browseLabel",publicName:"browseLabel",isSignal:!0,isRequired:!1,transformFunction:null},removeLabel:{classPropertyName:"removeLabel",publicName:"removeLabel",isSignal:!0,isRequired:!1,transformFunction:null},downloadLabel:{classPropertyName:"downloadLabel",publicName:"downloadLabel",isSignal:!0,isRequired:!1,transformFunction:null},uploadingLabel:{classPropertyName:"uploadingLabel",publicName:"uploadingLabel",isSignal:!0,isRequired:!1,transformFunction:null},errorLabel:{classPropertyName:"errorLabel",publicName:"errorLabel",isSignal:!0,isRequired:!1,transformFunction:null},disabledInput:{classPropertyName:"disabledInput",publicName:"disabled",isSignal:!0,isRequired:!1,transformFunction:null}},outputs:{fileDownload:"fileDownload"},host:{classAttribute:"block w-full"},providers:[ae(v)],ngImport:l,template:`
|
|
1
|
+
import*as l from"@angular/core";import{InjectionToken as x,inject as p,Injectable as X,isDevMode as je,makeEnvironmentProviders as We,input as c,booleanAttribute as Z,signal as f,computed as u,output as h,ChangeDetectionStrategy as R,Component as V,DestroyRef as ee,effect as N,untracked as q}from"@angular/core";import{NgComponentOutlet as te,NgTemplateOutlet as ae}from"@angular/common";import*as b from"@angular/forms";import{Validators as v,ReactiveFormsModule as O,FormsModule as ie,FormBuilder as Ke}from"@angular/forms";import{switchMap as ne,catchError as He,map as Ye,startWith as Je}from"rxjs/operators";import{takeUntilDestroyed as A}from"@angular/core/rxjs-interop";import{DgaToastService as Qe,DgaButton as E,DgaIcon as C,dgaProvideValueAccessor as oe,DgaField as re,DgaInput as le,DgaSelect as se,DgaCheckbox as de,DgaRadio as ce,DgaPhoneInput as ue,DgaChipInput as pe,DgaSwitch as fe,DgaUpload as me,DgaNumberInput as ge,DgaOtp as he,DgaAlert as be,DgaBadge as ve,DgaCard as ye,DgaProgress as xe,DgaStepper as De}from"@a.nemreen/dga-ui";import{of as D,throwError as we,startWith as Xe,catchError as Ze}from"rxjs";import{HttpClient as L,HttpHeaders as et}from"@angular/common/http";import{DgaDatePicker as Se}from"@a.nemreen/dga-ui/date-picker";const B=new x("DGA_LOOKUP_ADAPTER"),M=new x("DGA_SUBMIT_ADAPTER"),$=new x("DGA_FORM_TOAST_ADAPTER"),_=new x("DGA_CAPTCHA_ADAPTER"),U=new x("DGA_HTTP_SECURITY"),G=new x("DGA_FORM_I18N_ADAPTER"),Ce=new x("DGA_DYNAMIC_FORM_FIELD_REGISTRY"),Le=[["StartDate","EndDate"],["UseCaseStartDate","UseCaseEndDate"],["startDate","endDate"]];function Ie(i){return e=>e.value&&i.value!==e.value?{passwordMismatch:!0}:null}function tt(i){return e=>{if(!e.value||!i.value)return null;const t=new Date(e.value),a=new Date(i.value),n=new Date(a);return n.setDate(n.getDate()+1),t>=n?null:{endDateAfterStartDate:!0}}}function at(i){const e=(i??"").trim();if(e)return e.startsWith("+")?e:`+${e}`}function ke(i){const e=[...new Set((i??[]).map(t=>at(t?.code)).filter(t=>!!t&&t!=="+966"))].sort((t,a)=>a.length-t.length);return t=>{const a=(t.value??"").toString().trim();if(!a||!e.length)return j(t);const n=e.find(r=>a.startsWith(r));if(!n)return j(t);const o=a.slice(n.length).replace(/\s+/g,"");return o?/^\d+$/.test(o)?null:{invalidFormat:!0}:null}}function j(i){const e=(i.value??"").toString().trim();if(!e)return null;let t=e;return e.startsWith("+966")?t=e.slice(4):e.startsWith("966")&&(t=e.slice(3)),/^\d+$/.test(t)?t.startsWith("0")?t.length===10?null:{invalidLength:!0}:t.startsWith("5")?t.length===9?null:{invalidLength:!0}:{invalidPrefix:!0}:{invalidFormat:!0}}function it(i){return e=>{if(!e.value)return null;const t=new Date(e.value),a=new Date(i);return t>=a?null:{minDate:!0}}}function nt(i){return e=>{if(!e.value)return null;const t=new Date(e.value),a=new Date(i);return t<=a?null:{maxDate:!0}}}function ot(i){const e=i.value;return Array.isArray(e)&&e.some(a=>a&&typeof a=="object"&&a.status==="uploading")?{uploadInProgress:!0}:null}function Te(i,e){const t=i.get("password"),a=i.get("confirmPassword");t&&a&&(a.addValidators(Ie(t)),a.updateValueAndValidity({emitEvent:!1}));for(const[n,o]of Le){const r=i.get(n),s=i.get(o);if(!r||!s)continue;s.addValidators(tt(r));const d=e.find(S=>S.name===o),g=S=>{if(d?.validation){if(S){const Ge=new Date(S),z=new Date(Ge);z.setDate(z.getDate()+1),d.validation.minDate=z.toISOString().split("T")[0]}else delete d.validation.minDate;s.updateValueAndValidity({emitEvent:!1})}};g(r.value),r.valueChanges.subscribe(S=>g(S))}}const Fe=["checkbox","multiselect","chips","file","multifile","multifilestaged"],rt=["toggle"];function Ne(i){return i.value!==void 0?i.value:Fe.includes(i.type)?[]:rt.includes(i.type)?!1:""}function W(i,e){const t=[],a=i.validation;(e||i.required||a?.required)&&(Fe.includes(i.type)?t.push(lt):i.type==="toggle"?t.push(v.requiredTrue):t.push(v.required)),(i.type==="email"||a?.pattern==="email")&&t.push(v.email);const n=a?.minLength;n!=null&&t.push(v.minLength(n));const o=a?.maxLength??i.maxLength;if(o!=null&&t.push(v.maxLength(o)),a?.pattern&&a.pattern!=="email"){const r=a.pattern;if(typeof r=="string"&&r.length>0&&r.length<=200)try{t.push(v.pattern(r))}catch{}}return a?.min!=null&&t.push(v.min(a.min)),a?.max!=null&&t.push(v.max(a.max)),i.maxChips!=null&&i.type==="chips"&&t.push(st(i.maxChips)),i.type==="phone"&&t.push(ke(i.countries)),i.type==="multifilestaged"&&t.push(ot),a?.minDate&&t.push(it(a.minDate)),a?.maxDate&&t.push(nt(a.maxDate)),t}function lt(i){const e=i.value;return Array.isArray(e)&&e.length>0?null:{required:!0}}function st(i){return e=>{const t=e.value;return Array.isArray(t)&&t.length>i?{maxChips:{max:i,actual:t.length}}:null}}function Oe(i,e,t=!0){const a=!!e.disabled;return i.control({value:Ne(e),disabled:a},{validators:W(e,t&&!e.requiredWhen)})}function Ae(i,e){const t={};for(const a of e){if(a.hidden&&a.type==="hidden"){t[a.name]=i.control(a.value??"");continue}t[a.name]=Oe(i,a)}return i.group(t)}function Ee(i,e){return e?.length?e.flatMap(t=>t.fields):i}function K(i,e,t){i.setValidators(W(e,t)),i.updateValueAndValidity({emitEvent:!1})}function H(i,e){return Array.isArray(i)?i.some(t=>t==e):i==e}function dt(i){return i.label?.en??""}function ct(i){return i.label?.ar??""}function P(i,e,t,a){return Pe(a?.(i)??{name:i,type:"select",label:{en:"",ar:""}},e,t?.(i))}function ut(i,e,t,a,n){if(!i.showOnTitleEn&&!i.showOnTitleAr||t==null||t==="")return!1;const o=P(e,t,a,n);if(!o)return!1;const r=i.showOnTitleEn?dt(o)===i.showOnTitleEn:!0,s=i.showOnTitleAr?ct(o)===i.showOnTitleAr:!0;return r&&s}function Me(i,e,t,a){if(!i.extraField)return!0;const n=i.extraFieldTrigger||i.dependsOn;if(!n)return!1;const o=e[n];return P(n,o,t,a)?.requiresTextInput===!0}function Pe(i,e,t){return i?[...t??[],...i.options??[],...i.groupedOptions?.flatMap(n=>n.options)??[]].find(n=>n.value==e):void 0}function Y(i,e,t,a){if(i.hidden&&i.type!=="hidden"||i.type==="hidden")return!1;if(!i.dependsOn&&!i.extraField)return!0;const n=i.dependsOn??i.extraFieldTrigger;if(!n)return Me(i,e,t,a);const o=e[n];if(i.showOnValues?.length&&!i.showOnValues.some(r=>H(o,r))||(i.showOnTitleEn||i.showOnTitleAr)&&!ut(i,n,o,t,a))return!1;if(i.showWhenOptionProperty){const r=P(n,o,t,a),s=i.showWhenOptionProperty.property;if(!r||r[s]!==i.showWhenOptionProperty.value)return!1}return!(i.extraField&&!Me(i,e,t,a)||i.dependsOn&&!i.showOnValues?.length&&!i.showWhenOptionProperty&&!i.showOnTitleEn&&!i.showOnTitleAr&&!i.extraField&&(o==null||o===""||Array.isArray(o)&&o.length===0))}function J(i,e,t,a){const n=i.requiredWhen;if(!n)return!!i.required;const o=e[n.field];if(n.optionProperty!=null){const r=P(n.field,o,t,a);return!!r&&r[n.optionProperty]===n.optionPropertyValue}return n.values?.length?n.values.some(r=>H(o,r)):n.value!==void 0?H(o,n.value):o!=null&&o!==""}const pt=new Set(["otp","file"]),ze=/password|passwd|secret|token|otp|national.?id|ssn|pin$/i;class I{submitAdapter=p(M,{optional:!0});captcha=p(_,{optional:!0});buildPayload(e,t,a){const n=new Set(a.filter(r=>r.excludeFromPayload).map(r=>r.name));let o={};for(const[r,s]of Object.entries(t)){if(n.has(r))continue;const d=e.fieldMapping?.[r]??r;o[d]=s}return e.payloadTransformer?e.payloadTransformer(o):o}hasFileValues(e){return Object.values(e).some(t=>t instanceof File||Array.isArray(t)&&t.some(a=>a instanceof File||a?.file instanceof File))}toFormData(e){const t=new FormData;for(const[a,n]of Object.entries(e))if(n!=null)if(n instanceof File)t.append(a,n);else if(Array.isArray(n))for(const o of n)o instanceof File?t.append(a,o):o?.file instanceof File?t.append(a,o.file,o.name):t.append(a,typeof o=="string"?o:JSON.stringify(o));else typeof n=="object"?t.append(a,JSON.stringify(n)):t.append(a,String(n));return t}submitForm(e,t,a){if(!e.endpoint||!this.submitAdapter)return D(t);const n=this.buildPayload(e,t,a),o=n instanceof FormData?n:this.hasFileValues(n)?this.toFormData(n):n,r={};return e.idempotencyKey&&(r["Idempotency-Key"]=e.idempotencyKey),(this.captcha?.getToken("submit")??D(null)).pipe(ne(d=>(d&&(r["X-Recaptcha-Token"]=d),D({endpoint:e.endpoint,method:e.method??"POST",body:o,headers:r})))).pipe(ne(d=>this.submitAdapter.submit(d)),He(d=>{throw d}))}saveDraft(e,t,a=[]){if(typeof localStorage>"u")return;const n=new Map(a.map(r=>[r.name,r])),o={};for(const[r,s]of Object.entries(t)){const d=n.get(r);d&&this.isDraftBlocked(d)||!d&&ze.test(r)||s instanceof File||(o[r]=s)}localStorage.setItem(this.storageKey(e),JSON.stringify(o))}loadDraft(e){if(typeof localStorage>"u")return null;const t=localStorage.getItem(this.storageKey(e));if(!t)return null;try{return JSON.parse(t)}catch{return null}}clearDraft(e){typeof localStorage>"u"||localStorage.removeItem(this.storageKey(e))}isDraftBlocked(e){return e.excludeFromDraft||e.sensitive||e.excludeFromPayload||pt.has(e.type)?!0:ze.test(e.name)}storageKey(e){return`dga-dynamic-form:${e}`}static ɵfac=l.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.1.5",ngImport:l,type:I,deps:[],target:l.ɵɵFactoryTarget.Injectable});static ɵprov=l.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"22.1.5",ngImport:l,type:I,providedIn:"root"})}l.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"22.1.5",ngImport:l,type:I,decorators:[{type:X,args:[{providedIn:"root"}]}]});function m(i,e,t=""){if(!i)return t;const a=i[e];return a||(i.en?i.en:i.ar?i.ar:Object.values(i).find(o=>!!o)||t)}function Re(){return typeof document>"u"?"ar":(document.documentElement.lang||"ar").toLowerCase().split("-")[0]||"ar"}class k{extras=p(Ce,{optional:!0});map=new Map;constructor(){for(const e of this.extras??[])this.register(e)}register(e){this.map.set(e.type,e.component)}get(e){return this.map.get(e)??null}hasCustom(e){return this.map.has(e)}isBuiltIn(e){return ft.has(e)}static ɵfac=l.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.1.5",ngImport:l,type:k,deps:[],target:l.ɵɵFactoryTarget.Injectable});static ɵprov=l.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"22.1.5",ngImport:l,type:k,providedIn:"root"})}l.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"22.1.5",ngImport:l,type:k,decorators:[{type:X,args:[{providedIn:"root"}]}],ctorParameters:()=>[]});const ft=new Set(["text","email","textarea","select","multiselect","checkbox","radio","phone","file","multifile","multifilestaged","date","chips","toggle","hidden","number","otp","password"]),Ve={resolveLabel(i,e){return m(i,e)}},qe={getToken:()=>D(null)},Be={lookup:()=>D([])},mt=new Set(["__proto__","constructor","prototype"]);function T(i,e){const t=i.trim();if(!t)throw new Error("DGA dynamic form: empty HTTP URL");if(t.startsWith("/")&&!t.startsWith("//"))return t.replace(/\/$/,"")||"/";let a;try{a=new URL(t)}catch{throw new Error(`DGA dynamic form: invalid HTTP URL "${i}"`)}if(a.protocol!=="http:"&&a.protocol!=="https:")throw new Error(`DGA dynamic form: blocked URL protocol "${a.protocol}"`);if(e?.length&&!e.some(o=>{try{return new URL(o).origin===a.origin}catch{return o===a.origin}}))throw new Error(`DGA dynamic form: origin not allowlisted "${a.origin}"`);return a.toString().replace(/\/$/,"")}function $e(i=p(L),e={}){return{lookup(t){try{const n=`${T(t.domain,e.allowedOrigins)}/lookup/${encodeURIComponent(t.name)}`,o={};if(t.parentId!=null&&t.parentId!==""&&(o.parentId=String(t.parentId)),t.search){const r=t.searchParamName||"q";o[r]=t.search}return i.get(n,{params:o}).pipe(Ye(r=>Array.isArray(r)?r.map(gt):[]))}catch(a){return we(()=>a)}}}}function gt(i){const e=i??{},t=e.DisplayName??e.UserName??e.Email,a=e.value??e.id??e.Id??e.Code??t??"",n=String(e.labelEn??e.titleEn??e.en??e.TitleEn??e.Name??e.name??t??a),o=String(e.labelAr??e.titleAr??e.ar??e.TitleAr??e.NameAr??e.nameAr??n),r={value:a,label:{en:n,ar:o}};for(const[s,d]of Object.entries(e))mt.has(s)||s==="value"||s==="label"||s==="id"||s==="Id"||s==="labelEn"||s==="titleEn"||s==="en"||s==="TitleEn"||s==="labelAr"||s==="titleAr"||s==="ar"||s==="TitleAr"||(r[s]=d);return e.disabled!=null&&(r.disabled=!!e.disabled),e.requiresTextInput!=null&&(r.requiresTextInput=!!e.requiresTextInput),e.description&&typeof e.description=="object"&&(r.description=e.description),r}function _e(i=p(L),e={}){return{submit(t){try{const a=T(t.endpoint,e.allowedOrigins),n=new et(t.headers??{}),o=t.method.toUpperCase();return o==="GET"?i.get(a,{headers:n}):o==="DELETE"?i.delete(a,{headers:n,body:t.body}):o==="PUT"?i.put(a,t.body,{headers:n}):o==="PATCH"?i.patch(a,t.body,{headers:n}):i.post(a,t.body,{headers:n})}catch(a){return we(()=>a)}}}}function Ue(i=p(Qe)){return{show(e){i.show({title:e.title,message:e.message,variant:e.variant??"info"})}}}function ht(i={}){const e=i.httpLookup??!1,t=i.httpSubmit??!0,a=i.dgaToast??!0,n=i.requireAllowedOrigins??!1,o={allowedOrigins:i.allowedOrigins};if(n&&(e||t)&&!i.allowedOrigins?.length)throw new Error("DGA dynamic form: provideDgaDynamicForm({ allowedOrigins: [...] }) is required when requireAllowedOrigins is true. ");return je()&&(e||t)&&!i.allowedOrigins?.length&&console.warn("[dga-dynamic-form] HTTP adapters enabled without allowedOrigins. Absolute schema URLs can reach any https host — set allowedOrigins (and requireAllowedOrigins: true) for CMS schemas."),We([{provide:U,useValue:o},{provide:G,useValue:Ve},{provide:_,useValue:qe},{provide:B,useFactory:()=>e?$e(p(L),o):Be},{provide:M,useFactory:()=>t?_e(p(L),o):{submit:()=>D(null)}},{provide:$,useFactory:()=>a?Ue():{show:()=>{}}}])}function bt(i,e,t=""){return m(i,e,t)}class y{accept=c("",...ngDevMode?[{debugName:"accept"}]:[]);maxFileSize=c(0,...ngDevMode?[{debugName:"maxFileSize"}]:[]);maxFiles=c(0,...ngDevMode?[{debugName:"maxFiles"}]:[]);uploadEndpoint=c("",...ngDevMode?[{debugName:"uploadEndpoint"}]:[]);deleteEndpoint=c("",...ngDevMode?[{debugName:"deleteEndpoint"}]:[]);deleteMethod=c("DELETE",...ngDevMode?[{debugName:"deleteMethod"}]:[]);hint=c("Drag files here or browse",...ngDevMode?[{debugName:"hint"}]:[]);browseLabel=c("Choose files",...ngDevMode?[{debugName:"browseLabel"}]:[]);removeLabel=c("Remove",...ngDevMode?[{debugName:"removeLabel"}]:[]);downloadLabel=c("Download",...ngDevMode?[{debugName:"downloadLabel"}]:[]);uploadingLabel=c("Uploading…",...ngDevMode?[{debugName:"uploadingLabel"}]:[]);errorLabel=c("Upload failed",...ngDevMode?[{debugName:"errorLabel"}]:[]);disabledInput=c(!1,{...ngDevMode?{debugName:"disabledInput"}:{},alias:"disabled",transform:Z});cvaDisabled=f(!1,...ngDevMode?[{debugName:"cvaDisabled"}]:[]);disabled=u(()=>this.disabledInput()||this.cvaDisabled(),...ngDevMode?[{debugName:"disabled"}]:[]);fileDownload=h();http=p(L);httpSecurity=p(U,{optional:!0});files=f([],...ngDevMode?[{debugName:"files"}]:[]);dragging=f(!1,...ngDevMode?[{debugName:"dragging"}]:[]);onChange=()=>{};onTouched=()=>{};atLimit=u(()=>{const e=this.maxFiles();return e>0&&this.files().length>=e},...ngDevMode?[{debugName:"atLimit"}]:[]);onDragOver(e){e.preventDefault(),!this.disabled()&&!this.atLimit()&&this.dragging.set(!0)}onDrop(e){if(e.preventDefault(),this.dragging.set(!1),this.disabled()||this.atLimit())return;const t=e.dataTransfer?.files;t?.length&&this.addFiles(Array.from(t))}onPick(e){const t=e.target;t.files?.length&&this.addFiles(Array.from(t.files)),t.value=""}remove(e){if(e.status==="uploading")return;const t=this.isExisting(e),a=this.deleteEndpoint();if(!t&&a&&e.fileId){const n=a.includes(":id")?a.replace(":id",encodeURIComponent(e.fileId)):a.includes(":fileId")?a.replace(":fileId",encodeURIComponent(e.fileId)):a;try{const o=T(n,this.httpSecurity?.allowedOrigins);this.deleteMethod()==="POST"?this.http.post(o,{FileName:e.fileName}).subscribe({complete:()=>this.commit(this.files().filter(r=>r!==e))}):this.http.delete(o).subscribe({complete:()=>this.commit(this.files().filter(r=>r!==e))});return}catch{}}this.commit(this.files().filter(n=>n!==e))}onDownload(e){this.isExisting(e)&&this.fileDownload.emit({Id:Number(e.fileId),FileName:e.fileName,ContentType:""})}isExisting(e){return e.listKey?.startsWith("existing-")??!1}addFiles(e){const t=this.maxFileSize(),a=this.maxFiles();let n=a>0?a-this.files().length:e.length;if(!(n<=0))for(const o of e.slice(0,n))t>0&&o.size>t||this.uploadOne(o)}uploadOne(e){const t=`new-${e.name}-${Date.now()}-${Math.random().toString(36).slice(2,7)}`,a={fileId:"",fileName:e.name,sizeBytes:e.size,status:"uploading",listKey:t},n=[...this.files(),a];this.files.set(n),this.onChange(n);const o=this.uploadEndpoint();if(!o){a.status="success",a.fileId=t,this.commit([...this.files()]);return}try{const r=T(o,this.httpSecurity?.allowedOrigins),s=new FormData;s.append("file",e),this.http.post(r,s).subscribe({next:d=>{a.status="success",a.fileId=d.fileId??t,d.fileName&&(a.fileName=d.fileName),this.commit([...this.files()])},error:d=>{a.status="error",a.errorMessage=d?.message??this.errorLabel(),this.commit([...this.files()])}})}catch(r){a.status="error",a.errorMessage=r?.message??this.errorLabel(),this.commit([...this.files()])}}commit(e){this.files.set(e),this.onChange(e),this.onTouched()}writeValue(e){const a=(Array.isArray(e)?e:[]).map(n=>{if("Id"in n&&"FileName"in n){const o=n;return{fileId:String(o.Id),fileName:o.FileName,status:"success",listKey:`existing-${o.Id}`}}return n});this.files.set(a)}registerOnChange(e){this.onChange=e}registerOnTouched(e){this.onTouched=e}setDisabledState(e){this.cvaDisabled.set(e)}static ɵfac=l.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.1.5",ngImport:l,type:y,deps:[],target:l.ɵɵFactoryTarget.Component});static ɵcmp=l.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"22.1.5",type:y,isStandalone:!0,selector:"dga-dynamic-form-staged-upload",inputs:{accept:{classPropertyName:"accept",publicName:"accept",isSignal:!0,isRequired:!1,transformFunction:null},maxFileSize:{classPropertyName:"maxFileSize",publicName:"maxFileSize",isSignal:!0,isRequired:!1,transformFunction:null},maxFiles:{classPropertyName:"maxFiles",publicName:"maxFiles",isSignal:!0,isRequired:!1,transformFunction:null},uploadEndpoint:{classPropertyName:"uploadEndpoint",publicName:"uploadEndpoint",isSignal:!0,isRequired:!1,transformFunction:null},deleteEndpoint:{classPropertyName:"deleteEndpoint",publicName:"deleteEndpoint",isSignal:!0,isRequired:!1,transformFunction:null},deleteMethod:{classPropertyName:"deleteMethod",publicName:"deleteMethod",isSignal:!0,isRequired:!1,transformFunction:null},hint:{classPropertyName:"hint",publicName:"hint",isSignal:!0,isRequired:!1,transformFunction:null},browseLabel:{classPropertyName:"browseLabel",publicName:"browseLabel",isSignal:!0,isRequired:!1,transformFunction:null},removeLabel:{classPropertyName:"removeLabel",publicName:"removeLabel",isSignal:!0,isRequired:!1,transformFunction:null},downloadLabel:{classPropertyName:"downloadLabel",publicName:"downloadLabel",isSignal:!0,isRequired:!1,transformFunction:null},uploadingLabel:{classPropertyName:"uploadingLabel",publicName:"uploadingLabel",isSignal:!0,isRequired:!1,transformFunction:null},errorLabel:{classPropertyName:"errorLabel",publicName:"errorLabel",isSignal:!0,isRequired:!1,transformFunction:null},disabledInput:{classPropertyName:"disabledInput",publicName:"disabled",isSignal:!0,isRequired:!1,transformFunction:null}},outputs:{fileDownload:"fileDownload"},host:{classAttribute:"block w-full"},providers:[oe(y)],ngImport:l,template:`
|
|
2
2
|
<div class="flex flex-col gap-md">
|
|
3
3
|
<div
|
|
4
4
|
class="flex flex-col items-center justify-center gap-md rounded-lg border border-dashed border-border
|
|
@@ -76,7 +76,7 @@ import*as l from"@angular/core";import{InjectionToken as y,inject as c,Injectabl
|
|
|
76
76
|
</ul>
|
|
77
77
|
}
|
|
78
78
|
</div>
|
|
79
|
-
`,isInline:!0,dependencies:[{kind:"directive",type:
|
|
79
|
+
`,isInline:!0,dependencies:[{kind:"directive",type:E,selector:"button[dgaButton], a[dgaButton]",inputs:["variant","size","iconOnly","cooldownMs","loading","dgaButtonClass"]},{kind:"component",type:C,selector:"dga-icon",inputs:["name","glyph","size","tone","label"]}],changeDetection:l.ChangeDetectionStrategy.OnPush})}l.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"22.1.5",ngImport:l,type:y,decorators:[{type:V,args:[{selector:"dga-dynamic-form-staged-upload",standalone:!0,imports:[E,C],template:`
|
|
80
80
|
<div class="flex flex-col gap-md">
|
|
81
81
|
<div
|
|
82
82
|
class="flex flex-col items-center justify-center gap-md rounded-lg border border-dashed border-border
|
|
@@ -154,7 +154,7 @@ import*as l from"@angular/core";import{InjectionToken as y,inject as c,Injectabl
|
|
|
154
154
|
</ul>
|
|
155
155
|
}
|
|
156
156
|
</div>
|
|
157
|
-
`,changeDetection:
|
|
157
|
+
`,changeDetection:R.OnPush,host:{class:"block w-full"},providers:[oe(y)]}]}],propDecorators:{accept:[{type:l.Input,args:[{isSignal:!0,alias:"accept",required:!1}]}],maxFileSize:[{type:l.Input,args:[{isSignal:!0,alias:"maxFileSize",required:!1}]}],maxFiles:[{type:l.Input,args:[{isSignal:!0,alias:"maxFiles",required:!1}]}],uploadEndpoint:[{type:l.Input,args:[{isSignal:!0,alias:"uploadEndpoint",required:!1}]}],deleteEndpoint:[{type:l.Input,args:[{isSignal:!0,alias:"deleteEndpoint",required:!1}]}],deleteMethod:[{type:l.Input,args:[{isSignal:!0,alias:"deleteMethod",required:!1}]}],hint:[{type:l.Input,args:[{isSignal:!0,alias:"hint",required:!1}]}],browseLabel:[{type:l.Input,args:[{isSignal:!0,alias:"browseLabel",required:!1}]}],removeLabel:[{type:l.Input,args:[{isSignal:!0,alias:"removeLabel",required:!1}]}],downloadLabel:[{type:l.Input,args:[{isSignal:!0,alias:"downloadLabel",required:!1}]}],uploadingLabel:[{type:l.Input,args:[{isSignal:!0,alias:"uploadingLabel",required:!1}]}],errorLabel:[{type:l.Input,args:[{isSignal:!0,alias:"errorLabel",required:!1}]}],disabledInput:[{type:l.Input,args:[{isSignal:!0,alias:"disabled",required:!1}]}],fileDownload:[{type:l.Output,args:["fileDownload"]}]}});class w{field=c.required(...ngDevMode?[{debugName:"field"}]:[]);form=c.required(...ngDevMode?[{debugName:"form"}]:[]);locale=c("ar",...ngDevMode?[{debugName:"locale"}]:[]);required=c(!1,{...ngDevMode?{debugName:"required"}:{},transform:Z});error=c("",...ngDevMode?[{debugName:"error"}]:[]);runtimeOptions=c([],...ngDevMode?[{debugName:"runtimeOptions"}]:[]);consentBaseUrl=c(...ngDevMode?[void 0,{debugName:"consentBaseUrl"}]:[]);optionsLoaded=h();fileDownload=h();lookup=p(B,{optional:!0});http=p(L,{optional:!0});destroyRef=p(ee);loadedOptions=f([],...ngDevMode?[{debugName:"loadedOptions"}]:[]);controlId=`dga-df-${Math.random().toString(36).slice(2,9)}`;get control(){return this.form().controls[this.field().name]}labelText=u(()=>m(this.field().label,this.locale()),...ngDevMode?[{debugName:"labelText"}]:[]);hintText=u(()=>m(this.field().hint,this.locale()),...ngDevMode?[{debugName:"hintText"}]:[]);placeholderText=u(()=>m(this.field().placeholder,this.locale()),...ngDevMode?[{debugName:"placeholderText"}]:[]);phoneCountries=u(()=>(this.field().countries??[]).flatMap(e=>{const t=(e.code??"").trim();if(!t)return[];const a=t.startsWith("+")?t:`+${t}`;return[{code:a,label:(e.label??"").trim()||a,name:e.name}]}),...ngDevMode?[{debugName:"phoneCountries"}]:[]);resolvedOptions=u(()=>{const e=this.runtimeOptions();if(e.length)return e;const t=this.loadedOptions();if(t.length)return t;const a=this.field();return a.options?.length?a.options:a.groupedOptions?.flatMap(n=>n.options)??[]},...ngDevMode?[{debugName:"resolvedOptions"}]:[]);optionGroups=u(()=>{const e=this.runtimeOptions();if(e.length)return[{label:"",options:e}];const t=this.loadedOptions();if(t.length)return[{label:"",options:t}];const a=this.field();return a.groupedOptions?.length&&!a.options?.length?a.groupedOptions.map(n=>({label:m(n.groupLabel,this.locale()),options:n.options})):[{label:"",options:a.options??[]}]},...ngDevMode?[{debugName:"optionGroups"}]:[]);selectOptions=u(()=>this.resolvedOptions().map(e=>({value:String(e.value),label:this.optionLabel(e),disabled:!!e.disabled})),...ngDevMode?[{debugName:"selectOptions"}]:[]);ngOnInit(){const e=this.field();if(this.mapExistingFileValue(),e.consentServiceName&&this.consentBaseUrl()&&this.http&&this.fetchConsent(e),e.lookupDomain&&e.lookupName&&this.lookup){if(e.dependsOn&&e.useParentId!==!1){const t=this.form().get(e.dependsOn);if(t){t.valueChanges.pipe(Xe(t.value),A(this.destroyRef)).subscribe(a=>this.fetchLookup(e,a));return}}e.searchLookup||this.fetchLookup(e)}}mapExistingFileValue(){const e=this.field();if(e.type!=="file"&&e.type!=="multifile")return;const t=this.control.value;if(!Array.isArray(t)||!t.length)return;const a=t[0];if(!a||!("Id"in a)||!("FileName"in a))return;const n=t.map(o=>({id:String(o.Id),name:o.FileName,size:0}));this.control.setValue(n,{emitEvent:!1})}fetchConsent(e){const a=`${this.consentBaseUrl().replace(/\/$/,"")}/consents/${encodeURIComponent(e.consentServiceName)}`;this.http.get(a).pipe(Ze(()=>D(null)),A(this.destroyRef)).subscribe(n=>{if(!n?.Content)return;const o={en:n.Content.En||n.Content.Ar||"",ar:n.Content.Ar||n.Content.En||""};if(e.type==="checkbox"){const r=e.options?.length?[...e.options]:[{value:!0,label:{en:"",ar:""}}];r[0]={...r[0],label:o},this.loadedOptions.set(r),this.optionsLoaded.emit({name:e.name,options:r})}})}fetchLookup(e,t,a){if(!this.lookup||!e.lookupDomain||!e.lookupName)return;const n=e.minSearchLength??(e.searchLookup?3:0);a!=null&&a.length<n||this.lookup.lookup({domain:e.lookupDomain,name:e.lookupName,parentId:e.useParentId!==!1&&t!=null&&t!==""?t:void 0,search:a||void 0,searchParamName:e.searchParamName}).pipe(A(this.destroyRef)).subscribe(o=>{const r=this.applyLookupFilter(o);this.loadedOptions.set(r),this.optionsLoaded.emit({name:e.name,options:r})})}optionLabel(e){return m(e.label,this.locale())}optionDescription(e){return e.description?m(e.description,this.locale()):""}isCardsLayout(){return this.field().optionsLayout==="cards"}optionsContainerClass(){const e=this.field().optionsLayout;return e==="cards"?"grid grid-cols-1 gap-md sm:grid-cols-2":e==="grid"?"flex flex-wrap gap-lg":"flex flex-col gap-md"}choiceLabelClass(e){return this.isCardsLayout()?["flex min-h-7xl cursor-pointer items-start gap-lg rounded-lg border border-border bg-elevated p-xl text-start shadow-xs","transition-[border-color,box-shadow,background-color] hover:border-border-primary-light hover:shadow-sm","has-[:checked]:border-border-primary has-[:checked]:bg-primary-faint has-[:checked]:shadow-sm has-[:checked]:ring-2 has-[:checked]:ring-primary/20","has-[:focus-visible]:outline has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-focus",e.disabled||this.field().disabled?"pointer-events-none opacity-50":""].filter(Boolean).join(" "):"inline-flex max-w-full items-start gap-sm text-body-sm text-fg"}isPasswordField(){const e=this.field().name;return e==="password"||e==="confirmPassword"}isChecked(e){const t=this.control?.value;return Array.isArray(t)&&t.some(a=>a==e)}toggleCheckbox(e,t){const a=Array.isArray(this.control.value)?[...this.control.value]:[],n=t?a.some(o=>o==e)?a:[...a,e]:a.filter(o=>o!=e);this.control.setValue(n),this.control.markAsDirty()}onSelectSearchQuery(e){const t=this.field();t.searchLookup&&this.fetchLookup(t,this.form().get(t.dependsOn??"")?.value,e)}onStagedFileDownload(e){this.fileDownload.emit(e)}onRestrict(e){const t=this.field().inputRestriction;if(!t)return;const a=e.target;let n=a.value;t==="numbers"&&(n=n.replace(/\D+/g,"")),t==="english"&&(n=n.replace(/[^a-zA-Z0-9\s.,\-_/]/g,"")),t==="arabic"&&(n=n.replace(/[^\u0600-\u06FF0-9\s.,\-_/]/g,"")),n!==a.value&&(a.value=n,this.control.setValue(n))}applyLookupFilter(e){const t=this.field().lookupFilter;return t?e.filter(a=>a[t.property]===t.value):e}static ɵfac=l.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.1.5",ngImport:l,type:w,deps:[],target:l.ɵɵFactoryTarget.Component});static ɵcmp=l.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"22.1.5",type:w,isStandalone:!0,selector:"dga-dynamic-form-field",inputs:{field:{classPropertyName:"field",publicName:"field",isSignal:!0,isRequired:!0,transformFunction:null},form:{classPropertyName:"form",publicName:"form",isSignal:!0,isRequired:!0,transformFunction:null},locale:{classPropertyName:"locale",publicName:"locale",isSignal:!0,isRequired:!1,transformFunction:null},required:{classPropertyName:"required",publicName:"required",isSignal:!0,isRequired:!1,transformFunction:null},error:{classPropertyName:"error",publicName:"error",isSignal:!0,isRequired:!1,transformFunction:null},runtimeOptions:{classPropertyName:"runtimeOptions",publicName:"runtimeOptions",isSignal:!0,isRequired:!1,transformFunction:null},consentBaseUrl:{classPropertyName:"consentBaseUrl",publicName:"consentBaseUrl",isSignal:!0,isRequired:!1,transformFunction:null}},outputs:{optionsLoaded:"optionsLoaded",fileDownload:"fileDownload"},host:{properties:{"class.hidden":'field().type === "hidden"'},classAttribute:"block w-full"},ngImport:l,template:`
|
|
158
158
|
@if (field().type !== 'hidden') {
|
|
159
159
|
<dga-field
|
|
160
160
|
[label]="labelText()"
|
|
@@ -207,6 +207,8 @@ import*as l from"@angular/core";import{InjectionToken as y,inject as c,Injectabl
|
|
|
207
207
|
[disabled]="!!field().disabled"
|
|
208
208
|
[required]="required()"
|
|
209
209
|
[controlId]="controlId"
|
|
210
|
+
[locale]="locale()"
|
|
211
|
+
[countries]="phoneCountries()"
|
|
210
212
|
/>
|
|
211
213
|
}
|
|
212
214
|
@case ('date') {
|
|
@@ -297,44 +299,77 @@ import*as l from"@angular/core";import{InjectionToken as y,inject as c,Injectabl
|
|
|
297
299
|
/>
|
|
298
300
|
}
|
|
299
301
|
@case ('radio') {
|
|
300
|
-
<div
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
302
|
+
<div class="flex flex-col gap-lg" role="radiogroup" [attr.aria-labelledby]="controlId">
|
|
303
|
+
@for (group of optionGroups(); track $index) {
|
|
304
|
+
@if (group.label) {
|
|
305
|
+
<p class="m-0 text-label-sm font-medium text-muted">{{ group.label }}</p>
|
|
306
|
+
}
|
|
307
|
+
<div [class]="optionsContainerClass()">
|
|
308
|
+
@for (opt of group.options; track opt.value) {
|
|
309
|
+
<label [class]="choiceLabelClass(opt)">
|
|
310
|
+
<input
|
|
311
|
+
type="radio"
|
|
312
|
+
dgaRadio
|
|
313
|
+
class="peer mt-xxs"
|
|
314
|
+
[name]="field().name"
|
|
315
|
+
[value]="opt.value"
|
|
316
|
+
[formControl]="control"
|
|
317
|
+
[disabled]="!!opt.disabled || !!field().disabled"
|
|
318
|
+
[dgaInvalid]="!!error()"
|
|
319
|
+
/>
|
|
320
|
+
<span class="flex min-w-0 flex-col gap-xxs">
|
|
321
|
+
<span class="text-body-sm font-medium text-fg">{{ optionLabel(opt) }}</span>
|
|
322
|
+
@if (optionDescription(opt); as desc) {
|
|
323
|
+
<span class="text-body-xs text-muted">{{ desc }}</span>
|
|
324
|
+
}
|
|
325
|
+
</span>
|
|
326
|
+
@if (isCardsLayout()) {
|
|
327
|
+
<span
|
|
328
|
+
class="ms-auto hidden shrink-0 text-fg-primary peer-checked:inline-flex"
|
|
329
|
+
>
|
|
330
|
+
<dga-icon name="checkCircle" size="sm" tone="primary" />
|
|
331
|
+
</span>
|
|
332
|
+
}
|
|
333
|
+
</label>
|
|
334
|
+
}
|
|
335
|
+
</div>
|
|
318
336
|
}
|
|
319
337
|
</div>
|
|
320
338
|
}
|
|
321
339
|
@case ('checkbox') {
|
|
322
|
-
<div
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
<
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
340
|
+
<div class="flex flex-col gap-lg">
|
|
341
|
+
@for (group of optionGroups(); track $index) {
|
|
342
|
+
@if (group.label) {
|
|
343
|
+
<p class="m-0 text-label-sm font-medium text-muted">{{ group.label }}</p>
|
|
344
|
+
}
|
|
345
|
+
<div [class]="optionsContainerClass()">
|
|
346
|
+
@for (opt of group.options; track opt.value) {
|
|
347
|
+
<label [class]="choiceLabelClass(opt)">
|
|
348
|
+
<input
|
|
349
|
+
type="checkbox"
|
|
350
|
+
dgaCheckbox
|
|
351
|
+
class="peer mt-xxs"
|
|
352
|
+
[checked]="isChecked(opt.value)"
|
|
353
|
+
[disabled]="!!opt.disabled || !!field().disabled"
|
|
354
|
+
[dgaInvalid]="!!error()"
|
|
355
|
+
(change)="toggleCheckbox(opt.value, $any($event.target).checked)"
|
|
356
|
+
/>
|
|
357
|
+
<span class="flex min-w-0 flex-col gap-xxs">
|
|
358
|
+
<span class="text-body-sm font-medium text-fg">{{ optionLabel(opt) }}</span>
|
|
359
|
+
@if (optionDescription(opt); as desc) {
|
|
360
|
+
<span class="text-body-xs text-muted">{{ desc }}</span>
|
|
361
|
+
}
|
|
362
|
+
</span>
|
|
363
|
+
@if (isCardsLayout()) {
|
|
364
|
+
<span
|
|
365
|
+
class="ms-auto hidden shrink-0 text-fg-primary peer-checked:inline-flex"
|
|
366
|
+
>
|
|
367
|
+
<dga-icon name="checkCircle" size="sm" tone="primary" />
|
|
368
|
+
</span>
|
|
369
|
+
}
|
|
370
|
+
</label>
|
|
371
|
+
}
|
|
372
|
+
</div>
|
|
338
373
|
}
|
|
339
374
|
</div>
|
|
340
375
|
}
|
|
@@ -367,7 +402,7 @@ import*as l from"@angular/core";import{InjectionToken as y,inject as c,Injectabl
|
|
|
367
402
|
}
|
|
368
403
|
</dga-field>
|
|
369
404
|
}
|
|
370
|
-
`,isInline:!0,dependencies:[{kind:"ngmodule",type:O},{kind:"directive",type:
|
|
405
|
+
`,isInline:!0,dependencies:[{kind:"ngmodule",type:O},{kind:"directive",type:b.DefaultValueAccessor,selector:"input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]"},{kind:"directive",type:b.RadioControlValueAccessor,selector:"input[type=radio]:not([ngNoCva])[formControlName],input[type=radio]:not([ngNoCva])[formControl],input[type=radio]:not([ngNoCva])[ngModel]",inputs:["name","formControlName","value"]},{kind:"directive",type:b.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:b.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:b.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"ngmodule",type:ie},{kind:"component",type:re,selector:"dga-field",inputs:["label","labelHint","hint","error","status","statusMessage","controlId","required"]},{kind:"directive",type:le,selector:"input[dgaInput], textarea[dgaInput]",inputs:["size","dgaInvalid","status"]},{kind:"component",type:se,selector:"dga-select",inputs:["options","value","multiple","searchable","openMode","clearable","size","status","placeholder","label","removeLabel","clearLabel","emptyLabel","disabled","dgaInvalid"],outputs:["valueChange","searchChange"]},{kind:"directive",type:de,selector:'input[type="checkbox"][dgaCheckbox]',inputs:["size","dgaInvalid"]},{kind:"directive",type:ce,selector:'input[type="radio"][dgaRadio]',inputs:["size","dgaInvalid"]},{kind:"component",type:ue,selector:"dga-phone-input",inputs:["countries","locale","countryCode","nationalNumber","controlId","name","placeholder","autocomplete","codeLabel","disabled","required","invalid","value"],outputs:["countryCodeChange","nationalNumberChange","valueChange"]},{kind:"component",type:Se,selector:"dga-date-picker",inputs:["value","startValue","endValue","calendar","range","format","mode","locale","minDate","maxDate","yearBefore","yearAfter","placeholder","controlId","name","size","disabled","required","clearable","editable","dgaInvalid","status","rangeSeparator","todayLabel","clearLabel","closeLabel","saveLabel","ariaLabel"],outputs:["startValueChange","endValueChange","valueChange","rangeChange"]},{kind:"component",type:pe,selector:"dga-chip-input",inputs:["value","placeholder","label","removeLabel","disabled","allowDuplicates","dgaInvalid","status"],outputs:["valueChange"]},{kind:"component",type:fe,selector:"dga-switch",inputs:["checked","size","label","disabled"],outputs:["checkedChange","changed"]},{kind:"component",type:me,selector:"dga-upload",inputs:["files","accept","multiple","appearance","hint","browseLabel","removeLabel","disabled","maxSize","maxFiles","dragging"],outputs:["filesChange","rejected","draggingChange"]},{kind:"component",type:ge,selector:"dga-number-input",inputs:["value","min","max","step","size","label","controlId","name","incrementLabel","decrementLabel","disabled","dgaInvalid","status"],outputs:["valueChange"]},{kind:"component",type:he,selector:"dga-otp",inputs:["length","value","label","alphanumeric","disabled","dgaInvalid"],outputs:["valueChange","completed"]},{kind:"component",type:C,selector:"dga-icon",inputs:["name","glyph","size","tone","label"]},{kind:"component",type:y,selector:"dga-dynamic-form-staged-upload",inputs:["accept","maxFileSize","maxFiles","uploadEndpoint","deleteEndpoint","deleteMethod","hint","browseLabel","removeLabel","downloadLabel","uploadingLabel","errorLabel","disabled"],outputs:["fileDownload"]}],changeDetection:l.ChangeDetectionStrategy.OnPush})}l.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"22.1.5",ngImport:l,type:w,decorators:[{type:V,args:[{selector:"dga-dynamic-form-field",standalone:!0,imports:[O,ie,re,le,se,de,ce,ue,Se,pe,fe,me,ge,he,C,y],template:`
|
|
371
406
|
@if (field().type !== 'hidden') {
|
|
372
407
|
<dga-field
|
|
373
408
|
[label]="labelText()"
|
|
@@ -420,6 +455,8 @@ import*as l from"@angular/core";import{InjectionToken as y,inject as c,Injectabl
|
|
|
420
455
|
[disabled]="!!field().disabled"
|
|
421
456
|
[required]="required()"
|
|
422
457
|
[controlId]="controlId"
|
|
458
|
+
[locale]="locale()"
|
|
459
|
+
[countries]="phoneCountries()"
|
|
423
460
|
/>
|
|
424
461
|
}
|
|
425
462
|
@case ('date') {
|
|
@@ -510,44 +547,77 @@ import*as l from"@angular/core";import{InjectionToken as y,inject as c,Injectabl
|
|
|
510
547
|
/>
|
|
511
548
|
}
|
|
512
549
|
@case ('radio') {
|
|
513
|
-
<div
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
550
|
+
<div class="flex flex-col gap-lg" role="radiogroup" [attr.aria-labelledby]="controlId">
|
|
551
|
+
@for (group of optionGroups(); track $index) {
|
|
552
|
+
@if (group.label) {
|
|
553
|
+
<p class="m-0 text-label-sm font-medium text-muted">{{ group.label }}</p>
|
|
554
|
+
}
|
|
555
|
+
<div [class]="optionsContainerClass()">
|
|
556
|
+
@for (opt of group.options; track opt.value) {
|
|
557
|
+
<label [class]="choiceLabelClass(opt)">
|
|
558
|
+
<input
|
|
559
|
+
type="radio"
|
|
560
|
+
dgaRadio
|
|
561
|
+
class="peer mt-xxs"
|
|
562
|
+
[name]="field().name"
|
|
563
|
+
[value]="opt.value"
|
|
564
|
+
[formControl]="control"
|
|
565
|
+
[disabled]="!!opt.disabled || !!field().disabled"
|
|
566
|
+
[dgaInvalid]="!!error()"
|
|
567
|
+
/>
|
|
568
|
+
<span class="flex min-w-0 flex-col gap-xxs">
|
|
569
|
+
<span class="text-body-sm font-medium text-fg">{{ optionLabel(opt) }}</span>
|
|
570
|
+
@if (optionDescription(opt); as desc) {
|
|
571
|
+
<span class="text-body-xs text-muted">{{ desc }}</span>
|
|
572
|
+
}
|
|
573
|
+
</span>
|
|
574
|
+
@if (isCardsLayout()) {
|
|
575
|
+
<span
|
|
576
|
+
class="ms-auto hidden shrink-0 text-fg-primary peer-checked:inline-flex"
|
|
577
|
+
>
|
|
578
|
+
<dga-icon name="checkCircle" size="sm" tone="primary" />
|
|
579
|
+
</span>
|
|
580
|
+
}
|
|
581
|
+
</label>
|
|
582
|
+
}
|
|
583
|
+
</div>
|
|
531
584
|
}
|
|
532
585
|
</div>
|
|
533
586
|
}
|
|
534
587
|
@case ('checkbox') {
|
|
535
|
-
<div
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
<
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
588
|
+
<div class="flex flex-col gap-lg">
|
|
589
|
+
@for (group of optionGroups(); track $index) {
|
|
590
|
+
@if (group.label) {
|
|
591
|
+
<p class="m-0 text-label-sm font-medium text-muted">{{ group.label }}</p>
|
|
592
|
+
}
|
|
593
|
+
<div [class]="optionsContainerClass()">
|
|
594
|
+
@for (opt of group.options; track opt.value) {
|
|
595
|
+
<label [class]="choiceLabelClass(opt)">
|
|
596
|
+
<input
|
|
597
|
+
type="checkbox"
|
|
598
|
+
dgaCheckbox
|
|
599
|
+
class="peer mt-xxs"
|
|
600
|
+
[checked]="isChecked(opt.value)"
|
|
601
|
+
[disabled]="!!opt.disabled || !!field().disabled"
|
|
602
|
+
[dgaInvalid]="!!error()"
|
|
603
|
+
(change)="toggleCheckbox(opt.value, $any($event.target).checked)"
|
|
604
|
+
/>
|
|
605
|
+
<span class="flex min-w-0 flex-col gap-xxs">
|
|
606
|
+
<span class="text-body-sm font-medium text-fg">{{ optionLabel(opt) }}</span>
|
|
607
|
+
@if (optionDescription(opt); as desc) {
|
|
608
|
+
<span class="text-body-xs text-muted">{{ desc }}</span>
|
|
609
|
+
}
|
|
610
|
+
</span>
|
|
611
|
+
@if (isCardsLayout()) {
|
|
612
|
+
<span
|
|
613
|
+
class="ms-auto hidden shrink-0 text-fg-primary peer-checked:inline-flex"
|
|
614
|
+
>
|
|
615
|
+
<dga-icon name="checkCircle" size="sm" tone="primary" />
|
|
616
|
+
</span>
|
|
617
|
+
}
|
|
618
|
+
</label>
|
|
619
|
+
}
|
|
620
|
+
</div>
|
|
551
621
|
}
|
|
552
622
|
</div>
|
|
553
623
|
}
|
|
@@ -580,21 +650,107 @@ import*as l from"@angular/core";import{InjectionToken as y,inject as c,Injectabl
|
|
|
580
650
|
}
|
|
581
651
|
</dga-field>
|
|
582
652
|
}
|
|
583
|
-
`,changeDetection:V.OnPush,host:{class:"block w-full","[class.hidden]":'field().type === "hidden"'}}]}],propDecorators:{field:[{type:l.Input,args:[{isSignal:!0,alias:"field",required:!0}]}],form:[{type:l.Input,args:[{isSignal:!0,alias:"form",required:!0}]}],locale:[{type:l.Input,args:[{isSignal:!0,alias:"locale",required:!1}]}],required:[{type:l.Input,args:[{isSignal:!0,alias:"required",required:!1}]}],error:[{type:l.Input,args:[{isSignal:!0,alias:"error",required:!1}]}],runtimeOptions:[{type:l.Input,args:[{isSignal:!0,alias:"runtimeOptions",required:!1}]}],consentBaseUrl:[{type:l.Input,args:[{isSignal:!0,alias:"consentBaseUrl",required:!1}]}],optionsLoaded:[{type:l.Output,args:["optionsLoaded"]}],fileDownload:[{type:l.Output,args:["fileDownload"]}]}});const ct={1:"col-span-1",2:"col-span-2",3:"col-span-3",4:"col-span-4",5:"col-span-5",6:"col-span-6",7:"col-span-7",8:"col-span-8",9:"col-span-9",10:"col-span-10",11:"col-span-11",12:"col-span-12"},pt={1:"md:col-span-1",2:"md:col-span-2",3:"md:col-span-3",4:"md:col-span-4",5:"md:col-span-5",6:"md:col-span-6",7:"md:col-span-7",8:"md:col-span-8",9:"md:col-span-9",10:"md:col-span-10",11:"md:col-span-11",12:"md:col-span-12"},ft={1:"lg:col-span-1",2:"lg:col-span-2",3:"lg:col-span-3",4:"lg:col-span-4",5:"lg:col-span-5",6:"lg:col-span-6",7:"lg:col-span-7",8:"lg:col-span-8",9:"lg:col-span-9",10:"lg:col-span-10",11:"lg:col-span-11",12:"lg:col-span-12"};function H(i){return Number.isFinite(i)?Math.min(12,Math.max(1,Math.round(i))):12}class N{config=u.required(...ngDevMode?[{debugName:"config"}]:[]);localeInput=u(null,{...ngDevMode?{debugName:"localeInput"}:{},alias:"locale"});formSubmitted=g();formError=g();clearButtonClick=g();draftSaved=g();fileDownload=g();fb=c(_e);formService=c(C);submitAdapter=c(E,{optional:!0});toast=c(B,{optional:!0});i18n=c(U,{optional:!0});destroyRef=c(Q);registry=c(L);form;formSignature="";valueChangesSub=null;activeStep=m(0,...ngDevMode?[{debugName:"activeStep"}]:[]);submitting=m(!1,...ngDevMode?[{debugName:"submitting"}]:[]);optionsMap=m({},...ngDevMode?[{debugName:"optionsMap"}]:[]);formValues=m({},...ngDevMode?[{debugName:"formValues"}]:[]);locale=p(()=>this.localeInput()??Te(),...ngDevMode?[{debugName:"locale"}]:[]);wizardEnabled=p(()=>!!this.config().wizard?.enabled&&!!this.config().wizard?.steps?.length,...ngDevMode?[{debugName:"wizardEnabled"}]:[]);allFields=p(()=>Le(this.config().fields,this.config().wizard?.steps),...ngDevMode?[{debugName:"allFields"}]:[]);currentStepFields=p(()=>this.wizardEnabled()?this.config().wizard.steps[this.activeStep()]?.fields??[]:this.config().fields,...ngDevMode?[{debugName:"currentStepFields"}]:[]);visibleFields=p(()=>{const e=this.formValues(),t=this.optionsMap(),a=this.allFields(),n=o=>a.find(r=>r.name===o);return this.currentStepFields().filter(o=>W(o,e,r=>t[r],n))},...ngDevMode?[{debugName:"visibleFields"}]:[]);stepperSteps=p(()=>{const e=this.config().wizard?.steps??[],t=this.activeStep(),a=!!this.config().wizard?.allowSkipSteps;return e.map((n,o)=>({label:this.labelOf(n.title),description:n.description?this.labelOf(n.description):void 0,disabled:!a&&o>t}))},...ngDevMode?[{debugName:"stepperSteps"}]:[]);descriptionText=p(()=>this.labelOf(this.config().description),...ngDevMode?[{debugName:"descriptionText"}]:[]);constructor(){this.form=this.fb.group({}),this.destroyRef.onDestroy(()=>this.valueChangesSub?.unsubscribe()),k(()=>{const e=this.allFields(),t=e.map(n=>`${n.name}:${n.type}`).join("|"),a=this.config();q(()=>{if(t===this.formSignature)return;const n=Object.keys(this.form.controls).length?this.form.getRawValue():null,o=this.formSignature==="";this.formSignature=t;const r=Ce(this.fb,e);if(n)r.patchValue(n,{emitEvent:!1});else if(o&&a.formId&&a.enableLocalStorageSave){const f=this.formService.loadDraft(a.formId);f&&r.patchValue(f,{emitEvent:!1})}this.form=r,De(r,e);const s=r.get("password"),d=r.get("confirmPassword");s&&d&&s.valueChanges.pipe(T(this.destroyRef)).subscribe(()=>d.updateValueAndValidity({emitEvent:!1})),o||this.activeStep.set(0),this.formValues.set(r.getRawValue()),this.valueChangesSub?.unsubscribe(),this.valueChangesSub=r.valueChanges.pipe(Ge(r.getRawValue())).subscribe(f=>this.formValues.set(f))})}),k(()=>{const e=this.formValues(),t=this.optionsMap();if(this.form)for(const a of this.allFields()){const n=this.form.get(a.name);if(!n||!a.requiredWhen)continue;const o=this.allFields(),s=K(a,e,d=>t[d],d=>o.find(f=>f.name===d));Fe(n,a,s)}}),k(()=>{const e=this.allFields();q(()=>{if(!this.form)return;const t={};for(const a of e)a.value!==void 0&&(t[a.name]=a.value);Object.keys(t).length&&this.form.patchValue(t,{emitEvent:!1})})}),k(()=>{const e=this.activeStep(),t=this.config().wizard;q(()=>{!t?.steps?.[e]?.initialData||!this.form||this.form.patchValue(t.steps[e].initialData,{emitEvent:!1})})})}labelOf(e){return e?this.i18n?this.i18n.resolveLabel(e,this.locale()):I(e,this.locale()):""}submitLabel(){const e=this.config();return this.wizardEnabled()?this.labelOf(e.wizard?.submitButtonText??e.submitButtonLabel)||(this.locale()==="en"?"Submit":"إرسال"):this.labelOf(e.submitButtonLabel)||(this.locale()==="en"?"Submit":"إرسال")}nextLabel(){return this.labelOf(this.config().wizard?.nextButtonText)||(this.locale()==="en"?"Next":"التالي")}previousLabel(){return this.labelOf(this.config().wizard?.previousButtonText)||(this.locale()==="en"?"Previous":"السابق")}clearLabel(){return this.labelOf(this.config().clearButtonLabel)}saveLabel(){return this.labelOf(this.config().saveButtonLabel??this.config().wizard?.saveButtonText)||(this.locale()==="en"?"Save":"حفظ")}showSave(){const e=this.config();return!!(e.enableLocalStorageSave||e.wizard?.showSaveButton)}isLastStep(){return this.wizardEnabled()?this.activeStep()>=this.config().wizard.steps.length-1:!0}isRequired(e){const t=this.allFields(),a=n=>t.find(o=>o.name===n);return K(e,this.formValues(),n=>this.optionsMap()[n],a)}fieldError(e){const t=this.form?.get(e.name);if(!t||!(t.touched||t.dirty)||!t.errors)return"";const a=t.errors,n=e.validation?.errorMessages,o=this.locale(),r=s=>n?.[s]?this.labelOf(n[s]):"";return a.required?r("required")||(o==="en"?"Required":"مطلوب"):a.email?r("email")||(o==="en"?"Invalid email":"بريد غير صالح"):a.minlength?r("minLength")||(o==="en"?"Too short":"قصير جداً"):a.maxlength?r("maxLength")||(o==="en"?"Too long":"طويل جداً"):a.pattern?r("pattern")||(o==="en"?"Invalid format":"صيغة غير صالحة"):a.maxChips?r("maxChips")||(o==="en"?"Too many items":"عدد العناصر كبير"):a.invalidFormat?r("invalidFormat")||(o==="en"?"Invalid format":"صيغة غير صالحة"):a.invalidPrefix?r("invalidPrefix")||(o==="en"?"Invalid prefix":"بادئة غير صالحة"):a.invalidLength?r("invalidLength")||(o==="en"?"Invalid length":"طول غير صالح"):a.passwordMismatch?r("passwordMismatch")||(o==="en"?"Passwords do not match":"كلمات المرور غير متطابقة"):a.endDateAfterStartDate?r("endDateAfterStartDate")||(o==="en"?"End date must be after start date":"تاريخ النهاية يجب أن يكون بعد تاريخ البداية"):a.uploadInProgress?r("uploadInProgress")||(o==="en"?"Upload in progress":"جاري رفع الملفات"):a.maxFiles?r("maxFiles")||(o==="en"?"Too many files":"عدد الملفات كبير"):a.minDate?r("minDate")||(o==="en"?"Date is too early":"التاريخ مبكر جداً"):a.maxDate?r("maxDate")||(o==="en"?"Date is too late":"التاريخ متأخر جداً"):o==="en"?"Invalid":"غير صالح"}columnClass(e){const t=e.columns,a=H(t?.sm??t?.md??12),n=H(t?.md??a),o=H(t?.lg??n);return["w-full",ct[a],pt[n],ft[o]].join(" ")}customComponent(e){return this.registry.hasCustom(e.type)?this.registry.get(e.type):null}customInputs(e){return{field:e,form:this.form,locale:this.locale(),required:this.isRequired(e),error:this.fieldError(e)}}onOptionsLoaded(e){this.optionsMap.update(t=>({...t,[e.name]:e.options}))}previousStep(){this.activeStep()>0&&this.activeStep.update(e=>e-1)}canActivateStep=(e,t)=>{if(e<=t)return!0;const a=this.config().wizard;return!a?.allowSkipSteps&&e>t+1?!1:a?.validateOnStepChange===!1?!0:(this.markStepTouched(),this.stepValid())};nextStep(){this.config().wizard?.validateOnStepChange!==!1&&(this.markStepTouched(),!this.stepValid())||this.isLastStep()||(this.activeStep.update(t=>t+1),this.skipEmptyStepsForward())}skipEmptyStepsForward(){const e=this.config().wizard;if(e?.steps)for(;this.activeStep()<e.steps.length-1&&this.visibleFields().length===0;)this.activeStep.update(t=>t+1)}onClear(){this.form.reset();for(const t of this.allFields()){const a=this.form.get(t.name);a&&a.setValue(t.value!==void 0?t.value:["checkbox","multiselect","chips","file","multifile","multifilestaged"].includes(t.type)?[]:t.type==="toggle"?!1:"")}this.activeStep.set(0);const e=this.config().formId;e&&this.formService.clearDraft(e),this.clearButtonClick.emit()}onSaveDraft(){const e=this.form.getRawValue(),t=this.config(),a=t.formId;a&&this.formService.saveDraft(a,e,this.allFields());const n=t.wizard;if(n?.autoSave&&n.saveEndpoint&&this.submitAdapter){const o=this.formService.buildPayload(t,e,this.allFields());this.submitAdapter.submit({endpoint:n.saveEndpoint,method:n.saveMethod??"POST",body:o}).subscribe({error:r=>this.formError.emit(r)})}this.draftSaved.emit(e),this.toast?.show({variant:"success",message:this.locale()==="en"?"Draft saved":"تم حفظ المسودة"})}onSubmit(){if(this.wizardEnabled()&&!this.isLastStep()){this.nextStep();return}if(this.markVisibleTouched(),!this.visibleValid()){this.toast?.show({variant:"error",message:this.locale()==="en"?"Please fix the highlighted fields":"يرجى تصحيح الحقول المحددة"});return}const e=this.config(),t=this.form.getRawValue(),a=new Set(this.collectVisibleFieldNames()),n={};for(const o of this.allFields())!a.has(o.name)&&o.type!=="hidden"||(n[o.name]=t[o.name]);if(e.emitOnly||!e.endpoint){this.formSubmitted.emit(n),this.toast?.show({variant:"success",message:this.labelOf(e.successMessage)||(this.locale()==="en"?"Submitted":"تم الإرسال")});return}this.submitting.set(!0),this.formService.submitForm(e,n,this.allFields()).subscribe({next:o=>{this.submitting.set(!1),this.formSubmitted.emit(o),e.formId&&this.formService.clearDraft(e.formId),this.toast?.show({variant:"success",message:this.labelOf(e.successMessage)||(this.locale()==="en"?"Submitted successfully":"تم الإرسال بنجاح")})},error:o=>{this.submitting.set(!1),this.formError.emit(o),this.toast?.show({variant:"error",message:this.labelOf(e.errorMessage)||(this.locale()==="en"?"Submission failed":"فشل الإرسال")})}})}patchFormValues(e){this.form.patchValue(e)}getForm(){return this.form}markStepTouched(){for(const e of this.visibleFields())this.form.get(e.name)?.markAsTouched()}markVisibleTouched(){for(const e of this.collectVisibleFieldNames())this.form.get(e)?.markAsTouched()}stepValid(){return this.config().wizard?.steps[this.activeStep()]?.optional?!0:this.visibleFields().every(t=>{const a=this.form.get(t.name);return!a||a.disabled||a.valid})}visibleValid(){return this.collectVisibleFieldNames().every(e=>{const t=this.form.get(e);return!t||t.disabled||t.valid})}collectVisibleFieldNames(){const e=this.formValues(),t=this.optionsMap(),a=this.wizardEnabled()?this.allFields():this.config().fields,n=o=>a.find(r=>r.name===o);return a.filter(o=>o.type==="hidden"||W(o,e,r=>t[r],n)).map(o=>o.name)}static ɵfac=l.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.0.7",ngImport:l,type:N,deps:[],target:l.ɵɵFactoryTarget.Component});static ɵcmp=l.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"22.0.7",type:N,isStandalone:!0,selector:"dga-dynamic-form",inputs:{config:{classPropertyName:"config",publicName:"config",isSignal:!0,isRequired:!0,transformFunction:null},localeInput:{classPropertyName:"localeInput",publicName:"locale",isSignal:!0,isRequired:!1,transformFunction:null}},outputs:{formSubmitted:"formSubmitted",formError:"formError",clearButtonClick:"clearButtonClick",draftSaved:"draftSaved",fileDownload:"fileDownload"},host:{classAttribute:"block w-full"},ngImport:l,template:`
|
|
584
|
-
<form
|
|
653
|
+
`,changeDetection:R.OnPush,host:{class:"block w-full","[class.hidden]":'field().type === "hidden"'}}]}],propDecorators:{field:[{type:l.Input,args:[{isSignal:!0,alias:"field",required:!0}]}],form:[{type:l.Input,args:[{isSignal:!0,alias:"form",required:!0}]}],locale:[{type:l.Input,args:[{isSignal:!0,alias:"locale",required:!1}]}],required:[{type:l.Input,args:[{isSignal:!0,alias:"required",required:!1}]}],error:[{type:l.Input,args:[{isSignal:!0,alias:"error",required:!1}]}],runtimeOptions:[{type:l.Input,args:[{isSignal:!0,alias:"runtimeOptions",required:!1}]}],consentBaseUrl:[{type:l.Input,args:[{isSignal:!0,alias:"consentBaseUrl",required:!1}]}],optionsLoaded:[{type:l.Output,args:["optionsLoaded"]}],fileDownload:[{type:l.Output,args:["fileDownload"]}]}});const vt={1:"col-span-1",2:"col-span-2",3:"col-span-3",4:"col-span-4",5:"col-span-5",6:"col-span-6",7:"col-span-7",8:"col-span-8",9:"col-span-9",10:"col-span-10",11:"col-span-11",12:"col-span-12"},yt={1:"md:col-span-1",2:"md:col-span-2",3:"md:col-span-3",4:"md:col-span-4",5:"md:col-span-5",6:"md:col-span-6",7:"md:col-span-7",8:"md:col-span-8",9:"md:col-span-9",10:"md:col-span-10",11:"md:col-span-11",12:"md:col-span-12"},xt={1:"lg:col-span-1",2:"lg:col-span-2",3:"lg:col-span-3",4:"lg:col-span-4",5:"lg:col-span-5",6:"lg:col-span-6",7:"lg:col-span-7",8:"lg:col-span-8",9:"lg:col-span-9",10:"lg:col-span-10",11:"lg:col-span-11",12:"lg:col-span-12"};function Q(i){return Number.isFinite(i)?Math.min(12,Math.max(1,Math.round(i))):12}class F{config=c.required(...ngDevMode?[{debugName:"config"}]:[]);localeInput=c(null,{...ngDevMode?{debugName:"localeInput"}:{},alias:"locale"});formSubmitted=h();formError=h();clearButtonClick=h();draftSaved=h();fileDownload=h();fb=p(Ke);formService=p(I);submitAdapter=p(M,{optional:!0});toast=p($,{optional:!0});i18n=p(G,{optional:!0});destroyRef=p(ee);registry=p(k);form;formSignature="";valueChangesSub=null;activeStep=f(0,...ngDevMode?[{debugName:"activeStep"}]:[]);submitting=f(!1,...ngDevMode?[{debugName:"submitting"}]:[]);draftRestored=f(!1,...ngDevMode?[{debugName:"draftRestored"}]:[]);draftJustSaved=f(!1,...ngDevMode?[{debugName:"draftJustSaved"}]:[]);optionsMap=f({},...ngDevMode?[{debugName:"optionsMap"}]:[]);formValues=f({},...ngDevMode?[{debugName:"formValues"}]:[]);draftSavedTimer=null;locale=u(()=>this.localeInput()??Re(),...ngDevMode?[{debugName:"locale"}]:[]);wizardEnabled=u(()=>!!this.config().wizard?.enabled&&!!this.config().wizard?.steps?.length,...ngDevMode?[{debugName:"wizardEnabled"}]:[]);allFields=u(()=>Ee(this.config().fields,this.config().wizard?.steps),...ngDevMode?[{debugName:"allFields"}]:[]);currentStepFields=u(()=>this.wizardEnabled()?this.config().wizard.steps[this.activeStep()]?.fields??[]:this.config().fields,...ngDevMode?[{debugName:"currentStepFields"}]:[]);visibleFields=u(()=>{const e=this.formValues(),t=this.optionsMap(),a=this.allFields(),n=o=>a.find(r=>r.name===o);return this.currentStepFields().filter(o=>Y(o,e,r=>t[r],n))},...ngDevMode?[{debugName:"visibleFields"}]:[]);stepperSteps=u(()=>{const e=this.config().wizard?.steps??[],t=this.activeStep(),a=!!this.config().wizard?.allowSkipSteps;return e.map((n,o)=>({label:this.labelOf(n.title),disabled:!a&&o>t}))},...ngDevMode?[{debugName:"stepperSteps"}]:[]);descriptionText=u(()=>this.labelOf(this.config().description),...ngDevMode?[{debugName:"descriptionText"}]:[]);currentStep=u(()=>this.wizardEnabled()?this.config().wizard?.steps[this.activeStep()]:void 0,...ngDevMode?[{debugName:"currentStep"}]:[]);currentStepTitle=u(()=>this.labelOf(this.currentStep()?.title),...ngDevMode?[{debugName:"currentStepTitle"}]:[]);currentStepDescription=u(()=>this.labelOf(this.currentStep()?.description),...ngDevMode?[{debugName:"currentStepDescription"}]:[]);currentStepOptional=u(()=>!!this.currentStep()?.optional,...ngDevMode?[{debugName:"currentStepOptional"}]:[]);stepCount=u(()=>this.config().wizard?.steps.length??0,...ngDevMode?[{debugName:"stepCount"}]:[]);stepPercent=u(()=>{const e=this.stepCount();return e?Math.round((this.activeStep()+1)/e*100):0},...ngDevMode?[{debugName:"stepPercent"}]:[]);stepFraction(){return`${this.activeStep()+1}/${this.stepCount()}`}constructor(){this.form=this.fb.group({}),this.destroyRef.onDestroy(()=>{this.valueChangesSub?.unsubscribe(),this.draftSavedTimer&&clearTimeout(this.draftSavedTimer)}),N(()=>{const e=this.allFields(),t=e.map(n=>`${n.name}:${n.type}`).join("|"),a=this.config();q(()=>{if(t===this.formSignature)return;const n=Object.keys(this.form.controls).length?this.form.getRawValue():null,o=this.formSignature==="";this.formSignature=t;const r=Ae(this.fb,e);if(n)r.patchValue(n,{emitEvent:!1});else if(o&&a.formId&&a.enableLocalStorageSave){const g=this.formService.loadDraft(a.formId);g&&(r.patchValue(g,{emitEvent:!1}),this.draftRestored.set(!0))}this.form=r,Te(r,e);const s=r.get("password"),d=r.get("confirmPassword");s&&d&&s.valueChanges.pipe(A(this.destroyRef)).subscribe(()=>d.updateValueAndValidity({emitEvent:!1})),o||this.activeStep.set(0),this.formValues.set(r.getRawValue()),this.valueChangesSub?.unsubscribe(),this.valueChangesSub=r.valueChanges.pipe(Je(r.getRawValue())).subscribe(g=>this.formValues.set(g))})}),N(()=>{const e=this.formValues(),t=this.optionsMap();if(this.form)for(const a of this.allFields()){const n=this.form.get(a.name);if(n)if(a.requiredWhen){const o=this.allFields(),s=J(a,e,d=>t[d],d=>o.find(g=>g.name===d));K(n,a,s)}else a.type==="phone"&&K(n,a,!!(a.required||a.validation?.required))}}),N(()=>{const e=this.allFields();q(()=>{if(!this.form)return;const t={};for(const a of e)a.value!==void 0&&(t[a.name]=a.value);Object.keys(t).length&&this.form.patchValue(t,{emitEvent:!1})})}),N(()=>{const e=this.activeStep(),t=this.config().wizard;q(()=>{!t?.steps?.[e]?.initialData||!this.form||this.form.patchValue(t.steps[e].initialData,{emitEvent:!1})})})}labelOf(e){return e?this.i18n?this.i18n.resolveLabel(e,this.locale()):m(e,this.locale()):""}submitLabel(){const e=this.config();return this.wizardEnabled()?this.labelOf(e.wizard?.submitButtonText??e.submitButtonLabel)||(this.locale()==="en"?"Submit":"إرسال"):this.labelOf(e.submitButtonLabel)||(this.locale()==="en"?"Submit":"إرسال")}nextLabel(){return this.labelOf(this.config().wizard?.nextButtonText)||(this.locale()==="en"?"Next":"التالي")}previousLabel(){return this.labelOf(this.config().wizard?.previousButtonText)||(this.locale()==="en"?"Back":"رجوع")}clearLabel(){return this.labelOf(this.config().clearButtonLabel)}saveLabel(){return this.labelOf(this.config().saveButtonLabel??this.config().wizard?.saveButtonText)||(this.locale()==="en"?"Save as draft":"حفظ كمسودة")}draftSavedLabel(){return this.locale()==="en"?"Draft saved":"تم حفظ المسودة"}draftRestoredTitle(){return this.locale()==="en"?"Draft restored":"تم استعادة المسودة"}draftRestoredBody(){return this.locale()==="en"?"Your previous answers were loaded. You can continue or discard the draft.":"تم تحميل إجاباتك السابقة. يمكنك المتابعة أو حذف المسودة."}discardDraftLabel(){return this.locale()==="en"?"Discard draft":"حذف المسودة"}optionalBadgeLabel(){return this.locale()==="en"?"Optional":"اختياري"}stepProgressLabel(){const e=this.stepCount(),t=this.activeStep()+1;return this.locale()==="en"?`Step ${t} of ${e}`:`الخطوة ${t} من ${e}`}showSave(){const e=this.config();return!!(e.enableLocalStorageSave||e.wizard?.showSaveButton)}isLastStep(){return this.wizardEnabled()?this.activeStep()>=this.config().wizard.steps.length-1:!0}isRequired(e){const t=this.allFields(),a=n=>t.find(o=>o.name===n);return J(e,this.formValues(),n=>this.optionsMap()[n],a)}fieldError(e){const t=this.form?.get(e.name);if(!t||!(t.touched||t.dirty)||!t.errors)return"";const a=t.errors,n=e.validation?.errorMessages,o=this.locale(),r=s=>n?.[s]?this.labelOf(n[s]):"";return a.required?r("required")||(o==="en"?"Required":"مطلوب"):a.email?r("email")||(o==="en"?"Invalid email":"بريد غير صالح"):a.minlength?r("minLength")||(o==="en"?"Too short":"قصير جداً"):a.maxlength?r("maxLength")||(o==="en"?"Too long":"طويل جداً"):a.pattern?r("pattern")||(o==="en"?"Invalid format":"صيغة غير صالحة"):a.maxChips?r("maxChips")||(o==="en"?"Too many items":"عدد العناصر كبير"):a.invalidFormat?r("invalidFormat")||(o==="en"?"Invalid format":"صيغة غير صالحة"):a.invalidPrefix?r("invalidPrefix")||(o==="en"?"Invalid prefix":"بادئة غير صالحة"):a.invalidLength?r("invalidLength")||(o==="en"?"Invalid length":"طول غير صالح"):a.passwordMismatch?r("passwordMismatch")||(o==="en"?"Passwords do not match":"كلمات المرور غير متطابقة"):a.endDateAfterStartDate?r("endDateAfterStartDate")||(o==="en"?"End date must be after start date":"تاريخ النهاية يجب أن يكون بعد تاريخ البداية"):a.uploadInProgress?r("uploadInProgress")||(o==="en"?"Upload in progress":"جاري رفع الملفات"):a.maxFiles?r("maxFiles")||(o==="en"?"Too many files":"عدد الملفات كبير"):a.minDate?r("minDate")||(o==="en"?"Date is too early":"التاريخ مبكر جداً"):a.maxDate?r("maxDate")||(o==="en"?"Date is too late":"التاريخ متأخر جداً"):o==="en"?"Invalid":"غير صالح"}columnClass(e){const t=e.columns,a=Q(t?.sm??t?.md??12),n=Q(t?.md??a),o=Q(t?.lg??n);return["w-full",vt[a],yt[n],xt[o]].join(" ")}customComponent(e){return this.registry.hasCustom(e.type)?this.registry.get(e.type):null}customInputs(e){return{field:e,form:this.form,locale:this.locale(),required:this.isRequired(e),error:this.fieldError(e)}}onOptionsLoaded(e){this.optionsMap.update(t=>({...t,[e.name]:e.options}))}previousStep(){this.activeStep()>0&&this.activeStep.update(e=>e-1)}canActivateStep=(e,t)=>{if(e<=t)return!0;const a=this.config().wizard;return!a?.allowSkipSteps&&e>t+1?!1:a?.validateOnStepChange===!1?!0:(this.markStepTouched(),this.stepValid())};nextStep(){this.config().wizard?.validateOnStepChange!==!1&&(this.markStepTouched(),!this.stepValid())||this.isLastStep()||(this.activeStep.update(t=>t+1),this.skipEmptyStepsForward())}skipEmptyStepsForward(){const e=this.config().wizard;if(e?.steps)for(;this.activeStep()<e.steps.length-1&&this.visibleFields().length===0;)this.activeStep.update(t=>t+1)}onClear(){this.form.reset();for(const t of this.allFields()){const a=this.form.get(t.name);a&&a.setValue(t.value!==void 0?t.value:["checkbox","multiselect","chips","file","multifile","multifilestaged"].includes(t.type)?[]:t.type==="toggle"?!1:"")}this.activeStep.set(0),this.draftRestored.set(!1),this.draftJustSaved.set(!1);const e=this.config().formId;e&&this.formService.clearDraft(e),this.clearButtonClick.emit()}onSaveDraft(){const e=this.form.getRawValue(),t=this.config(),a=t.formId;a&&this.formService.saveDraft(a,e,this.allFields());const n=t.wizard;if(n?.autoSave&&n.saveEndpoint&&this.submitAdapter){const o=this.formService.buildPayload(t,e,this.allFields());this.submitAdapter.submit({endpoint:n.saveEndpoint,method:n.saveMethod??"POST",body:o}).subscribe({error:r=>this.formError.emit(r)})}this.draftSaved.emit(e),this.draftRestored.set(!1),this.draftJustSaved.set(!0),this.draftSavedTimer&&clearTimeout(this.draftSavedTimer),this.draftSavedTimer=setTimeout(()=>this.draftJustSaved.set(!1),2500),this.toast?.show({variant:"success",message:this.locale()==="en"?"Draft saved":"تم حفظ المسودة"})}dismissDraftBanner(){this.draftRestored.set(!1)}onDiscardDraft(){this.draftRestored.set(!1),this.onClear()}onSubmit(){if(this.wizardEnabled()&&!this.isLastStep()){this.nextStep();return}if(this.markVisibleTouched(),!this.visibleValid()){this.toast?.show({variant:"error",message:this.locale()==="en"?"Please fix the highlighted fields":"يرجى تصحيح الحقول المحددة"});return}const e=this.config(),t=this.form.getRawValue(),a=new Set(this.collectVisibleFieldNames()),n={};for(const o of this.allFields())!a.has(o.name)&&o.type!=="hidden"||(n[o.name]=t[o.name]);if(e.emitOnly||!e.endpoint){this.formSubmitted.emit(n),this.toast?.show({variant:"success",message:this.labelOf(e.successMessage)||(this.locale()==="en"?"Submitted":"تم الإرسال")});return}this.submitting.set(!0),this.formService.submitForm(e,n,this.allFields()).subscribe({next:o=>{this.submitting.set(!1),this.formSubmitted.emit(o),e.formId&&this.formService.clearDraft(e.formId),this.toast?.show({variant:"success",message:this.labelOf(e.successMessage)||(this.locale()==="en"?"Submitted successfully":"تم الإرسال بنجاح")})},error:o=>{this.submitting.set(!1),this.formError.emit(o),this.toast?.show({variant:"error",message:this.labelOf(e.errorMessage)||(this.locale()==="en"?"Submission failed":"فشل الإرسال")})}})}patchFormValues(e){this.form.patchValue(e)}getForm(){return this.form}markStepTouched(){for(const e of this.visibleFields())this.form.get(e.name)?.markAsTouched()}markVisibleTouched(){for(const e of this.collectVisibleFieldNames())this.form.get(e)?.markAsTouched()}stepValid(){return this.config().wizard?.steps[this.activeStep()]?.optional?!0:this.visibleFields().every(t=>{const a=this.form.get(t.name);return!a||a.disabled||a.valid})}visibleValid(){return this.collectVisibleFieldNames().every(e=>{const t=this.form.get(e);return!t||t.disabled||t.valid})}collectVisibleFieldNames(){const e=this.formValues(),t=this.optionsMap(),a=this.wizardEnabled()?this.allFields():this.config().fields,n=o=>a.find(r=>r.name===o);return a.filter(o=>o.type==="hidden"||Y(o,e,r=>t[r],n)).map(o=>o.name)}static ɵfac=l.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.1.5",ngImport:l,type:F,deps:[],target:l.ɵɵFactoryTarget.Component});static ɵcmp=l.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"22.1.5",type:F,isStandalone:!0,selector:"dga-dynamic-form",inputs:{config:{classPropertyName:"config",publicName:"config",isSignal:!0,isRequired:!0,transformFunction:null},localeInput:{classPropertyName:"localeInput",publicName:"locale",isSignal:!0,isRequired:!1,transformFunction:null}},outputs:{formSubmitted:"formSubmitted",formError:"formError",clearButtonClick:"clearButtonClick",draftSaved:"draftSaved",fileDownload:"fileDownload"},host:{classAttribute:"block w-full"},ngImport:l,template:`
|
|
654
|
+
<form
|
|
655
|
+
class="flex w-full flex-col"
|
|
656
|
+
[class.gap-2xl]="wizardEnabled()"
|
|
657
|
+
[class.gap-3xl]="!wizardEnabled()"
|
|
658
|
+
[formGroup]="form"
|
|
659
|
+
(ngSubmit)="onSubmit()"
|
|
660
|
+
>
|
|
585
661
|
@if (descriptionText()) {
|
|
586
662
|
<p class="text-body-md text-paragraph">{{ descriptionText() }}</p>
|
|
587
663
|
}
|
|
588
664
|
|
|
589
665
|
@if (wizardEnabled()) {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
666
|
+
@if (draftRestored()) {
|
|
667
|
+
<dga-alert
|
|
668
|
+
variant="info"
|
|
669
|
+
display="inline"
|
|
670
|
+
color
|
|
671
|
+
[title]="draftRestoredTitle()"
|
|
672
|
+
[closeLabel]="locale() === 'en' ? 'Dismiss' : 'إغلاق'"
|
|
673
|
+
dismissible
|
|
674
|
+
(dismissed)="dismissDraftBanner()"
|
|
675
|
+
>
|
|
676
|
+
{{ draftRestoredBody() }}
|
|
677
|
+
<button
|
|
678
|
+
dgaAlertActions
|
|
679
|
+
dgaButton
|
|
680
|
+
type="button"
|
|
681
|
+
variant="ghost"
|
|
682
|
+
size="sm"
|
|
683
|
+
(click)="onDiscardDraft()"
|
|
684
|
+
>
|
|
685
|
+
{{ discardDraftLabel() }}
|
|
686
|
+
</button>
|
|
687
|
+
</dga-alert>
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
<dga-card appearance="outline" padding="lg">
|
|
691
|
+
<div class="flex flex-col gap-2xl">
|
|
692
|
+
<div
|
|
693
|
+
class="flex items-center gap-xl rounded-lg bg-sunken px-xl py-lg"
|
|
694
|
+
>
|
|
695
|
+
<dga-stepper
|
|
696
|
+
class="min-w-0 flex-1"
|
|
697
|
+
[steps]="stepperSteps()"
|
|
698
|
+
[(active)]="activeStep"
|
|
699
|
+
[beforeActiveChange]="canActivateStep"
|
|
700
|
+
[label]="stepProgressLabel()"
|
|
701
|
+
/>
|
|
702
|
+
<div
|
|
703
|
+
class="flex shrink-0 items-center justify-center rounded-full bg-card p-sm shadow-xs"
|
|
704
|
+
>
|
|
705
|
+
<dga-progress
|
|
706
|
+
appearance="radial"
|
|
707
|
+
size="md"
|
|
708
|
+
[value]="stepPercent()"
|
|
709
|
+
[valueText]="stepFraction()"
|
|
710
|
+
[label]="stepProgressLabel()"
|
|
711
|
+
/>
|
|
712
|
+
</div>
|
|
713
|
+
</div>
|
|
714
|
+
|
|
715
|
+
<div class="flex flex-col gap-xl">
|
|
716
|
+
<div class="flex flex-wrap items-start justify-between gap-md">
|
|
717
|
+
<div class="min-w-0 flex-1">
|
|
718
|
+
@if (currentStepTitle()) {
|
|
719
|
+
<h3 class="m-0 text-display-xs font-semibold text-display">
|
|
720
|
+
{{ currentStepTitle() }}
|
|
721
|
+
</h3>
|
|
722
|
+
}
|
|
723
|
+
@if (currentStepDescription()) {
|
|
724
|
+
<p class="m-0 mt-sm text-body-sm text-muted">
|
|
725
|
+
{{ currentStepDescription() }}
|
|
726
|
+
</p>
|
|
727
|
+
}
|
|
728
|
+
</div>
|
|
729
|
+
@if (currentStepOptional()) {
|
|
730
|
+
<dga-badge variant="neutral" size="sm">
|
|
731
|
+
{{ optionalBadgeLabel() }}
|
|
732
|
+
</dga-badge>
|
|
733
|
+
}
|
|
734
|
+
</div>
|
|
735
|
+
<ng-container *ngTemplateOutlet="fieldsTpl" />
|
|
736
|
+
</div>
|
|
737
|
+
</div>
|
|
738
|
+
<div
|
|
739
|
+
dgaCardActions
|
|
740
|
+
class="flex w-full flex-col gap-lg rounded-md bg-sunken px-xl py-lg sm:flex-row sm:items-center"
|
|
741
|
+
>
|
|
742
|
+
<ng-container *ngTemplateOutlet="actionsTpl" />
|
|
743
|
+
</div>
|
|
744
|
+
</dga-card>
|
|
745
|
+
} @else {
|
|
746
|
+
<ng-container *ngTemplateOutlet="fieldsTpl" />
|
|
747
|
+
<div class="flex w-full flex-col gap-lg sm:flex-row sm:items-center">
|
|
748
|
+
<ng-container *ngTemplateOutlet="actionsTpl" />
|
|
749
|
+
</div>
|
|
596
750
|
}
|
|
751
|
+
</form>
|
|
597
752
|
|
|
753
|
+
<ng-template #fieldsTpl>
|
|
598
754
|
<div class="grid grid-cols-12 gap-xl">
|
|
599
755
|
@for (field of visibleFields(); track field.name) {
|
|
600
756
|
<div [class]="columnClass(field)">
|
|
@@ -616,29 +772,22 @@ import*as l from"@angular/core";import{InjectionToken as y,inject as c,Injectabl
|
|
|
616
772
|
</div>
|
|
617
773
|
}
|
|
618
774
|
</div>
|
|
775
|
+
</ng-template>
|
|
619
776
|
|
|
777
|
+
<ng-template #actionsTpl>
|
|
620
778
|
<div class="flex flex-wrap items-center gap-md">
|
|
621
|
-
@if (wizardEnabled()
|
|
779
|
+
@if (wizardEnabled()) {
|
|
622
780
|
<button
|
|
623
781
|
dgaButton
|
|
624
782
|
type="button"
|
|
625
|
-
variant="
|
|
783
|
+
variant="outlineMuted"
|
|
784
|
+
[disabled]="activeStep() === 0"
|
|
626
785
|
(click)="previousStep()"
|
|
627
786
|
>
|
|
787
|
+
<dga-icon name="arrowPrev" size="sm" />
|
|
628
788
|
{{ previousLabel() }}
|
|
629
789
|
</button>
|
|
630
790
|
}
|
|
631
|
-
|
|
632
|
-
@if (wizardEnabled() && !isLastStep()) {
|
|
633
|
-
<button dgaButton type="button" (click)="nextStep()">
|
|
634
|
-
{{ nextLabel() }}
|
|
635
|
-
</button>
|
|
636
|
-
} @else {
|
|
637
|
-
<button dgaButton type="submit" [disabled]="submitting()">
|
|
638
|
-
{{ submitLabel() }}
|
|
639
|
-
</button>
|
|
640
|
-
}
|
|
641
|
-
|
|
642
791
|
@if (config().clearButtonLabel) {
|
|
643
792
|
<button
|
|
644
793
|
dgaButton
|
|
@@ -649,34 +798,133 @@ import*as l from"@angular/core";import{InjectionToken as y,inject as c,Injectabl
|
|
|
649
798
|
{{ clearLabel() }}
|
|
650
799
|
</button>
|
|
651
800
|
}
|
|
801
|
+
</div>
|
|
652
802
|
|
|
803
|
+
<div class="flex flex-wrap items-center gap-md sm:ms-auto">
|
|
653
804
|
@if (showSave()) {
|
|
654
805
|
<button
|
|
655
806
|
dgaButton
|
|
656
807
|
type="button"
|
|
657
|
-
variant="
|
|
808
|
+
variant="ghost"
|
|
658
809
|
(click)="onSaveDraft()"
|
|
659
810
|
>
|
|
660
|
-
|
|
811
|
+
<dga-icon [name]="draftJustSaved() ? 'check' : 'folder'" size="sm" />
|
|
812
|
+
{{ draftJustSaved() ? draftSavedLabel() : saveLabel() }}
|
|
813
|
+
</button>
|
|
814
|
+
}
|
|
815
|
+
@if (wizardEnabled() && !isLastStep()) {
|
|
816
|
+
<button dgaButton type="button" (click)="nextStep()">
|
|
817
|
+
{{ nextLabel() }}
|
|
818
|
+
<dga-icon name="arrowNext" size="sm" />
|
|
819
|
+
</button>
|
|
820
|
+
} @else {
|
|
821
|
+
<button dgaButton type="submit" [disabled]="submitting()" [loading]="submitting()">
|
|
822
|
+
{{ submitLabel() }}
|
|
661
823
|
</button>
|
|
662
824
|
}
|
|
663
825
|
</div>
|
|
664
|
-
</
|
|
665
|
-
`,isInline:!0,dependencies:[{kind:"ngmodule",type:O},{kind:"directive",type:
|
|
666
|
-
<form
|
|
826
|
+
</ng-template>
|
|
827
|
+
`,isInline:!0,dependencies:[{kind:"ngmodule",type:O},{kind:"directive",type:b.ɵNgNoValidate,selector:"form:not([ngNoForm]):not([ngNativeValidate])"},{kind:"directive",type:b.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:b.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"component",type:w,selector:"dga-dynamic-form-field",inputs:["field","form","locale","required","error","runtimeOptions","consentBaseUrl"],outputs:["optionsLoaded","fileDownload"]},{kind:"component",type:be,selector:"dga-alert",inputs:["variant","title","shadow","color","display","dismissible","closeLabel"],outputs:["dismissed"]},{kind:"component",type:ve,selector:"dga-badge",inputs:["variant","size"]},{kind:"directive",type:E,selector:"button[dgaButton], a[dgaButton]",inputs:["variant","size","iconOnly","cooldownMs","loading","dgaButtonClass"]},{kind:"component",type:ye,selector:"dga-card",inputs:["appearance","padding","border","shadow","title","description","titleTruncate","descriptionClamp","icon","iconSize","iconAppearance","badges","badgeSize","primaryLabel","primaryHref","primaryVariant","secondaryLabel","secondaryHref","secondaryVariant","actionSize","actionsAlign","interactive"],outputs:["primaryClick","secondaryClick"]},{kind:"component",type:C,selector:"dga-icon",inputs:["name","glyph","size","tone","label"]},{kind:"component",type:xe,selector:"dga-progress",inputs:["value","size","tone","appearance","showValue","valueText","label"]},{kind:"component",type:De,selector:"dga-stepper",inputs:["steps","active","label","beforeActiveChange"],outputs:["activeChange"]},{kind:"directive",type:te,selector:"[ngComponentOutlet]",inputs:["ngComponentOutlet","ngComponentOutletInputs","ngComponentOutletInjector","ngComponentOutletEnvironmentInjector","ngComponentOutletContent","ngComponentOutletNgModule"],exportAs:["ngComponentOutlet"]},{kind:"directive",type:ae,selector:"[ngTemplateOutlet]",inputs:["ngTemplateOutletContext","ngTemplateOutlet","ngTemplateOutletInjector"]}],changeDetection:l.ChangeDetectionStrategy.OnPush})}l.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"22.1.5",ngImport:l,type:F,decorators:[{type:V,args:[{selector:"dga-dynamic-form",standalone:!0,imports:[O,w,be,ve,E,ye,C,xe,De,te,ae],template:`
|
|
828
|
+
<form
|
|
829
|
+
class="flex w-full flex-col"
|
|
830
|
+
[class.gap-2xl]="wizardEnabled()"
|
|
831
|
+
[class.gap-3xl]="!wizardEnabled()"
|
|
832
|
+
[formGroup]="form"
|
|
833
|
+
(ngSubmit)="onSubmit()"
|
|
834
|
+
>
|
|
667
835
|
@if (descriptionText()) {
|
|
668
836
|
<p class="text-body-md text-paragraph">{{ descriptionText() }}</p>
|
|
669
837
|
}
|
|
670
838
|
|
|
671
839
|
@if (wizardEnabled()) {
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
840
|
+
@if (draftRestored()) {
|
|
841
|
+
<dga-alert
|
|
842
|
+
variant="info"
|
|
843
|
+
display="inline"
|
|
844
|
+
color
|
|
845
|
+
[title]="draftRestoredTitle()"
|
|
846
|
+
[closeLabel]="locale() === 'en' ? 'Dismiss' : 'إغلاق'"
|
|
847
|
+
dismissible
|
|
848
|
+
(dismissed)="dismissDraftBanner()"
|
|
849
|
+
>
|
|
850
|
+
{{ draftRestoredBody() }}
|
|
851
|
+
<button
|
|
852
|
+
dgaAlertActions
|
|
853
|
+
dgaButton
|
|
854
|
+
type="button"
|
|
855
|
+
variant="ghost"
|
|
856
|
+
size="sm"
|
|
857
|
+
(click)="onDiscardDraft()"
|
|
858
|
+
>
|
|
859
|
+
{{ discardDraftLabel() }}
|
|
860
|
+
</button>
|
|
861
|
+
</dga-alert>
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
<dga-card appearance="outline" padding="lg">
|
|
865
|
+
<div class="flex flex-col gap-2xl">
|
|
866
|
+
<div
|
|
867
|
+
class="flex items-center gap-xl rounded-lg bg-sunken px-xl py-lg"
|
|
868
|
+
>
|
|
869
|
+
<dga-stepper
|
|
870
|
+
class="min-w-0 flex-1"
|
|
871
|
+
[steps]="stepperSteps()"
|
|
872
|
+
[(active)]="activeStep"
|
|
873
|
+
[beforeActiveChange]="canActivateStep"
|
|
874
|
+
[label]="stepProgressLabel()"
|
|
875
|
+
/>
|
|
876
|
+
<div
|
|
877
|
+
class="flex shrink-0 items-center justify-center rounded-full bg-card p-sm shadow-xs"
|
|
878
|
+
>
|
|
879
|
+
<dga-progress
|
|
880
|
+
appearance="radial"
|
|
881
|
+
size="md"
|
|
882
|
+
[value]="stepPercent()"
|
|
883
|
+
[valueText]="stepFraction()"
|
|
884
|
+
[label]="stepProgressLabel()"
|
|
885
|
+
/>
|
|
886
|
+
</div>
|
|
887
|
+
</div>
|
|
888
|
+
|
|
889
|
+
<div class="flex flex-col gap-xl">
|
|
890
|
+
<div class="flex flex-wrap items-start justify-between gap-md">
|
|
891
|
+
<div class="min-w-0 flex-1">
|
|
892
|
+
@if (currentStepTitle()) {
|
|
893
|
+
<h3 class="m-0 text-display-xs font-semibold text-display">
|
|
894
|
+
{{ currentStepTitle() }}
|
|
895
|
+
</h3>
|
|
896
|
+
}
|
|
897
|
+
@if (currentStepDescription()) {
|
|
898
|
+
<p class="m-0 mt-sm text-body-sm text-muted">
|
|
899
|
+
{{ currentStepDescription() }}
|
|
900
|
+
</p>
|
|
901
|
+
}
|
|
902
|
+
</div>
|
|
903
|
+
@if (currentStepOptional()) {
|
|
904
|
+
<dga-badge variant="neutral" size="sm">
|
|
905
|
+
{{ optionalBadgeLabel() }}
|
|
906
|
+
</dga-badge>
|
|
907
|
+
}
|
|
908
|
+
</div>
|
|
909
|
+
<ng-container *ngTemplateOutlet="fieldsTpl" />
|
|
910
|
+
</div>
|
|
911
|
+
</div>
|
|
912
|
+
<div
|
|
913
|
+
dgaCardActions
|
|
914
|
+
class="flex w-full flex-col gap-lg rounded-md bg-sunken px-xl py-lg sm:flex-row sm:items-center"
|
|
915
|
+
>
|
|
916
|
+
<ng-container *ngTemplateOutlet="actionsTpl" />
|
|
917
|
+
</div>
|
|
918
|
+
</dga-card>
|
|
919
|
+
} @else {
|
|
920
|
+
<ng-container *ngTemplateOutlet="fieldsTpl" />
|
|
921
|
+
<div class="flex w-full flex-col gap-lg sm:flex-row sm:items-center">
|
|
922
|
+
<ng-container *ngTemplateOutlet="actionsTpl" />
|
|
923
|
+
</div>
|
|
678
924
|
}
|
|
925
|
+
</form>
|
|
679
926
|
|
|
927
|
+
<ng-template #fieldsTpl>
|
|
680
928
|
<div class="grid grid-cols-12 gap-xl">
|
|
681
929
|
@for (field of visibleFields(); track field.name) {
|
|
682
930
|
<div [class]="columnClass(field)">
|
|
@@ -698,29 +946,22 @@ import*as l from"@angular/core";import{InjectionToken as y,inject as c,Injectabl
|
|
|
698
946
|
</div>
|
|
699
947
|
}
|
|
700
948
|
</div>
|
|
949
|
+
</ng-template>
|
|
701
950
|
|
|
951
|
+
<ng-template #actionsTpl>
|
|
702
952
|
<div class="flex flex-wrap items-center gap-md">
|
|
703
|
-
@if (wizardEnabled()
|
|
953
|
+
@if (wizardEnabled()) {
|
|
704
954
|
<button
|
|
705
955
|
dgaButton
|
|
706
956
|
type="button"
|
|
707
|
-
variant="
|
|
957
|
+
variant="outlineMuted"
|
|
958
|
+
[disabled]="activeStep() === 0"
|
|
708
959
|
(click)="previousStep()"
|
|
709
960
|
>
|
|
961
|
+
<dga-icon name="arrowPrev" size="sm" />
|
|
710
962
|
{{ previousLabel() }}
|
|
711
963
|
</button>
|
|
712
964
|
}
|
|
713
|
-
|
|
714
|
-
@if (wizardEnabled() && !isLastStep()) {
|
|
715
|
-
<button dgaButton type="button" (click)="nextStep()">
|
|
716
|
-
{{ nextLabel() }}
|
|
717
|
-
</button>
|
|
718
|
-
} @else {
|
|
719
|
-
<button dgaButton type="submit" [disabled]="submitting()">
|
|
720
|
-
{{ submitLabel() }}
|
|
721
|
-
</button>
|
|
722
|
-
}
|
|
723
|
-
|
|
724
965
|
@if (config().clearButtonLabel) {
|
|
725
966
|
<button
|
|
726
967
|
dgaButton
|
|
@@ -731,17 +972,30 @@ import*as l from"@angular/core";import{InjectionToken as y,inject as c,Injectabl
|
|
|
731
972
|
{{ clearLabel() }}
|
|
732
973
|
</button>
|
|
733
974
|
}
|
|
975
|
+
</div>
|
|
734
976
|
|
|
977
|
+
<div class="flex flex-wrap items-center gap-md sm:ms-auto">
|
|
735
978
|
@if (showSave()) {
|
|
736
979
|
<button
|
|
737
980
|
dgaButton
|
|
738
981
|
type="button"
|
|
739
|
-
variant="
|
|
982
|
+
variant="ghost"
|
|
740
983
|
(click)="onSaveDraft()"
|
|
741
984
|
>
|
|
742
|
-
|
|
985
|
+
<dga-icon [name]="draftJustSaved() ? 'check' : 'folder'" size="sm" />
|
|
986
|
+
{{ draftJustSaved() ? draftSavedLabel() : saveLabel() }}
|
|
987
|
+
</button>
|
|
988
|
+
}
|
|
989
|
+
@if (wizardEnabled() && !isLastStep()) {
|
|
990
|
+
<button dgaButton type="button" (click)="nextStep()">
|
|
991
|
+
{{ nextLabel() }}
|
|
992
|
+
<dga-icon name="arrowNext" size="sm" />
|
|
993
|
+
</button>
|
|
994
|
+
} @else {
|
|
995
|
+
<button dgaButton type="submit" [disabled]="submitting()" [loading]="submitting()">
|
|
996
|
+
{{ submitLabel() }}
|
|
743
997
|
</button>
|
|
744
998
|
}
|
|
745
999
|
</div>
|
|
746
|
-
</
|
|
747
|
-
`,changeDetection:
|
|
1000
|
+
</ng-template>
|
|
1001
|
+
`,changeDetection:R.OnPush,host:{class:"block w-full"}}]}],ctorParameters:()=>[],propDecorators:{config:[{type:l.Input,args:[{isSignal:!0,alias:"config",required:!0}]}],localeInput:[{type:l.Input,args:[{isSignal:!0,alias:"locale",required:!1}]}],formSubmitted:[{type:l.Output,args:["formSubmitted"]}],formError:[{type:l.Output,args:["formError"]}],clearButtonClick:[{type:l.Output,args:["clearButtonClick"]}],draftSaved:[{type:l.Output,args:["draftSaved"]}],fileDownload:[{type:l.Output,args:["fileDownload"]}]}});export{_ as DGA_CAPTCHA_ADAPTER,Le as DGA_DATE_RANGE_PAIRS,Ce as DGA_DYNAMIC_FORM_FIELD_REGISTRY,G as DGA_FORM_I18N_ADAPTER,$ as DGA_FORM_TOAST_ADAPTER,U as DGA_HTTP_SECURITY,B as DGA_LOOKUP_ADAPTER,M as DGA_SUBMIT_ADAPTER,F as DgaDynamicForm,w as DgaDynamicFormField,k as DgaDynamicFormFieldRegistry,I as DgaDynamicFormService,Ue as createDgaToastAdapter,$e as createHttpLookupAdapter,_e as createHttpSubmitAdapter,Ve as defaultFormI18nAdapter,Te as dgaApplyCrossFieldValidators,T as dgaAssertSafeHttpUrl,Ae as dgaBuildFormGroup,W as dgaBuildValidators,Ee as dgaCollectFields,Oe as dgaCreateControl,Ne as dgaDefaultValueForField,Re as dgaDetectLocale,Pe as dgaFindSelectedOption,Y as dgaIsFieldVisible,J as dgaIsRequiredWhen,Ie as dgaPasswordMatchValidator,ke as dgaPhoneFieldValidator,m as dgaResolveLabel,j as dgaSaudiMobileValidator,K as dgaSetControlValidators,Be as emptyLookupAdapter,qe as noopCaptchaAdapter,ht as provideDgaDynamicForm,bt as resolveFormLabel};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@a.nemreen/dga-dynamic-form",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Schema-driven Angular dynamic forms — 18 field types, wizard, cross-field validators (password, Saudi phone, date range), staged uploads, lookup, reCAPTCHA v3, and conditional visibility. Built on @a.nemreen/dga-ui.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
import * as _a_nemreen_dga_dynamic_form from '@a.nemreen/dga-dynamic-form';
|
|
1
2
|
import * as _angular_core from '@angular/core';
|
|
2
3
|
import { InjectionToken, Type, OnInit, EnvironmentProviders } from '@angular/core';
|
|
3
4
|
import { FormGroup, FormControl, FormBuilder, ValidatorFn, AbstractControl, ValidationErrors } from '@angular/forms';
|
|
4
|
-
import { DgaStep, DgaSelectOption, DgaToastService } from '@a.nemreen/dga-ui';
|
|
5
|
+
import { DgaStep, DgaPhoneCountry, DgaSelectOption, DgaToastService } from '@a.nemreen/dga-ui';
|
|
5
6
|
import { Observable } from 'rxjs';
|
|
6
7
|
import { HttpClient } from '@angular/common/http';
|
|
7
8
|
|
|
8
|
-
/**
|
|
9
|
+
/** Localized label (en/ar required for schemas; extra locale keys optional). */
|
|
9
10
|
interface DgaFormLabel {
|
|
10
11
|
en: string;
|
|
11
12
|
ar: string;
|
|
13
|
+
[locale: string]: string;
|
|
12
14
|
}
|
|
13
15
|
interface DgaFormFieldColumns {
|
|
14
16
|
xl?: number;
|
|
@@ -43,6 +45,15 @@ interface DgaStagedFileRef {
|
|
|
43
45
|
listKey?: string;
|
|
44
46
|
}
|
|
45
47
|
type DgaInputRestriction = 'numbers' | 'english' | 'arabic';
|
|
48
|
+
/** Extra dial code for `type: 'phone'` (KSA `+966` is always first). */
|
|
49
|
+
interface DgaFormPhoneCountry {
|
|
50
|
+
/** Dial code including `+`, e.g. `+971`. */
|
|
51
|
+
code: string;
|
|
52
|
+
/** Short prefix-select label. Defaults to `code`. */
|
|
53
|
+
label?: string;
|
|
54
|
+
/** Searchable country name. */
|
|
55
|
+
name?: DgaFormLabel;
|
|
56
|
+
}
|
|
46
57
|
type DgaHttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
47
58
|
interface DgaFormField {
|
|
48
59
|
name: string;
|
|
@@ -100,11 +111,20 @@ interface DgaFormField {
|
|
|
100
111
|
monthPicker?: boolean;
|
|
101
112
|
maxChips?: number;
|
|
102
113
|
allowDuplicates?: boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Extra dial codes for `type: 'phone'`.
|
|
116
|
+
* KSA (`+966`) is always first; duplicate codes are skipped.
|
|
117
|
+
*/
|
|
118
|
+
countries?: DgaFormPhoneCountry[];
|
|
103
119
|
disabled?: boolean;
|
|
104
120
|
readonly?: boolean;
|
|
105
121
|
value?: unknown;
|
|
106
122
|
columns?: DgaFormFieldColumns;
|
|
107
|
-
|
|
123
|
+
/**
|
|
124
|
+
* Radio / checkbox arrangement.
|
|
125
|
+
* `cards` renders each option as a selectable DGA card (title + description).
|
|
126
|
+
*/
|
|
127
|
+
optionsLayout?: 'stack' | 'grid' | 'cards';
|
|
108
128
|
excludeFromPayload?: boolean;
|
|
109
129
|
/**
|
|
110
130
|
* When true, the field value is never written to draft storage.
|
|
@@ -182,7 +202,7 @@ interface DgaDynamicFormConfig {
|
|
|
182
202
|
*/
|
|
183
203
|
consentBaseUrl?: string;
|
|
184
204
|
}
|
|
185
|
-
type DgaFormLocale =
|
|
205
|
+
type DgaFormLocale = string;
|
|
186
206
|
|
|
187
207
|
interface DgaLookupRequest {
|
|
188
208
|
domain: string;
|
|
@@ -216,11 +236,8 @@ interface DgaCaptchaAdapter {
|
|
|
216
236
|
getToken(action?: string): Observable<string | null>;
|
|
217
237
|
}
|
|
218
238
|
interface DgaFormI18nAdapter {
|
|
219
|
-
/** Resolve a
|
|
220
|
-
resolveLabel(label:
|
|
221
|
-
en: string;
|
|
222
|
-
ar: string;
|
|
223
|
-
}, locale: DgaFormLocale): string;
|
|
239
|
+
/** Resolve a localized label for the active locale. */
|
|
240
|
+
resolveLabel(label: DgaFormLabel, locale: DgaFormLocale): string;
|
|
224
241
|
/** Optional free-form key lookup (e.g. ngx-translate). */
|
|
225
242
|
translate?(key: string, locale: DgaFormLocale): string;
|
|
226
243
|
}
|
|
@@ -268,7 +285,7 @@ declare class DgaDynamicFormFieldRegistry {
|
|
|
268
285
|
|
|
269
286
|
declare class DgaDynamicForm {
|
|
270
287
|
readonly config: _angular_core.InputSignal<DgaDynamicFormConfig>;
|
|
271
|
-
readonly localeInput: _angular_core.InputSignal<
|
|
288
|
+
readonly localeInput: _angular_core.InputSignal<string | null>;
|
|
272
289
|
readonly formSubmitted: _angular_core.OutputEmitterRef<unknown>;
|
|
273
290
|
readonly formError: _angular_core.OutputEmitterRef<unknown>;
|
|
274
291
|
readonly clearButtonClick: _angular_core.OutputEmitterRef<void>;
|
|
@@ -286,25 +303,38 @@ declare class DgaDynamicForm {
|
|
|
286
303
|
private valueChangesSub;
|
|
287
304
|
readonly activeStep: _angular_core.WritableSignal<number>;
|
|
288
305
|
readonly submitting: _angular_core.WritableSignal<boolean>;
|
|
306
|
+
readonly draftRestored: _angular_core.WritableSignal<boolean>;
|
|
307
|
+
readonly draftJustSaved: _angular_core.WritableSignal<boolean>;
|
|
289
308
|
readonly optionsMap: _angular_core.WritableSignal<Record<string, DgaFormFieldOption[]>>;
|
|
290
309
|
private readonly formValues;
|
|
291
|
-
|
|
310
|
+
private draftSavedTimer;
|
|
311
|
+
readonly locale: _angular_core.Signal<string>;
|
|
292
312
|
readonly wizardEnabled: _angular_core.Signal<boolean>;
|
|
293
313
|
readonly allFields: _angular_core.Signal<DgaFormField[]>;
|
|
294
314
|
readonly currentStepFields: _angular_core.Signal<DgaFormField[]>;
|
|
295
315
|
readonly visibleFields: _angular_core.Signal<DgaFormField[]>;
|
|
296
316
|
readonly stepperSteps: _angular_core.Signal<DgaStep[]>;
|
|
297
317
|
readonly descriptionText: _angular_core.Signal<string>;
|
|
318
|
+
readonly currentStep: _angular_core.Signal<_a_nemreen_dga_dynamic_form.DgaFormStep | undefined>;
|
|
319
|
+
readonly currentStepTitle: _angular_core.Signal<string>;
|
|
320
|
+
readonly currentStepDescription: _angular_core.Signal<string>;
|
|
321
|
+
readonly currentStepOptional: _angular_core.Signal<boolean>;
|
|
322
|
+
readonly stepCount: _angular_core.Signal<number>;
|
|
323
|
+
readonly stepPercent: _angular_core.Signal<number>;
|
|
324
|
+
stepFraction(): string;
|
|
298
325
|
constructor();
|
|
299
|
-
labelOf(label:
|
|
300
|
-
en: string;
|
|
301
|
-
ar: string;
|
|
302
|
-
} | undefined): string;
|
|
326
|
+
labelOf(label: DgaFormLabel | undefined): string;
|
|
303
327
|
submitLabel(): string;
|
|
304
328
|
nextLabel(): string;
|
|
305
329
|
previousLabel(): string;
|
|
306
330
|
clearLabel(): string;
|
|
307
331
|
saveLabel(): string;
|
|
332
|
+
draftSavedLabel(): string;
|
|
333
|
+
draftRestoredTitle(): string;
|
|
334
|
+
draftRestoredBody(): string;
|
|
335
|
+
discardDraftLabel(): string;
|
|
336
|
+
optionalBadgeLabel(): string;
|
|
337
|
+
stepProgressLabel(): string;
|
|
308
338
|
showSave(): boolean;
|
|
309
339
|
isLastStep(): boolean;
|
|
310
340
|
isRequired(field: DgaFormField): boolean;
|
|
@@ -323,6 +353,8 @@ declare class DgaDynamicForm {
|
|
|
323
353
|
private skipEmptyStepsForward;
|
|
324
354
|
onClear(): void;
|
|
325
355
|
onSaveDraft(): void;
|
|
356
|
+
dismissDraftBanner(): void;
|
|
357
|
+
onDiscardDraft(): void;
|
|
326
358
|
onSubmit(): void;
|
|
327
359
|
/** Imperative helpers for host apps. */
|
|
328
360
|
patchFormValues(values: Record<string, unknown>): void;
|
|
@@ -339,7 +371,7 @@ declare class DgaDynamicForm {
|
|
|
339
371
|
declare class DgaDynamicFormField implements OnInit {
|
|
340
372
|
readonly field: _angular_core.InputSignal<DgaFormField>;
|
|
341
373
|
readonly form: _angular_core.InputSignal<FormGroup<any>>;
|
|
342
|
-
readonly locale: _angular_core.InputSignal<
|
|
374
|
+
readonly locale: _angular_core.InputSignal<string>;
|
|
343
375
|
readonly required: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
344
376
|
readonly error: _angular_core.InputSignal<string>;
|
|
345
377
|
readonly runtimeOptions: _angular_core.InputSignal<DgaFormFieldOption[]>;
|
|
@@ -358,13 +390,23 @@ declare class DgaDynamicFormField implements OnInit {
|
|
|
358
390
|
readonly labelText: _angular_core.Signal<string>;
|
|
359
391
|
readonly hintText: _angular_core.Signal<string>;
|
|
360
392
|
readonly placeholderText: _angular_core.Signal<string>;
|
|
393
|
+
/** Extra dial codes after KSA; empty/invalid entries are dropped. */
|
|
394
|
+
readonly phoneCountries: _angular_core.Signal<DgaPhoneCountry[]>;
|
|
361
395
|
readonly resolvedOptions: _angular_core.Signal<DgaFormFieldOption[]>;
|
|
396
|
+
readonly optionGroups: _angular_core.Signal<{
|
|
397
|
+
label: string;
|
|
398
|
+
options: DgaFormFieldOption[];
|
|
399
|
+
}[]>;
|
|
362
400
|
readonly selectOptions: _angular_core.Signal<DgaSelectOption[]>;
|
|
363
401
|
ngOnInit(): void;
|
|
364
402
|
private mapExistingFileValue;
|
|
365
403
|
private fetchConsent;
|
|
366
404
|
private fetchLookup;
|
|
367
405
|
optionLabel(opt: DgaFormFieldOption): string;
|
|
406
|
+
optionDescription(opt: DgaFormFieldOption): string;
|
|
407
|
+
isCardsLayout(): boolean;
|
|
408
|
+
optionsContainerClass(): string;
|
|
409
|
+
choiceLabelClass(opt: DgaFormFieldOption): string;
|
|
368
410
|
isPasswordField(): boolean;
|
|
369
411
|
isChecked(value: unknown): boolean;
|
|
370
412
|
toggleCheckbox(value: unknown, checked: boolean): void;
|
|
@@ -418,6 +460,13 @@ declare function dgaIsRequiredWhen(field: DgaFormField, values: Record<string, u
|
|
|
418
460
|
/** Known start/end date field pairs used by cross-field validators. */
|
|
419
461
|
declare const DGA_DATE_RANGE_PAIRS: ReadonlyArray<[string, string]>;
|
|
420
462
|
declare function dgaPasswordMatchValidator(passwordControl: AbstractControl): ValidatorFn;
|
|
463
|
+
/**
|
|
464
|
+
* Phone validator used by `type: phone`.
|
|
465
|
+
* KSA numbers keep Saudi mobile rules; extra `countries` codes only require digits.
|
|
466
|
+
*/
|
|
467
|
+
declare function dgaPhoneFieldValidator(extraCountries?: ReadonlyArray<{
|
|
468
|
+
code?: string;
|
|
469
|
+
} | null | undefined>): ValidatorFn;
|
|
421
470
|
/**
|
|
422
471
|
* Saudi mobile validation for type: phone fields.
|
|
423
472
|
* Accepts E.164 (+966…) or national digits (0xxxxxxxx or 5xxxxxxxx).
|
|
@@ -426,7 +475,7 @@ declare function dgaSaudiMobileValidator(control: AbstractControl): ValidationEr
|
|
|
426
475
|
/** Wire password match + date-range validators after form group is built. */
|
|
427
476
|
declare function dgaApplyCrossFieldValidators(form: FormGroup, fields: DgaFormField[]): void;
|
|
428
477
|
|
|
429
|
-
/** Default
|
|
478
|
+
/** Default localized label resolver. */
|
|
430
479
|
declare const defaultFormI18nAdapter: DgaFormI18nAdapter;
|
|
431
480
|
/** No-op captcha (always null token). */
|
|
432
481
|
declare const noopCaptchaAdapter: DgaCaptchaAdapter;
|
|
@@ -467,13 +516,11 @@ interface ProvideDgaDynamicFormOptions {
|
|
|
467
516
|
*/
|
|
468
517
|
declare function provideDgaDynamicForm(options?: ProvideDgaDynamicFormOptions): EnvironmentProviders;
|
|
469
518
|
/** Helper for templates / host apps. */
|
|
470
|
-
declare function resolveFormLabel(label:
|
|
471
|
-
en: string;
|
|
472
|
-
ar: string;
|
|
473
|
-
} | undefined, locale: DgaFormLocale, fallback?: string): string;
|
|
519
|
+
declare function resolveFormLabel(label: DgaFormLabel | undefined, locale: DgaFormLocale, fallback?: string): string;
|
|
474
520
|
|
|
475
|
-
|
|
521
|
+
type LocalizedMap = Partial<Record<string, string>>;
|
|
522
|
+
declare function dgaResolveLabel(label: LocalizedMap | DgaFormLabel | undefined, locale: DgaFormLocale, fallback?: string): string;
|
|
476
523
|
declare function dgaDetectLocale(): DgaFormLocale;
|
|
477
524
|
|
|
478
|
-
export { DGA_CAPTCHA_ADAPTER, DGA_DATE_RANGE_PAIRS, DGA_DYNAMIC_FORM_FIELD_REGISTRY, DGA_FORM_I18N_ADAPTER, DGA_FORM_TOAST_ADAPTER, DGA_HTTP_SECURITY, DGA_LOOKUP_ADAPTER, DGA_SUBMIT_ADAPTER, DgaDynamicForm, DgaDynamicFormField, DgaDynamicFormFieldRegistry, DgaDynamicFormService, createDgaToastAdapter, createHttpLookupAdapter, createHttpSubmitAdapter, defaultFormI18nAdapter, dgaApplyCrossFieldValidators, dgaAssertSafeHttpUrl, dgaBuildFormGroup, dgaBuildValidators, dgaCollectFields, dgaCreateControl, dgaDefaultValueForField, dgaDetectLocale, dgaFindSelectedOption, dgaIsFieldVisible, dgaIsRequiredWhen, dgaPasswordMatchValidator, dgaResolveLabel, dgaSaudiMobileValidator, dgaSetControlValidators, emptyLookupAdapter, noopCaptchaAdapter, provideDgaDynamicForm, resolveFormLabel };
|
|
479
|
-
export type { DgaCaptchaAdapter, DgaDynamicFieldHostContext, DgaDynamicFieldRenderer, DgaDynamicFormConfig, DgaDynamicFormPayloadTransformer, DgaExistingAttachment, DgaFormField, DgaFormFieldColumns, DgaFormFieldOption, DgaFormFieldType, DgaFormI18nAdapter, DgaFormLabel, DgaFormLocale, DgaFormStep, DgaFormToastAdapter, DgaHttpAdapterSecurityOptions, DgaHttpMethod, DgaHttpSecurityOptions, DgaInputRestriction, DgaLookupAdapter, DgaLookupRequest, DgaStagedFileRef, DgaSubmitAdapter, DgaSubmitRequest, DgaToastVariant, DgaWizardConfig, ProvideDgaDynamicFormOptions };
|
|
525
|
+
export { DGA_CAPTCHA_ADAPTER, DGA_DATE_RANGE_PAIRS, DGA_DYNAMIC_FORM_FIELD_REGISTRY, DGA_FORM_I18N_ADAPTER, DGA_FORM_TOAST_ADAPTER, DGA_HTTP_SECURITY, DGA_LOOKUP_ADAPTER, DGA_SUBMIT_ADAPTER, DgaDynamicForm, DgaDynamicFormField, DgaDynamicFormFieldRegistry, DgaDynamicFormService, createDgaToastAdapter, createHttpLookupAdapter, createHttpSubmitAdapter, defaultFormI18nAdapter, dgaApplyCrossFieldValidators, dgaAssertSafeHttpUrl, dgaBuildFormGroup, dgaBuildValidators, dgaCollectFields, dgaCreateControl, dgaDefaultValueForField, dgaDetectLocale, dgaFindSelectedOption, dgaIsFieldVisible, dgaIsRequiredWhen, dgaPasswordMatchValidator, dgaPhoneFieldValidator, dgaResolveLabel, dgaSaudiMobileValidator, dgaSetControlValidators, emptyLookupAdapter, noopCaptchaAdapter, provideDgaDynamicForm, resolveFormLabel };
|
|
526
|
+
export type { DgaCaptchaAdapter, DgaDynamicFieldHostContext, DgaDynamicFieldRenderer, DgaDynamicFormConfig, DgaDynamicFormPayloadTransformer, DgaExistingAttachment, DgaFormField, DgaFormFieldColumns, DgaFormFieldOption, DgaFormFieldType, DgaFormI18nAdapter, DgaFormLabel, DgaFormLocale, DgaFormPhoneCountry, DgaFormStep, DgaFormToastAdapter, DgaHttpAdapterSecurityOptions, DgaHttpMethod, DgaHttpSecurityOptions, DgaInputRestriction, DgaLookupAdapter, DgaLookupRequest, DgaStagedFileRef, DgaSubmitAdapter, DgaSubmitRequest, DgaToastVariant, DgaWizardConfig, ProvideDgaDynamicFormOptions };
|